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>
This commit is contained in:
2026-04-25 00:08:01 -04:00
parent 65b552bb08
commit 7c684a42cc
48450 changed files with 5679671 additions and 383 deletions

155
node_modules/ox/core/Abi.ts generated vendored Normal file
View File

@@ -0,0 +1,155 @@
import * as abitype from 'abitype'
import type * as Errors from './Errors.js'
import * as internal from './internal/abi.js'
import type * as AbiItem_internal from './internal/abiItem.js'
/** Root type for an ABI. */
export type Abi = abitype.Abi
/** @internal */
export function format<const abi extends Abi>(abi: abi): format.ReturnType<abi>
/**
* Formats an {@link ox#Abi.Abi} into a **Human Readable ABI**.
*
* @example
* ```ts twoslash
* import { Abi } from 'ox'
*
* const formatted = Abi.format([{
* type: 'function',
* name: 'approve',
* stateMutability: 'nonpayable',
* inputs: [
* {
* name: 'spender',
* type: 'address',
* },
* {
* name: 'amount',
* type: 'uint256',
* },
* ],
* outputs: [{ type: 'bool' }],
* }])
*
* formatted
* // ^?
*
*
*
* ```
*
* @param abi - The ABI to format.
* @returns The formatted ABI.
*/
export function format(abi: Abi | readonly unknown[]): readonly string[]
/** @internal */
export function format(abi: Abi | readonly unknown[]): format.ReturnType {
return abitype.formatAbi(abi) as never
}
export declare namespace format {
type ReturnType<abi extends Abi | readonly unknown[] = Abi> =
abitype.FormatAbi<abi>
type ErrorType = Errors.GlobalErrorType
}
/** @internal */
export function from<const abi extends Abi | readonly string[]>(
abi: abi &
(abi extends readonly string[]
? AbiItem_internal.Signatures<abi>
: unknown),
): from.ReturnType<abi>
/**
* Parses an arbitrary **JSON ABI** or **Human Readable ABI** into a typed {@link ox#Abi.Abi}.
*
* @example
* ### JSON ABIs
*
* ```ts twoslash
* import { Abi } from 'ox'
*
* const abi = Abi.from([{
* type: 'function',
* name: 'approve',
* stateMutability: 'nonpayable',
* inputs: [
* {
* name: 'spender',
* type: 'address',
* },
* {
* name: 'amount',
* type: 'uint256',
* },
* ],
* outputs: [{ type: 'bool' }],
* }])
*
* abi
* //^?
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
* ```
*
* @example
* ### Human Readable ABIs
*
* ```ts twoslash
* import { Abi } from 'ox'
*
* const abi = Abi.from([
* 'function approve(address spender, uint256 amount) returns (bool)'
* ])
*
* abi
* //^?
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
* ```
*
* @param abi - The ABI to parse.
* @returns The typed ABI.
*/
export function from(abi: Abi | readonly string[]): Abi
/** @internal */
export function from(abi: Abi | readonly string[]): from.ReturnType {
if (internal.isSignatures(abi)) return abitype.parseAbi(abi)
return abi
}
export declare namespace from {
type ReturnType<
abi extends Abi | readonly string[] | readonly unknown[] = Abi,
> = abi extends readonly string[] ? abitype.ParseAbi<abi> : abi
type ErrorType = Errors.GlobalErrorType
}

393
node_modules/ox/core/AbiConstructor.ts generated vendored Normal file
View File

@@ -0,0 +1,393 @@
import * as abitype from 'abitype'
import type * as Abi from './Abi.js'
import * as AbiItem from './AbiItem.js'
import * as AbiParameters from './AbiParameters.js'
import type * as Errors from './Errors.js'
import * as Hex from './Hex.js'
import type * as internal from './internal/abiConstructor.js'
import type { IsNarrowable } from './internal/types.js'
/** Root type for an {@link ox#AbiItem.AbiItem} with a `constructor` type. */
export type AbiConstructor = abitype.AbiConstructor
/** @internal */
export function decode<const abiConstructor extends AbiConstructor>(
abiConstructor: abiConstructor,
options: decode.Options,
): decode.ReturnType<abiConstructor>
/**
* ABI-decodes the provided constructor input (`inputs`).
*
* @example
* ```ts twoslash
* import { AbiConstructor } from 'ox'
*
* const constructor = AbiConstructor.from('constructor(address, uint256)')
*
* const bytecode = '0x...'
*
* const data = AbiConstructor.encode(constructor, {
* bytecode,
* args: ['0xd8da6bf26964af9d7eed9e03e53415d37aa96045', 123n],
* })
*
* const decoded = AbiConstructor.decode(constructor, { // [!code focus]
* bytecode, // [!code focus]
* data, // [!code focus]
* }) // [!code focus]
* ```
*
* @param abiConstructor - The ABI Constructor to decode.
* @param options - Decoding options.
* @returns The decoded constructor inputs.
*/
export function decode(
abiConstructor: AbiConstructor,
options: decode.Options,
): readonly unknown[] | undefined
/** @internal */
export function decode(
abiConstructor: AbiConstructor,
options: decode.Options,
): decode.ReturnType {
const { bytecode } = options
if (abiConstructor.inputs.length === 0) return undefined
const data = options.data.replace(bytecode, '0x') as Hex.Hex
return AbiParameters.decode(abiConstructor.inputs, data)
}
export declare namespace decode {
interface Options {
/** The bytecode of the contract. */
bytecode: Hex.Hex
/** The encoded constructor. */
data: Hex.Hex
}
type ReturnType<abiConstructor extends AbiConstructor = AbiConstructor> =
| (abiConstructor['inputs']['length'] extends 0
? undefined
: abitype.AbiParametersToPrimitiveTypes<abiConstructor['inputs']>)
| (IsNarrowable<abiConstructor, AbiConstructor> extends true
? never
: undefined)
type ErrorType = Errors.GlobalErrorType
}
/**
* ABI-encodes the provided constructor input (`inputs`).
*
* @example
* ```ts twoslash
* import { AbiConstructor } from 'ox'
*
* const constructor = AbiConstructor.from('constructor(address, uint256)')
*
* const data = AbiConstructor.encode(constructor, {
* bytecode: '0x...',
* args: ['0xd8da6bf26964af9d7eed9e03e53415d37aa96045', 123n],
* })
* ```
*
* @example
* ### End-to-end
*
* Below is an end-to-end example of using `AbiConstructor.encode` to encode the constructor of a contract and deploy it.
*
* ```ts twoslash
* import 'ox/window'
* import { AbiConstructor, Hex } from 'ox'
*
* // 1. Instantiate the ABI Constructor.
* const constructor = AbiConstructor.from(
* 'constructor(address owner, uint256 amount)',
* )
*
* // 2. Encode the ABI Constructor.
* const data = AbiConstructor.encode(constructor, {
* bytecode: '0x...',
* args: ['0xd8da6bf26964af9d7eed9e03e53415d37aa96045', 123n],
* })
*
* // 3. Deploy the contract.
* const hash = await window.ethereum!.request({
* method: 'eth_sendTransaction',
* params: [{ data }],
* })
* ```
*
* :::note
*
* For simplicity, the above example uses `window.ethereum.request`, but you can use any
* type of JSON-RPC interface.
*
* :::
*
* @param abiConstructor - The ABI Constructor to encode.
* @param options - Encoding options.
* @returns The encoded constructor.
*/
export function encode<const abiConstructor extends AbiConstructor>(
abiConstructor: abiConstructor,
options: encode.Options<abiConstructor>,
): encode.ReturnType {
const { bytecode, args } = options
return Hex.concat(
bytecode,
abiConstructor.inputs?.length && args?.length
? AbiParameters.encode(abiConstructor.inputs, args as readonly unknown[])
: '0x',
)
}
export declare namespace encode {
type Options<
abiConstructor extends AbiConstructor = AbiConstructor,
///
args extends abitype.AbiParametersToPrimitiveTypes<
abiConstructor['inputs']
> = abitype.AbiParametersToPrimitiveTypes<abiConstructor['inputs']>,
> = {
/** The bytecode of the contract. */
bytecode: Hex.Hex
/** The constructor arguments to encode. */
args?: args | undefined
} & (readonly [] extends args
? {}
: {
/** The constructor arguments to encode. */
args: args
})
type ReturnType = Hex.Hex
type ErrorType =
| Hex.concat.ErrorType
| AbiParameters.encode.ErrorType
| Errors.GlobalErrorType
}
/** @internal */
export function format<const abiConstructor extends AbiConstructor>(
abiConstructor: abiConstructor,
): format.ReturnType<abiConstructor>
/**
* Formats an {@link ox#AbiConstructor.AbiConstructor} into a **Human Readable ABI Function**.
*
* @example
* ```ts twoslash
* import { AbiConstructor } from 'ox'
*
* const formatted = AbiConstructor.format({
* inputs: [
* { name: 'owner', type: 'address' },
* ],
* payable: false,
* stateMutability: 'nonpayable',
* type: 'constructor',
* })
*
* formatted
* // ^?
*
*
* ```
*
* @param abiConstructor - The ABI Constructor to format.
* @returns The formatted ABI Constructor.
*/
export function format(abiConstructor: AbiConstructor): string
/** @internal */
export function format(abiConstructor: AbiConstructor): format.ReturnType {
return abitype.formatAbiItem(abiConstructor)
}
export declare namespace format {
type ReturnType<abiConstructor extends AbiConstructor = AbiConstructor> =
abitype.FormatAbiItem<abiConstructor>
type ErrorType = Errors.GlobalErrorType
}
/** @internal */
export function from<
const abiConstructor extends AbiConstructor | string | readonly string[],
>(
abiConstructor: (abiConstructor | string | readonly string[]) &
(
| (abiConstructor extends string
? internal.Signature<abiConstructor>
: never)
| (abiConstructor extends readonly string[]
? internal.Signatures<abiConstructor>
: never)
| AbiConstructor
),
): from.ReturnType<abiConstructor>
/**
* Parses an arbitrary **JSON ABI Constructor** or **Human Readable ABI Constructor** into a typed {@link ox#AbiConstructor.AbiConstructor}.
*
* @example
* ### JSON ABIs
*
* ```ts twoslash
* import { AbiConstructor } from 'ox'
*
* const constructor = AbiConstructor.from({
* inputs: [
* { name: 'owner', type: 'address' },
* ],
* payable: false,
* stateMutability: 'nonpayable',
* type: 'constructor',
* })
*
* constructor
* //^?
*
*
*
*
*
*
*
*
*
*
*
*
* ```
*
* @example
* ### Human Readable ABIs
*
* A Human Readable ABI can be parsed into a typed ABI object:
*
* ```ts twoslash
* import { AbiConstructor } from 'ox'
*
* const constructor = AbiConstructor.from(
* 'constructor(address owner)' // [!code hl]
* )
*
* constructor
* //^?
*
*
*
*
*
*
*
*
*
*
*
*
*
* ```
*
* @example
* It is possible to specify `struct`s along with your definitions:
*
* ```ts twoslash
* import { AbiConstructor } from 'ox'
*
* const constructor = AbiConstructor.from([
* 'struct Foo { address owner; uint256 amount; }', // [!code hl]
* 'constructor(Foo foo)',
* ])
*
* constructor
* //^?
*
*
*
*
*
*
*
*
*
*
*
*
* ```
*
*
*
* @param abiConstructor - The ABI Constructor to parse.
* @returns Typed ABI Constructor.
*/
export function from(
abiConstructor: AbiConstructor | string | readonly string[],
): AbiConstructor
/** @internal */
export function from(
abiConstructor: AbiConstructor | string | readonly string[],
): from.ReturnType {
return AbiItem.from(abiConstructor as AbiConstructor)
}
export declare namespace from {
type ReturnType<
abiConstructor extends
| AbiConstructor
| string
| readonly string[] = AbiConstructor,
> = AbiItem.from.ReturnType<abiConstructor>
type ErrorType = AbiItem.from.ErrorType | Errors.GlobalErrorType
}
/** @internal */
export function fromAbi<const abi extends Abi.Abi | readonly unknown[]>(
abi: abi | Abi.Abi | readonly unknown[],
): fromAbi.ReturnType<abi>
/**
* Extracts an {@link ox#AbiConstructor.AbiConstructor} from an {@link ox#Abi.Abi} given a name and optional arguments.
*
* @example
* ### Extracting by Name
*
* ABI Events can be extracted by their name using the `name` option:
*
* ```ts twoslash
* import { Abi, AbiConstructor } from 'ox'
*
* const abi = Abi.from([
* 'constructor(address owner)',
* 'function foo()',
* 'event Transfer(address owner, address to, uint256 tokenId)',
* 'function bar(string a) returns (uint256 x)',
* ])
*
* const item = AbiConstructor.fromAbi(abi) // [!code focus]
* // ^?
*
*
*
*
*
*
* ```
*
* @returns The ABI constructor.
*/
export function fromAbi(abi: Abi.Abi | readonly unknown[]): AbiConstructor
/** @internal */
export function fromAbi(abi: Abi.Abi | readonly unknown[]): fromAbi.ReturnType {
const item = (abi as Abi.Abi).find((item) => item.type === 'constructor')
if (!item) throw new AbiItem.NotFoundError({ name: 'constructor' })
return item
}
export declare namespace fromAbi {
type ReturnType<abi extends Abi.Abi | readonly unknown[] = Abi.Abi> = Extract<
abi[number],
{ type: 'constructor' }
>
type ErrorType = AbiItem.NotFoundError | Errors.GlobalErrorType
}

700
node_modules/ox/core/AbiError.ts generated vendored Normal file
View File

@@ -0,0 +1,700 @@
import * as abitype from 'abitype'
import type * as Abi from './Abi.js'
import * as AbiItem from './AbiItem.js'
import * as AbiParameters from './AbiParameters.js'
import type * as Errors from './Errors.js'
import * as Hex from './Hex.js'
import type * as internal from './internal/abiError.js'
import type * as AbiItem_internal from './internal/abiItem.js'
import type { IsNarrowable, IsNever } from './internal/types.js'
/** Root type for an {@link ox#AbiItem.AbiItem} with an `error` type. */
export type AbiError = abitype.AbiError & {
hash?: Hex.Hex | undefined
overloads?: readonly AbiError[] | undefined
}
/** @internal */
export function decode<
const abiError extends AbiError,
as extends 'Object' | 'Array' = 'Array',
>(
abiError: abiError,
data: Hex.Hex,
options?: decode.Options<as> | undefined,
): decode.ReturnType<abiError, as>
/**
* ABI-decodes the provided error input (`inputs`).
*
* :::tip
*
* This function is typically used to decode contract function reverts (e.g. a JSON-RPC error response).
*
* See the [End-to-end Example](#end-to-end).
*
* :::
*
* @example
* ```ts twoslash
* import { AbiError } from 'ox'
*
* const error = AbiError.from('error InvalidSignature(uint r, uint s, uint8 yParity)')
*
* const value = AbiError.decode(error, '0xecde634900000000000000000000000000000000000000000000000000000000000001a400000000000000000000000000000000000000000000000000000000000000450000000000000000000000000000000000000000000000000000000000000001')
* // @log: [420n, 69n, 1]
* ```
*
* @example
* You can extract an ABI Error from a JSON ABI with {@link ox#AbiError.(fromAbi:function)}:
*
* ```ts twoslash
* // @noErrors
* import { Abi, AbiError } from 'ox'
*
* const abi = Abi.from([...]) // [!code hl]
* const error = AbiError.fromAbi(abi, 'InvalidSignature') // [!code hl]
*
* const value = AbiError.decode(error, '0xecde634900000000000000000000000000000000000000000000000000000000000001a400000000000000000000000000000000000000000000000000000000000000450000000000000000000000000000000000000000000000000000000000000001')
* // @log: [420n, 69n, 1]
* ```
*
* @example
* You can pass the error `data` to the `name` property of {@link ox#AbiError.(fromAbi:function)} to extract and infer the error by its 4-byte selector:
*
* ```ts twoslash
* // @noErrors
* import { Abi, AbiError } from 'ox'
*
* const data = '0xecde634900000000000000000000000000000000000000000000000000000000000001a400000000000000000000000000000000000000000000000000000000000000450000000000000000000000000000000000000000000000000000000000000001'
*
* const abi = Abi.from([...])
* const error = AbiError.fromAbi(abi, data) // [!code hl]
*
* const value = AbiError.decode(error, data)
* // @log: [420n, 69n, 1]
* ```
*
* @example
* ### End-to-end
*
* Below is an end-to-end example of using `AbiError.decode` to decode the revert error of an `approve` contract call on the [Wagmi Mint Example contract](https://etherscan.io/address/0xfba3912ca04dd458c843e2ee08967fc04f3579c2).
*
* ```ts twoslash
* // @noErrors
* import 'ox/window'
* import { Abi, AbiError, AbiFunction } from 'ox'
*
* // 1. Extract the Function from the Contract's ABI.
* const abi = Abi.from([
* // ...
* {
* inputs: [
* { name: 'to', type: 'address' },
* { name: 'tokenId', type: 'uint256' },
* ],
* name: 'approve',
* outputs: [],
* stateMutability: 'nonpayable',
* type: 'function',
* },
* // ...
* ])
* const approve = AbiFunction.fromAbi(abi, 'approve')
*
* // 2. Encode the Function Input.
* const data = AbiFunction.encodeData(
* approve,
* ['0xd8da6bf26964af9d7eed9e03e53415d37aa96045', 69420n]
* )
*
* try {
* // 3. Attempt to perform the the Contract Call.
* await window.ethereum!.request({
* method: 'eth_call',
* params: [
* {
* data,
* to: '0xfba3912ca04dd458c843e2ee08967fc04f3579c2',
* },
* ],
* })
* } catch (e) { // [!code focus]
* // 4. Extract and decode the Error. // [!code focus]
* const error = AbiError.fromAbi(abi, e.data) // [!code focus]
* const value = AbiError.decode(error, e.data) // [!code focus]
* console.error(`${error.name}(${value})`) // [!code focus]
* // @error: Error(ERC721: approve caller is not owner nor approved for all)
* } // [!code focus]
* ```
*
* :::note
*
* For simplicity, the above example uses `window.ethereum.request`, but you can use any
* type of JSON-RPC interface.
*
* :::
*
* @param abiError - The ABI Error to decode.
* @param data - The error data.
* @param options - Decoding options.
* @returns The decoded error.
*/
export function decode(
abiError: AbiError,
data: Hex.Hex,
options?: decode.Options | undefined,
): unknown | readonly unknown[] | undefined
/** @internal */
export function decode(
abiError: AbiError,
data: Hex.Hex,
options: decode.Options = {},
): decode.ReturnType {
if (Hex.size(data) < 4) throw new AbiItem.InvalidSelectorSizeError({ data })
if (abiError.inputs.length === 0) return undefined
const values = AbiParameters.decode(
abiError.inputs,
Hex.slice(data, 4),
options,
)
if (values && Object.keys(values).length === 1) {
if (Array.isArray(values)) return values[0]
return Object.values(values)[0]
}
return values
}
export declare namespace decode {
type Options<as extends 'Object' | 'Array' = 'Array'> = {
/**
* Whether the decoded values should be returned as an `Object` or `Array`.
*
* @default "Array"
*/
as?: as | 'Array' | 'Object' | undefined
}
type ReturnType<
abiError extends AbiError = AbiError,
as extends 'Object' | 'Array' = 'Array',
> = IsNarrowable<abiError, AbiError> extends true
? abiError['inputs'] extends readonly []
? undefined
: abiError['inputs'] extends readonly [
infer type extends abitype.AbiParameter,
]
? abitype.AbiParameterToPrimitiveType<type>
: AbiParameters.decode.ReturnType<
abiError['inputs'],
as
> extends infer types
? types extends readonly []
? undefined
: types extends readonly [infer type]
? type
: types
: never
: unknown | readonly unknown[] | undefined
type ErrorType =
| AbiParameters.decode.ErrorType
| Hex.size.ErrorType
| typeof AbiItem.InvalidSelectorSizeError
| Errors.GlobalErrorType
}
/**
* ABI-encodes the provided error input (`inputs`), prefixed with the 4 byte error selector.
*
* @example
* ```ts twoslash
* import { AbiError } from 'ox'
*
* const error = AbiError.from(
* 'error InvalidSignature(uint r, uint s, uint8 yParity)'
* )
*
* const data = AbiError.encode( // [!code focus]
* error, // [!code focus]
* [1n, 2n, 0] // [!code focus]
* ) // [!code focus]
* // @log: '0x095ea7b3000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa960450000000000000000000000000000000000000000000000000000000000010f2c'
* ```
*
* @example
* You can extract an ABI Error from a JSON ABI with {@link ox#AbiError.(fromAbi:function)}:
*
* ```ts twoslash
* // @noErrors
* import { Abi, AbiError } from 'ox'
*
* const abi = Abi.from([ // [!code hl]
* // ... // [!code hl]
* { // [!code hl]
* name: 'InvalidSignature', // [!code hl]
* type: 'error', // [!code hl]
* inputs: [ // [!code hl]
* { name: 'r', type: 'uint256' }, // [!code hl]
* { name: 's', type: 'uint256' }, // [!code hl]
* { name: 'yParity', type: 'uint8' }, // [!code hl]
* ], // [!code hl]
* }, // [!code hl]
* // ... // [!code hl]
* ]) // [!code hl]
* const error = AbiError.fromAbi(abi, 'InvalidSignature') // [!code hl]
*
* const data = AbiError.encode(
* error,
* ['0xd8da6bf26964af9d7eed9e03e53415d37aa96045', 69420n]
* )
* // @log: '0x095ea7b3000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa960450000000000000000000000000000000000000000000000000000000000010f2c'
* ```
*
* @param abiError - ABI Error to encode
* @param args - Error arguments
* @returns ABI-encoded error name and arguments
*/
export function encode<const abiError extends AbiError>(
abiError: abiError,
...args: encode.Args<abiError>
): encode.ReturnType {
const selector = getSelector(abiError)
const data =
args.length > 0
? AbiParameters.encode(abiError.inputs, (args as any)[0])
: undefined
return data ? Hex.concat(selector, data) : selector
}
export declare namespace encode {
type Args<abiError extends AbiError = AbiError> = IsNarrowable<
abiError,
AbiError
> extends true
? abitype.AbiParametersToPrimitiveTypes<
abiError['inputs']
> extends readonly []
? []
: [abitype.AbiParametersToPrimitiveTypes<abiError['inputs']>]
: readonly unknown[]
type ReturnType = Hex.Hex
type ErrorType = Errors.GlobalErrorType
}
/**
* Formats an {@link ox#AbiError.AbiError} into a **Human Readable ABI Error**.
*
* @example
* ```ts twoslash
* import { AbiError } from 'ox'
*
* const formatted = AbiError.format({
* type: 'error',
* name: 'Example',
* inputs: [
* {
* name: 'spender',
* type: 'address',
* },
* {
* name: 'amount',
* type: 'uint256',
* },
* ],
* })
*
* formatted
* // ^?
*
*
* ```
*
* @param abiError - The ABI Error to format.
* @returns The formatted ABI Error.
*/
export function format<const abiError extends AbiError>(
abiError: abiError | AbiError,
): abitype.FormatAbiItem<abiError> {
return abitype.formatAbiItem(abiError) as never
}
export declare namespace format {
type ErrorType = Errors.GlobalErrorType
}
/**
* Parses an arbitrary **JSON ABI Error** or **Human Readable ABI Error** into a typed {@link ox#AbiError.AbiError}.
*
* @example
* ### JSON ABIs
*
* ```ts twoslash
* import { AbiError } from 'ox'
*
* const badSignatureVError = AbiError.from({
* inputs: [{ name: 'v', type: 'uint8' }],
* name: 'BadSignatureV',
* type: 'error',
* })
*
* badSignatureVError
* //^?
*
*
*
*
*
*
*
*
*
*
*
*
* ```
*
* @example
* ### Human Readable ABIs
*
* A Human Readable ABI can be parsed into a typed ABI object:
*
* ```ts twoslash
* import { AbiError } from 'ox'
*
* const badSignatureVError = AbiError.from(
* 'error BadSignatureV(uint8 v)' // [!code hl]
* )
*
* badSignatureVError
* //^?
*
*
*
*
*
*
*
*
*
*
*
*
*
* ```
*
* @example
* It is possible to specify `struct`s along with your definitions:
*
* ```ts twoslash
* import { AbiError } from 'ox'
*
* const badSignatureVError = AbiError.from([
* 'struct Signature { uint8 v; }', // [!code hl]
* 'error BadSignatureV(Signature signature)',
* ])
*
* badSignatureVError
* //^?
*
*
*
*
*
*
*
*
*
*
*
*
* ```
*
*
*
* @param abiError - The ABI Error to parse.
* @returns Typed ABI Error.
*/
export function from<
const abiError extends AbiError | string | readonly string[],
>(
abiError: (abiError | AbiError | string | readonly string[]) &
(
| (abiError extends string ? internal.Signature<abiError> : never)
| (abiError extends readonly string[]
? internal.Signatures<abiError>
: never)
| AbiError
),
options: from.Options = {},
): from.ReturnType<abiError> {
return AbiItem.from(abiError as AbiError, options) as never
}
export declare namespace from {
type Options = {
/**
* Whether or not to prepare the extracted function (optimization for encoding performance).
* When `true`, the `hash` property is computed and included in the returned value.
*
* @default true
*/
prepare?: boolean | undefined
}
type ReturnType<abiError extends AbiError | string | readonly string[]> =
AbiItem.from.ReturnType<abiError>
type ErrorType = AbiItem.from.ErrorType | Errors.GlobalErrorType
}
/**
* Extracts an {@link ox#AbiError.AbiError} from an {@link ox#Abi.Abi} given a name and optional arguments.
*
* @example
* ### Extracting by Name
*
* ABI Errors can be extracted by their name using the `name` option:
*
* ```ts twoslash
* import { Abi, AbiError } from 'ox'
*
* const abi = Abi.from([
* 'function foo()',
* 'error BadSignatureV(uint8 v)',
* 'function bar(string a) returns (uint256 x)',
* ])
*
* const item = AbiError.fromAbi(abi, 'BadSignatureV') // [!code focus]
* // ^?
*
*
*
*
*
*
* ```
*
* @example
* ### Extracting by Selector
*
* ABI Errors can be extract by their selector when {@link ox#Hex.Hex} is provided to `name`.
*
* ```ts twoslash
* import { Abi, AbiError } from 'ox'
*
* const abi = Abi.from([
* 'function foo()',
* 'error BadSignatureV(uint8 v)',
* 'function bar(string a) returns (uint256 x)',
* ])
* const item = AbiError.fromAbi(abi, '0x095ea7b3') // [!code focus]
* // ^?
*
*
*
*
*
*
*
*
*
* ```
*
* :::note
*
* Extracting via a hex selector is useful when extracting an ABI Error from JSON-RPC error data.
*
* :::
*
* @param abi - The ABI to extract from.
* @param name - The name (or selector) of the ABI item to extract.
* @param options - Extraction options.
* @returns The ABI item.
*/
export function fromAbi<
const abi extends Abi.Abi | readonly unknown[],
name extends Name<abi>,
const args extends
| AbiItem_internal.ExtractArgs<abi, name>
| undefined = undefined,
//
allNames = Name<abi>,
>(
abi: abi | Abi.Abi | readonly unknown[],
name: Hex.Hex | (name extends allNames ? name : never),
options?: AbiItem.fromAbi.Options<
abi,
name,
args,
AbiItem_internal.ExtractArgs<abi, name>
>,
): fromAbi.ReturnType<abi, name, args> {
if (name === 'Error') return solidityError as never
if (name === 'Panic') return solidityPanic as never
if (Hex.validate(name, { strict: false })) {
const selector = Hex.slice(name, 0, 4)
if (selector === solidityErrorSelector) return solidityError as never
if (selector === solidityPanicSelector) return solidityPanic as never
}
const item = AbiItem.fromAbi(abi, name, options as any)
if (item.type !== 'error')
throw new AbiItem.NotFoundError({ name, type: 'error' })
return item as never
}
export declare namespace fromAbi {
type ReturnType<
abi extends Abi.Abi | readonly unknown[] = Abi.Abi,
name extends Name<abi> = Name<abi>,
args extends
| AbiItem_internal.ExtractArgs<abi, name>
| undefined = AbiItem_internal.ExtractArgs<abi, name>,
> = IsNarrowable<name, Name<abi>> extends true
?
| (name extends 'Error' ? typeof solidityError : never)
| (name extends 'Panic'
? typeof solidityPanic
: never) extends infer result
? IsNever<result> extends true
? AbiItem.fromAbi.ReturnType<abi, name, args, AbiError>
: result
: never
:
| AbiItem.fromAbi.ReturnType<abi, name, args, AbiError>
| typeof solidityError
| typeof solidityPanic
type ErrorType = AbiItem.fromAbi.ErrorType | Errors.GlobalErrorType
}
/**
* Computes the [4-byte selector](https://solidity-by-example.org/function-selector/) for an {@link ox#AbiError.AbiError}.
*
* @example
* ```ts twoslash
* import { AbiError } from 'ox'
*
* const selector = AbiError.getSelector('error BadSignatureV(uint8 v)')
* // @log: '0x6352211e'
* ```
*
* @example
* ```ts twoslash
* import { AbiError } from 'ox'
*
* const selector = AbiError.getSelector({
* inputs: [{ name: 'v', type: 'uint8' }],
* name: 'BadSignatureV',
* type: 'error'
* })
* // @log: '0x6352211e'
* ```
*
* @param abiItem - The ABI item to compute the selector for.
* @returns The first 4 bytes of the {@link ox#Hash.(keccak256:function)} hash of the error signature.
*/
export function getSelector(abiItem: string | AbiError): Hex.Hex {
return AbiItem.getSelector(abiItem)
}
export declare namespace getSelector {
type ErrorType = AbiItem.getSelector.ErrorType | Errors.GlobalErrorType
}
// https://docs.soliditylang.org/en/v0.8.16/control-structures.html#panic-via-assert-and-error-via-require
export const panicReasons = {
1: 'An `assert` condition failed.',
17: 'Arithmetic operation resulted in underflow or overflow.',
18: 'Division or modulo by zero (e.g. `5 / 0` or `23 % 0`).',
33: 'Attempted to convert to an invalid type.',
34: 'Attempted to access a storage byte array that is incorrectly encoded.',
49: 'Performed `.pop()` on an empty array',
50: 'Array index is out of bounds.',
65: 'Allocated too much memory or created an array which is too large.',
81: 'Attempted to call a zero-initialized variable of internal function type.',
} as Record<number, string>
export const solidityError = /*#__PURE__*/ from({
inputs: [
{
name: 'message',
type: 'string',
},
],
name: 'Error',
type: 'error',
})
export const solidityErrorSelector = '0x08c379a0'
export const solidityPanic = /*#__PURE__*/ from({
inputs: [
{
name: 'reason',
type: 'uint8',
},
],
name: 'Panic',
type: 'error',
})
export const solidityPanicSelector = '0x4e487b71'
/**
* Extracts an {@link ox#AbiError.AbiError} item from an {@link ox#Abi.Abi}, given a name.
*
* @example
* ```ts twoslash
* import { Abi, AbiError } from 'ox'
*
* const abi = Abi.from([
* 'error Foo(string)',
* 'error Bar(uint256)',
* ])
*
* type Foo = AbiError.FromAbi<typeof abi, 'Foo'>
* // ^?
*
*
*
*
*
*
*
*
* ```
*/
export type FromAbi<
abi extends Abi.Abi,
name extends ExtractNames<abi>,
> = abitype.ExtractAbiError<abi, name>
/**
* Extracts the names of all {@link ox#AbiError.AbiError} items in an {@link ox#Abi.Abi}.
*
* @example
* ```ts twoslash
* import { Abi, AbiError } from 'ox'
*
* const abi = Abi.from([
* 'error Foo(string)',
* 'error Bar(uint256)',
* ])
*
* type names = AbiError.Name<typeof abi>
* // ^?
* ```
*/
export type Name<abi extends Abi.Abi | readonly unknown[] = Abi.Abi> =
abi extends Abi.Abi ? ExtractNames<abi> : string
export type ExtractNames<abi extends Abi.Abi> =
| abitype.ExtractAbiErrorNames<abi>
| 'Panic'
| 'Error'

1259
node_modules/ox/core/AbiEvent.ts generated vendored Normal file

File diff suppressed because it is too large Load Diff

794
node_modules/ox/core/AbiFunction.ts generated vendored Normal file
View File

@@ -0,0 +1,794 @@
import * as abitype from 'abitype'
import type * as Abi from './Abi.js'
import * as AbiItem from './AbiItem.js'
import * as AbiParameters from './AbiParameters.js'
import type * as Errors from './Errors.js'
import * as Hex from './Hex.js'
import type * as internal from './internal/abiFunction.js'
import type * as AbiItem_internal from './internal/abiItem.js'
import type * as AbiParameters_internal from './internal/abiParameters.js'
import type { IsNarrowable } from './internal/types.js'
/** Root type for an {@link ox#AbiItem.AbiItem} with a `function` type. */
export type AbiFunction = abitype.AbiFunction & {
hash?: Hex.Hex | undefined
overloads?: readonly AbiFunction[] | undefined
}
/**
* Extracts an {@link ox#AbiFunction.AbiFunction} item from an {@link ox#Abi.Abi}, given a name.
*
* @example
* ```ts twoslash
* import { Abi, AbiFunction } from 'ox'
*
* const abi = Abi.from([
* 'function foo(string)',
* 'function bar(uint256)',
* ])
*
* type Foo = AbiFunction.FromAbi<typeof abi, 'foo'>
* // ^?
*
*
*
*
*
*
*
*
* ```
*/
export type FromAbi<
abi extends Abi.Abi,
name extends ExtractNames<abi>,
> = abitype.ExtractAbiFunction<abi, name>
/**
* Extracts the names of all {@link ox#AbiFunction.AbiFunction} items in an {@link ox#Abi.Abi}.
*
* @example
* ```ts twoslash
* import { Abi, AbiFunction } from 'ox'
*
* const abi = Abi.from([
* 'function foo(string)',
* 'function bar(uint256)',
* ])
*
* type names = AbiFunction.Name<typeof abi>
* // ^?
*
*
* ```
*/
export type Name<abi extends Abi.Abi | readonly unknown[] = Abi.Abi> =
abi extends Abi.Abi ? ExtractNames<abi> : string
export type ExtractNames<
abi extends Abi.Abi,
abiStateMutability extends
abitype.AbiStateMutability = abitype.AbiStateMutability,
> = abitype.ExtractAbiFunctionNames<abi, abiStateMutability>
/**
* ABI-decodes function arguments according to the ABI Item's input types (`inputs`).
*
* @example
* ```ts twoslash
* import { AbiFunction } from 'ox'
*
* const approve = AbiFunction.from('function approve(address, uint256)')
*
* const data = AbiFunction.encodeData(
* approve,
* ['0xd8da6bf26964af9d7eed9e03e53415d37aa96045', 69420n]
* )
* // '0x095ea7b3000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa960450000000000000000000000000000000000000000000000000000000000010f2c'
*
* const input = AbiFunction.decodeData(approve, data) // [!code focus]
* // @log: ['0xd8da6bf26964af9d7eed9e03e53415d37aa96045', 69420n]
* ```
*
* @param abiFunction - The ABI Item to decode.
* @param data - The data to decode.
*/
export function decodeData<const abiItem extends AbiFunction>(
abiFunction: abiItem | AbiFunction,
data: Hex.Hex,
): decodeData.ReturnType<abiItem> {
const { overloads } = abiFunction
if (Hex.size(data) < 4) throw new AbiItem.InvalidSelectorSizeError({ data })
if (abiFunction.inputs.length === 0) return undefined
const item = overloads
? fromAbi([abiFunction, ...overloads], data as never)
: abiFunction
if (Hex.size(data) <= 4) return undefined
return AbiParameters.decode(item.inputs, Hex.slice(data, 4))
}
export declare namespace decodeData {
type ReturnType<abiFunction extends AbiFunction = AbiFunction> = IsNarrowable<
abiFunction,
AbiFunction
> extends true
? abiFunction['inputs'] extends readonly []
? undefined
:
| AbiParameters_internal.ToPrimitiveTypes<abiFunction['inputs']>
| (abiFunction['overloads'] extends readonly AbiFunction[]
? AbiParameters_internal.ToPrimitiveTypes<
abiFunction['overloads'][number]['inputs']
>
: never)
: unknown
type ErrorType =
| fromAbi.ErrorType
| AbiParameters.decode.ErrorType
| Hex.size.ErrorType
| Hex.slice.ErrorType
| Errors.GlobalErrorType
}
/**
* ABI-decodes a function's result according to the ABI Item's output types (`outputs`).
*
* :::tip
*
* This function is typically used to decode contract function return values (e.g. the response of an `eth_call` or the `input` property of a Transaction).
*
* See the [End-to-end Example](#end-to-end).
*
* :::
*
* @example
* ```ts twoslash
* import { AbiFunction } from 'ox'
*
* const data = '0x000000000000000000000000000000000000000000000000000000000000002a'
*
* const totalSupply = AbiFunction.from('function totalSupply() returns (uint256)')
*
* const output = AbiFunction.decodeResult(totalSupply, data)
* // @log: 42n
* ```
*
* @example
* You can extract an ABI Function from a JSON ABI with {@link ox#AbiFunction.(fromAbi:function)}:
*
* ```ts twoslash
* // @noErrors
* import { Abi, AbiFunction } from 'ox'
*
* const data = '0x000000000000000000000000000000000000000000000000000000000000002a'
*
* const erc20Abi = Abi.from([...]) // [!code hl]
* const totalSupply = AbiFunction.fromAbi(erc20Abi, 'totalSupply') // [!code hl]
*
* const output = AbiFunction.decodeResult(totalSupply, data)
* // @log: 42n
* ```
*
* @example
* ### End-to-end
*
* Below is an end-to-end example of using `AbiFunction.decodeResult` to decode the result of a `balanceOf` contract call on the [Wagmi Mint Example contract](https://etherscan.io/address/0xfba3912ca04dd458c843e2ee08967fc04f3579c2).
*
* ```ts twoslash
* import 'ox/window'
* import { Abi, AbiFunction } from 'ox'
*
* // 1. Extract the Function from the Contract's ABI.
* const abi = Abi.from([
* // ...
* {
* name: 'balanceOf',
* type: 'function',
* inputs: [{ name: 'account', type: 'address' }],
* outputs: [{ name: 'balance', type: 'uint256' }],
* stateMutability: 'view',
* },
* // ...
* ])
* const balanceOf = AbiFunction.fromAbi(abi, 'balanceOf')
*
* // 2. Encode the Function Input.
* const data = AbiFunction.encodeData(
* balanceOf,
* ['0xd2135CfB216b74109775236E36d4b433F1DF507B']
* )
*
* // 3. Perform the Contract Call.
* const response = await window.ethereum!.request({
* method: 'eth_call',
* params: [
* {
* data,
* to: '0xfba3912ca04dd458c843e2ee08967fc04f3579c2',
* },
* ],
* })
*
* // 4. Decode the Function Output. // [!code focus]
* const balance = AbiFunction.decodeResult(balanceOf, response) // [!code focus]
* // @log: 42n
* ```
*
* :::note
*
* For simplicity, the above example uses `window.ethereum.request`, but you can use any
* type of JSON-RPC interface.
*
* :::
*
* @param abiFunction - ABI Function to decode
* @param data - ABI-encoded function output
* @param options - Decoding options
* @returns Decoded function output
*/
export function decodeResult<
const abiFunction extends AbiFunction,
as extends 'Object' | 'Array' = 'Array',
>(
abiFunction: abiFunction | AbiFunction,
data: Hex.Hex,
options: decodeResult.Options<as> = {},
): decodeResult.ReturnType<abiFunction, as> {
const values = AbiParameters.decode(abiFunction.outputs, data, options)
if (values && Object.keys(values).length === 0) return undefined
if (values && Object.keys(values).length === 1) {
if (Array.isArray(values)) return values[0]
return Object.values(values)[0]
}
return values
}
export declare namespace decodeResult {
type Options<as extends 'Object' | 'Array'> = {
/**
* Whether the decoded values should be returned as an `Object` or `Array`.
*
* @default "Array"
*/
as?: as | 'Array' | 'Object' | undefined
}
type ReturnType<
abiFunction extends AbiFunction = AbiFunction,
as extends 'Object' | 'Array' = 'Array',
> = IsNarrowable<abiFunction, AbiFunction> extends true
? abiFunction['outputs'] extends readonly []
? undefined
: abiFunction['outputs'] extends readonly [
infer type extends abitype.AbiParameter,
]
? abitype.AbiParameterToPrimitiveType<type>
: AbiParameters.decode.ReturnType<
abiFunction['outputs'],
as
> extends infer types
? types extends readonly []
? undefined
: types extends readonly [infer type]
? type
: types
: never
: unknown
type ErrorType = AbiParameters.decode.ErrorType | Errors.GlobalErrorType
}
/**
* ABI-encodes function arguments (`inputs`), prefixed with the 4 byte function selector.
*
* :::tip
*
* This function is typically used to encode a contract function and its arguments for contract calls (e.g. `data` parameter of an `eth_call` or `eth_sendTransaction`).
*
* See the [End-to-end Example](#end-to-end).
*
* :::
*
* @example
* ```ts twoslash
* import { AbiFunction } from 'ox'
*
* const approve = AbiFunction.from('function approve(address, uint256)')
*
* const data = AbiFunction.encodeData( // [!code focus]
* approve, // [!code focus]
* ['0xd8da6bf26964af9d7eed9e03e53415d37aa96045', 69420n] // [!code focus]
* ) // [!code focus]
* // @log: '0x095ea7b3000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa960450000000000000000000000000000000000000000000000000000000000010f2c'
* ```
*
* @example
* You can extract an ABI Function from a JSON ABI with {@link ox#AbiFunction.(fromAbi:function)}:
*
* ```ts twoslash
* // @noErrors
* import { Abi, AbiFunction } from 'ox'
*
* const erc20Abi = Abi.from([...]) // [!code hl]
* const approve = AbiFunction.fromAbi(erc20Abi, 'approve') // [!code hl]
*
* const data = AbiFunction.encodeData(
* approve,
* ['0xd8da6bf26964af9d7eed9e03e53415d37aa96045', 69420n]
* )
* // @log: '0x095ea7b3000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa960450000000000000000000000000000000000000000000000000000000000010f2c'
* ```
*
* @example
* ### End-to-end
*
* Below is an end-to-end example of using `AbiFunction.encodeData` to encode the input of a `balanceOf` contract call on the [Wagmi Mint Example contract](https://etherscan.io/address/0xfba3912ca04dd458c843e2ee08967fc04f3579c2).
*
* ```ts twoslash
* import 'ox/window'
* import { Abi, AbiFunction } from 'ox'
*
* // 1. Extract the Function from the Contract's ABI.
* const abi = Abi.from([
* // ...
* {
* name: 'balanceOf',
* type: 'function',
* inputs: [{ name: 'account', type: 'address' }],
* outputs: [{ name: 'balance', type: 'uint256' }],
* stateMutability: 'view',
* },
* // ...
* ])
* const balanceOf = AbiFunction.fromAbi(abi, 'balanceOf')
*
* // 2. Encode the Function Input. // [!code focus]
* const data = AbiFunction.encodeData( // [!code focus]
* balanceOf, // [!code focus]
* ['0xd2135CfB216b74109775236E36d4b433F1DF507B'] // [!code focus]
* ) // [!code focus]
*
* // 3. Perform the Contract Call.
* const response = await window.ethereum!.request({
* method: 'eth_call',
* params: [
* {
* data,
* to: '0xfba3912ca04dd458c843e2ee08967fc04f3579c2',
* },
* ],
* })
*
* // 4. Decode the Function Output.
* const balance = AbiFunction.decodeResult(balanceOf, response)
* ```
*
* :::note
*
* For simplicity, the above example uses `window.ethereum.request`, but you can use any
* type of JSON-RPC interface.
*
* :::
*
* @param abiFunction - ABI Function to encode
* @param args - Function arguments
* @returns ABI-encoded function name and arguments
*/
export function encodeData<const abiFunction extends AbiFunction>(
abiFunction: abiFunction | AbiFunction,
...args: encodeData.Args<abiFunction>
): Hex.Hex {
const { overloads } = abiFunction
const item = overloads
? (fromAbi([abiFunction as AbiFunction, ...overloads], abiFunction.name, {
args: (args as any)[0],
}) as AbiFunction)
: abiFunction
const selector = getSelector(item)
const data =
args.length > 0
? AbiParameters.encode(item.inputs, (args as any)[0])
: undefined
return data ? Hex.concat(selector, data) : selector
}
export declare namespace encodeData {
type Args<abiFunction extends AbiFunction = AbiFunction> = IsNarrowable<
abiFunction,
AbiFunction
> extends true
?
| (abitype.AbiParametersToPrimitiveTypes<
abiFunction['inputs']
> extends readonly []
? []
: [abitype.AbiParametersToPrimitiveTypes<abiFunction['inputs']>])
| (abiFunction['overloads'] extends readonly AbiFunction[]
? [
abitype.AbiParametersToPrimitiveTypes<
abiFunction['overloads'][number]['inputs']
>,
]
: [])
: readonly unknown[]
type ErrorType = Errors.GlobalErrorType
}
/**
* ABI-encodes a function's result (`outputs`).
*
* @example
* ```ts twoslash
* import { AbiFunction } from 'ox'
*
* const totalSupply = AbiFunction.from('function totalSupply() returns (uint256)')
* const output = AbiFunction.decodeResult(totalSupply, '0x000000000000000000000000000000000000000000000000000000000000002a')
* // 42n
*
* const data = AbiFunction.encodeResult(totalSupply, 42n) // [!code focus]
* // @log: '0x000000000000000000000000000000000000000000000000000000000000002a'
* ```
*
* @param abiFunction - The ABI item to encode the function output for.
* @param output - The function output to encode.
* @param options - Encoding options.
* @returns The encoded function output.
*/
export function encodeResult<
const abiFunction extends AbiFunction,
as extends 'Object' | 'Array' = 'Array',
>(
abiFunction: abiFunction | AbiFunction,
output: encodeResult.Output<abiFunction, as>,
options: encodeResult.Options<as> = {},
): Hex.Hex {
const { as = 'Array' } = options
const values = (() => {
if (abiFunction.outputs.length === 1) return [output]
if (Array.isArray(output)) return output
if (as === 'Object') return Object.values(output as any)
return [output]
})()
return AbiParameters.encode(abiFunction.outputs, values)
}
export declare namespace encodeResult {
type Output<
abiFunction extends AbiFunction = AbiFunction,
as extends 'Object' | 'Array' = 'Array',
> = abiFunction['outputs'] extends readonly []
? never
: abiFunction['outputs']['length'] extends 1
? AbiParameters_internal.ToPrimitiveTypes<abiFunction['outputs']>[0]
: as extends 'Object'
? AbiParameters_internal.ToObject<abiFunction['outputs']>
: AbiParameters_internal.ToPrimitiveTypes<abiFunction['outputs']>
type Options<as extends 'Object' | 'Array'> = {
as?: as | 'Object' | 'Array' | undefined
}
type ErrorType = AbiParameters.encode.ErrorType | Errors.GlobalErrorType
}
/**
* Formats an {@link ox#AbiFunction.AbiFunction} into a **Human Readable ABI Function**.
*
* @example
* ```ts twoslash
* import { AbiFunction } from 'ox'
*
* const formatted = AbiFunction.format({
* type: 'function',
* name: 'approve',
* stateMutability: 'nonpayable',
* inputs: [
* {
* name: 'spender',
* type: 'address',
* },
* {
* name: 'amount',
* type: 'uint256',
* },
* ],
* outputs: [{ type: 'bool' }],
* })
*
* formatted
* // ^?
*
*
* ```
*
* @param abiFunction - The ABI Function to format.
* @returns The formatted ABI Function.
*/
export function format<const abiFunction extends AbiFunction>(
abiFunction: abiFunction | AbiFunction,
): abitype.FormatAbiItem<abiFunction> {
return abitype.formatAbiItem(abiFunction) as never
}
export declare namespace format {
type ErrorType = Errors.GlobalErrorType
}
/**
* Parses an arbitrary **JSON ABI Function** or **Human Readable ABI Function** into a typed {@link ox#AbiFunction.AbiFunction}.
*
* @example
* ### JSON ABIs
*
* ```ts twoslash
* import { AbiFunction } from 'ox'
*
* const approve = AbiFunction.from({
* type: 'function',
* name: 'approve',
* stateMutability: 'nonpayable',
* inputs: [
* {
* name: 'spender',
* type: 'address',
* },
* {
* name: 'amount',
* type: 'uint256',
* },
* ],
* outputs: [{ type: 'bool' }],
* })
*
* approve
* //^?
*
*
*
*
*
*
*
*
*
*
*
*
* ```
*
* @example
* ### Human Readable ABIs
*
* A Human Readable ABI can be parsed into a typed ABI object:
*
* ```ts twoslash
* import { AbiFunction } from 'ox'
*
* const approve = AbiFunction.from(
* 'function approve(address spender, uint256 amount) returns (bool)' // [!code hl]
* )
*
* approve
* //^?
*
*
*
*
*
*
*
*
*
*
*
*
*
* ```
*
* @example
* It is possible to specify `struct`s along with your definitions:
*
* ```ts twoslash
* import { AbiFunction } from 'ox'
*
* const approve = AbiFunction.from([
* 'struct Foo { address spender; uint256 amount; }', // [!code hl]
* 'function approve(Foo foo) returns (bool)',
* ])
*
* approve
* //^?
*
*
*
*
*
*
*
*
*
*
*
*
* ```
*
*
*
* @param abiFunction - The ABI Function to parse.
* @returns Typed ABI Function.
*/
export function from<
const abiFunction extends AbiFunction | string | readonly string[],
>(
abiFunction: (abiFunction | AbiFunction | string | readonly string[]) &
(
| (abiFunction extends string ? internal.Signature<abiFunction> : never)
| (abiFunction extends readonly string[]
? internal.Signatures<abiFunction>
: never)
| AbiFunction
),
options: from.Options = {},
): from.ReturnType<abiFunction> {
return AbiItem.from(abiFunction as AbiFunction, options) as never
}
export declare namespace from {
type Options = {
/**
* Whether or not to prepare the extracted function (optimization for encoding performance).
* When `true`, the `hash` property is computed and included in the returned value.
*
* @default true
*/
prepare?: boolean | undefined
}
type ReturnType<
abiFunction extends AbiFunction | string | readonly string[],
> = AbiItem.from.ReturnType<abiFunction>
type ErrorType = AbiItem.from.ErrorType | Errors.GlobalErrorType
}
/**
* Extracts an {@link ox#AbiFunction.AbiFunction} from an {@link ox#Abi.Abi} given a name and optional arguments.
*
* @example
* ### Extracting by Name
*
* ABI Functions can be extracted by their name using the `name` option:
*
* ```ts twoslash
* import { Abi, AbiFunction } from 'ox'
*
* const abi = Abi.from([
* 'function foo()',
* 'event Transfer(address owner, address to, uint256 tokenId)',
* 'function bar(string a) returns (uint256 x)',
* ])
*
* const item = AbiFunction.fromAbi(abi, 'foo') // [!code focus]
* // ^?
*
*
*
*
*
*
* ```
*
* @example
* ### Extracting by Selector
*
* ABI Functions can be extract by their selector when {@link ox#Hex.Hex} is provided to `name`.
*
* ```ts twoslash
* import { Abi, AbiFunction } from 'ox'
*
* const abi = Abi.from([
* 'function foo()',
* 'event Transfer(address owner, address to, uint256 tokenId)',
* 'function bar(string a) returns (uint256 x)',
* ])
* const item = AbiFunction.fromAbi(abi, '0x095ea7b3') // [!code focus]
* // ^?
*
*
*
*
*
*
*
*
*
* ```
*
* :::note
*
* Extracting via a hex selector is useful when extracting an ABI Function from an `eth_call` RPC response or
* from a Transaction `input`.
*
* :::
*
* @param abi - The ABI to extract from.
* @param name - The name (or selector) of the ABI item to extract.
* @param options - Extraction options.
* @returns The ABI item.
*/
export function fromAbi<
const abi extends Abi.Abi | readonly unknown[],
name extends Name<abi>,
const args extends
| AbiItem_internal.ExtractArgs<abi, name>
| undefined = undefined,
//
allNames = Name<abi>,
>(
abi: abi | Abi.Abi | readonly unknown[],
name: Hex.Hex | (name extends allNames ? name : never),
options?: AbiItem.fromAbi.Options<
abi,
name,
args,
AbiItem_internal.ExtractArgs<abi, name>
>,
): AbiItem.fromAbi.ReturnType<abi, name, args, AbiFunction> {
const item = AbiItem.fromAbi(abi, name, options as any)
if (item.type !== 'function')
throw new AbiItem.NotFoundError({ name, type: 'function' })
return item as never
}
export declare namespace fromAbi {
type ErrorType = AbiItem.fromAbi.ErrorType | Errors.GlobalErrorType
}
/**
* Computes the [4-byte selector](https://solidity-by-example.org/function-selector/) for an {@link ox#AbiFunction.AbiFunction}.
*
* Useful for computing function selectors for calldata.
*
* @example
* ```ts twoslash
* import { AbiFunction } from 'ox'
*
* const selector = AbiFunction.getSelector('function ownerOf(uint256 tokenId)')
* // @log: '0x6352211e'
* ```
*
* @example
* ```ts twoslash
* import { AbiFunction } from 'ox'
*
* const selector = AbiFunction.getSelector({
* inputs: [{ type: 'uint256' }],
* name: 'ownerOf',
* outputs: [],
* stateMutability: 'view',
* type: 'function'
* })
* // @log: '0x6352211e'
* ```
*
* @param abiItem - The ABI item to compute the selector for.
* @returns The first 4 bytes of the {@link ox#Hash.(keccak256:function)} hash of the function signature.
*/
export function getSelector(abiItem: string | AbiFunction): Hex.Hex {
return AbiItem.getSelector(abiItem)
}
export declare namespace getSelector {
type ErrorType = AbiItem.getSelector.ErrorType | Errors.GlobalErrorType
}

757
node_modules/ox/core/AbiItem.ts generated vendored Normal file
View File

@@ -0,0 +1,757 @@
import * as abitype from 'abitype'
import type * as Abi from './Abi.js'
import * as Errors from './Errors.js'
import * as Hash from './Hash.js'
import * as Hex from './Hex.js'
import * as internal from './internal/abiItem.js'
import type { UnionCompute } from './internal/types.js'
/** Root type for an item on an {@link ox#Abi.Abi}. */
export type AbiItem = Abi.Abi[number]
/**
* Extracts an {@link ox#AbiItem.AbiItem} item from an {@link ox#Abi.Abi}, given a name.
*
* @example
* ```ts twoslash
* import { Abi, AbiItem } from 'ox'
*
* const abi = Abi.from([
* 'error Foo(string)',
* 'function foo(string)',
* 'event Bar(uint256)',
* ])
*
* type Foo = AbiItem.FromAbi<typeof abi, 'Foo'>
* // ^?
*
*
*
*
*
*
*
*
* ```
*/
export type FromAbi<
abi extends Abi.Abi,
name extends ExtractNames<abi>,
> = Extract<abi[number], { name: name }>
/**
* Extracts the names of all {@link ox#AbiItem.AbiItem} items in an {@link ox#Abi.Abi}.
*
* @example
* ```ts twoslash
* import { Abi, AbiItem } from 'ox'
*
* const abi = Abi.from([
* 'error Foo(string)',
* 'function foo(string)',
* 'event Bar(uint256)',
* ])
*
* type names = AbiItem.Name<typeof abi>
* // ^?
*
* ```
*/
export type Name<abi extends Abi.Abi | readonly unknown[] = Abi.Abi> =
abi extends Abi.Abi ? ExtractNames<abi> : string
export type ExtractNames<abi extends Abi.Abi> = Extract<
abi[number],
{ name: string }
>['name']
/**
* Formats an {@link ox#AbiItem.AbiItem} into a **Human Readable ABI Item**.
*
* @example
* ```ts twoslash
* import { AbiItem } from 'ox'
*
* const formatted = AbiItem.format({
* type: 'function',
* name: 'approve',
* stateMutability: 'nonpayable',
* inputs: [
* {
* name: 'spender',
* type: 'address',
* },
* {
* name: 'amount',
* type: 'uint256',
* },
* ],
* outputs: [{ type: 'bool' }],
* })
*
* formatted
* // ^?
*
*
* ```
*
* @param abiItem - The ABI Item to format.
* @returns The formatted ABI Item .
*/
export function format<const abiItem extends AbiItem>(
abiItem: abiItem | AbiItem,
): abitype.FormatAbiItem<abiItem> {
return abitype.formatAbiItem(abiItem) as never
}
export declare namespace format {
type ErrorType = Errors.GlobalErrorType
}
/**
* Parses an arbitrary **JSON ABI Item** or **Human Readable ABI Item** into a typed {@link ox#AbiItem.AbiItem}.
*
* @example
* ### JSON ABIs
*
* ```ts twoslash
* import { AbiItem } from 'ox'
*
* const abiItem = AbiItem.from({
* type: 'function',
* name: 'approve',
* stateMutability: 'nonpayable',
* inputs: [
* {
* name: 'spender',
* type: 'address',
* },
* {
* name: 'amount',
* type: 'uint256',
* },
* ],
* outputs: [{ type: 'bool' }],
* })
*
* abiItem
* //^?
*
*
*
*
*
*
*
*
*
*
*
*
* ```
*
* @example
* ### Human Readable ABIs
*
* A Human Readable ABI can be parsed into a typed ABI object:
*
* ```ts twoslash
* import { AbiItem } from 'ox'
*
* const abiItem = AbiItem.from(
* 'function approve(address spender, uint256 amount) returns (bool)' // [!code hl]
* )
*
* abiItem
* //^?
*
*
*
*
*
*
*
*
*
*
*
*
*
* ```
*
* @example
* It is possible to specify `struct`s along with your definitions:
*
* ```ts twoslash
* import { AbiItem } from 'ox'
*
* const abiItem = AbiItem.from([
* 'struct Foo { address spender; uint256 amount; }', // [!code hl]
* 'function approve(Foo foo) returns (bool)',
* ])
*
* abiItem
* //^?
*
*
*
*
*
*
*
*
*
*
*
*
* ```
*
*
*
* @param abiItem - The ABI Item to parse.
* @returns The typed ABI Item.
*/
export function from<
const abiItem extends AbiItem | string | readonly string[],
>(
abiItem: (abiItem | AbiItem | string | readonly string[]) &
(
| (abiItem extends string ? internal.Signature<abiItem> : never)
| (abiItem extends readonly string[]
? internal.Signatures<abiItem>
: never)
| AbiItem
),
options: from.Options = {},
): from.ReturnType<abiItem> {
const { prepare = true } = options
const item = (() => {
if (Array.isArray(abiItem)) return abitype.parseAbiItem(abiItem)
if (typeof abiItem === 'string')
return abitype.parseAbiItem(abiItem as never)
return abiItem
})() as AbiItem
return {
...item,
...(prepare ? { hash: getSignatureHash(item) } : {}),
} as never
}
export declare namespace from {
type Options = {
/**
* Whether or not to prepare the extracted item (optimization for encoding performance).
* When `true`, the `hash` property is computed and included in the returned value.
*
* @default true
*/
prepare?: boolean | undefined
}
type ReturnType<abiItem extends AbiItem | string | readonly string[]> =
abiItem extends string
? abitype.ParseAbiItem<abiItem>
: abiItem extends readonly string[]
? abitype.ParseAbiItem<abiItem>
: abiItem
type ErrorType = Errors.GlobalErrorType
}
/**
* Extracts an {@link ox#AbiItem.AbiItem} from an {@link ox#Abi.Abi} given a name and optional arguments.
*
* @example
* ABI Items can be extracted by their name using the `name` option:
*
* ```ts twoslash
* import { Abi, AbiItem } from 'ox'
*
* const abi = Abi.from([
* 'function foo()',
* 'event Transfer(address owner, address to, uint256 tokenId)',
* 'function bar(string a) returns (uint256 x)',
* ])
*
* const item = AbiItem.fromAbi(abi, 'Transfer') // [!code focus]
* // ^?
*
*
*
*
*
*
* ```
*
* @example
* ### Extracting by Selector
*
* ABI Items can be extract by their selector when {@link ox#Hex.Hex} is provided to `name`.
*
* ```ts twoslash
* import { Abi, AbiItem } from 'ox'
*
* const abi = Abi.from([
* 'function foo()',
* 'event Transfer(address owner, address to, uint256 tokenId)',
* 'function bar(string a) returns (uint256 x)',
* ])
* const item = AbiItem.fromAbi(abi, '0x095ea7b3') // [!code focus]
* // ^?
*
*
*
*
*
*
*
*
*
*
*
*
*
* ```
*
* :::note
*
* Extracting via a hex selector is useful when extracting an ABI Item from an `eth_call` RPC response,
* a Transaction `input`, or from Event Log `topics`.
*
* :::
*
* @param abi - The ABI to extract from.
* @param name - The name (or selector) of the ABI item to extract.
* @param options - Extraction options.
* @returns The ABI item.
*/
export function fromAbi<
const abi extends Abi.Abi | readonly unknown[],
name extends Name<abi>,
const args extends internal.ExtractArgs<abi, name> | undefined = undefined,
//
allNames = Name<abi>,
>(
abi: abi | Abi.Abi | readonly unknown[],
name: Hex.Hex | (name extends allNames ? name : never),
options?: fromAbi.Options<abi, name, args>,
): fromAbi.ReturnType<abi, name, args> {
const { args = [], prepare = true } = (options ??
{}) as unknown as fromAbi.Options
const isSelector = Hex.validate(name, { strict: false })
const abiItems = (abi as Abi.Abi).filter((abiItem) => {
if (isSelector) {
if (abiItem.type === 'function' || abiItem.type === 'error')
return getSelector(abiItem) === Hex.slice(name, 0, 4)
if (abiItem.type === 'event') return getSignatureHash(abiItem) === name
return false
}
return 'name' in abiItem && abiItem.name === name
})
if (abiItems.length === 0) throw new NotFoundError({ name: name as string })
if (abiItems.length === 1)
return {
...abiItems[0],
...(prepare ? { hash: getSignatureHash(abiItems[0]!) } : {}),
} as never
let matchedAbiItem: AbiItem | undefined = undefined
for (const abiItem of abiItems) {
if (!('inputs' in abiItem)) continue
if (!args || args.length === 0) {
if (!abiItem.inputs || abiItem.inputs.length === 0)
return {
...abiItem,
...(prepare ? { hash: getSignatureHash(abiItem) } : {}),
} as never
continue
}
if (!abiItem.inputs) continue
if (abiItem.inputs.length === 0) continue
if (abiItem.inputs.length !== args.length) continue
const matched = args.every((arg, index) => {
const abiParameter = 'inputs' in abiItem && abiItem.inputs![index]
if (!abiParameter) return false
return internal.isArgOfType(arg, abiParameter)
})
if (matched) {
// Check for ambiguity against already matched parameters (e.g. `address` vs `bytes20`).
if (
matchedAbiItem &&
'inputs' in matchedAbiItem &&
matchedAbiItem.inputs
) {
const ambiguousTypes = internal.getAmbiguousTypes(
abiItem.inputs,
matchedAbiItem.inputs,
args as readonly unknown[],
)
if (ambiguousTypes)
throw new AmbiguityError(
{
abiItem,
type: ambiguousTypes[0]!,
},
{
abiItem: matchedAbiItem,
type: ambiguousTypes[1]!,
},
)
}
matchedAbiItem = abiItem
}
}
const abiItem = (() => {
if (matchedAbiItem) return matchedAbiItem
const [abiItem, ...overloads] = abiItems
return { ...abiItem!, overloads }
})()
if (!abiItem) throw new NotFoundError({ name: name as string })
return {
...abiItem,
...(prepare ? { hash: getSignatureHash(abiItem) } : {}),
} as never
}
export declare namespace fromAbi {
type Options<
abi extends Abi.Abi | readonly unknown[] = Abi.Abi,
name extends Name<abi> = Name<abi>,
args extends
| internal.ExtractArgs<abi, name>
| undefined = internal.ExtractArgs<abi, name>,
///
allArgs = internal.ExtractArgs<abi, name>,
> = {
/**
* Whether or not to prepare the extracted item (optimization for encoding performance).
* When `true`, the `hash` property is computed and included in the returned value.
*
* @default true
*/
prepare?: boolean | undefined
} & UnionCompute<
readonly [] extends allArgs
? {
args?:
| allArgs // show all options
// infer value, widen inferred value of `args` conditionally to match `allArgs`
| (abi extends Abi.Abi
? args extends allArgs
? internal.Widen<args>
: never
: never)
| undefined
}
: {
args?:
| allArgs // show all options
| (internal.Widen<args> & (args extends allArgs ? unknown : never)) // infer value, widen inferred value of `args` match `allArgs` (e.g. avoid union `args: readonly [123n] | readonly [bigint]`)
| undefined
}
>
type ReturnType<
abi extends Abi.Abi | readonly unknown[] = Abi.Abi,
name extends Name<abi> = Name<abi>,
args extends
| internal.ExtractArgs<abi, name>
| undefined = internal.ExtractArgs<abi, name>,
fallback = AbiItem,
> = abi extends Abi.Abi
? Abi.Abi extends abi
? fallback
: internal.ExtractForArgs<
abi,
name,
args extends internal.ExtractArgs<abi, name>
? args
: internal.ExtractArgs<abi, name>
>
: fallback
type ErrorType = Errors.GlobalErrorType
}
/**
* Computes the [4-byte selector](https://solidity-by-example.org/function-selector/) for an {@link ox#AbiItem.AbiItem}.
*
* Useful for computing function selectors for calldata.
*
* @example
* ```ts twoslash
* import { AbiItem } from 'ox'
*
* const selector = AbiItem.getSelector('function ownerOf(uint256 tokenId)')
* // @log: '0x6352211e'
* ```
*
* @example
* ```ts twoslash
* import { AbiItem } from 'ox'
*
* const selector = AbiItem.getSelector({
* inputs: [{ type: 'uint256' }],
* name: 'ownerOf',
* outputs: [],
* stateMutability: 'view',
* type: 'function'
* })
* // @log: '0x6352211e'
* ```
*
* @param abiItem - The ABI item to compute the selector for. Can be a signature or an ABI item for an error, event, function, etc.
* @returns The first 4 bytes of the {@link ox#Hash.(keccak256:function)} hash of the function signature.
*/
export function getSelector(abiItem: string | AbiItem): Hex.Hex {
return Hex.slice(getSignatureHash(abiItem), 0, 4)
}
export declare namespace getSelector {
type ErrorType =
| getSignatureHash.ErrorType
| Hex.slice.ErrorType
| Errors.GlobalErrorType
}
/**
* Computes the stringified signature for a given {@link ox#AbiItem.AbiItem}.
*
* @example
* ```ts twoslash
* import { AbiItem } from 'ox'
*
* const signature = AbiItem.getSignature('function ownerOf(uint256 tokenId)')
* // @log: 'ownerOf(uint256)'
* ```
*
* @example
* ```ts twoslash
* import { AbiItem } from 'ox'
*
* const signature = AbiItem.getSignature({
* name: 'ownerOf',
* type: 'function',
* inputs: [{ name: 'tokenId', type: 'uint256' }],
* outputs: [],
* stateMutability: 'view',
* })
* // @log: 'ownerOf(uint256)'
* ```
*
* @param abiItem - The ABI Item to compute the signature for.
* @returns The stringified signature of the ABI Item.
*/
export function getSignature(abiItem: string | AbiItem): string {
const signature = (() => {
if (typeof abiItem === 'string') return abiItem
return abitype.formatAbiItem(abiItem)
})()
return internal.normalizeSignature(signature)
}
export declare namespace getSignature {
type ErrorType =
| internal.normalizeSignature.ErrorType
| Errors.GlobalErrorType
}
/**
* Computes the signature hash for an {@link ox#AbiItem.AbiItem}.
*
* Useful for computing Event Topic values.
*
* @example
* ```ts twoslash
* import { AbiItem } from 'ox'
*
* const hash = AbiItem.getSignatureHash('event Transfer(address indexed from, address indexed to, uint256 amount)')
* // @log: '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'
* ```
*
* @example
* ```ts twoslash
* import { AbiItem } from 'ox'
*
* const hash = AbiItem.getSignatureHash({
* name: 'Transfer',
* type: 'event',
* inputs: [
* { name: 'from', type: 'address', indexed: true },
* { name: 'to', type: 'address', indexed: true },
* { name: 'amount', type: 'uint256', indexed: false },
* ],
* })
* // @log: '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'
* ```
*
* @param abiItem - The ABI Item to compute the signature hash for.
* @returns The {@link ox#Hash.(keccak256:function)} hash of the ABI item's signature.
*/
export function getSignatureHash(abiItem: string | AbiItem): Hex.Hex {
if (typeof abiItem !== 'string' && 'hash' in abiItem && abiItem.hash)
return abiItem.hash as Hex.Hex
return Hash.keccak256(Hex.fromString(getSignature(abiItem)))
}
export declare namespace getSignatureHash {
type ErrorType =
| getSignature.ErrorType
| Hash.keccak256.ErrorType
| Hex.fromString.ErrorType
| Errors.GlobalErrorType
}
/**
* Throws when ambiguous types are found on overloaded ABI items.
*
* @example
* ```ts twoslash
* import { Abi, AbiFunction } from 'ox'
*
* const foo = Abi.from(['function foo(address)', 'function foo(bytes20)'])
* AbiFunction.fromAbi(foo, 'foo', {
* args: ['0xA0Cf798816D4b9b9866b5330EEa46a18382f251e'],
* })
* // @error: AbiItem.AmbiguityError: Found ambiguous types in overloaded ABI Items.
* // @error: `bytes20` in `foo(bytes20)`, and
* // @error: `address` in `foo(address)`
* // @error: These types encode differently and cannot be distinguished at runtime.
* // @error: Remove one of the ambiguous items in the ABI.
* ```
*
* ### Solution
*
* Remove one of the ambiguous types from the ABI.
*
* ```ts twoslash
* import { Abi, AbiFunction } from 'ox'
*
* const foo = Abi.from([
* 'function foo(address)',
* 'function foo(bytes20)' // [!code --]
* ])
* AbiFunction.fromAbi(foo, 'foo', {
* args: ['0xA0Cf798816D4b9b9866b5330EEa46a18382f251e'],
* })
* // @error: AbiItem.AmbiguityError: Found ambiguous types in overloaded ABI Items.
* // @error: `bytes20` in `foo(bytes20)`, and
* // @error: `address` in `foo(address)`
* // @error: These types encode differently and cannot be distinguished at runtime.
* // @error: Remove one of the ambiguous items in the ABI.
* ```
*/
export class AmbiguityError extends Errors.BaseError {
override readonly name = 'AbiItem.AmbiguityError'
constructor(
x: { abiItem: Abi.Abi[number]; type: string },
y: { abiItem: Abi.Abi[number]; type: string },
) {
super('Found ambiguous types in overloaded ABI Items.', {
metaMessages: [
// TODO: abitype to add support for signature-formatted ABI items.
`\`${x.type}\` in \`${internal.normalizeSignature(abitype.formatAbiItem(x.abiItem))}\`, and`,
`\`${y.type}\` in \`${internal.normalizeSignature(abitype.formatAbiItem(y.abiItem))}\``,
'',
'These types encode differently and cannot be distinguished at runtime.',
'Remove one of the ambiguous items in the ABI.',
],
})
}
}
/**
* Throws when an ABI item is not found in the ABI.
*
* @example
* ```ts twoslash
* // @noErrors
* import { Abi, AbiFunction } from 'ox'
*
* const foo = Abi.from([
* 'function foo(address)',
* 'function bar(uint)'
* ])
* AbiFunction.fromAbi(foo, 'baz')
* // @error: AbiItem.NotFoundError: ABI function with name "baz" not found.
* ```
*
* ### Solution
*
* Ensure the ABI item exists on the ABI.
*
* ```ts twoslash
* // @noErrors
* import { Abi, AbiFunction } from 'ox'
*
* const foo = Abi.from([
* 'function foo(address)',
* 'function bar(uint)',
* 'function baz(bool)' // [!code ++]
* ])
* AbiFunction.fromAbi(foo, 'baz')
* ```
*/
export class NotFoundError extends Errors.BaseError {
override readonly name = 'AbiItem.NotFoundError'
constructor({
name,
data,
type = 'item',
}: {
name?: string | undefined
data?: Hex.Hex | undefined
type?: string | undefined
}) {
const selector = (() => {
if (name) return ` with name "${name}"`
if (data) return ` with data "${data}"`
return ''
})()
super(`ABI ${type}${selector} not found.`)
}
}
/**
* Throws when the selector size is invalid.
*
* @example
* ```ts twoslash
* import { Abi, AbiFunction } from 'ox'
*
* const foo = Abi.from([
* 'function foo(address)',
* 'function bar(uint)'
* ])
* AbiFunction.fromAbi(foo, '0xaaa')
* // @error: AbiItem.InvalidSelectorSizeError: Selector size is invalid. Expected 4 bytes. Received 2 bytes ("0xaaa").
* ```
*
* ### Solution
*
* Ensure the selector size is 4 bytes.
*
* ```ts twoslash
* // @noErrors
* import { Abi, AbiFunction } from 'ox'
*
* const foo = Abi.from([
* 'function foo(address)',
* 'function bar(uint)'
* ])
* AbiFunction.fromAbi(foo, '0x7af82b1a')
* ```
*/
export class InvalidSelectorSizeError extends Errors.BaseError {
override readonly name = 'AbiItem.InvalidSelectorSizeError'
constructor({ data }: { data: Hex.Hex }) {
super(
`Selector size is invalid. Expected 4 bytes. Received ${Hex.size(data)} bytes ("${data}").`,
)
}
}

716
node_modules/ox/core/AbiParameters.ts generated vendored Normal file
View File

@@ -0,0 +1,716 @@
import * as abitype from 'abitype'
import * as Address from './Address.js'
import * as Bytes from './Bytes.js'
import * as Errors from './Errors.js'
import * as Hex from './Hex.js'
import * as Solidity from './Solidity.js'
import * as internal from './internal/abiParameters.js'
import * as Cursor from './internal/cursor.js'
/** Root type for ABI parameters. */
export type AbiParameters = readonly abitype.AbiParameter[]
/** A parameter on an {@link ox#AbiParameters.AbiParameters}. */
export type Parameter = abitype.AbiParameter
/** A packed ABI type. */
export type PackedAbiType =
| abitype.SolidityAddress
| abitype.SolidityBool
| abitype.SolidityBytes
| abitype.SolidityInt
| abitype.SolidityString
| abitype.SolidityArrayWithoutTuple
/**
* Decodes ABI-encoded data into its respective primitive values based on ABI Parameters.
*
* @example
* ```ts twoslash
* import { AbiParameters } from 'ox'
*
* const data = AbiParameters.decode(
* AbiParameters.from(['string', 'uint', 'bool']),
* '0x000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001a4000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000057761676d69000000000000000000000000000000000000000000000000000000',
* )
* // @log: ['wagmi', 420n, true]
* ```
*
* @example
* ### JSON Parameters
*
* You can pass **JSON ABI** Parameters:
*
* ```ts twoslash
* import { AbiParameters } from 'ox'
*
* const data = AbiParameters.decode(
* [
* { name: 'x', type: 'string' },
* { name: 'y', type: 'uint' },
* { name: 'z', type: 'bool' },
* ],
* '0x000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001a4000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000057761676d69000000000000000000000000000000000000000000000000000000',
* )
* // @log: ['wagmi', 420n, true]
* ```
*
* @param parameters - The set of ABI parameters to decode, in the shape of the `inputs` or `outputs` attribute of an ABI Item. These parameters must include valid [ABI types](https://docs.soliditylang.org/en/latest/types.html).
* @param data - ABI encoded data.
* @param options - Decoding options.
* @returns Array of decoded values.
*/
export function decode<
const parameters extends AbiParameters,
as extends 'Object' | 'Array' = 'Array',
>(
parameters: parameters,
data: Bytes.Bytes | Hex.Hex,
options?: decode.Options<as>,
): decode.ReturnType<parameters, as>
// eslint-disable-next-line jsdoc/require-jsdoc
export function decode(
parameters: AbiParameters,
data: Bytes.Bytes | Hex.Hex,
options: {
as?: 'Array' | 'Object' | undefined
checksumAddress?: boolean | undefined
} = {},
): readonly unknown[] | Record<string, unknown> {
const { as = 'Array', checksumAddress = false } = options
const bytes = typeof data === 'string' ? Bytes.fromHex(data) : data
const cursor = Cursor.create(bytes)
if (Bytes.size(bytes) === 0 && parameters.length > 0)
throw new ZeroDataError()
if (Bytes.size(bytes) && Bytes.size(bytes) < 32)
throw new DataSizeTooSmallError({
data: typeof data === 'string' ? data : Hex.fromBytes(data),
parameters: parameters as readonly Parameter[],
size: Bytes.size(bytes),
})
let consumed = 0
const values: any = as === 'Array' ? [] : {}
for (let i = 0; i < parameters.length; ++i) {
const param = parameters[i] as Parameter
cursor.setPosition(consumed)
const [data, consumed_] = internal.decodeParameter(cursor, param, {
checksumAddress,
staticPosition: 0,
})
consumed += consumed_
if (as === 'Array') values.push(data)
else values[param.name ?? i] = data
}
return values
}
export declare namespace decode {
type Options<as extends 'Object' | 'Array'> = {
/**
* Whether the decoded values should be returned as an `Object` or `Array`.
*
* @default "Array"
*/
as?: as | 'Object' | 'Array' | undefined
/**
* Whether decoded addresses should be checksummed.
*
* @default false
*/
checksumAddress?: boolean | undefined
}
type ReturnType<
parameters extends AbiParameters = AbiParameters,
as extends 'Object' | 'Array' = 'Array',
> = parameters extends readonly []
? as extends 'Object'
? {}
: []
: as extends 'Object'
? internal.ToObject<parameters>
: internal.ToPrimitiveTypes<parameters>
type ErrorType =
| Bytes.fromHex.ErrorType
| internal.decodeParameter.ErrorType
| ZeroDataError
| DataSizeTooSmallError
| Errors.GlobalErrorType
}
/**
* Encodes primitive values into ABI encoded data as per the [Application Binary Interface (ABI) Specification](https://docs.soliditylang.org/en/latest/abi-spec).
*
* @example
* ```ts twoslash
* import { AbiParameters } from 'ox'
*
* const data = AbiParameters.encode(
* AbiParameters.from(['string', 'uint', 'bool']),
* ['wagmi', 420n, true],
* )
* ```
*
* @example
* ### JSON Parameters
*
* Specify **JSON ABI** Parameters as schema:
*
* ```ts twoslash
* import { AbiParameters } from 'ox'
*
* const data = AbiParameters.encode(
* [
* { type: 'string', name: 'name' },
* { type: 'uint', name: 'age' },
* { type: 'bool', name: 'isOwner' },
* ],
* ['wagmi', 420n, true],
* )
* ```
*
* @param parameters - The set of ABI parameters to encode, in the shape of the `inputs` or `outputs` attribute of an ABI Item. These parameters must include valid [ABI types](https://docs.soliditylang.org/en/latest/types.html).
* @param values - The set of primitive values that correspond to the ABI types defined in `parameters`.
* @returns ABI encoded data.
*/
export function encode<
const parameters extends AbiParameters | readonly unknown[],
>(
parameters: parameters,
values: parameters extends AbiParameters
? internal.ToPrimitiveTypes<parameters>
: never,
options?: encode.Options,
): Hex.Hex {
const { checksumAddress = false } = options ?? {}
if (parameters.length !== values.length)
throw new LengthMismatchError({
expectedLength: parameters.length as number,
givenLength: values.length as any,
})
// Prepare the parameters to determine dynamic types to encode.
const preparedParameters = internal.prepareParameters({
checksumAddress,
parameters: parameters as readonly Parameter[],
values: values as any,
})
const data = internal.encode(preparedParameters)
if (data.length === 0) return '0x'
return data
}
export declare namespace encode {
type ErrorType =
| LengthMismatchError
| internal.encode.ErrorType
| internal.prepareParameters.ErrorType
| Errors.GlobalErrorType
type Options = {
/**
* Whether addresses should be checked against their checksum.
*
* @default false
*/
checksumAddress?: boolean | undefined
}
}
/**
* Encodes an array of primitive values to a [packed ABI encoding](https://docs.soliditylang.org/en/latest/abi-spec.html#non-standard-packed-mode).
*
* @example
* ```ts twoslash
* import { AbiParameters } from 'ox'
*
* const encoded = AbiParameters.encodePacked(
* ['address', 'string'],
* ['0xd8da6bf26964af9d7eed9e03e53415d37aa96045', 'hello world'],
* )
* // @log: '0xd8da6bf26964af9d7eed9e03e53415d37aa9604568656c6c6f20776f726c64'
* ```
*
* @param types - Set of ABI types to pack encode.
* @param values - The set of primitive values that correspond to the ABI types defined in `types`.
* @returns The encoded packed data.
*/
export function encodePacked<
const packedAbiTypes extends readonly PackedAbiType[] | readonly unknown[],
>(types: packedAbiTypes, values: encodePacked.Values<packedAbiTypes>): Hex.Hex {
if (types.length !== values.length)
throw new LengthMismatchError({
expectedLength: types.length as number,
givenLength: values.length as number,
})
const data: Hex.Hex[] = []
for (let i = 0; i < (types as unknown[]).length; i++) {
const type = types[i]
const value = values[i]
data.push(encodePacked.encode(type, value))
}
return Hex.concat(...data)
}
export namespace encodePacked {
export type ErrorType =
| Hex.concat.ErrorType
| LengthMismatchError
| Errors.GlobalErrorType
export type Values<
packedAbiTypes extends readonly PackedAbiType[] | readonly unknown[],
> = {
[key in keyof packedAbiTypes]: packedAbiTypes[key] extends abitype.AbiType
? abitype.AbiParameterToPrimitiveType<{ type: packedAbiTypes[key] }>
: unknown
}
// eslint-disable-next-line jsdoc/require-jsdoc
export function encode<const packedAbiType extends PackedAbiType | unknown>(
type: packedAbiType,
value: Values<[packedAbiType]>[0],
isArray = false,
): Hex.Hex {
if (type === 'address') {
const address = value as Address.Address
Address.assert(address)
return Hex.padLeft(
address.toLowerCase() as Hex.Hex,
isArray ? 32 : 0,
) as Address.Address
}
if (type === 'string') return Hex.fromString(value as string)
if (type === 'bytes') return value as Hex.Hex
if (type === 'bool')
return Hex.padLeft(Hex.fromBoolean(value as boolean), isArray ? 32 : 1)
const intMatch = (type as string).match(Solidity.integerRegex)
if (intMatch) {
const [_type, baseType, bits = '256'] = intMatch
const size = Number.parseInt(bits) / 8
return Hex.fromNumber(value as number, {
size: isArray ? 32 : size,
signed: baseType === 'int',
})
}
const bytesMatch = (type as string).match(Solidity.bytesRegex)
if (bytesMatch) {
const [_type, size] = bytesMatch
if (Number.parseInt(size!) !== ((value as Hex.Hex).length - 2) / 2)
throw new BytesSizeMismatchError({
expectedSize: Number.parseInt(size!),
value: value as Hex.Hex,
})
return Hex.padRight(value as Hex.Hex, isArray ? 32 : 0) as Hex.Hex
}
const arrayMatch = (type as string).match(Solidity.arrayRegex)
if (arrayMatch && Array.isArray(value)) {
const [_type, childType] = arrayMatch
const data: Hex.Hex[] = []
for (let i = 0; i < value.length; i++) {
data.push(encode(childType, value[i], true))
}
if (data.length === 0) return '0x'
return Hex.concat(...data)
}
throw new InvalidTypeError(type as string)
}
}
/**
* Formats {@link ox#AbiParameters.AbiParameters} into **Human Readable ABI Parameters**.
*
* @example
* ```ts twoslash
* import { AbiParameters } from 'ox'
*
* const formatted = AbiParameters.format([
* {
* name: 'spender',
* type: 'address',
* },
* {
* name: 'amount',
* type: 'uint256',
* },
* ])
*
* formatted
* // ^?
*
*
* ```
*
* @param parameters - The ABI Parameters to format.
* @returns The formatted ABI Parameters .
*/
export function format<
const parameters extends readonly [
Parameter | abitype.AbiEventParameter,
...(readonly (Parameter | abitype.AbiEventParameter)[]),
],
>(
parameters:
| parameters
| readonly [
Parameter | abitype.AbiEventParameter,
...(readonly (Parameter | abitype.AbiEventParameter)[]),
],
): abitype.FormatAbiParameters<parameters> {
return abitype.formatAbiParameters(parameters)
}
export declare namespace format {
type ErrorType = Errors.GlobalErrorType
}
/**
* Parses arbitrary **JSON ABI Parameters** or **Human Readable ABI Parameters** into typed {@link ox#AbiParameters.AbiParameters}.
*
* @example
* ### JSON Parameters
*
* ```ts twoslash
* import { AbiParameters } from 'ox'
*
* const parameters = AbiParameters.from([
* {
* name: 'spender',
* type: 'address',
* },
* {
* name: 'amount',
* type: 'uint256',
* },
* ])
*
* parameters
* //^?
*
*
*
*
*
*
*
* ```
*
* @example
* ### Human Readable Parameters
*
* Human Readable ABI Parameters can be parsed into a typed {@link ox#AbiParameters.AbiParameters}:
*
* ```ts twoslash
* import { AbiParameters } from 'ox'
*
* const parameters = AbiParameters.from('address spender, uint256 amount')
*
* parameters
* //^?
*
*
*
*
*
*
*
* ```
*
* @example
* It is possible to specify `struct`s along with your definitions:
*
* ```ts twoslash
* import { AbiParameters } from 'ox'
*
* const parameters = AbiParameters.from([
* 'struct Foo { address spender; uint256 amount; }', // [!code hl]
* 'Foo foo, address bar',
* ])
*
* parameters
* //^?
*
*
*
*
*
*
*
*
*
*
*
*
* ```
*
*
*
* @param parameters - The ABI Parameters to parse.
* @returns The typed ABI Parameters.
*/
export function from<
const parameters extends AbiParameters | string | readonly string[],
>(
parameters: parameters | AbiParameters | string | readonly string[],
): from.ReturnType<parameters> {
if (Array.isArray(parameters) && typeof parameters[0] === 'string')
return abitype.parseAbiParameters(parameters) as never
if (typeof parameters === 'string')
return abitype.parseAbiParameters(parameters) as never
return parameters as never
}
export declare namespace from {
type ReturnType<
parameters extends AbiParameters | string | readonly string[],
> = parameters extends string
? abitype.ParseAbiParameters<parameters>
: parameters extends readonly string[]
? abitype.ParseAbiParameters<parameters>
: parameters
type ErrorType = Errors.GlobalErrorType
}
/**
* Throws when the data size is too small for the given parameters.
*
* @example
* ```ts twoslash
* import { AbiParameters } from 'ox'
*
* AbiParameters.decode([{ type: 'uint256' }], '0x010f')
* // ↑ ❌ 2 bytes
* // @error: AbiParameters.DataSizeTooSmallError: Data size of 2 bytes is too small for given parameters.
* // @error: Params: (uint256)
* // @error: Data: 0x010f (2 bytes)
* ```
*
* ### Solution
*
* Pass a valid data size.
*
* ```ts twoslash
* import { AbiParameters } from 'ox'
*
* AbiParameters.decode([{ type: 'uint256' }], '0x00000000000000000000000000000000000000000000000000000000000010f')
* // ↑ ✅ 32 bytes
* ```
*/
export class DataSizeTooSmallError extends Errors.BaseError {
override readonly name = 'AbiParameters.DataSizeTooSmallError'
constructor({
data,
parameters,
size,
}: { data: Hex.Hex; parameters: readonly Parameter[]; size: number }) {
super(`Data size of ${size} bytes is too small for given parameters.`, {
metaMessages: [
`Params: (${abitype.formatAbiParameters(parameters as readonly [Parameter])})`,
`Data: ${data} (${size} bytes)`,
],
})
}
}
/**
* Throws when zero data is provided, but data is expected.
*
* @example
* ```ts twoslash
* import { AbiParameters } from 'ox'
*
* AbiParameters.decode([{ type: 'uint256' }], '0x')
* // ↑ ❌ zero data
* // @error: AbiParameters.DataSizeTooSmallError: Data size of 2 bytes is too small for given parameters.
* // @error: Params: (uint256)
* // @error: Data: 0x010f (2 bytes)
* ```
*
* ### Solution
*
* Pass valid data.
*
* ```ts twoslash
* import { AbiParameters } from 'ox'
*
* AbiParameters.decode([{ type: 'uint256' }], '0x00000000000000000000000000000000000000000000000000000000000010f')
* // ↑ ✅ 32 bytes
* ```
*/
export class ZeroDataError extends Errors.BaseError {
override readonly name = 'AbiParameters.ZeroDataError'
constructor() {
super('Cannot decode zero data ("0x") with ABI parameters.')
}
}
/**
* The length of the array value does not match the length specified in the corresponding ABI parameter.
*
* ### Example
*
* ```ts twoslash
* // @noErrors
* import { AbiParameters } from 'ox'
* // ---cut---
* AbiParameters.encode(AbiParameters.from('uint256[3]'), [[69n, 420n]])
* // ↑ expected: 3 ↑ ❌ length: 2
* // @error: AbiParameters.ArrayLengthMismatchError: ABI encoding array length mismatch
* // @error: for type `uint256[3]`. Expected: `3`. Given: `2`.
* ```
*
* ### Solution
*
* Pass an array of the correct length.
*
* ```ts twoslash
* import { AbiParameters } from 'ox'
* // ---cut---
* AbiParameters.encode(AbiParameters.from(['uint256[3]']), [[69n, 420n, 69n]])
* // ↑ ✅ length: 3
* ```
*/
export class ArrayLengthMismatchError extends Errors.BaseError {
override readonly name = 'AbiParameters.ArrayLengthMismatchError'
constructor({
expectedLength,
givenLength,
type,
}: { expectedLength: number; givenLength: number; type: string }) {
super(
`Array length mismatch for type \`${type}\`. Expected: \`${expectedLength}\`. Given: \`${givenLength}\`.`,
)
}
}
/**
* The size of the bytes value does not match the size specified in the corresponding ABI parameter.
*
* ### Example
*
* ```ts twoslash
* // @noErrors
* import { AbiParameters } from 'ox'
* // ---cut---
* AbiParameters.encode(AbiParameters.from('bytes8'), [['0xdeadbeefdeadbeefdeadbeef']])
* // ↑ expected: 8 bytes ↑ ❌ size: 12 bytes
* // @error: BytesSizeMismatchError: Size of bytes "0xdeadbeefdeadbeefdeadbeef"
* // @error: (bytes12) does not match expected size (bytes8).
* ```
*
* ### Solution
*
* Pass a bytes value of the correct size.
*
* ```ts twoslash
* import { AbiParameters } from 'ox'
* // ---cut---
* AbiParameters.encode(AbiParameters.from(['bytes8']), ['0xdeadbeefdeadbeef'])
* // ↑ ✅ size: 8 bytes
* ```
*/
export class BytesSizeMismatchError extends Errors.BaseError {
override readonly name = 'AbiParameters.BytesSizeMismatchError'
constructor({
expectedSize,
value,
}: { expectedSize: number; value: Hex.Hex }) {
super(
`Size of bytes "${value}" (bytes${Hex.size(
value,
)}) does not match expected size (bytes${expectedSize}).`,
)
}
}
/**
* The length of the values to encode does not match the length of the ABI parameters.
*
* ### Example
*
* ```ts twoslash
* // @noErrors
* import { AbiParameters } from 'ox'
* // ---cut---
* AbiParameters.encode(AbiParameters.from(['string', 'uint256']), ['hello'])
* // @error: LengthMismatchError: ABI encoding params/values length mismatch.
* // @error: Expected length (params): 2
* // @error: Given length (values): 1
* ```
*
* ### Solution
*
* Pass the correct number of values to encode.
*
* ### Solution
*
* Pass a [valid ABI type](https://docs.soliditylang.org/en/develop/abi-spec.html#types).
*/
export class LengthMismatchError extends Errors.BaseError {
override readonly name = 'AbiParameters.LengthMismatchError'
constructor({
expectedLength,
givenLength,
}: { expectedLength: number; givenLength: number }) {
super(
[
'ABI encoding parameters/values length mismatch.',
`Expected length (parameters): ${expectedLength}`,
`Given length (values): ${givenLength}`,
].join('\n'),
)
}
}
/**
* The value provided is not a valid array as specified in the corresponding ABI parameter.
*
* ### Example
*
* ```ts twoslash
* // @noErrors
* import { AbiParameters } from 'ox'
* // ---cut---
* AbiParameters.encode(AbiParameters.from(['uint256[3]']), [69])
* ```
*
* ### Solution
*
* Pass an array value.
*/
export class InvalidArrayError extends Errors.BaseError {
override readonly name = 'AbiParameters.InvalidArrayError'
constructor(value: unknown) {
super(`Value \`${value}\` is not a valid array.`)
}
}
/**
* Throws when the ABI parameter type is invalid.
*
* @example
* ```ts twoslash
* import { AbiParameters } from 'ox'
*
* AbiParameters.decode([{ type: 'lol' }], '0x00000000000000000000000000000000000000000000000000000000000010f')
* // ↑ ❌ invalid type
* // @error: AbiParameters.InvalidTypeError: Type `lol` is not a valid ABI Type.
* ```
*/
export class InvalidTypeError extends Errors.BaseError {
override readonly name = 'AbiParameters.InvalidTypeError'
constructor(type: string) {
super(`Type \`${type}\` is not a valid ABI Type.`)
}
}

124
node_modules/ox/core/AccessList.ts generated vendored Normal file
View File

@@ -0,0 +1,124 @@
import * as Address from './Address.js'
import * as Errors from './Errors.js'
import * as Hash from './Hash.js'
import * as Hex from './Hex.js'
import type { Compute, Mutable } from './internal/types.js'
export type AccessList = Compute<readonly Item[]>
export type Item = Compute<{
address: Address.Address
storageKeys: readonly Hex.Hex[]
}>
export type ItemTuple = Compute<
[address: Address.Address, storageKeys: readonly Hex.Hex[]]
>
export type Tuple = readonly ItemTuple[]
/**
* Converts a list of Access List tuples into a object-formatted list.
*
* @example
* ```ts twoslash
* import { AccessList } from 'ox'
*
* const accessList = AccessList.fromTupleList([
* [
* '0x0000000000000000000000000000000000000000',
* [
* '0x0000000000000000000000000000000000000000000000000000000000000001',
* '0x60fdd29ff912ce880cd3edaf9f932dc61d3dae823ea77e0323f94adb9f6a72fe',
* ],
* ],
* ])
* // @log: [
* // @log: {
* // @log: address: '0x0000000000000000000000000000000000000000',
* // @log: storageKeys: [
* // @log: '0x0000000000000000000000000000000000000000000000000000000000000001',
* // @log: '0x60fdd29ff912ce880cd3edaf9f932dc61d3dae823ea77e0323f94adb9f6a72fe',
* // @log: ],
* // @log: },
* // @log: ]
* ```
*
* @param accessList - List of tuples.
* @returns Access list.
*/
export function fromTupleList(accessList: Tuple): AccessList {
const list: Mutable<AccessList> = []
for (let i = 0; i < accessList.length; i++) {
const [address, storageKeys] = accessList[i] as [Hex.Hex, Hex.Hex[]]
if (address) Address.assert(address, { strict: false })
list.push({
address: address,
storageKeys: storageKeys.map((key) =>
Hash.validate(key) ? key : Hex.trimLeft(key),
),
})
}
return list
}
/**
* Converts a structured Access List into a list of tuples.
*
* @example
* ```ts twoslash
* import { AccessList } from 'ox'
*
* const accessList = AccessList.toTupleList([
* {
* address: '0x0000000000000000000000000000000000000000',
* storageKeys: [
* '0x0000000000000000000000000000000000000000000000000000000000000001',
* '0x60fdd29ff912ce880cd3edaf9f932dc61d3dae823ea77e0323f94adb9f6a72fe'],
* },
* ])
* // @log: [
* // @log: [
* // @log: '0x0000000000000000000000000000000000000000',
* // @log: [
* // @log: '0x0000000000000000000000000000000000000000000000000000000000000001',
* // @log: '0x60fdd29ff912ce880cd3edaf9f932dc61d3dae823ea77e0323f94adb9f6a72fe',
* // @log: ],
* // @log: ],
* // @log: ]
* ```
*
* @param accessList - Access list.
* @returns List of tuples.
*/
export function toTupleList(
accessList?: AccessList | undefined,
): Compute<Tuple> {
if (!accessList || accessList.length === 0) return []
const tuple: Mutable<Tuple> = []
for (const { address, storageKeys } of accessList) {
for (let j = 0; j < storageKeys.length; j++)
if (Hex.size(storageKeys[j]!) !== 32)
throw new InvalidStorageKeySizeError({
storageKey: storageKeys[j]!,
})
if (address) Address.assert(address, { strict: false })
tuple.push([address, storageKeys])
}
return tuple
}
/** Thrown when the size of a storage key is invalid. */
export class InvalidStorageKeySizeError extends Errors.BaseError {
override readonly name = 'AccessList.InvalidStorageKeySizeError'
constructor({ storageKey }: { storageKey: Hex.Hex }) {
super(
`Size for storage key "${storageKey}" is invalid. Expected 32 bytes. Got ${Hex.size(storageKey)} bytes.`,
)
}
}

35
node_modules/ox/core/AccountProof.ts generated vendored Normal file
View File

@@ -0,0 +1,35 @@
import type { Address, Hex } from '../index.js'
/** An Account Proof as defined in the [Execution API specification](https://github.com/ethereum/execution-apis/blob/main/src/schemas/state.yaml). */
export type AccountProof<bigintType = bigint, numberType = number> = {
/** The address of the account. */
address: Address.Address
/** The balance of the account. */
balance: bigintType
/** The code hash of the account. */
codeHash: Hex.Hex
/** The nonce of the account. */
nonce: numberType
/** The storage hash of the account. */
storageHash: Hex.Hex
/** The account proofs. */
accountProof: readonly Hex.Hex[]
/** The storage proofs. */
storageProof: readonly StorageProof<bigintType>[]
}
/** An RPC Account Proof as defined in the [Execution API specification](https://github.com/ethereum/execution-apis/blob/main/src/schemas/state.yaml). */
export type Rpc = AccountProof<Hex.Hex, Hex.Hex>
/** A Storage Proof as defined in the [Execution API specification](https://github.com/ethereum/execution-apis/blob/main/src/schemas/state.yaml). */
export type StorageProof<bigintType = bigint> = {
/** The key of the storage. */
key: Hex.Hex
/** The proofs of the storage. */
proof: readonly Hex.Hex[]
/** The value of the storage. */
value: bigintType
}
/** An RPC Storage Proof as defined in the [Execution API specification](https://github.com/ethereum/execution-apis/blob/main/src/schemas/state.yaml). */
export type StorageProofRpc = StorageProof<Hex.Hex>

341
node_modules/ox/core/Address.ts generated vendored Normal file
View File

@@ -0,0 +1,341 @@
import type { Address as abitype_Address } from 'abitype'
import * as Bytes from './Bytes.js'
import * as Caches from './Caches.js'
import * as Errors from './Errors.js'
import * as Hash from './Hash.js'
import * as PublicKey from './PublicKey.js'
const addressRegex = /*#__PURE__*/ /^0x[a-fA-F0-9]{40}$/
/** Root type for Address. */
export type Address = abitype_Address
/**
* Asserts that the given value is a valid {@link ox#Address.Address}.
*
* @example
* ```ts twoslash
* import { Address } from 'ox'
*
* Address.assert('0xA0Cf798816D4b9b9866b5330EEa46a18382f251e')
* ```
*
* @example
* ```ts twoslash
* import { Address } from 'ox'
*
* Address.assert('0xdeadbeef')
* // @error: InvalidAddressError: Address "0xdeadbeef" is invalid.
* ```
*
* @param value - Value to assert if it is a valid address.
* @param options - Assertion options.
*/
export function assert(
value: string,
options: assert.Options = {},
): asserts value is Address {
const { strict = true } = options
if (!addressRegex.test(value))
throw new InvalidAddressError({
address: value,
cause: new InvalidInputError(),
})
if (strict) {
if (value.toLowerCase() === value) return
if (checksum(value as Address) !== value)
throw new InvalidAddressError({
address: value,
cause: new InvalidChecksumError(),
})
}
}
export declare namespace assert {
type Options = {
/**
* Enables strict mode. Whether or not to compare the address against its checksum.
*
* @default true
*/
strict?: boolean | undefined
}
type ErrorType = InvalidAddressError | Errors.GlobalErrorType
}
/**
* Computes the checksum address for the given {@link ox#Address.Address}.
*
* @example
* ```ts twoslash
* import { Address } from 'ox'
*
* Address.checksum('0xa0cf798816d4b9b9866b5330eea46a18382f251e')
* // @log: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e'
* ```
*
* @param address - The address to compute the checksum for.
* @returns The checksummed address.
*/
export function checksum(address: string): Address {
if (Caches.checksum.has(address)) return Caches.checksum.get(address)!
assert(address, { strict: false })
const hexAddress = address.substring(2).toLowerCase()
const hash = Hash.keccak256(Bytes.fromString(hexAddress), { as: 'Bytes' })
const characters = hexAddress.split('')
for (let i = 0; i < 40; i += 2) {
if (hash[i >> 1]! >> 4 >= 8 && characters[i]) {
characters[i] = characters[i]!.toUpperCase()
}
if ((hash[i >> 1]! & 0x0f) >= 8 && characters[i + 1]) {
characters[i + 1] = characters[i + 1]!.toUpperCase()
}
}
const result = `0x${characters.join('')}` as const
Caches.checksum.set(address, result)
return result
}
export declare namespace checksum {
type ErrorType =
| assert.ErrorType
| Hash.keccak256.ErrorType
| Bytes.fromString.ErrorType
| Errors.GlobalErrorType
}
/**
* Converts a stringified address to a typed (checksummed) {@link ox#Address.Address}.
*
* @example
* ```ts twoslash
* import { Address } from 'ox'
*
* Address.from('0xa0cf798816d4b9b9866b5330eea46a18382f251e')
* // @log: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e'
* ```
*
* @example
* ```ts twoslash
* import { Address } from 'ox'
*
* Address.from('0xa0cf798816d4b9b9866b5330eea46a18382f251e', {
* checksum: false
* })
* // @log: '0xa0cf798816d4b9b9866b5330eea46a18382f251e'
* ```
*
* @example
* ```ts twoslash
* import { Address } from 'ox'
*
* Address.from('hello')
* // @error: InvalidAddressError: Address "0xa" is invalid.
* ```
*
* @param address - An address string to convert to a typed Address.
* @param options - Conversion options.
* @returns The typed Address.
*/
export function from(address: string, options: from.Options = {}): Address {
const { checksum: checksumVal = false } = options
assert(address)
if (checksumVal) return checksum(address)
return address as Address
}
export declare namespace from {
type Options = {
/**
* Whether to checksum the address.
*
* @default false
*/
checksum?: boolean | undefined
}
type ErrorType =
| assert.ErrorType
| checksum.ErrorType
| Errors.GlobalErrorType
}
/**
* Converts an ECDSA public key to an {@link ox#Address.Address}.
*
* @example
* ```ts twoslash
* import { Address, PublicKey } from 'ox'
*
* const publicKey = PublicKey.from(
* '0x048318535b54105d4a7aae60c08fc45f9687181b4fdfc625bd1a753fa7397fed753547f11ca8696646f2f3acb08e31016afac23e630c5d11f59f61fef57b0d2aa5',
* )
* const address = Address.fromPublicKey(publicKey)
* // @log: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266'
* ```
*
* @param publicKey - The ECDSA public key to convert to an {@link ox#Address.Address}.
* @param options - Conversion options.
* @returns The {@link ox#Address.Address} corresponding to the public key.
*/
export function fromPublicKey(
publicKey: PublicKey.PublicKey,
options: fromPublicKey.Options = {},
): Address {
const address = Hash.keccak256(
`0x${PublicKey.toHex(publicKey).slice(4)}`,
).substring(26)
return from(`0x${address}`, options)
}
export declare namespace fromPublicKey {
type Options = {
/**
* Whether to checksum the address.
*
* @default false
*/
checksum?: boolean | undefined
}
type ErrorType =
| Hash.keccak256.ErrorType
| PublicKey.toHex.ErrorType
| Errors.GlobalErrorType
}
/**
* Checks if two {@link ox#Address.Address} are equal.
*
* @example
* ```ts twoslash
* import { Address } from 'ox'
*
* Address.isEqual(
* '0xa0cf798816d4b9b9866b5330eea46a18382f251e',
* '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e'
* )
* // @log: true
* ```
*
* @example
* ```ts twoslash
* import { Address } from 'ox'
*
* Address.isEqual(
* '0xa0cf798816d4b9b9866b5330eea46a18382f251e',
* '0xA0Cf798816D4b9b9866b5330EEa46a18382f251f'
* )
* // @log: false
* ```
*
* @param addressA - The first address to compare.
* @param addressB - The second address to compare.
* @returns Whether the addresses are equal.
*/
export function isEqual(addressA: Address, addressB: Address): boolean {
assert(addressA, { strict: false })
assert(addressB, { strict: false })
return addressA.toLowerCase() === addressB.toLowerCase()
}
export declare namespace isEqual {
type ErrorType = assert.ErrorType | Errors.GlobalErrorType
}
/**
* Checks if the given address is a valid {@link ox#Address.Address}.
*
* @example
* ```ts twoslash
* import { Address } from 'ox'
*
* Address.validate('0xA0Cf798816D4b9b9866b5330EEa46a18382f251e')
* // @log: true
* ```
*
* @example
* ```ts twoslash
* import { Address } from 'ox'
*
* Address.validate('0xdeadbeef')
* // @log: false
* ```
*
* @param address - Value to check if it is a valid address.
* @param options - Check options.
* @returns Whether the address is a valid address.
*/
export function validate(
address: string,
options: validate.Options = {},
): address is Address {
const { strict = true } = options ?? {}
try {
assert(address, { strict })
return true
} catch {
return false
}
}
export declare namespace validate {
type Options = {
/**
* Enables strict mode. Whether or not to compare the address against its checksum.
*
* @default true
*/
strict?: boolean | undefined
}
}
/**
* Thrown when an address is invalid.
*
* @example
* ```ts twoslash
* import { Address } from 'ox'
*
* Address.from('0x123')
* // @error: Address.InvalidAddressError: Address `0x123` is invalid.
* ```
*/
export class InvalidAddressError<
cause extends InvalidInputError | InvalidChecksumError =
| InvalidInputError
| InvalidChecksumError,
> extends Errors.BaseError<cause> {
override readonly name = 'Address.InvalidAddressError'
constructor({ address, cause }: { address: string; cause: cause }) {
super(`Address "${address}" is invalid.`, {
cause,
})
}
}
/** Thrown when an address is not a 20 byte (40 hexadecimal character) value. */
export class InvalidInputError extends Errors.BaseError {
override readonly name = 'Address.InvalidInputError'
constructor() {
super('Address is not a 20 byte (40 hexadecimal character) value.')
}
}
/** Thrown when an address does not match its checksum counterpart. */
export class InvalidChecksumError extends Errors.BaseError {
override readonly name = 'Address.InvalidChecksumError'
constructor() {
super('Address does not match its checksum counterpart.')
}
}

204
node_modules/ox/core/AesGcm.ts generated vendored Normal file
View File

@@ -0,0 +1,204 @@
import * as Bytes from './Bytes.js'
import type * as Errors from './Errors.js'
import * as Hex from './Hex.js'
export const ivLength = 16
/**
* Decrypts encrypted data using AES-GCM.
*
* @example
* ```ts twoslash
* import { AesGcm, Hex } from 'ox'
*
* const key = await AesGcm.getKey({ password: 'qwerty' })
* const secret = Hex.fromString('i am a secret message')
*
* const encrypted = await AesGcm.encrypt(secret, key)
*
* const decrypted = await AesGcm.decrypt(encrypted, key) // [!code focus]
* // @log: Hex.fromString('i am a secret message')
* ```
*
* @param value - The data to encrypt.
* @param key - The `CryptoKey` to use for encryption.
* @param options - Decryption options.
* @returns The decrypted data.
*/
export async function decrypt<
value extends Hex.Hex | Bytes.Bytes,
as extends 'Hex' | 'Bytes' =
| (value extends Hex.Hex ? 'Hex' : never)
| (value extends Bytes.Bytes ? 'Bytes' : never),
>(
value: value | Bytes.Bytes | Hex.Hex,
key: CryptoKey,
options: decrypt.Options<as> = {},
): Promise<decrypt.ReturnType<as>> {
const { as = typeof value === 'string' ? 'Hex' : 'Bytes' } = options
const encrypted = Bytes.from(value)
const iv = encrypted.slice(0, ivLength)
const data = encrypted.slice(ivLength)
const decrypted = await globalThis.crypto.subtle.decrypt(
{
name: 'AES-GCM',
iv,
},
key,
Bytes.from(data),
)
const result = new Uint8Array(decrypted)
if (as === 'Bytes') return result as never
return Hex.from(result) as never
}
export declare namespace decrypt {
type Options<as extends 'Bytes' | 'Hex' = 'Bytes' | 'Hex'> = {
/** The output format. @default 'Bytes' */
as?: as | 'Bytes' | 'Hex' | undefined
}
type ReturnType<as extends 'Bytes' | 'Hex' = 'Bytes' | 'Hex'> =
| (as extends 'Bytes' ? Bytes.Bytes : never)
| (as extends 'Hex' ? Hex.Hex : never)
type ErrorType =
| Bytes.from.ErrorType
| Hex.from.ErrorType
| Errors.GlobalErrorType
}
/**
* Encrypts data using AES-GCM.
*
* @example
* ```ts twoslash
* import { AesGcm, Hex } from 'ox'
*
* const key = await AesGcm.getKey({ password: 'qwerty' })
* const secret = Hex.fromString('i am a secret message')
*
* const encrypted = await AesGcm.encrypt(secret, key) // [!code focus]
* // @log: '0x5e257b25bcf53d5431e54e5a68ca0138306d31bb6154f35a97bb8ea18111e7d82bcf619d3c76c4650688bc5310eed80b8fc86d1e3e'
* ```
*
* @param value - The data to encrypt.
* @param key - The `CryptoKey` to use for encryption.
* @param options - Encryption options.
* @returns The encrypted data.
*/
export async function encrypt<
value extends Hex.Hex | Bytes.Bytes,
as extends 'Bytes' | 'Hex' =
| (value extends Hex.Hex ? 'Hex' : never)
| (value extends Bytes.Bytes ? 'Bytes' : never),
>(
value: value | Bytes.Bytes | Hex.Hex,
key: CryptoKey,
options: encrypt.Options<as> = {},
): Promise<encrypt.ReturnType<as>> {
const { as = typeof value === 'string' ? 'Hex' : 'Bytes' } = options
const iv = Bytes.random(ivLength)
const encrypted = await globalThis.crypto.subtle.encrypt(
{
name: 'AES-GCM',
iv,
},
key,
Bytes.from(value),
)
const result = Bytes.concat(iv, new Uint8Array(encrypted))
if (as === 'Bytes') return result as never
return Hex.from(result) as never
}
export declare namespace encrypt {
type Options<as extends 'Bytes' | 'Hex' = 'Bytes' | 'Hex'> = {
/** The output format. @default 'Hex' */
as?: as | 'Bytes' | 'Hex' | undefined
}
type ReturnType<as extends 'Bytes' | 'Hex' = 'Bytes' | 'Hex'> =
| (as extends 'Bytes' ? Bytes.Bytes : never)
| (as extends 'Hex' ? Hex.Hex : never)
type ErrorType =
| Bytes.concat.ErrorType
| Bytes.from.ErrorType
| Bytes.random.ErrorType
| Hex.from.ErrorType
| Errors.GlobalErrorType
}
/**
* Derives an AES-GCM key from a password using PBKDF2.
*
* @example
* ```ts twoslash
* import { AesGcm } from 'ox'
*
* const key = await AesGcm.getKey({ password: 'qwerty' })
* // @log: CryptoKey {}
* ```
*
* @param options - Options for key derivation.
* @returns The derived key.
*/
export async function getKey(options: getKey.Options): Promise<CryptoKey> {
const { iterations = 900_000, password, salt = randomSalt(32) } = options
const baseKey = await globalThis.crypto.subtle.importKey(
'raw',
Bytes.fromString(password),
{ name: 'PBKDF2' },
false,
['deriveBits', 'deriveKey'],
)
const key = await globalThis.crypto.subtle.deriveKey(
{
name: 'PBKDF2',
salt,
iterations,
hash: 'SHA-256',
},
baseKey,
{ name: 'AES-GCM', length: 256 },
false,
['encrypt', 'decrypt'],
)
return key
}
export declare namespace getKey {
type Options = {
/** The number of iterations to use. @default 900_000 */
iterations?: number | undefined
/** Password to derive key from. */
password: string
/** Salt to use for key derivation. @default `AesGcm.randomSalt(32)` */
salt?: Bytes.Bytes | undefined
}
type ErrorType = Errors.GlobalErrorType
}
/**
* Generates a random salt of the specified size.
*
* @example
* ```ts twoslash
* import { AesGcm } from 'ox'
*
* const salt = AesGcm.randomSalt()
* // @log: Uint8Array [123, 79, 183, 167, 163, 136, 136, 16, 168, 126, 13, 165, 170, 166, 136, 136, 16, 168, 126, 13, 165, 170, 166, 136, 136, 16, 168, 126, 13, 165, 170, 166]
* ```
*
* @param size - The size of the salt to generate. Defaults to `32`.
* @returns A random salt of the specified size.
*/
export function randomSalt(size = 32): Bytes.Bytes {
return Bytes.random(size)
}
export declare namespace randomSalt {
type ErrorType = Bytes.random.ErrorType | Errors.GlobalErrorType
}

595
node_modules/ox/core/Authorization.ts generated vendored Normal file
View File

@@ -0,0 +1,595 @@
import type * as Address from './Address.js'
import type * as Errors from './Errors.js'
import * as Hash from './Hash.js'
import * as Hex from './Hex.js'
import * as Rlp from './Rlp.js'
import * as Signature from './Signature.js'
import type { Compute, Mutable, Undefined } from './internal/types.js'
/** Root type for an EIP-7702 Authorization. */
export type Authorization<
signed extends boolean = boolean,
bigintType = bigint,
numberType = number,
> = Compute<
{
/** Address of the contract to set as code for the Authority. */
address: Address.Address
/** Chain ID to authorize. */
chainId: numberType
/** Nonce of the Authority to authorize. */
nonce: bigintType
} & (signed extends true
? Signature.Signature<true, bigintType, numberType>
: Undefined<Signature.Signature>)
>
/** RPC representation of an {@link ox#Authorization.Authorization}. */
export type Rpc = Authorization<true, Hex.Hex, Hex.Hex>
/** List of {@link ox#Authorization.Authorization}. */
export type List<
signed extends boolean = boolean,
bigintType = bigint,
numberType = number,
> = Compute<readonly Authorization<signed, bigintType, numberType>[]>
/** RPC representation of an {@link ox#Authorization.List}. */
export type ListRpc = List<true, Hex.Hex, Hex.Hex>
/** Signed representation of a list of {@link ox#Authorization.Authorization}. */
export type ListSigned<bigintType = bigint, numberType = number> = List<
true,
bigintType,
numberType
>
/** Signed representation of an {@link ox#Authorization.Authorization}. */
export type Signed<bigintType = bigint, numberType = number> = Authorization<
true,
bigintType,
numberType
>
/** Tuple representation of an {@link ox#Authorization.Authorization}. */
export type Tuple<signed extends boolean = boolean> = signed extends true
? readonly [
chainId: Hex.Hex,
address: Hex.Hex,
nonce: Hex.Hex,
yParity: Hex.Hex,
r: Hex.Hex,
s: Hex.Hex,
]
: readonly [chainId: Hex.Hex, address: Hex.Hex, nonce: Hex.Hex]
/** Tuple representation of a signed {@link ox#Authorization.Authorization}. */
export type TupleSigned = Tuple<true>
/** Tuple representation of a list of {@link ox#Authorization.Authorization}. */
export type TupleList<signed extends boolean = boolean> =
readonly Tuple<signed>[]
/** Tuple representation of a list of signed {@link ox#Authorization.Authorization}. */
export type TupleListSigned = TupleList<true>
/**
* Converts an [EIP-7702](https://eips.ethereum.org/EIPS/eip-7702) Authorization object into a typed {@link ox#Authorization.Authorization}.
*
* @example
* An Authorization can be instantiated from an [EIP-7702](https://eips.ethereum.org/EIPS/eip-7702) Authorization tuple in object format.
*
* ```ts twoslash
* import { Authorization } from 'ox'
*
* const authorization = Authorization.from({
* address: '0x1234567890abcdef1234567890abcdef12345678',
* chainId: 1,
* nonce: 69n,
* })
* ```
*
* @example
* ### Attaching Signatures
*
* A {@link ox#Signature.Signature} can be attached with the `signature` option. The example below demonstrates signing
* an Authorization with {@link ox#Secp256k1.(sign:function)}.
*
* ```ts twoslash
* import { Authorization, Secp256k1 } from 'ox'
*
* const authorization = Authorization.from({
* address: '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c',
* chainId: 1,
* nonce: 40n,
* })
*
* const signature = Secp256k1.sign({
* payload: Authorization.getSignPayload(authorization),
* privateKey: '0x...',
* })
*
* const authorization_signed = Authorization.from(authorization, { signature }) // [!code focus]
* ```
*
* @param authorization - An [EIP-7702](https://eips.ethereum.org/EIPS/eip-7702) Authorization tuple in object format.
* @param options - Authorization options.
* @returns The {@link ox#Authorization.Authorization}.
*/
export function from<
const authorization extends Authorization | Rpc,
const signature extends Signature.Signature | undefined = undefined,
>(
authorization: authorization | Authorization,
options: from.Options<signature> = {},
): from.ReturnType<authorization, signature> {
if (typeof authorization.chainId === 'string')
return fromRpc(authorization) as never
return { ...authorization, ...options.signature } as never
}
export declare namespace from {
type Options<
signature extends Signature.Signature | undefined =
| Signature.Signature
| undefined,
> = {
/** The {@link ox#Signature.Signature} to attach to the Authorization. */
signature?: signature | Signature.Signature | undefined
}
type ReturnType<
authorization extends Authorization | Rpc = Authorization,
signature extends Signature.Signature | undefined =
| Signature.Signature
| undefined,
> = Compute<
authorization extends Rpc
? Signed
: authorization &
(signature extends Signature.Signature ? Readonly<signature> : {})
>
type ErrorType = Errors.GlobalErrorType
}
/**
* Converts an {@link ox#Authorization.Rpc} to an {@link ox#Authorization.Authorization}.
*
* @example
* ```ts twoslash
* import { Authorization } from 'ox'
*
* const authorization = Authorization.fromRpc({
* address: '0x0000000000000000000000000000000000000000',
* chainId: '0x1',
* nonce: '0x1',
* r: '0x635dc2033e60185bb36709c29c75d64ea51dfbd91c32ef4be198e4ceb169fb4d',
* s: '0x50c2667ac4c771072746acfdcf1f1483336dcca8bd2df47cd83175dbe60f0540',
* yParity: '0x0',
* })
* ```
*
* @param authorization - The RPC-formatted Authorization.
* @returns A signed {@link ox#Authorization.Authorization}.
*/
export function fromRpc(authorization: Rpc): Signed {
const { address, chainId, nonce } = authorization
const signature = Signature.extract(authorization)!
return {
address,
chainId: Number(chainId),
nonce: BigInt(nonce),
...signature,
}
}
export declare namespace fromRpc {
type ErrorType = Errors.GlobalErrorType
}
/**
* Converts an {@link ox#Authorization.ListRpc} to an {@link ox#Authorization.List}.
*
* @example
* ```ts twoslash
* import { Authorization } from 'ox'
*
* const authorizationList = Authorization.fromRpcList([{
* address: '0x0000000000000000000000000000000000000000',
* chainId: '0x1',
* nonce: '0x1',
* r: '0x635dc2033e60185bb36709c29c75d64ea51dfbd91c32ef4be198e4ceb169fb4d',
* s: '0x50c2667ac4c771072746acfdcf1f1483336dcca8bd2df47cd83175dbe60f0540',
* yParity: '0x0',
* }])
* ```
*
* @param authorizationList - The RPC-formatted Authorization list.
* @returns A signed {@link ox#Authorization.List}.
*/
export function fromRpcList(authorizationList: ListRpc): ListSigned {
return authorizationList.map(fromRpc)
}
export declare namespace fromRpcList {
type ErrorType = Errors.GlobalErrorType
}
/**
* Converts an {@link ox#Authorization.Tuple} to an {@link ox#Authorization.Authorization}.
*
* @example
* ```ts twoslash
* import { Authorization } from 'ox'
*
* const authorization = Authorization.fromTuple([
* '0x1',
* '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c',
* '0x3'
* ])
* // @log: {
* // @log: address: '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c',
* // @log: chainId: 1,
* // @log: nonce: 3n
* // @log: }
* ```
*
* @example
* It is also possible to append a Signature tuple to the end of an Authorization tuple.
*
* ```ts twoslash
* import { Authorization } from 'ox'
*
* const authorization = Authorization.fromTuple([
* '0x1',
* '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c',
* '0x3',
* '0x1',
* '0x68a020a209d3d56c46f38cc50a33f704f4a9a10a59377f8dd762ac66910e9b90',
* '0x7e865ad05c4035ab5792787d4a0297a43617ae897930a6fe4d822b8faea52064',
* ])
* // @log: {
* // @log: address: '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c',
* // @log: chainId: 1,
* // @log: nonce: 3n
* // @log: r: BigInt('0x68a020a209d3d56c46f38cc50a33f704f4a9a10a59377f8dd762ac66910e9b90'),
* // @log: s: BigInt('0x7e865ad05c4035ab5792787d4a0297a43617ae897930a6fe4d822b8faea52064'),
* // @log: yParity: 0,
* // @log: }
* ```
*
* @param tuple - The [EIP-7702](https://eips.ethereum.org/EIPS/eip-7702) Authorization tuple.
* @returns The {@link ox#Authorization.Authorization}.
*/
export function fromTuple<const tuple extends Tuple>(
tuple: tuple,
): fromTuple.ReturnType<tuple> {
const [chainId, address, nonce, yParity, r, s] = tuple
const signature =
yParity && r && s ? Signature.fromTuple([yParity, r, s]) : undefined
return from({
address,
chainId: Number(chainId),
nonce: BigInt(nonce),
...signature,
}) as never
}
export declare namespace fromTuple {
type ReturnType<authorization extends Tuple = Tuple> = Compute<
Authorization<authorization extends Tuple<true> ? true : false>
>
type ErrorType = Errors.GlobalErrorType
}
/**
* Converts an {@link ox#Authorization.TupleList} to an {@link ox#Authorization.List}.
*
* @example
* ```ts twoslash
* import { Authorization } from 'ox'
*
* const authorizationList = Authorization.fromTupleList([
* ['0x1', '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c', '0x3'],
* ['0x3', '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c', '0x14'],
* ])
* // @log: [
* // @log: {
* // @log: address: '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c',
* // @log: chainId: 1,
* // @log: nonce: 3n,
* // @log: },
* // @log: {
* // @log: address: '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c',
* // @log: chainId: 3,
* // @log: nonce: 20n,
* // @log: },
* // @log: ]
* ```
*
* @example
* It is also possible to append a Signature tuple to the end of an Authorization tuple.
*
* ```ts twoslash
* import { Authorization } from 'ox'
*
* const authorizationList = Authorization.fromTupleList([
* ['0x1', '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c', '0x3', '0x1', '0x68a020a209d3d56c46f38cc50a33f704f4a9a10a59377f8dd762ac66910e9b90', '0x7e865ad05c4035ab5792787d4a0297a43617ae897930a6fe4d822b8faea52064'],
* ['0x3', '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c', '0x14', '0x1', '0x68a020a209d3d56c46f38cc50a33f704f4a9a10a59377f8dd762ac66910e9b90', '0x7e865ad05c4035ab5792787d4a0297a43617ae897930a6fe4d822b8faea52064'],
* ])
* // @log: [
* // @log: {
* // @log: address: '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c',
* // @log: chainId: 1,
* // @log: nonce: 3n,
* // @log: r: BigInt('0x68a020a209d3d56c46f38cc50a33f704f4a9a10a59377f8dd762ac66910e9b90'),
* // @log: s: BigInt('0x7e865ad05c4035ab5792787d4a0297a43617ae897930a6fe4d822b8faea52064'),
* // @log: yParity: 0,
* // @log: },
* // @log: {
* // @log: address: '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c',
* // @log: chainId: 3,
* // @log: nonce: 20n,
* // @log: r: BigInt('0x68a020a209d3d56c46f38cc50a33f704f4a9a10a59377f8dd762ac66910e9b90'),
* // @log: s: BigInt('0x7e865ad05c4035ab5792787d4a0297a43617ae897930a6fe4d822b8faea52064'),
* // @log: yParity: 0,
* // @log: },
* // @log: ]
* ```
*
* @param tupleList - The [EIP-7702](https://eips.ethereum.org/EIPS/eip-7702) Authorization tuple list.
* @returns An {@link ox#Authorization.List}.
*/
export function fromTupleList<const tupleList extends TupleList>(
tupleList: tupleList,
): fromTupleList.ReturnType<tupleList> {
const list: Mutable<List> = []
for (const tuple of tupleList) list.push(fromTuple(tuple))
return list as never
}
export declare namespace fromTupleList {
type ReturnType<tupleList extends TupleList> = Compute<
TupleList<tupleList extends TupleList<true> ? true : false>
>
type ErrorType = Errors.GlobalErrorType
}
/**
* Computes the sign payload for an {@link ox#Authorization.Authorization} in [EIP-7702 format](https://eips.ethereum.org/EIPS/eip-7702): `keccak256('0x05' || rlp([chain_id, address, nonce]))`.
*
* @example
* The example below demonstrates computing the sign payload for an {@link ox#Authorization.Authorization}. This payload
* can then be passed to signing functions like {@link ox#Secp256k1.(sign:function)}.
*
* ```ts twoslash
* import { Authorization, Secp256k1 } from 'ox'
*
* const authorization = Authorization.from({
* address: '0x1234567890abcdef1234567890abcdef12345678',
* chainId: 1,
* nonce: 69n,
* })
*
* const payload = Authorization.getSignPayload(authorization) // [!code focus]
*
* const signature = Secp256k1.sign({
* payload,
* privateKey: '0x...',
* })
* ```
*
* @param authorization - The {@link ox#Authorization.Authorization}.
* @returns The sign payload.
*/
export function getSignPayload(authorization: Authorization): Hex.Hex {
return hash(authorization)
}
export declare namespace getSignPayload {
type ErrorType = hash.ErrorType | Errors.GlobalErrorType
}
/**
* Computes the hash for an {@link ox#Authorization.Authorization} in [EIP-7702 format](https://eips.ethereum.org/EIPS/eip-7702): `keccak256('0x05' || rlp([chain_id, address, nonce]))`.
*
* @example
* ```ts twoslash
* import { Authorization } from 'ox'
*
* const authorization = Authorization.from({
* address: '0x1234567890abcdef1234567890abcdef12345678',
* chainId: 1,
* nonce: 69n,
* })
*
* const hash = Authorization.hash(authorization) // [!code focus]
* ```
*
* @param authorization - The {@link ox#Authorization.Authorization}.
* @returns The hash.
*/
export function hash(authorization: Authorization): Hex.Hex {
return Hash.keccak256(Hex.concat('0x05', Rlp.fromHex(toTuple(authorization))))
}
export declare namespace hash {
type ErrorType =
| toTuple.ErrorType
| Hash.keccak256.ErrorType
| Hex.concat.ErrorType
| Rlp.fromHex.ErrorType
| Errors.GlobalErrorType
}
/**
* Converts an {@link ox#Authorization.Authorization} to an {@link ox#Authorization.Rpc}.
*
* @example
* ```ts twoslash
* import { Authorization } from 'ox'
*
* const authorization = Authorization.toRpc({
* address: '0x0000000000000000000000000000000000000000',
* chainId: 1,
* nonce: 1n,
* r: 44944627813007772897391531230081695102703289123332187696115181104739239197517n,
* s: 36528503505192438307355164441104001310566505351980369085208178712678799181120n,
* yParity: 0,
* })
* ```
*
* @param authorization - An Authorization.
* @returns An RPC-formatted Authorization.
*/
export function toRpc(authorization: Signed): Rpc {
const { address, chainId, nonce, ...signature } = authorization
return {
address,
chainId: Hex.fromNumber(chainId),
nonce: Hex.fromNumber(nonce),
...Signature.toRpc(signature),
}
}
export declare namespace toRpc {
type ErrorType = Errors.GlobalErrorType
}
/**
* Converts an {@link ox#Authorization.List} to an {@link ox#Authorization.ListRpc}.
*
* @example
* ```ts twoslash
* import { Authorization } from 'ox'
*
* const authorization = Authorization.toRpcList([{
* address: '0x0000000000000000000000000000000000000000',
* chainId: 1,
* nonce: 1n,
* r: 44944627813007772897391531230081695102703289123332187696115181104739239197517n,
* s: 36528503505192438307355164441104001310566505351980369085208178712678799181120n,
* yParity: 0,
* }])
* ```
*
* @param authorizationList - An Authorization List.
* @returns An RPC-formatted Authorization List.
*/
export function toRpcList(authorizationList: ListSigned): ListRpc {
return authorizationList.map(toRpc)
}
export declare namespace toRpcList {
type ErrorType = Errors.GlobalErrorType
}
/**
* Converts an {@link ox#Authorization.Authorization} to an {@link ox#Authorization.Tuple}.
*
* @example
* ```ts twoslash
* import { Authorization } from 'ox'
*
* const authorization = Authorization.from({
* address: '0x1234567890abcdef1234567890abcdef12345678',
* chainId: 1,
* nonce: 69n,
* })
*
* const tuple = Authorization.toTuple(authorization) // [!code focus]
* // @log: [
* // @log: address: '0x1234567890abcdef1234567890abcdef12345678',
* // @log: chainId: 1,
* // @log: nonce: 69n,
* // @log: ]
* ```
*
* @param authorization - The {@link ox#Authorization.Authorization}.
* @returns An [EIP-7702](https://eips.ethereum.org/EIPS/eip-7702) Authorization tuple.
*/
export function toTuple<const authorization extends Authorization>(
authorization: authorization,
): toTuple.ReturnType<authorization> {
const { address, chainId, nonce } = authorization
const signature = Signature.extract(authorization)
return [
chainId ? Hex.fromNumber(chainId) : '0x',
address,
nonce ? Hex.fromNumber(nonce) : '0x',
...(signature ? Signature.toTuple(signature) : []),
] as never
}
export declare namespace toTuple {
type ReturnType<authorization extends Authorization = Authorization> =
Compute<Tuple<authorization extends Signature.Signature ? true : false>>
type ErrorType = Errors.GlobalErrorType
}
/**
* Converts an {@link ox#Authorization.List} to an {@link ox#Authorization.TupleList}.
*
* @example
* ```ts twoslash
* import { Authorization } from 'ox'
*
* const authorization_1 = Authorization.from({
* address: '0x1234567890abcdef1234567890abcdef12345678',
* chainId: 1,
* nonce: 69n,
* })
* const authorization_2 = Authorization.from({
* address: '0x1234567890abcdef1234567890abcdef12345678',
* chainId: 3,
* nonce: 20n,
* })
*
* const tuple = Authorization.toTupleList([authorization_1, authorization_2]) // [!code focus]
* // @log: [
* // @log: [
* // @log: address: '0x1234567890abcdef1234567890abcdef12345678',
* // @log: chainId: 1,
* // @log: nonce: 69n,
* // @log: ],
* // @log: [
* // @log: address: '0x1234567890abcdef1234567890abcdef12345678',
* // @log: chainId: 3,
* // @log: nonce: 20n,
* // @log: ],
* // @log: ]
* ```
*
* @param list - An {@link ox#Authorization.List}.
* @returns An [EIP-7702](https://eips.ethereum.org/EIPS/eip-7702) Authorization tuple list.
*/
export function toTupleList<
const list extends
| readonly Authorization<true>[]
| readonly Authorization<false>[],
>(list?: list | undefined): toTupleList.ReturnType<list> {
if (!list || list.length === 0) return []
const tupleList: Mutable<TupleList> = []
for (const authorization of list) tupleList.push(toTuple(authorization))
return tupleList as never
}
export declare namespace toTupleList {
type ReturnType<
list extends
| readonly Authorization<true>[]
| readonly Authorization<false>[],
> = Compute<
TupleList<list extends readonly Authorization<true>[] ? true : false>
>
type ErrorType = Errors.GlobalErrorType
}

156
node_modules/ox/core/Base58.ts generated vendored Normal file
View File

@@ -0,0 +1,156 @@
import * as Bytes from './Bytes.js'
import type * as Errors from './Errors.js'
import * as Hex from './Hex.js'
import * as internal from './internal/base58.js'
/**
* Encodes a {@link ox#Bytes.Bytes} to a Base58-encoded string.
*
* @example
* ```ts twoslash
* import { Base58, Bytes } from 'ox'
*
* const value = Base58.fromBytes(Bytes.fromString('Hello World!'))
* // @log: '2NEpo7TZRRrLZSi2U'
* ```
*
* @param value - The byte array to encode.
* @returns The Base58 encoded string.
*/
export function fromBytes(value: Bytes.Bytes) {
return internal.from(value)
}
export declare namespace fromBytes {
type ErrorType = internal.from.ErrorType | Errors.GlobalErrorType
}
/**
* Encodes a {@link ox#Hex.Hex} to a Base58-encoded string.
*
* @example
* ```ts twoslash
* import { Base58, Hex } from 'ox'
*
* const value = Base58.fromHex(Hex.fromString('Hello World!'))
* // @log: '2NEpo7TZRRrLZSi2U'
* ```
*
* @param value - The byte array to encode.
* @returns The Base58 encoded string.
*/
export function fromHex(value: Hex.Hex) {
return internal.from(value)
}
export declare namespace fromHex {
type ErrorType = internal.from.ErrorType | Errors.GlobalErrorType
}
/**
* Encodes a string to a Base58-encoded string.
*
* @example
* ```ts twoslash
* import { Base58 } from 'ox'
*
* const value = Base58.fromString('Hello World!')
* // @log: '2NEpo7TZRRrLZSi2U'
* ```
*
* @param value - The string to encode.
* @returns The Base58 encoded string.
*/
export function fromString(value: string) {
return internal.from(Bytes.fromString(value))
}
export declare namespace fromString {
type ErrorType = internal.from.ErrorType | Errors.GlobalErrorType
}
/**
* Decodes a Base58-encoded string to a {@link ox#Bytes.Bytes}.
*
* @example
* ```ts twoslash
* import { Base58 } from 'ox'
*
* const value = Base58.toBytes('2NEpo7TZRRrLZSi2U')
* // @log: Uint8Array [ 72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33 ]
* ```
*
* @param value - The Base58 encoded string.
* @returns The decoded byte array.
*/
export function toBytes(value: string): Bytes.Bytes {
return Bytes.fromHex(toHex(value))
}
export declare namespace toBytes {
type ErrorType = Errors.GlobalErrorType
}
/**
* Decodes a Base58-encoded string to {@link ox#Hex.Hex}.
*
* @example
* ```ts twoslash
* import { Base58 } from 'ox'
*
* const value = Base58.toHex('2NEpo7TZRRrLZSi2U')
* // @log: '0x48656c6c6f20576f726c6421'
* ```
*
* @param value - The Base58 encoded string.
* @returns The decoded hex string.
*/
export function toHex(value: string): Hex.Hex {
let integer = BigInt(0)
let pad = 0
let checkPad = true
for (let i = 0; i < value.length; i++) {
const char = value[i]!
// check for leading 1s
if (checkPad && char === '1') pad++
else checkPad = false
// check for invalid characters
if (typeof internal.alphabetToInteger[char] !== 'bigint')
throw new Error('invalid base58 character: ' + char)
integer = integer * 58n
integer = integer + internal.alphabetToInteger[char]!
}
if (!pad) return `0x${integer.toString(16)}` as Hex.Hex
return `0x${'0'.repeat(pad * 2)}${integer.toString(16)}` as Hex.Hex
}
export declare namespace toHex {
type ErrorType = Errors.GlobalErrorType
}
/**
* Decodes a Base58-encoded string to a string.
*
* @example
* ```ts twoslash
* import { Base58 } from 'ox'
*
* const value = Base58.toString('2NEpo7TZRRrLZSi2U')
* // @log: 'Hello World!'
* ```
*
* @param value - The Base58 encoded string.
* @returns The decoded string.
*/
export function toString(value: string): string {
return Hex.toString(toHex(value))
}
export declare namespace toString {
type ErrorType = Errors.GlobalErrorType
}

309
node_modules/ox/core/Base64.ts generated vendored Normal file
View File

@@ -0,0 +1,309 @@
import * as Bytes from './Bytes.js'
import type * as Errors from './Errors.js'
import * as Hex from './Hex.js'
const encoder = /*#__PURE__*/ new TextEncoder()
const decoder = /*#__PURE__*/ new TextDecoder()
const integerToCharacter = /*#__PURE__*/ Object.fromEntries(
Array.from(
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',
).map((a, i) => [i, a.charCodeAt(0)]),
)
const characterToInteger = /*#__PURE__*/ {
...Object.fromEntries(
Array.from(
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',
).map((a, i) => [a.charCodeAt(0), i]),
),
['='.charCodeAt(0)]: 0,
['-'.charCodeAt(0)]: 62,
['_'.charCodeAt(0)]: 63,
} as Record<number, number>
/**
* Encodes a {@link ox#Bytes.Bytes} to a Base64-encoded string (with optional padding and/or URL-safe characters).
*
* @example
* ```ts twoslash
* import { Base64, Bytes } from 'ox'
*
* const value = Base64.fromBytes(Bytes.fromString('hello world'))
* // @log: 'aGVsbG8gd29ybGQ='
* ```
*
* @example
* ### No Padding
*
* Turn off [padding of encoded data](https://datatracker.ietf.org/doc/html/rfc4648#section-3.2) with the `pad` option:
*
* ```ts twoslash
* import { Base64, Bytes } from 'ox'
*
* const value = Base64.fromBytes(Bytes.fromString('hello world'), { pad: false })
* // @log: 'aGVsbG8gd29ybGQ'
* ```
*
* ### URL-safe Encoding
*
* Turn on [URL-safe encoding](https://datatracker.ietf.org/doc/html/rfc4648#section-5) (Base64 URL) with the `url` option:
*
* ```ts twoslash
* import { Base64, Bytes } from 'ox'
*
* const value = Base64.fromBytes(Bytes.fromString('hello wod'), { url: true })
* // @log: 'aGVsbG8gd29_77-9ZA=='
* ```
*
* @param value - The byte array to encode.
* @param options - Encoding options.
* @returns The Base64 encoded string.
*/
export function fromBytes(value: Bytes.Bytes, options: fromBytes.Options = {}) {
const { pad = true, url = false } = options
const encoded = new Uint8Array(Math.ceil(value.length / 3) * 4)
for (let i = 0, j = 0; j < value.length; i += 4, j += 3) {
const y = (value[j]! << 16) + (value[j + 1]! << 8) + (value[j + 2]! | 0)
encoded[i] = integerToCharacter[y >> 18]!
encoded[i + 1] = integerToCharacter[(y >> 12) & 0x3f]!
encoded[i + 2] = integerToCharacter[(y >> 6) & 0x3f]!
encoded[i + 3] = integerToCharacter[y & 0x3f]!
}
const k = value.length % 3
const end = Math.floor(value.length / 3) * 4 + (k && k + 1)
let base64 = decoder.decode(new Uint8Array(encoded.buffer, 0, end))
if (pad && k === 1) base64 += '=='
if (pad && k === 2) base64 += '='
if (url) base64 = base64.replaceAll('+', '-').replaceAll('/', '_')
return base64
}
export declare namespace fromBytes {
type Options = {
/**
* Whether to [pad](https://datatracker.ietf.org/doc/html/rfc4648#section-3.2) the Base64 encoded string.
*
* @default true
*/
pad?: boolean | undefined
/**
* Whether to Base64 encode with [URL safe characters](https://datatracker.ietf.org/doc/html/rfc4648#section-5).
*
* @default false
*/
url?: boolean | undefined
}
type ErrorType = Errors.GlobalErrorType
}
/**
* Encodes a {@link ox#Hex.Hex} to a Base64-encoded string (with optional padding and/or URL-safe characters).
*
* @example
* ```ts twoslash
* import { Base64, Hex } from 'ox'
*
* const value = Base64.fromHex(Hex.fromString('hello world'))
* // @log: 'aGVsbG8gd29ybGQ='
* ```
*
* @example
* ### No Padding
*
* Turn off [padding of encoded data](https://datatracker.ietf.org/doc/html/rfc4648#section-3.2) with the `pad` option:
*
* ```ts twoslash
* import { Base64, Hex } from 'ox'
*
* const value = Base64.fromHex(Hex.fromString('hello world'), { pad: false })
* // @log: 'aGVsbG8gd29ybGQ'
* ```
*
* ### URL-safe Encoding
*
* Turn on [URL-safe encoding](https://datatracker.ietf.org/doc/html/rfc4648#section-5) (Base64 URL) with the `url` option:
*
* ```ts twoslash
* import { Base64, Hex } from 'ox'
*
* const value = Base64.fromHex(Hex.fromString('hello wod'), { url: true })
* // @log: 'aGVsbG8gd29_77-9ZA=='
* ```
*
* @param value - The hex value to encode.
* @param options - Encoding options.
* @returns The Base64 encoded string.
*/
export function fromHex(value: Hex.Hex, options: fromHex.Options = {}) {
return fromBytes(Bytes.fromHex(value), options)
}
export declare namespace fromHex {
type Options = {
/**
* Whether to [pad](https://datatracker.ietf.org/doc/html/rfc4648#section-3.2) the Base64 encoded string.
*
* @default true
*/
pad?: boolean | undefined
/**
* Whether to Base64 encode with [URL safe characters](https://datatracker.ietf.org/doc/html/rfc4648#section-5).
*
* @default false
*/
url?: boolean | undefined
}
type ErrorType = fromBytes.ErrorType | Errors.GlobalErrorType
}
/**
* Encodes a string to a Base64-encoded string (with optional padding and/or URL-safe characters).
*
* @example
* ```ts twoslash
* import { Base64 } from 'ox'
*
* const value = Base64.fromString('hello world')
* // @log: 'aGVsbG8gd29ybGQ='
* ```
*
* @example
* ### No Padding
*
* Turn off [padding of encoded data](https://datatracker.ietf.org/doc/html/rfc4648#section-3.2) with the `pad` option:
*
* ```ts twoslash
* import { Base64 } from 'ox'
*
* const value = Base64.fromString('hello world', { pad: false })
* // @log: 'aGVsbG8gd29ybGQ'
* ```
*
* ### URL-safe Encoding
*
* Turn on [URL-safe encoding](https://datatracker.ietf.org/doc/html/rfc4648#section-5) (Base64 URL) with the `url` option:
*
* ```ts twoslash
* import { Base64 } from 'ox'
*
* const value = Base64.fromString('hello wod', { url: true })
* // @log: 'aGVsbG8gd29_77-9ZA=='
* ```
*
* @param value - The string to encode.
* @param options - Encoding options.
* @returns The Base64 encoded string.
*/
export function fromString(value: string, options: fromString.Options = {}) {
return fromBytes(Bytes.fromString(value), options)
}
export declare namespace fromString {
type Options = {
/**
* Whether to [pad](https://datatracker.ietf.org/doc/html/rfc4648#section-3.2) the Base64 encoded string.
*
* @default true
*/
pad?: boolean | undefined
/**
* Whether to Base64 encode with [URL safe characters](https://datatracker.ietf.org/doc/html/rfc4648#section-5).
*
* @default false
*/
url?: boolean | undefined
}
type ErrorType = fromBytes.ErrorType | Errors.GlobalErrorType
}
/**
* Decodes a Base64-encoded string (with optional padding and/or URL-safe characters) to {@link ox#Bytes.Bytes}.
*
* @example
* ```ts twoslash
* import { Base64, Bytes } from 'ox'
*
* const value = Base64.toBytes('aGVsbG8gd29ybGQ=')
* // @log: Uint8Array([104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100])
* ```
*
* @param value - The string, hex value, or byte array to encode.
* @returns The Base64 decoded {@link ox#Bytes.Bytes}.
*/
export function toBytes(value: string): Bytes.Bytes {
const base64 = value.replace(/=+$/, '')
const size = base64.length
const decoded = new Uint8Array(size + 3)
encoder.encodeInto(base64 + '===', decoded)
for (let i = 0, j = 0; i < base64.length; i += 4, j += 3) {
const x =
(characterToInteger[decoded[i]!]! << 18) +
(characterToInteger[decoded[i + 1]!]! << 12) +
(characterToInteger[decoded[i + 2]!]! << 6) +
characterToInteger[decoded[i + 3]!]!
decoded[j] = x >> 16
decoded[j + 1] = (x >> 8) & 0xff
decoded[j + 2] = x & 0xff
}
const decodedSize = (size >> 2) * 3 + (size % 4 && (size % 4) - 1)
return new Uint8Array(decoded.buffer, 0, decodedSize)
}
export declare namespace toBytes {
type ErrorType = Errors.GlobalErrorType
}
/**
* Decodes a Base64-encoded string (with optional padding and/or URL-safe characters) to {@link ox#Hex.Hex}.
*
* @example
* ```ts twoslash
* import { Base64, Hex } from 'ox'
*
* const value = Base64.toHex('aGVsbG8gd29ybGQ=')
* // @log: 0x68656c6c6f20776f726c64
* ```
*
* @param value - The string, hex value, or byte array to encode.
* @returns The Base64 decoded {@link ox#Hex.Hex}.
*/
export function toHex(value: string): Hex.Hex {
return Hex.fromBytes(toBytes(value))
}
export declare namespace toHex {
type ErrorType = toBytes.ErrorType | Errors.GlobalErrorType
}
/**
* Decodes a Base64-encoded string (with optional padding and/or URL-safe characters) to a string.
*
* @example
* ```ts twoslash
* import { Base64 } from 'ox'
*
* const value = Base64.toString('aGVsbG8gd29ybGQ=')
* // @log: 'hello world'
* ```
*
* @param value - The string, hex value, or byte array to encode.
* @returns The Base64 decoded string.
*/
export function toString(value: string): string {
return Bytes.toString(toBytes(value))
}
export declare namespace toString {
type ErrorType = toBytes.ErrorType | Errors.GlobalErrorType
}

271
node_modules/ox/core/BinaryStateTree.ts generated vendored Normal file
View File

@@ -0,0 +1,271 @@
import { blake3 } from '@noble/hashes/blake3'
import * as Bytes from './Bytes.js'
import type { OneOf } from './internal/types.js'
/** Type that defines a Binary State Tree instance. */
export type BinaryStateTree = {
root: Node
}
/** Type defining a node of the BST. */
export type Node = OneOf<EmptyNode | StemNode | InternalNode>
/**
* Creates a new Binary State Tree instance.
*
* @example
* ```ts twoslash
* import { BinaryStateTree } from 'ox'
*
* const tree = BinaryStateTree.create()
* ```
*
* @returns A Binary State Tree.
*/
export function create(): BinaryStateTree {
return {
root: emptyNode(),
}
}
/**
* Inserts a key-value pair into the Binary State Tree.
*
* @example
* ```ts twoslash
* import { BinaryStateTree, Bytes } from 'ox'
*
* const tree = BinaryStateTree.create()
*
* BinaryStateTree.insert( // [!code focus]
* tree, // [!code focus]
* Bytes.fromHex('0xe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54'), // [!code focus]
* Bytes.fromHex('0xd4fd4e189132273036449fc9e11198c739161b4c0116a9a2dccdfa1c492006f1') // [!code focus]
* ) // [!code focus]
* ```
*
* @param tree - Binary State Tree instance.
* @param key - Key to insert.
* @param value - Value to insert.
*/
export function insert(
tree: BinaryStateTree,
key: Bytes.Bytes,
value: Bytes.Bytes,
): void {
const stem = Bytes.slice(key, 0, 31)
const subIndex = Bytes.slice(key, 31)[0]!
if (tree.root.type === 'empty') {
tree.root = stemNode(stem)
tree.root.values[subIndex] = value
return
}
function inner(
node_: Node,
stem: Bytes.Bytes,
subIndex: number,
value: Bytes.Bytes,
depth: number,
): Node {
let node = node_
if (node.type === 'empty') {
node = stemNode(stem)
node.values[subIndex!] = value
return node
}
const stemBits = bytesToBits(stem)
if (node.type === 'stem') {
if (Bytes.isEqual(node.stem, stem)) {
node.values[subIndex!] = value
return node
}
const existingStemBits = bytesToBits(node.stem)
return splitLeaf(node, stemBits, existingStemBits, subIndex, value, depth)
}
if (node.type === 'internal') {
const bit = stemBits[depth]
if (bit === 0) {
node.left = inner(node.left, stem, subIndex, value, depth + 1)
} else {
node.right = inner(node.right, stem, subIndex, value, depth + 1)
}
return node
}
return emptyNode()
}
tree.root = inner(tree.root, stem, subIndex, value, 0)
}
/**
* Merkelizes a Binary State Tree.
*
* @example
* ```ts twoslash
* import { BinaryStateTree, Bytes } from 'ox'
*
* const tree = BinaryStateTree.create()
*
* BinaryStateTree.insert(
* tree,
* Bytes.fromHex('0xe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54'),
* Bytes.fromHex('0xd4fd4e189132273036449fc9e11198c739161b4c0116a9a2dccdfa1c492006f1')
* )
*
* const hash = BinaryStateTree.merkelize(tree) // [!code focus]
* ```
*
* @param tree - Binary State Tree instance.
* @returns Merkle hash.
*/
export function merkelize(tree: BinaryStateTree): Bytes.Bytes {
function inner(node: Node): Bytes.Bytes {
if (node.type === 'empty') return new Uint8Array(32).fill(0)
if (node.type === 'internal') {
const hash_left = inner(node.left)
const hash_right = inner(node.right)
return hash(Bytes.concat(hash_left, hash_right))
}
let level = node.values.map(hash)
while (level.length > 1) {
const level_ = []
for (let i = 0; i < level.length; i += 2)
level_.push(hash(Bytes.concat(level[i]!, level[i + 1]!)))
level = level_
}
return hash(Bytes.concat(node.stem, new Uint8Array(1).fill(0), level[0]!))
}
return inner(tree.root)
}
//////////////////////////////////////////////////////////////////////////////
// Internal
//////////////////////////////////////////////////////////////////////////////
/** @internal */
type EmptyNode = {
type: 'empty'
}
/** @internal */
type InternalNode = {
left: Node
right: Node
type: 'internal'
}
/** @internal */
type StemNode = {
stem: Bytes.Bytes
values: (Bytes.Bytes | undefined)[]
type: 'stem'
}
/** @internal */
function splitLeaf(
leaf: Node,
stemBits: number[],
existingStemBits: number[],
subIndex: number,
value: Bytes.Bytes,
depth: number,
): Node {
if (stemBits[depth] === existingStemBits[depth]) {
const internal = internalNode()
const bit = stemBits[depth]
if (bit === 0) {
internal.left = splitLeaf(
leaf,
stemBits,
existingStemBits,
subIndex,
value,
depth + 1,
)
} else {
internal.right = splitLeaf(
leaf,
stemBits,
existingStemBits,
subIndex,
value,
depth + 1,
)
}
return internal
}
const internal = internalNode()
const bit = stemBits[depth]
const stem = bitsToBytes(stemBits)
if (bit === 0) {
internal.left = stemNode(stem)
internal.left.values[subIndex] = value
internal.right = leaf
} else {
internal.right = stemNode(stem)
internal.right.values[subIndex] = value
internal.left = leaf
}
return internal
}
/** @internal */
function emptyNode(): EmptyNode {
return {
type: 'empty',
}
}
/** @internal */
function internalNode(): InternalNode {
return {
left: emptyNode(),
right: emptyNode(),
type: 'internal',
}
}
/** @internal */
function stemNode(stem: Bytes.Bytes): StemNode {
return {
stem,
values: Array.from({ length: 256 }, () => undefined),
type: 'stem',
}
}
/** @internal */
function bytesToBits(bytes: Bytes.Bytes): number[] {
const bits = []
for (const byte of bytes)
for (let i = 0; i < 8; i++) bits.push((byte >> (7 - i)) & 1)
return bits
}
/** @internal */
function bitsToBytes(bits: number[]): Bytes.Bytes {
const byte_data = new Uint8Array(bits.length / 8)
for (let i = 0; i < bits.length; i += 8) {
let byte = 0
for (let j = 0; j < 8; j++) byte |= bits[i + j]! << (7 - j)
byte_data[i / 8] = byte
}
return byte_data
}
/** @internal */
function hash(bytes: Bytes.Bytes | undefined): Bytes.Bytes {
if (!bytes) return new Uint8Array(32).fill(0)
if (!bytes.some((byte) => byte !== 0)) return new Uint8Array(32).fill(0)
return blake3(bytes)
}

943
node_modules/ox/core/Blobs.ts generated vendored Normal file
View File

@@ -0,0 +1,943 @@
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}`,
],
})
}
}

324
node_modules/ox/core/Block.ts generated vendored Normal file
View File

@@ -0,0 +1,324 @@
import type * as Address from './Address.js'
import type * as Errors from './Errors.js'
import * as Hex from './Hex.js'
import * as Transaction from './Transaction.js'
import * as Withdrawal from './Withdrawal.js'
import type { Compute, OneOf } from './internal/types.js'
/** A Block as defined in the [Execution API specification](https://github.com/ethereum/execution-apis/blob/main/src/schemas/block.yaml). */
export type Block<
includeTransactions extends boolean = false,
blockTag extends Tag = 'latest',
bigintType = bigint,
numberType = number,
transaction = Transaction.Transaction<
blockTag extends 'pending' ? true : false,
bigintType,
numberType
>,
> = Compute<{
/** Base fee per gas */
baseFeePerGas?: bigintType | undefined
/** Total used blob gas by all transactions in this block */
blobGasUsed?: bigintType | undefined
/** Difficulty for this block */
difficulty?: bigintType | undefined
/** Excess blob gas */
excessBlobGas?: bigintType | undefined
/** "Extra data" field of this block */
extraData?: Hex.Hex | undefined
/** Maximum gas allowed in this block */
gasLimit: bigintType
/** Total used gas by all transactions in this block */
gasUsed: bigintType
/** Block hash or `null` if pending */
hash: blockTag extends 'pending' ? null : Hex.Hex
/** Logs bloom filter or `null` if pending */
logsBloom: blockTag extends 'pending' ? null : Hex.Hex
/** Address that received this blocks mining rewards */
miner: Address.Address
/** Unique identifier for the block. */
mixHash: Hex.Hex
/** Proof-of-work hash or `null` if pending */
nonce: blockTag extends 'pending' ? null : Hex.Hex
/** Block number or `null` if pending */
number: blockTag extends 'pending' ? null : bigintType
parentBeaconBlockRoot?: Hex.Hex | undefined
/** Parent block hash */
parentHash: Hex.Hex
/** Root of the this blocks receipts trie */
receiptsRoot: Hex.Hex
sealFields?: readonly Hex.Hex[] | undefined
/** SHA3 of the uncles data in this block */
sha3Uncles: Hex.Hex
/** Size of this block in bytes */
size: bigintType
/** Root of this blocks final state trie */
stateRoot: Hex.Hex
/** Unix timestamp of when this block was collated */
timestamp: bigintType
/** Total difficulty of the chain until this block */
totalDifficulty?: bigintType | undefined
/** List of transaction objects or hashes */
transactions: includeTransactions extends true
? readonly transaction[]
: readonly Hex.Hex[]
/** Root of this blocks transaction trie */
transactionsRoot: Hex.Hex
/** List of uncle hashes */
uncles: readonly Hex.Hex[]
/** List of withdrawal objects */
withdrawals?:
| readonly Withdrawal.Withdrawal<bigintType, numberType>[]
| undefined
/** Root of the this blocks withdrawals trie */
withdrawalsRoot?: Hex.Hex | undefined
}>
/** A Block hash. */
export type Hash = Hex.Hex
/** A Block identifier. */
export type Identifier<bigintType = bigint> = {
/** Whether or not to throw an error if the block is not in the canonical chain as described below. Only allowed in conjunction with the blockHash tag. Defaults to false. */
requireCanonical?: boolean | undefined
} & OneOf<
| {
/** The block in the canonical chain with this number */
blockNumber: Number<bigintType>
}
| {
/** The block uniquely identified by this hash. The `blockNumber` and `blockHash` properties are mutually exclusive; exactly one of them must be set. */
blockHash: Hash
}
>
/** A Block number. */
export type Number<bigintType = bigint> = bigintType
/** An RPC Block as defined in the [Execution API specification](https://github.com/ethereum/execution-apis/blob/main/src/schemas/block.yaml). */
export type Rpc<
includeTransactions extends boolean = boolean,
blockTag extends Tag = 'latest',
transaction = Transaction.Rpc<blockTag extends 'pending' ? true : false>,
> = Block<includeTransactions, blockTag, Hex.Hex, Hex.Hex, transaction>
/**
* A Block Tag as defined in the [Execution API specification](https://github.com/ethereum/execution-apis/blob/main/src/schemas/block.yaml).
*
* - `earliest`: The lowest numbered block the client has available;
* - `finalized`: The most recent crypto-economically secure block, cannot be re-orged outside of manual intervention driven by community coordination;
* - `safe`: The most recent block that is safe from re-orgs under honest majority and certain synchronicity assumptions;
* - `latest`: The most recent block in the canonical chain observed by the client, this block may be re-orged out of the canonical chain even under healthy/normal conditions;
* - `pending`: A sample next block built by the client on top of `latest` and containing the set of transactions usually taken from local mempool.
*/
export type Tag = 'latest' | 'earliest' | 'pending' | 'safe' | 'finalized'
/**
* Converts a {@link ox#Block.Block} to an {@link ox#Block.Rpc}.
*
* @example
* ```ts twoslash
* // @noErrors
* import { Block } from 'ox'
*
* const block = Block.toRpc({
* // ...
* hash: '0xebc3644804e4040c0a74c5a5bbbc6b46a71a5d4010fe0c92ebb2fdf4a43ea5dd',
* number: 19868020n,
* size: 520n
* timestamp: 1662222222n,
* // ...
* })
* // @log: {
* // @log: // ...
* // @log: hash: '0xebc3644804e4040c0a74c5a5bbbc6b46a71a5d4010fe0c92ebb2fdf4a43ea5dd',
* // @log: number: '0xec6fc6',
* // @log: size: '0x208',
* // @log: timestamp: '0x63198f6f',
* // @log: // ...
* // @log: }
* ```
*
* @param block - The Block to convert.
* @returns An RPC Block.
*/
export function toRpc<
includeTransactions extends boolean = false,
blockTag extends Tag = 'latest',
>(
block: Block<includeTransactions, blockTag>,
_options: toRpc.Options<includeTransactions, blockTag> = {},
): Rpc<boolean, blockTag> {
const transactions = block.transactions.map((transaction) => {
if (typeof transaction === 'string') return transaction
return Transaction.toRpc(transaction as any) as any
})
return {
baseFeePerGas:
typeof block.baseFeePerGas === 'bigint'
? Hex.fromNumber(block.baseFeePerGas)
: undefined,
blobGasUsed:
typeof block.blobGasUsed === 'bigint'
? Hex.fromNumber(block.blobGasUsed)
: undefined,
excessBlobGas:
typeof block.excessBlobGas === 'bigint'
? Hex.fromNumber(block.excessBlobGas)
: undefined,
extraData: block.extraData,
difficulty:
typeof block.difficulty === 'bigint'
? Hex.fromNumber(block.difficulty)
: undefined,
gasLimit: Hex.fromNumber(block.gasLimit),
gasUsed: Hex.fromNumber(block.gasUsed),
hash: block.hash,
logsBloom: block.logsBloom,
miner: block.miner,
mixHash: block.mixHash,
nonce: block.nonce,
number: (typeof block.number === 'bigint'
? Hex.fromNumber(block.number)
: null) as never,
parentBeaconBlockRoot: block.parentBeaconBlockRoot,
parentHash: block.parentHash,
receiptsRoot: block.receiptsRoot,
sealFields: block.sealFields,
sha3Uncles: block.sha3Uncles,
size: Hex.fromNumber(block.size),
stateRoot: block.stateRoot,
timestamp: Hex.fromNumber(block.timestamp),
totalDifficulty:
typeof block.totalDifficulty === 'bigint'
? Hex.fromNumber(block.totalDifficulty)
: undefined,
transactions,
transactionsRoot: block.transactionsRoot,
uncles: block.uncles,
withdrawals: block.withdrawals?.map(Withdrawal.toRpc),
withdrawalsRoot: block.withdrawalsRoot,
}
}
export declare namespace toRpc {
type Options<
includeTransactions extends boolean = false,
blockTag extends Tag = 'latest',
> = {
blockTag?: blockTag | Tag | undefined
includeTransactions?: includeTransactions | boolean | undefined
}
type ErrorType = Errors.GlobalErrorType
}
/**
* Converts a {@link ox#Block.Rpc} to an {@link ox#Block.Block}.
*
* @example
* ```ts twoslash
* // @noErrors
* import { Block } from 'ox'
*
* const block = Block.fromRpc({
* // ...
* hash: '0xebc3644804e4040c0a74c5a5bbbc6b46a71a5d4010fe0c92ebb2fdf4a43ea5dd',
* number: '0xec6fc6',
* size: '0x208',
* timestamp: '0x63198f6f',
* // ...
* })
* // @log: {
* // @log: // ...
* // @log: hash: '0xebc3644804e4040c0a74c5a5bbbc6b46a71a5d4010fe0c92ebb2fdf4a43ea5dd',
* // @log: number: 19868020n,
* // @log: size: 520n,
* // @log: timestamp: 1662222222n,
* // @log: // ...
* // @log: }
* ```
*
* @example
* ### End-to-end
*
* Below is an end-to-end example of using `Block.fromRpc` to fetch a block from the network and convert it to an {@link ox#Block.Block}.
*
* ```ts twoslash
* import 'ox/window'
* import { Block } from 'ox'
*
* const block = await window.ethereum!
* .request({
* method: 'eth_getBlockByNumber',
* params: ['latest', false],
* })
* .then(Block.fromRpc) // [!code hl]
* // @log: {
* // @log: // ...
* // @log: hash: '0xebc3644804e4040c0a74c5a5bbbc6b46a71a5d4010fe0c92ebb2fdf4a43ea5dd',
* // @log: number: 19868020n,
* // @log: size: 520n,
* // @log: timestamp: 1662222222n,
* // @log: // ...
* // @log: }
* ```
*
* :::note
*
* For simplicity, the above example uses `window.ethereum.request`, but you can use any
* type of JSON-RPC interface.
*
* :::
*
* @param block - The RPC block to convert.
* @returns An instantiated {@link ox#Block.Block}.
*/
export function fromRpc<
const block extends Rpc | null,
includeTransactions extends boolean = false,
blockTag extends Tag = 'latest',
>(
block: block | Rpc | null,
_options: fromRpc.Options<includeTransactions, blockTag> = {},
): block extends Rpc ? Block<includeTransactions, blockTag> : null {
if (!block) return null as never
const transactions = block.transactions.map((transaction) => {
if (typeof transaction === 'string') return transaction
return Transaction.fromRpc(transaction) as any
})
return {
...block,
baseFeePerGas: block.baseFeePerGas
? BigInt(block.baseFeePerGas)
: undefined,
blobGasUsed: block.blobGasUsed ? BigInt(block.blobGasUsed) : undefined,
difficulty: block.difficulty ? BigInt(block.difficulty) : undefined,
excessBlobGas: block.excessBlobGas
? BigInt(block.excessBlobGas)
: undefined,
gasLimit: BigInt(block.gasLimit ?? 0n),
gasUsed: BigInt(block.gasUsed ?? 0n),
number: block.number ? BigInt(block.number) : null,
size: BigInt(block.size ?? 0n),
stateRoot: block.stateRoot,
timestamp: BigInt(block.timestamp ?? 0n),
totalDifficulty: BigInt(block.totalDifficulty ?? 0n),
transactions,
withdrawals: block.withdrawals?.map(Withdrawal.fromRpc),
} as Block as never
}
export declare namespace fromRpc {
type Options<
includeTransactions extends boolean = false,
blockTag extends Tag = 'latest',
> = {
blockTag?: blockTag | Tag | undefined
includeTransactions?: includeTransactions | boolean | undefined
}
type ErrorType = Errors.GlobalErrorType
}

146
node_modules/ox/core/BlockOverrides.ts generated vendored Normal file
View File

@@ -0,0 +1,146 @@
import type * as Address from './Address.js'
import * as Hex from './Hex.js'
import * as Withdrawal from './Withdrawal.js'
/**
* Block overrides.
*/
export type BlockOverrides<bigintType = bigint, numberType = number> = {
/** Base fee per gas. */
baseFeePerGas?: bigintType | undefined
/** Blob base fee. */
blobBaseFee?: bigintType | undefined
/** Fee recipient (also known as coinbase). */
feeRecipient?: Address.Address | undefined
/** Gas limit. */
gasLimit?: bigintType | undefined
/** Block number. */
number?: bigintType | undefined
/** The previous value of randomness beacon. */
prevRandao?: bigintType | undefined
/** Block timestamp. */
time?: bigintType | undefined
/** Withdrawals made by validators. */
withdrawals?: Withdrawal.Withdrawal<bigintType, numberType>[] | undefined
}
/**
* RPC block overrides.
*/
export type Rpc = BlockOverrides<Hex.Hex, Hex.Hex>
/**
* Converts an {@link ox#BlockOverrides.Rpc} to an {@link ox#BlockOverrides.BlockOverrides}.
*
* @example
* ```ts twoslash
* import { BlockOverrides } from 'ox'
*
* const blockOverrides = BlockOverrides.fromRpc({
* baseFeePerGas: '0x1',
* blobBaseFee: '0x2',
* feeRecipient: '0x0000000000000000000000000000000000000000',
* gasLimit: '0x4',
* number: '0x5',
* prevRandao: '0x6',
* time: '0x1234567890',
* withdrawals: [
* {
* address: '0x0000000000000000000000000000000000000000',
* amount: '0x1',
* index: '0x0',
* validatorIndex: '0x1',
* },
* ],
* })
* ```
*
* @param rpcBlockOverrides - The RPC block overrides to convert.
* @returns An instantiated {@link ox#BlockOverrides.BlockOverrides}.
*/
export function fromRpc(rpcBlockOverrides: Rpc): BlockOverrides {
return {
...(rpcBlockOverrides.baseFeePerGas && {
baseFeePerGas: BigInt(rpcBlockOverrides.baseFeePerGas),
}),
...(rpcBlockOverrides.blobBaseFee && {
blobBaseFee: BigInt(rpcBlockOverrides.blobBaseFee),
}),
...(rpcBlockOverrides.feeRecipient && {
feeRecipient: rpcBlockOverrides.feeRecipient,
}),
...(rpcBlockOverrides.gasLimit && {
gasLimit: BigInt(rpcBlockOverrides.gasLimit),
}),
...(rpcBlockOverrides.number && {
number: BigInt(rpcBlockOverrides.number),
}),
...(rpcBlockOverrides.prevRandao && {
prevRandao: BigInt(rpcBlockOverrides.prevRandao),
}),
...(rpcBlockOverrides.time && {
time: BigInt(rpcBlockOverrides.time),
}),
...(rpcBlockOverrides.withdrawals && {
withdrawals: rpcBlockOverrides.withdrawals.map(Withdrawal.fromRpc),
}),
}
}
/**
* Converts an {@link ox#BlockOverrides.BlockOverrides} to an {@link ox#BlockOverrides.Rpc}.
*
* @example
* ```ts twoslash
* import { BlockOverrides } from 'ox'
*
* const blockOverrides = BlockOverrides.toRpc({
* baseFeePerGas: 1n,
* blobBaseFee: 2n,
* feeRecipient: '0x0000000000000000000000000000000000000000',
* gasLimit: 4n,
* number: 5n,
* prevRandao: 6n,
* time: 78187493520n,
* withdrawals: [
* {
* address: '0x0000000000000000000000000000000000000000',
* amount: 1n,
* index: 0,
* validatorIndex: 1,
* },
* ],
* })
* ```
*
* @param blockOverrides - The block overrides to convert.
* @returns An instantiated {@link ox#BlockOverrides.Rpc}.
*/
export function toRpc(blockOverrides: BlockOverrides): Rpc {
return {
...(typeof blockOverrides.baseFeePerGas === 'bigint' && {
baseFeePerGas: Hex.fromNumber(blockOverrides.baseFeePerGas),
}),
...(typeof blockOverrides.blobBaseFee === 'bigint' && {
blobBaseFee: Hex.fromNumber(blockOverrides.blobBaseFee),
}),
...(typeof blockOverrides.feeRecipient === 'string' && {
feeRecipient: blockOverrides.feeRecipient,
}),
...(typeof blockOverrides.gasLimit === 'bigint' && {
gasLimit: Hex.fromNumber(blockOverrides.gasLimit),
}),
...(typeof blockOverrides.number === 'bigint' && {
number: Hex.fromNumber(blockOverrides.number),
}),
...(typeof blockOverrides.prevRandao === 'bigint' && {
prevRandao: Hex.fromNumber(blockOverrides.prevRandao),
}),
...(typeof blockOverrides.time === 'bigint' && {
time: Hex.fromNumber(blockOverrides.time),
}),
...(blockOverrides.withdrawals && {
withdrawals: blockOverrides.withdrawals.map(Withdrawal.toRpc),
}),
}
}

73
node_modules/ox/core/Bloom.ts generated vendored Normal file
View File

@@ -0,0 +1,73 @@
import * as Bytes from './Bytes.js'
import type * as Errors from './Errors.js'
import * as Hash from './Hash.js'
import * as Hex from './Hex.js'
/**
* Checks if an input is matched in the bloom filter.
*
* @example
* ```ts twoslash
* import { Bloom } from 'ox'
*
* Bloom.contains(
* '0x00000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002020000000000000000000000000000000000000000000008000000001000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
* '0xef2d6d194084c2de36e0dabfce45d046b37d1106',
* )
* // @log: true
* ```
*
* @param bloom - Bloom filter value.
* @param input - Input to check.
* @returns Whether the input is matched in the bloom filter.
*/
export function contains(
bloom: Hex.Hex,
input: Hex.Hex | Bytes.Bytes,
): boolean {
const filter = Bytes.fromHex(bloom)
const hash = Hash.keccak256(input, { as: 'Bytes' })
for (const i of [0, 2, 4]) {
const bit = (hash[i + 1]! + (hash[i]! << 8)) & 0x7ff
if ((filter[256 - 1 - Math.floor(bit / 8)]! & (1 << (bit % 8))) === 0)
return false
}
return true
}
export declare namespace contains {
type ErrorType =
| Bytes.fromHex.ErrorType
| Hash.keccak256.ErrorType
| Errors.GlobalErrorType
}
/**
* Checks if a string is a valid bloom filter value.
*
* @example
* ```ts twoslash
* import { Bloom } from 'ox'
*
* Bloom.validate('0x')
* // @log: false
*
* Bloom.validate('0x00000000000000000000008000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000044000200000000000000000002000000000000000000000040000000000000000000000000000020000000000000000000800000000000800000000000800000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000808002000000000400000000000000000000000060000000000000000000000000000000000000000000000100000000000002000000')
* // @log: true
* ```
*
* @param value - Value to check.
* @returns Whether the value is a valid bloom filter.
*/
export function validate(value: string): value is Hex.Hex {
return Hex.validate(value) && Hex.size(value) === 256
}
export declare namespace validate {
type ErrorType =
| Hex.validate.ErrorType
| Hex.size.ErrorType
| Errors.GlobalErrorType
}

485
node_modules/ox/core/Bls.ts generated vendored Normal file
View File

@@ -0,0 +1,485 @@
import type { ProjPointType } from '@noble/curves/abstract/weierstrass'
import { bls12_381 as bls } from '@noble/curves/bls12-381'
import type * as BlsPoint from './BlsPoint.js'
import * as Bytes from './Bytes.js'
import type * as Errors from './Errors.js'
import * as Hex from './Hex.js'
import type { OneOf } from './internal/types.js'
export type Size = 'short-key:long-sig' | 'long-key:short-sig'
/** Re-export of noble/curves BLS12-381 utilities. */
export const noble = bls
/**
* Aggregates a set of BLS points that are either on the G1 or G2 curves (ie. public keys or signatures).
*
* @example
* ### Aggregating Signatures
*
* ```ts twoslash
* import { Bls, Hex } from 'ox'
*
* const payload = Hex.random(32)
*
* const signatures = [
* Bls.sign({ payload, privateKey: '0x...' }),
* Bls.sign({ payload, privateKey: '0x...' }),
* ]
* const signature = Bls.aggregate(signatures)
* ```
*
* @example
* ### Aggregating Public Keys
*
* ```ts twoslash
* import { Bls } from 'ox'
*
* const publicKeys = [
* Bls.getPublicKey({ privateKey: '0x...' }),
* Bls.getPublicKey({ privateKey: '0x...' }),
* ]
* const publicKey = Bls.aggregate(publicKeys)
* ```
*
* @param points - The points to aggregate.
* @returns The aggregated point.
*/
export function aggregate<const points extends readonly BlsPoint.BlsPoint[]>(
points: points,
): points extends readonly BlsPoint.G1[] ? BlsPoint.G1 : BlsPoint.G2
// eslint-disable-next-line jsdoc/require-jsdoc
export function aggregate(
points: readonly BlsPoint.BlsPoint[],
): BlsPoint.BlsPoint {
const group = typeof points[0]?.x === 'bigint' ? bls.G1 : bls.G2
const point = points.reduce(
(acc, point) =>
acc.add(new (group as any).ProjectivePoint(point.x, point.y, point.z)),
group.ProjectivePoint.ZERO,
)
return {
x: point.px,
y: point.py,
z: point.pz,
}
}
export declare namespace aggregate {
type ErrorType = Errors.GlobalErrorType
}
/**
* Computes the BLS12-381 public key from a provided private key.
*
* Public Keys can be derived as a point on one of the BLS12-381 groups:
*
* - G1 Point (Default):
* - short (48 bytes)
* - computes longer G2 Signatures (96 bytes)
* - G2 Point:
* - long (96 bytes)
* - computes short G1 Signatures (48 bytes)
*
* @example
* ### Short G1 Public Keys (Default)
*
* ```ts twoslash
* import { Bls } from 'ox'
*
* const publicKey = Bls.getPublicKey({ privateKey: '0x...' })
* // ^?
*
*
*
*
*
*
*
* ```
*
* @example
* ### Long G2 Public Keys
*
* A G2 Public Key can be derived as a G2 point (96 bytes) using `size: 'long-key:short-sig'`.
*
* This will allow you to compute G1 Signatures (48 bytes) with {@link ox#Bls.(sign:function)}.
*
* ```ts twoslash
* import { Bls } from 'ox'
*
* const publicKey = Bls.getPublicKey({
* privateKey: '0x...',
* size: 'long-key:short-sig',
* })
*
* publicKey
* // ^?
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
* ```
*
* ### Serializing
*
* Public Keys can be serialized to hex or bytes using {@link ox#BlsPoint.(toHex:function)} or {@link ox#BlsPoint.(toBytes:function)}:
*
* ```ts twoslash
* import { Bls, BlsPoint } from 'ox'
*
* const publicKey = Bls.getPublicKey({ privateKey: '0x...' })
*
* const publicKeyHex = BlsPoint.toHex(publicKey)
* // ^?
*
*
* const publicKeyBytes = BlsPoint.toBytes(publicKey)
* // ^?
*
* ```
*
* They can also be deserialized from hex or bytes using {@link ox#BlsPoint.(fromHex:function)} or {@link ox#BlsPoint.(fromBytes:function)}:
*
* ```ts twoslash
* import { Bls, BlsPoint } from 'ox'
*
* const publicKeyHex = '0x...'
*
* const publicKey = BlsPoint.fromHex(publicKeyHex, 'G1')
* // ^?
*
*
*
*
*
*
*
* ```
*
* @param options - The options to compute the public key.
* @returns The computed public key.
*/
export function getPublicKey<size extends Size = 'short-key:long-sig'>(
options: getPublicKey.Options<size>,
): size extends 'short-key:long-sig' ? BlsPoint.G1 : BlsPoint.G2
// eslint-disable-next-line jsdoc/require-jsdoc
export function getPublicKey(options: getPublicKey.Options): BlsPoint.BlsPoint {
const { privateKey, size = 'short-key:long-sig' } = options
const group = size === 'short-key:long-sig' ? bls.G1 : bls.G2
const { px, py, pz } = group.ProjectivePoint.fromPrivateKey(
Hex.from(privateKey).slice(2),
)
return { x: px, y: py, z: pz }
}
export declare namespace getPublicKey {
type Options<size extends Size = 'short-key:long-sig'> = {
/**
* Private key to compute the public key from.
*/
privateKey: Hex.Hex | Bytes.Bytes
/**
* Size of the public key to compute.
*
* - `'short-key:long-sig'`: 48 bytes; computes long signatures (96 bytes)
* - `'long-key:short-sig'`: 96 bytes; computes short signatures (48 bytes)
*
* @default 'short-key:long-sig'
*/
size?: size | Size | undefined
}
type ErrorType = Hex.from.ErrorType | Errors.GlobalErrorType
}
/**
* Generates a random BLS12-381 private key.
*
* @example
* ```ts twoslash
* import { Bls } from 'ox'
*
* const privateKey = Bls.randomPrivateKey()
* ```
*
* @param options - The options to generate the private key.
* @returns The generated private key.
*/
export function randomPrivateKey<as extends 'Hex' | 'Bytes' = 'Hex'>(
options: randomPrivateKey.Options<as> = {},
): randomPrivateKey.ReturnType<as> {
const { as = 'Hex' } = options
const bytes = bls.utils.randomPrivateKey()
if (as === 'Hex') return Hex.fromBytes(bytes) as never
return bytes as never
}
export declare namespace randomPrivateKey {
type Options<as extends 'Hex' | 'Bytes' = 'Hex'> = {
/**
* Format of the returned private key.
* @default 'Hex'
*/
as?: as | 'Hex' | 'Bytes' | undefined
}
type ReturnType<as extends 'Hex' | 'Bytes'> =
| (as extends 'Bytes' ? Bytes.Bytes : never)
| (as extends 'Hex' ? Hex.Hex : never)
type ErrorType = Hex.fromBytes.ErrorType | Errors.GlobalErrorType
}
/**
* Signs the payload with the provided private key.
*
* @example
* ```ts twoslash
* import { Bls, Hex } from 'ox'
*
* const signature = Bls.sign({ // [!code focus]
* payload: Hex.random(32), // [!code focus]
* privateKey: '0x...' // [!code focus]
* }) // [!code focus]
* ```
*
* @example
* ### Serializing
*
* Signatures can be serialized to hex or bytes using {@link ox#BlsPoint.(toHex:function)} or {@link ox#BlsPoint.(toBytes:function)}:
*
* ```ts twoslash
* import { Bls, BlsPoint, Hex } from 'ox'
*
* const signature = Bls.sign({ payload: Hex.random(32), privateKey: '0x...' })
*
* const signatureHex = BlsPoint.toHex(signature)
* // ^?
*
*
*
* const signatureBytes = BlsPoint.toBytes(signature)
* // ^?
*
*
* ```
*
* They can also be deserialized from hex or bytes using {@link ox#BlsPoint.(fromHex:function)} or {@link ox#BlsPoint.(fromBytes:function)}:
*
* ```ts twoslash
* import { Bls, BlsPoint } from 'ox'
*
* const signatureHex = '0x...'
*
* const signature = BlsPoint.fromHex(signatureHex, 'G2')
* // ^?
*
*
*
*
*
*
*
*
*
*
*
*
*
* ```
*
* @param options - The signing options.
* @returns BLS Point.
*/
export function sign<size extends Size = 'short-key:long-sig'>(
options: sign.Options<size>,
): size extends 'short-key:long-sig' ? BlsPoint.G2 : BlsPoint.G1
// eslint-disable-next-line jsdoc/require-jsdoc
export function sign(options: sign.Options): BlsPoint.BlsPoint {
const { payload, privateKey, suite, size = 'short-key:long-sig' } = options
const payloadGroup = size === 'short-key:long-sig' ? bls.G2 : bls.G1
const payloadPoint = payloadGroup.hashToCurve(
Bytes.from(payload),
suite ? { DST: Bytes.fromString(suite) } : undefined,
)
const privateKeyGroup = size === 'short-key:long-sig' ? bls.G1 : bls.G2
const signature = payloadPoint.multiply(
privateKeyGroup.normPrivateKeyToScalar(privateKey.slice(2)),
) as ProjPointType<any>
return {
x: signature.px,
y: signature.py,
z: signature.pz,
}
}
export declare namespace sign {
type Options<size extends Size = 'short-key:long-sig'> = {
/**
* Payload to sign.
*/
payload: Hex.Hex | Bytes.Bytes
/**
* BLS private key.
*/
privateKey: Hex.Hex | Bytes.Bytes
/**
* Ciphersuite to use for signing. Defaults to "Basic".
*
* @see https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-bls-signature-05#section-4
* @default 'BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_NUL_'
*/
suite?: string | undefined
/**
* Size of the signature to compute.
*
* - `'long-key:short-sig'`: 48 bytes
* - `'short-key:long-sig'`: 96 bytes
*
* @default 'short-key:long-sig'
*/
size?: size | Size | undefined
}
type ErrorType = Bytes.from.ErrorType | Errors.GlobalErrorType
}
/**
* Verifies a payload was signed by the provided public key(s).
*
* @example
*
* ```ts twoslash
* import { Bls, Hex } from 'ox'
*
* const payload = Hex.random(32)
* const privateKey = Bls.randomPrivateKey()
*
* const publicKey = Bls.getPublicKey({ privateKey })
* const signature = Bls.sign({ payload, privateKey })
*
* const verified = Bls.verify({ // [!code focus]
* payload, // [!code focus]
* publicKey, // [!code focus]
* signature, // [!code focus]
* }) // [!code focus]
* ```
*
* @example
* ### Verify Aggregated Signatures
*
* We can also pass a public key and signature that was aggregated with {@link ox#Bls.(aggregate:function)} to `Bls.verify`.
*
* ```ts twoslash
* import { Bls, Hex } from 'ox'
*
* const payload = Hex.random(32)
* const privateKeys = Array.from({ length: 100 }, () => Bls.randomPrivateKey())
*
* const publicKeys = privateKeys.map((privateKey) =>
* Bls.getPublicKey({ privateKey }),
* )
* const signatures = privateKeys.map((privateKey) =>
* Bls.sign({ payload, privateKey }),
* )
*
* const publicKey = Bls.aggregate(publicKeys) // [!code focus]
* const signature = Bls.aggregate(signatures) // [!code focus]
*
* const valid = Bls.verify({ payload, publicKey, signature }) // [!code focus]
* ```
*
* @param options - Verification options.
* @returns Whether the payload was signed by the provided public key.
*/
export function verify(options: verify.Options): boolean {
const { payload, suite } = options
const publicKey = options.publicKey as unknown as BlsPoint.BlsPoint<any>
const signature = options.signature as unknown as BlsPoint.BlsPoint<any>
const isShortSig = typeof signature.x === 'bigint'
const group = isShortSig ? bls.G1 : bls.G2
const payloadPoint = group.hashToCurve(
Bytes.from(payload),
suite ? { DST: Bytes.fromString(suite) } : undefined,
) as ProjPointType<any>
const shortSigPairing = () =>
bls.pairingBatch([
{
g1: payloadPoint,
g2: new bls.G2.ProjectivePoint(publicKey.x, publicKey.y, publicKey.z),
},
{
g1: new bls.G1.ProjectivePoint(signature.x, signature.y, signature.z),
g2: bls.G2.ProjectivePoint.BASE.negate(),
},
])
const longSigPairing = () =>
bls.pairingBatch([
{
g1: new bls.G1.ProjectivePoint(
publicKey.x,
publicKey.y,
publicKey.z,
).negate(),
g2: payloadPoint,
},
{
g1: bls.G1.ProjectivePoint.BASE,
g2: new bls.G2.ProjectivePoint(signature.x, signature.y, signature.z),
},
])
return bls.fields.Fp12.eql(
isShortSig ? shortSigPairing() : longSigPairing(),
bls.fields.Fp12.ONE,
)
}
export declare namespace verify {
type Options = {
/**
* Payload that was signed.
*/
payload: Hex.Hex | Bytes.Bytes
/**
* Ciphersuite to use for verification. Defaults to "Basic".
*
* @see https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-bls-signature-05#section-4
* @default 'BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_NUL_'
*/
suite?: string | undefined
} & OneOf<
| {
publicKey: BlsPoint.G1
signature: BlsPoint.G2
}
| {
publicKey: BlsPoint.G2
signature: BlsPoint.G1
}
>
type ErrorType = Errors.GlobalErrorType
}

220
node_modules/ox/core/BlsPoint.ts generated vendored Normal file
View File

@@ -0,0 +1,220 @@
import { bls12_381 as bls } from '@noble/curves/bls12-381'
import type * as Bytes from './Bytes.js'
import type * as Errors from './Errors.js'
import * as Hex from './Hex.js'
import type { Branded, Compute } from './internal/types.js'
/** Type for a field element in the base field of the BLS12-381 curve. */
export type Fp = bigint
/** Type for a field element in the extension field of the BLS12-381 curve. */
export type Fp2 = Compute<{ c0: bigint; c1: bigint }>
/** Root type for a BLS point on the G1 or G2 curve. */
export type BlsPoint<type = Fp | Fp2> = Compute<{
x: type
y: type
z: type
}>
/** Type for a BLS point on the G1 curve. */
export type G1 = BlsPoint<Fp>
/** Branded type for a bytes representation of a G1 point. */
export type G1Bytes = Branded<Bytes.Bytes, 'G1'>
/** Branded type for a hex representation of a G1 point. */
export type G1Hex = Branded<Hex.Hex, 'G1'>
/** Type for a BLS point on the G2 curve. */
export type G2 = BlsPoint<Fp2>
/** Branded type for a bytes representation of a G2 point. */
export type G2Bytes = Branded<Bytes.Bytes, 'G2'>
/** Branded type for a hex representation of a G2 point. */
export type G2Hex = Branded<Hex.Hex, 'G2'>
/**
* Converts a BLS point to {@link ox#Bytes.Bytes}.
*
* @example
* ### Public Key to Bytes
* ```ts twoslash
* import { Bls, BlsPoint } from 'ox'
*
* const publicKey = Bls.getPublicKey({ privateKey: '0x...' })
* const publicKeyBytes = BlsPoint.toBytes(publicKey)
* // @log: Uint8Array [172, 175, 255, ...]
* ```
*
* @example
* ### Signature to Bytes
* ```ts twoslash
* import { Bls, BlsPoint } from 'ox'
*
* const signature = Bls.sign({ payload: '0x...', privateKey: '0x...' })
* const signatureBytes = BlsPoint.toBytes(signature)
* // @log: Uint8Array [172, 175, 255, ...]
* ```
*
* @param point - The BLS point to convert.
* @returns The bytes representation of the BLS point.
*/
export function toBytes<point extends G1 | G2>(
point: point,
): point extends G1 ? G1Bytes : G2Bytes {
const group = typeof point.z === 'bigint' ? bls.G1 : bls.G2
return new (group as any).ProjectivePoint(
point.x,
point.y,
point.z,
).toRawBytes()
}
export declare namespace toBytes {
type ErrorType = Errors.GlobalErrorType
}
/**
* Converts a BLS point to {@link ox#Hex.Hex}.
*
* @example
* ### Public Key to Hex
*
* ```ts twoslash
* import { Bls, BlsPoint } from 'ox'
*
* const publicKey = Bls.getPublicKey({ privateKey: '0x...' })
* const publicKeyHex = BlsPoint.toHex(publicKey)
* // @log: '0xacafff52270773ad1728df2807c0f1b0b271fa6b37dfb8b2f75448573c76c81bcd6790328a60e40ef5a13343b32d9e66'
* ```
*
* @example
* ### Signature to Hex
*
* ```ts twoslash
* import { Bls, BlsPoint } from 'ox'
*
* const signature = Bls.sign({ payload: '0x...', privateKey: '0x...' })
* const signatureHex = BlsPoint.toHex(signature)
* // @log: '0xb4698f7611999fba87033b9cf72312c76c683bbc48175e2d4cb275907d6a267ab9840a66e3051e5ed36fd13aa712f9a9024f9fa9b67f716dfb74ae4efb7d9f1b7b43b4679abed6644cf476c12e79f309351ea8452487cd93f66e29e04ebe427c'
* ```
*
* @param point - The BLS point to convert.
* @returns The hex representation of the BLS point.
*/
export function toHex<point extends G1 | G2>(
point: point,
): point extends G1 ? G1Hex : G2Hex
// eslint-disable-next-line jsdoc/require-jsdoc
export function toHex(point: G1 | G2): Hex.Hex {
return Hex.fromBytes(toBytes(point))
}
export declare namespace toHex {
type ErrorType = Errors.GlobalErrorType
}
/**
* Converts {@link ox#Bytes.Bytes} to a BLS point.
*
* @example
* ### Bytes to Public Key
*
* ```ts twoslash
* // @noErrors
* import { BlsPoint } from 'ox'
*
* const publicKey = BlsPoint.fromBytes(Bytes.from([172, 175, 255, ...]), 'G1')
* // @log: {
* // @log: x: 172...n,
* // @log: y: 175...n,
* // @log: z: 1n,
* // @log: }
* ```
*
* @example
* ### Bytes to Signature
*
* ```ts twoslash
* // @noErrors
* import { BlsPoint } from 'ox'
*
* const signature = BlsPoint.fromBytes(Bytes.from([172, 175, 255, ...]), 'G2')
* // @log: {
* // @log: x: 511...n,
* // @log: y: 234...n,
* // @log: z: 1n,
* // @log: }
* ```
*
* @param bytes - The bytes to convert.
* @returns The BLS point.
*/
export function fromBytes<group extends 'G1' | 'G2'>(
bytes: Bytes.Bytes,
group: group,
): group extends 'G1' ? G1 : G2
// eslint-disable-next-line jsdoc/require-jsdoc
export function fromBytes(bytes: Bytes.Bytes): BlsPoint<any> {
const group = bytes.length === 48 ? bls.G1 : bls.G2
const point = group.ProjectivePoint.fromHex(bytes)
return {
x: point.px,
y: point.py,
z: point.pz,
}
}
export declare namespace fromBytes {
type ErrorType = Errors.GlobalErrorType
}
/**
* Converts {@link ox#Hex.Hex} to a BLS point.
*
* @example
* ### Hex to Public Key
*
* ```ts twoslash
* // @noErrors
* import { BlsPoint } from 'ox'
*
* const publicKey = BlsPoint.fromHex('0xacafff52270773ad1728df2807c0f1b0b271fa6b37dfb8b2f75448573c76c81bcd6790328a60e40ef5a13343b32d9e66', 'G1')
* // @log: {
* // @log: x: 172...n,
* // @log: y: 175...n,
* // @log: z: 1n,
* // @log: }
* ```
*
* @example
* ### Hex to Signature
*
* ```ts twoslash
* // @noErrors
* import { BlsPoint } from 'ox'
*
* const signature = BlsPoint.fromHex(
* '0xb4698f7611999fba87033b9cf72312c76c683bbc48175e2d4cb275907d6a267ab9840a66e3051e5ed36fd13aa712f9a9024f9fa9b67f716dfb74ae4efb7d9f1b7b43b4679abed6644cf476c12e79f309351ea8452487cd93f66e29e04ebe427c',
* 'G2',
* )
* // @log: {
* // @log: x: 511...n,
* // @log: y: 234...n,
* // @log: z: 1n,
* // @log: }
* ```
*
* @param bytes - The bytes to convert.
* @returns The BLS point.
*/
export function fromHex<group extends 'G1' | 'G2'>(
hex: Hex.Hex,
group: group,
): group extends 'G1' ? G1 : G2
// eslint-disable-next-line jsdoc/require-jsdoc
export function fromHex(hex: Hex.Hex, group: 'G1' | 'G2'): BlsPoint<any> {
return fromBytes(Hex.toBytes(hex), group)
}
export declare namespace fromHex {
type ErrorType = Errors.GlobalErrorType
}

886
node_modules/ox/core/Bytes.ts generated vendored Normal file
View File

@@ -0,0 +1,886 @@
import { equalBytes } from '@noble/curves/abstract/utils'
import * as Errors from './Errors.js'
import * as Hex from './Hex.js'
import * as Json from './Json.js'
import * as internal from './internal/bytes.js'
import * as internal_hex from './internal/hex.js'
const decoder = /*#__PURE__*/ new TextDecoder()
const encoder = /*#__PURE__*/ new TextEncoder()
/** Root type for a Bytes array. */
export type Bytes = Uint8Array
/**
* Asserts if the given value is {@link ox#Bytes.Bytes}.
*
* @example
* ```ts twoslash
* import { Bytes } from 'ox'
*
* Bytes.assert('abc')
* // @error: Bytes.InvalidBytesTypeError:
* // @error: Value `"abc"` of type `string` is an invalid Bytes value.
* // @error: Bytes values must be of type `Uint8Array`.
* ```
*
* @param value - Value to assert.
*/
export function assert(value: unknown): asserts value is Bytes {
if (value instanceof Uint8Array) return
if (!value) throw new InvalidBytesTypeError(value)
if (typeof value !== 'object') throw new InvalidBytesTypeError(value)
if (!('BYTES_PER_ELEMENT' in value)) throw new InvalidBytesTypeError(value)
if (value.BYTES_PER_ELEMENT !== 1 || value.constructor.name !== 'Uint8Array')
throw new InvalidBytesTypeError(value)
}
export declare namespace assert {
type ErrorType = InvalidBytesTypeError | Errors.GlobalErrorType
}
/**
* Concatenates two or more {@link ox#Bytes.Bytes}.
*
* @example
* ```ts twoslash
* import { Bytes } from 'ox'
*
* const bytes = Bytes.concat(
* Bytes.from([1]),
* Bytes.from([69]),
* Bytes.from([420, 69]),
* )
* // @log: Uint8Array [ 1, 69, 420, 69 ]
* ```
*
* @param values - Values to concatenate.
* @returns Concatenated {@link ox#Bytes.Bytes}.
*/
export function concat(...values: readonly Bytes[]): Bytes {
let length = 0
for (const arr of values) {
length += arr.length
}
const result = new Uint8Array(length)
for (let i = 0, index = 0; i < values.length; i++) {
const arr = values[i]
result.set(arr!, index)
index += arr!.length
}
return result
}
export declare namespace concat {
type ErrorType = Errors.GlobalErrorType
}
/**
* Instantiates a {@link ox#Bytes.Bytes} value from a `Uint8Array`, a hex string, or an array of unsigned 8-bit integers.
*
* :::tip
*
* To instantiate from a **Boolean**, **String**, or **Number**, use one of the following:
*
* - `Bytes.fromBoolean`
*
* - `Bytes.fromString`
*
* - `Bytes.fromNumber`
*
* :::
*
* @example
* ```ts twoslash
* // @noErrors
* import { Bytes } from 'ox'
*
* const data = Bytes.from([255, 124, 5, 4])
* // @log: Uint8Array([255, 124, 5, 4])
*
* const data = Bytes.from('0xdeadbeef')
* // @log: Uint8Array([222, 173, 190, 239])
* ```
*
* @param value - Value to convert.
* @returns A {@link ox#Bytes.Bytes} instance.
*/
export function from(value: Hex.Hex | Bytes | readonly number[]): Bytes {
if (value instanceof Uint8Array) return value
if (typeof value === 'string') return fromHex(value)
return fromArray(value)
}
export declare namespace from {
type ErrorType =
| fromHex.ErrorType
| fromArray.ErrorType
| Errors.GlobalErrorType
}
/**
* Converts an array of unsigned 8-bit integers into {@link ox#Bytes.Bytes}.
*
* @example
* ```ts twoslash
* import { Bytes } from 'ox'
*
* const data = Bytes.fromArray([255, 124, 5, 4])
* // @log: Uint8Array([255, 124, 5, 4])
* ```
*
* @param value - Value to convert.
* @returns A {@link ox#Bytes.Bytes} instance.
*/
export function fromArray(value: readonly number[] | Uint8Array): Bytes {
return value instanceof Uint8Array ? value : new Uint8Array(value)
}
export declare namespace fromArray {
type ErrorType = Errors.GlobalErrorType
}
/**
* Encodes a boolean value into {@link ox#Bytes.Bytes}.
*
* @example
* ```ts twoslash
* import { Bytes } from 'ox'
*
* const data = Bytes.fromBoolean(true)
* // @log: Uint8Array([1])
* ```
*
* @example
* ```ts twoslash
* import { Bytes } from 'ox'
*
* const data = Bytes.fromBoolean(true, { size: 32 })
* // @log: Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1])
* ```
*
* @param value - Boolean value to encode.
* @param options - Encoding options.
* @returns Encoded {@link ox#Bytes.Bytes}.
*/
export function fromBoolean(value: boolean, options: fromBoolean.Options = {}) {
const { size } = options
const bytes = new Uint8Array(1)
bytes[0] = Number(value)
if (typeof size === 'number') {
internal.assertSize(bytes, size)
return padLeft(bytes, size)
}
return bytes
}
export declare namespace fromBoolean {
type Options = {
/** Size of the output bytes. */
size?: number | undefined
}
type ErrorType =
| internal.assertSize.ErrorType
| padLeft.ErrorType
| Errors.GlobalErrorType
}
/**
* Encodes a {@link ox#Hex.Hex} value into {@link ox#Bytes.Bytes}.
*
* @example
* ```ts twoslash
* import { Bytes } from 'ox'
*
* const data = Bytes.fromHex('0x48656c6c6f20776f726c6421')
* // @log: Uint8Array([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33])
* ```
*
* @example
* ```ts twoslash
* import { Bytes } from 'ox'
*
* const data = Bytes.fromHex('0x48656c6c6f20776f726c6421', { size: 32 })
* // @log: Uint8Array([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
* ```
*
* @param value - {@link ox#Hex.Hex} value to encode.
* @param options - Encoding options.
* @returns Encoded {@link ox#Bytes.Bytes}.
*/
export function fromHex(value: Hex.Hex, options: fromHex.Options = {}): Bytes {
const { size } = options
let hex = value
if (size) {
internal_hex.assertSize(value, size)
hex = Hex.padRight(value, size)
}
let hexString = hex.slice(2) as string
if (hexString.length % 2) hexString = `0${hexString}`
const length = hexString.length / 2
const bytes = new Uint8Array(length)
for (let index = 0, j = 0; index < length; index++) {
const nibbleLeft = internal.charCodeToBase16(hexString.charCodeAt(j++))
const nibbleRight = internal.charCodeToBase16(hexString.charCodeAt(j++))
if (nibbleLeft === undefined || nibbleRight === undefined) {
throw new Errors.BaseError(
`Invalid byte sequence ("${hexString[j - 2]}${hexString[j - 1]}" in "${hexString}").`,
)
}
bytes[index] = nibbleLeft * 16 + nibbleRight
}
return bytes
}
export declare namespace fromHex {
type Options = {
/** Size of the output bytes. */
size?: number | undefined
}
type ErrorType =
| internal_hex.assertSize.ErrorType
| Hex.padRight.ErrorType
| Errors.GlobalErrorType
}
/**
* Encodes a number value into {@link ox#Bytes.Bytes}.
*
* @example
* ```ts twoslash
* import { Bytes } from 'ox'
*
* const data = Bytes.fromNumber(420)
* // @log: Uint8Array([1, 164])
* ```
*
* @example
* ```ts twoslash
* import { Bytes } from 'ox'
*
* const data = Bytes.fromNumber(420, { size: 4 })
* // @log: Uint8Array([0, 0, 1, 164])
* ```
*
* @param value - Number value to encode.
* @param options - Encoding options.
* @returns Encoded {@link ox#Bytes.Bytes}.
*/
export function fromNumber(
value: bigint | number,
options?: fromNumber.Options | undefined,
) {
const hex = Hex.fromNumber(value, options)
return fromHex(hex)
}
export declare namespace fromNumber {
export type Options = Hex.fromNumber.Options
export type ErrorType =
| Hex.fromNumber.ErrorType
| fromHex.ErrorType
| Errors.GlobalErrorType
}
/**
* Encodes a string into {@link ox#Bytes.Bytes}.
*
* @example
* ```ts twoslash
* import { Bytes } from 'ox'
*
* const data = Bytes.fromString('Hello world!')
* // @log: Uint8Array([72, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 33])
* ```
*
* @example
* ```ts twoslash
* import { Bytes } from 'ox'
*
* const data = Bytes.fromString('Hello world!', { size: 32 })
* // @log: Uint8Array([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
* ```
*
* @param value - String to encode.
* @param options - Encoding options.
* @returns Encoded {@link ox#Bytes.Bytes}.
*/
export function fromString(
value: string,
options: fromString.Options = {},
): Bytes {
const { size } = options
const bytes = encoder.encode(value)
if (typeof size === 'number') {
internal.assertSize(bytes, size)
return padRight(bytes, size)
}
return bytes
}
export declare namespace fromString {
type Options = {
/** Size of the output bytes. */
size?: number | undefined
}
type ErrorType =
| internal.assertSize.ErrorType
| padRight.ErrorType
| Errors.GlobalErrorType
}
/**
* Checks if two {@link ox#Bytes.Bytes} values are equal.
*
* @example
* ```ts twoslash
* import { Bytes } from 'ox'
*
* Bytes.isEqual(Bytes.from([1]), Bytes.from([1]))
* // @log: true
*
* Bytes.isEqual(Bytes.from([1]), Bytes.from([2]))
* // @log: false
* ```
*
* @param bytesA - First {@link ox#Bytes.Bytes} value.
* @param bytesB - Second {@link ox#Bytes.Bytes} value.
* @returns `true` if the two values are equal, otherwise `false`.
*/
export function isEqual(bytesA: Bytes, bytesB: Bytes) {
return equalBytes(bytesA, bytesB)
}
export declare namespace isEqual {
type ErrorType = Errors.GlobalErrorType
}
/**
* Pads a {@link ox#Bytes.Bytes} value to the left with zero bytes until it reaches the given `size` (default: 32 bytes).
*
* @example
* ```ts twoslash
* import { Bytes } from 'ox'
*
* Bytes.padLeft(Bytes.from([1]), 4)
* // @log: Uint8Array([0, 0, 0, 1])
* ```
*
* @param value - {@link ox#Bytes.Bytes} value to pad.
* @param size - Size to pad the {@link ox#Bytes.Bytes} value to.
* @returns Padded {@link ox#Bytes.Bytes} value.
*/
export function padLeft(
value: Bytes,
size?: number | undefined,
): padLeft.ReturnType {
return internal.pad(value, { dir: 'left', size })
}
export declare namespace padLeft {
type ReturnType = internal.pad.ReturnType
type ErrorType = internal.pad.ErrorType | Errors.GlobalErrorType
}
/**
* Pads a {@link ox#Bytes.Bytes} value to the right with zero bytes until it reaches the given `size` (default: 32 bytes).
*
* @example
* ```ts twoslash
* import { Bytes } from 'ox'
*
* Bytes.padRight(Bytes.from([1]), 4)
* // @log: Uint8Array([1, 0, 0, 0])
* ```
*
* @param value - {@link ox#Bytes.Bytes} value to pad.
* @param size - Size to pad the {@link ox#Bytes.Bytes} value to.
* @returns Padded {@link ox#Bytes.Bytes} value.
*/
export function padRight(
value: Bytes,
size?: number | undefined,
): padRight.ReturnType {
return internal.pad(value, { dir: 'right', size })
}
export declare namespace padRight {
type ReturnType = internal.pad.ReturnType
type ErrorType = internal.pad.ErrorType | Errors.GlobalErrorType
}
/**
* Generates random {@link ox#Bytes.Bytes} of the specified length.
*
* @example
* ```ts twoslash
* import { Bytes } from 'ox'
*
* const bytes = Bytes.random(32)
* // @log: Uint8Array([... x32])
* ```
*
* @param length - Length of the random {@link ox#Bytes.Bytes} to generate.
* @returns Random {@link ox#Bytes.Bytes} of the specified length.
*/
export function random(length: number): Bytes {
return crypto.getRandomValues(new Uint8Array(length))
}
export declare namespace random {
type ErrorType = Errors.GlobalErrorType
}
/**
* Retrieves the size of a {@link ox#Bytes.Bytes} value.
*
* @example
* ```ts twoslash
* import { Bytes } from 'ox'
*
* Bytes.size(Bytes.from([1, 2, 3, 4]))
* // @log: 4
* ```
*
* @param value - {@link ox#Bytes.Bytes} value.
* @returns Size of the {@link ox#Bytes.Bytes} value.
*/
export function size(value: Bytes): number {
return value.length
}
export declare namespace size {
export type ErrorType = Errors.GlobalErrorType
}
/**
* Returns a section of a {@link ox#Bytes.Bytes} value given a start/end bytes offset.
*
* @example
* ```ts twoslash
* import { Bytes } from 'ox'
*
* Bytes.slice(
* Bytes.from([1, 2, 3, 4, 5, 6, 7, 8, 9]),
* 1,
* 4,
* )
* // @log: Uint8Array([2, 3, 4])
* ```
*
* @param value - The {@link ox#Bytes.Bytes} value.
* @param start - Start offset.
* @param end - End offset.
* @param options - Slice options.
* @returns Sliced {@link ox#Bytes.Bytes} value.
*/
export function slice(
value: Bytes,
start?: number | undefined,
end?: number | undefined,
options: slice.Options = {},
): Bytes {
const { strict } = options
internal.assertStartOffset(value, start)
const value_ = value.slice(start, end)
if (strict) internal.assertEndOffset(value_, start, end)
return value_
}
export declare namespace slice {
type Options = {
/** Asserts that the sliced value is the same size as the given start/end offsets. */
strict?: boolean | undefined
}
export type ErrorType =
| internal.assertStartOffset.ErrorType
| internal.assertEndOffset.ErrorType
| Errors.GlobalErrorType
}
/**
* Decodes a {@link ox#Bytes.Bytes} into a bigint.
*
* @example
* ```ts
* import { Bytes } from 'ox'
*
* Bytes.toBigInt(Bytes.from([1, 164]))
* // @log: 420n
* ```
*
* @param bytes - The {@link ox#Bytes.Bytes} to decode.
* @param options - Decoding options.
* @returns Decoded bigint.
*/
export function toBigInt(bytes: Bytes, options: toBigInt.Options = {}): bigint {
const { size } = options
if (typeof size !== 'undefined') internal.assertSize(bytes, size)
const hex = Hex.fromBytes(bytes, options)
return Hex.toBigInt(hex, options)
}
export declare namespace toBigInt {
type Options = {
/** Whether or not the number of a signed representation. */
signed?: boolean | undefined
/** Size of the bytes. */
size?: number | undefined
}
type ErrorType =
| Hex.fromBytes.ErrorType
| Hex.toBigInt.ErrorType
| Errors.GlobalErrorType
}
/**
* Decodes a {@link ox#Bytes.Bytes} into a boolean.
*
* @example
* ```ts
* import { Bytes } from 'ox'
*
* Bytes.toBoolean(Bytes.from([1]))
* // @log: true
* ```
*
* @param bytes - The {@link ox#Bytes.Bytes} to decode.
* @param options - Decoding options.
* @returns Decoded boolean.
*/
export function toBoolean(
bytes: Bytes,
options: toBoolean.Options = {},
): boolean {
const { size } = options
let bytes_ = bytes
if (typeof size !== 'undefined') {
internal.assertSize(bytes_, size)
bytes_ = trimLeft(bytes_)
}
if (bytes_.length > 1 || bytes_[0]! > 1)
throw new InvalidBytesBooleanError(bytes_)
return Boolean(bytes_[0])
}
export declare namespace toBoolean {
type Options = {
/** Size of the bytes. */
size?: number | undefined
}
type ErrorType =
| internal.assertSize.ErrorType
| trimLeft.ErrorType
| Errors.GlobalErrorType
}
/**
* Encodes a {@link ox#Bytes.Bytes} value into a {@link ox#Hex.Hex} value.
*
* @example
* ```ts twoslash
* import { Bytes } from 'ox'
*
* Bytes.toHex(Bytes.from([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33]))
* // '0x48656c6c6f20576f726c6421'
* ```
*
* @param value - The {@link ox#Bytes.Bytes} to decode.
* @param options - Options.
* @returns Decoded {@link ox#Hex.Hex} value.
*/
export function toHex(value: Bytes, options: toHex.Options = {}): Hex.Hex {
return Hex.fromBytes(value, options)
}
export declare namespace toHex {
type Options = {
/** Size of the bytes. */
size?: number | undefined
}
type ErrorType = Hex.fromBytes.ErrorType | Errors.GlobalErrorType
}
/**
* Decodes a {@link ox#Bytes.Bytes} into a number.
*
* @example
* ```ts twoslash
* import { Bytes } from 'ox'
*
* Bytes.toNumber(Bytes.from([1, 164]))
* // @log: 420
* ```
*/
export function toNumber(bytes: Bytes, options: toNumber.Options = {}): number {
const { size } = options
if (typeof size !== 'undefined') internal.assertSize(bytes, size)
const hex = Hex.fromBytes(bytes, options)
return Hex.toNumber(hex, options)
}
export declare namespace toNumber {
type Options = {
/** Whether or not the number of a signed representation. */
signed?: boolean | undefined
/** Size of the bytes. */
size?: number | undefined
}
type ErrorType =
| Hex.fromBytes.ErrorType
| Hex.toNumber.ErrorType
| Errors.GlobalErrorType
}
/**
* Decodes a {@link ox#Bytes.Bytes} into a string.
*
* @example
* ```ts twoslash
* import { Bytes } from 'ox'
*
* const data = Bytes.toString(Bytes.from([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33]))
* // @log: 'Hello world'
* ```
*
* @param bytes - The {@link ox#Bytes.Bytes} to decode.
* @param options - Options.
* @returns Decoded string.
*/
export function toString(bytes: Bytes, options: toString.Options = {}): string {
const { size } = options
let bytes_ = bytes
if (typeof size !== 'undefined') {
internal.assertSize(bytes_, size)
bytes_ = trimRight(bytes_)
}
return decoder.decode(bytes_)
}
export declare namespace toString {
export type Options = {
/** Size of the bytes. */
size?: number | undefined
}
export type ErrorType =
| internal.assertSize.ErrorType
| trimRight.ErrorType
| Errors.GlobalErrorType
}
/**
* Trims leading zeros from a {@link ox#Bytes.Bytes} value.
*
* @example
* ```ts twoslash
* import { Bytes } from 'ox'
*
* Bytes.trimLeft(Bytes.from([0, 0, 0, 0, 1, 2, 3]))
* // @log: Uint8Array([1, 2, 3])
* ```
*
* @param value - {@link ox#Bytes.Bytes} value.
* @returns Trimmed {@link ox#Bytes.Bytes} value.
*/
export function trimLeft(value: Bytes): Bytes {
return internal.trim(value, { dir: 'left' })
}
export declare namespace trimLeft {
type ErrorType = internal.trim.ErrorType | Errors.GlobalErrorType
}
/**
* Trims trailing zeros from a {@link ox#Bytes.Bytes} value.
*
* @example
* ```ts twoslash
* import { Bytes } from 'ox'
*
* Bytes.trimRight(Bytes.from([1, 2, 3, 0, 0, 0, 0]))
* // @log: Uint8Array([1, 2, 3])
* ```
*
* @param value - {@link ox#Bytes.Bytes} value.
* @returns Trimmed {@link ox#Bytes.Bytes} value.
*/
export function trimRight(value: Bytes): Bytes {
return internal.trim(value, { dir: 'right' })
}
export declare namespace trimRight {
export type ErrorType = internal.trim.ErrorType | Errors.GlobalErrorType
}
/**
* Checks if the given value is {@link ox#Bytes.Bytes}.
*
* @example
* ```ts twoslash
* import { Bytes } from 'ox'
*
* Bytes.validate('0x')
* // @log: false
*
* Bytes.validate(Bytes.from([1, 2, 3]))
* // @log: true
* ```
*
* @param value - Value to check.
* @returns `true` if the value is {@link ox#Bytes.Bytes}, otherwise `false`.
*/
export function validate(value: unknown): value is Bytes {
try {
assert(value)
return true
} catch {
return false
}
}
export declare namespace validate {
export type ErrorType = Errors.GlobalErrorType
}
/**
* Thrown when the bytes value cannot be represented as a boolean.
*
* @example
* ```ts twoslash
* import { Bytes } from 'ox'
*
* Bytes.toBoolean(Bytes.from([5]))
* // @error: Bytes.InvalidBytesBooleanError: Bytes value `[5]` is not a valid boolean.
* // @error: The bytes array must contain a single byte of either a `0` or `1` value.
* ```
*/
export class InvalidBytesBooleanError extends Errors.BaseError {
override readonly name = 'Bytes.InvalidBytesBooleanError'
constructor(bytes: Bytes) {
super(`Bytes value \`${bytes}\` is not a valid boolean.`, {
metaMessages: [
'The bytes array must contain a single byte of either a `0` or `1` value.',
],
})
}
}
/**
* Thrown when a value cannot be converted to bytes.
*
* @example
* ```ts twoslash
* // @noErrors
* import { Bytes } from 'ox'
*
* Bytes.from('foo')
* // @error: Bytes.InvalidBytesTypeError: Value `foo` of type `string` is an invalid Bytes value.
* ```
*/
export class InvalidBytesTypeError extends Errors.BaseError {
override readonly name = 'Bytes.InvalidBytesTypeError'
constructor(value: unknown) {
super(
`Value \`${typeof value === 'object' ? Json.stringify(value) : value}\` of type \`${typeof value}\` is an invalid Bytes value.`,
{
metaMessages: ['Bytes values must be of type `Bytes`.'],
},
)
}
}
/**
* Thrown when a size exceeds the maximum allowed size.
*
* @example
* ```ts twoslash
* import { Bytes } from 'ox'
*
* Bytes.fromString('Hello World!', { size: 8 })
* // @error: Bytes.SizeOverflowError: Size cannot exceed `8` bytes. Given size: `12` bytes.
* ```
*/
export class SizeOverflowError extends Errors.BaseError {
override readonly name = 'Bytes.SizeOverflowError'
constructor({ givenSize, maxSize }: { givenSize: number; maxSize: number }) {
super(
`Size cannot exceed \`${maxSize}\` bytes. Given size: \`${givenSize}\` bytes.`,
)
}
}
/**
* Thrown when a slice offset is out-of-bounds.
*
* @example
* ```ts twoslash
* import { Bytes } from 'ox'
*
* Bytes.slice(Bytes.from([1, 2, 3]), 4)
* // @error: Bytes.SliceOffsetOutOfBoundsError: Slice starting at offset `4` is out-of-bounds (size: `3`).
* ```
*/
export class SliceOffsetOutOfBoundsError extends Errors.BaseError {
override readonly name = 'Bytes.SliceOffsetOutOfBoundsError'
constructor({
offset,
position,
size,
}: { offset: number; position: 'start' | 'end'; size: number }) {
super(
`Slice ${
position === 'start' ? 'starting' : 'ending'
} at offset \`${offset}\` is out-of-bounds (size: \`${size}\`).`,
)
}
}
/**
* Thrown when a the padding size exceeds the maximum allowed size.
*
* @example
* ```ts twoslash
* import { Bytes } from 'ox'
*
* Bytes.padLeft(Bytes.fromString('Hello World!'), 8)
* // @error: [Bytes.SizeExceedsPaddingSizeError: Bytes size (`12`) exceeds padding size (`8`).
* ```
*/
export class SizeExceedsPaddingSizeError extends Errors.BaseError {
override readonly name = 'Bytes.SizeExceedsPaddingSizeError'
constructor({
size,
targetSize,
type,
}: {
size: number
targetSize: number
type: 'Hex' | 'Bytes'
}) {
super(
`${type.charAt(0).toUpperCase()}${type
.slice(1)
.toLowerCase()} size (\`${size}\`) exceeds padding size (\`${targetSize}\`).`,
)
}
}

21
node_modules/ox/core/Caches.ts generated vendored Normal file
View File

@@ -0,0 +1,21 @@
import type * as Address from './Address.js'
import { LruMap } from './internal/lru.js'
const caches = {
checksum: /*#__PURE__*/ new LruMap<Address.Address>(8192),
}
export const checksum = caches.checksum
/**
* Clears all global caches.
*
* @example
* ```ts
* import { Caches } from 'ox'
* Caches.clear()
* ```
*/
export function clear() {
for (const cache of Object.values(caches)) cache.clear()
}

169
node_modules/ox/core/ContractAddress.ts generated vendored Normal file
View File

@@ -0,0 +1,169 @@
import * as Address from './Address.js'
import * as Bytes from './Bytes.js'
import type * as Errors from './Errors.js'
import * as Hash from './Hash.js'
import * as Hex from './Hex.js'
import * as Rlp from './Rlp.js'
import type { OneOf } from './internal/types.js'
/**
* Computes Contract Address generated by the [CREATE](https://ethereum.stackexchange.com/questions/68943/create-opcode-what-does-it-really-do/68945#68945) or [CREATE2](https://eips.ethereum.org/EIPS/eip-1014) opcode.
*
* @example
* ### CREATE
*
* Computes via the [CREATE](https://ethereum.stackexchange.com/questions/68943/create-opcode-what-does-it-really-do/68945#68945) opcode. Shorthand for {@link ox#ContractAddress.(fromCreate:function)}.
*
* ```ts twoslash
* import { ContractAddress } from 'ox'
* ContractAddress.from({
* from: '0x1a1e021a302c237453d3d45c7b82b19ceeb7e2e6',
* nonce: 0n,
* })
* // @log: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2'
* ```
*
* @example
* ### CREATE2
*
* Computes via the [CREATE2](https://eips.ethereum.org/EIPS/eip-1014) opcode. Shorthand for {@link ox#ContractAddress.(fromCreate2:function)}.
*
* ```ts twoslash
* import { ContractAddress, Hex } from 'ox'
* ContractAddress.from({
* from: '0x1a1e021a302c237453d3d45c7b82b19ceeb7e2e6',
* bytecode: '0x6394198df16000526103ff60206004601c335afa6040516060f3',
* salt: Hex.fromString('hello world'),
* })
* // @log: '0x59fbB593ABe27Cb193b6ee5C5DC7bbde312290aB'
* ```
*
* @param options - Options.
* @returns Contract Address.
*/
export function from(options: from.Options): Address.Address {
if (options.salt) return fromCreate2(options)
return fromCreate(options)
}
export declare namespace from {
export type Options = OneOf<fromCreate.Options | fromCreate2.Options>
type ErrorType =
| fromCreate.ErrorType
| fromCreate2.ErrorType
| Errors.GlobalErrorType
}
/**
* Computes contract address via [CREATE](https://ethereum.stackexchange.com/questions/68943/create-opcode-what-does-it-really-do/68945#68945) opcode.
*
* @example
* ```ts twoslash
* import { ContractAddress } from 'ox'
*
* ContractAddress.fromCreate({
* from: '0x1a1e021a302c237453d3d45c7b82b19ceeb7e2e6',
* nonce: 0n,
* })
* // @log: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2'
* ```
*
* @param options - Options for retrieving address.
* @returns Contract Address.
*/
export function fromCreate(options: fromCreate.Options): Address.Address {
const from = Bytes.fromHex(Address.from(options.from))
let nonce = Bytes.fromNumber(options.nonce)
if (nonce[0] === 0) nonce = new Uint8Array([])
return Address.from(
`0x${Hash.keccak256(Rlp.fromBytes([from, nonce], { as: 'Hex' })).slice(26)}` as Address.Address,
)
}
export declare namespace fromCreate {
type Options = {
/** The address the contract was deployed from. */
from: Address.Address
/** The nonce of the transaction which deployed the contract. */
nonce: bigint
}
type ErrorType =
| Hash.keccak256.ErrorType
| Address.from.ErrorType
| Bytes.fromHex.ErrorType
| Bytes.fromNumber.ErrorType
| Rlp.fromBytes.ErrorType
| Errors.GlobalErrorType
}
/**
* Computes contract address via [CREATE2](https://eips.ethereum.org/EIPS/eip-1014) opcode.
*
* @example
* ```ts twoslash
* import { ContractAddress, Hex } from 'ox'
*
* ContractAddress.fromCreate2({
* from: '0x1a1e021a302c237453d3d45c7b82b19ceeb7e2e6',
* bytecode: '0x6394198df16000526103ff60206004601c335afa6040516060f3',
* salt: Hex.fromString('hello world'),
* })
* // @log: '0x59fbB593ABe27Cb193b6ee5C5DC7bbde312290aB'
* ```
*
* @param options - Options for retrieving address.
* @returns Contract Address.
*/
export function fromCreate2(options: fromCreate2.Options): Address.Address {
const from = Bytes.fromHex(Address.from(options.from))
const salt = Bytes.padLeft(
Bytes.validate(options.salt) ? options.salt : Bytes.fromHex(options.salt),
32,
)
const bytecodeHash = (() => {
if ('bytecodeHash' in options) {
if (Bytes.validate(options.bytecodeHash)) return options.bytecodeHash
return Bytes.fromHex(options.bytecodeHash)
}
return Hash.keccak256(options.bytecode, { as: 'Bytes' })
})()
return Address.from(
Hex.slice(
Hash.keccak256(
Bytes.concat(Bytes.fromHex('0xff'), from, salt, bytecodeHash),
{ as: 'Hex' },
),
12,
),
)
}
export declare namespace fromCreate2 {
type Options =
| {
bytecode: Bytes.Bytes | Hex.Hex
from: Address.Address
salt: Bytes.Bytes | Hex.Hex
}
| {
bytecodeHash: Bytes.Bytes | Hex.Hex
from: Address.Address
salt: Bytes.Bytes | Hex.Hex
}
type ErrorType =
| Address.from.ErrorType
| Bytes.concat.ErrorType
| Bytes.validate.ErrorType
| Bytes.padLeft.ErrorType
| Hash.keccak256.ErrorType
| Hex.slice.ErrorType
| Bytes.fromHex.ErrorType
| Errors.GlobalErrorType
}

104
node_modules/ox/core/Ens.ts generated vendored Normal file
View File

@@ -0,0 +1,104 @@
import { ens_normalize } from '@adraffy/ens-normalize'
import * as Bytes from './Bytes.js'
import type * as Errors from './Errors.js'
import * as Hash from './Hash.js'
import * as Hex from './Hex.js'
import * as internal from './internal/ens.js'
/**
* Hashes ENS label.
*
* Since ENS labels prohibit certain forbidden characters (e.g. underscore) and have other validation rules, you likely want to [normalize ENS labels](https://docs.ens.domains/contract-api-reference/name-processing#normalising-names) with [UTS-46 normalization](https://unicode.org/reports/tr46) before passing them to `labelhash`. You can use the built-in {@link ox#Ens.(normalize:function)} function for this.
*
* @example
* ```ts twoslash
* import { Ens } from 'ox'
* Ens.labelhash('eth')
* '0x4f5b812789fc606be1b3b16908db13fc7a9adf7ca72641f84d75b47069d3d7f0'
* ```
*
* @param label - ENS label.
* @returns ENS labelhash.
*/
export function labelhash(label: string) {
const result = new Uint8Array(32).fill(0)
if (!label) return Hex.fromBytes(result)
return (
internal.unwrapLabelhash(label) || Hash.keccak256(Hex.fromString(label))
)
}
export declare namespace labelhash {
type ErrorType =
| Hex.fromBytes.ErrorType
| internal.unwrapLabelhash.ErrorType
| Hash.keccak256.ErrorType
| Hex.fromString.ErrorType
| Errors.GlobalErrorType
}
/**
* Hashes ENS name.
*
* Since ENS names prohibit certain forbidden characters (e.g. underscore) and have other validation rules, you likely want to [normalize ENS names](https://docs.ens.domains/contract-api-reference/name-processing#normalising-names) with [UTS-46 normalization](https://unicode.org/reports/tr46) before passing them to `namehash`. You can use the built-in {@link ox#Ens.(normalize:function)} function for this.
*
* @example
* ```ts twoslash
* import { Ens } from 'ox'
* Ens.namehash('wevm.eth')
* // @log: '0xf246651c1b9a6b141d19c2604e9a58f567973833990f830d882534a747801359'
* ```
*
* @param name - ENS name.
* @returns ENS namehash.
*/
export function namehash(name: string) {
let result = new Uint8Array(32).fill(0)
if (!name) return Hex.fromBytes(result)
const labels = name.split('.')
// Iterate in reverse order building up hash
for (let i = labels.length - 1; i >= 0; i -= 1) {
const hashFromEncodedLabel = internal.unwrapLabelhash(labels[i]!)
const hashed = hashFromEncodedLabel
? Bytes.fromHex(hashFromEncodedLabel)
: Hash.keccak256(Bytes.fromString(labels[i]!), { as: 'Bytes' })
result = Hash.keccak256(Bytes.concat(result, hashed), { as: 'Bytes' })
}
return Hex.fromBytes(result)
}
export declare namespace namehash {
type ErrorType =
| Hex.fromBytes.ErrorType
| internal.unwrapLabelhash.ErrorType
| Bytes.fromHex.ErrorType
| Hash.keccak256.ErrorType
| Bytes.fromString.ErrorType
| Bytes.concat.ErrorType
| Errors.GlobalErrorType
}
/**
* Normalizes ENS name according to [ENSIP-15](https://github.com/ensdomains/docs/blob/9edf9443de4333a0ea7ec658a870672d5d180d53/ens-improvement-proposals/ensip-15-normalization-standard.md).
*
* For more info see [ENS documentation](https://docs.ens.domains/contract-api-reference/name-processing#normalising-names) on name processing.
*
* @example
* ```ts twoslash
* import { Ens } from 'ox'
* Ens.normalize('wevm.eth')
* // @log: 'wevm.eth'
* ```
*
* @param name - ENS name.
* @returns Normalized ENS name.
*/
export function normalize(name: string): string {
return ens_normalize(name)
}
export declare namespace normalize {
type ErrorType = Errors.GlobalErrorType
}

95
node_modules/ox/core/Errors.ts generated vendored Normal file
View File

@@ -0,0 +1,95 @@
import { getVersion } from './internal/errors.js'
export type GlobalErrorType<name extends string = 'Error'> = Error & {
name: name
}
/**
* Base error class inherited by all errors thrown by ox.
*
* @example
* ```ts
* import { Errors } from 'ox'
* throw new Errors.BaseError('An error occurred')
* ```
*/
export class BaseError<
cause extends Error | undefined = undefined,
> extends Error {
details: string
docs?: string | undefined
docsPath?: string | undefined
shortMessage: string
override cause: cause
override name = 'BaseError'
version = `ox@${getVersion()}`
constructor(shortMessage: string, options: BaseError.Options<cause> = {}) {
const details = (() => {
if (options.cause instanceof BaseError) {
if (options.cause.details) return options.cause.details
if (options.cause.shortMessage) return options.cause.shortMessage
}
if (options.cause?.message) return options.cause.message
return options.details!
})()
const docsPath = (() => {
if (options.cause instanceof BaseError)
return options.cause.docsPath || options.docsPath
return options.docsPath
})()
const docsBaseUrl = 'https://oxlib.sh'
const docs = `${docsBaseUrl}${docsPath ?? ''}`
const message = [
shortMessage || 'An error occurred.',
...(options.metaMessages ? ['', ...options.metaMessages] : []),
...(details || docsPath
? [
'',
details ? `Details: ${details}` : undefined,
docsPath ? `See: ${docs}` : undefined,
]
: []),
]
.filter((x) => typeof x === 'string')
.join('\n')
super(message, options.cause ? { cause: options.cause } : undefined)
this.cause = options.cause as any
this.details = details
this.docs = docs
this.docsPath = docsPath
this.shortMessage = shortMessage
}
walk(): Error
walk(fn: (err: unknown) => boolean): Error | null
walk(fn?: any): any {
return walk(this, fn)
}
}
export declare namespace BaseError {
type Options<cause extends Error | undefined = Error | undefined> = {
cause?: cause | undefined
details?: string | undefined
docsPath?: string | undefined
metaMessages?: (string | undefined)[] | undefined
}
}
/** @internal */
function walk(
err: unknown,
fn?: ((err: unknown) => boolean) | undefined,
): unknown {
if (fn?.(err)) return err
if (err && typeof err === 'object' && 'cause' in err && err.cause)
return walk(err.cause, fn)
return fn ? null : err
}

57
node_modules/ox/core/Fee.ts generated vendored Normal file
View File

@@ -0,0 +1,57 @@
import type * as Hex from './Hex.js'
import type { Compute, OneOf } from './internal/types.js'
export type FeeHistory<bigintType = bigint> = Compute<{
/**
* An array of block base fees per gas (in wei). This includes the next block after
* the newest of the returned range, because this value can be derived from the newest block.
* Zeroes are returned for pre-EIP-1559 blocks. */
baseFeePerGas: bigintType[]
/** An array of block gas used ratios. These are calculated as the ratio of gasUsed and gasLimit. */
gasUsedRatio: number[]
/** Lowest number block of the returned range. */
oldestBlock: bigintType
/** An array of effective priority fees (in wei) per gas data points from a single block. All zeroes are returned if the block is empty. */
reward?: bigintType[][] | undefined
}>
export type FeeHistoryRpc = FeeHistory<Hex.Hex>
export type FeeValuesLegacy<bigintType = bigint> = {
/** Base fee per gas. */
gasPrice: bigintType
}
export type FeeValuesLegacyRpc = FeeValuesLegacy<Hex.Hex>
export type FeeValuesEip1559<bigintType = bigint> = {
/** Total fee per gas in wei (gasPrice/baseFeePerGas + maxPriorityFeePerGas). */
maxFeePerGas: bigintType
/** Max priority fee per gas (in wei). */
maxPriorityFeePerGas: bigintType
}
export type FeeValuesEip1559Rpc = FeeValuesEip1559<Hex.Hex>
export type FeeValuesEip4844<bigintType = bigint> = {
/** Maximum total fee per gas sender is willing to pay for blob gas (in wei). */
maxFeePerBlobGas: bigintType
/** Total fee per gas in wei (gasPrice/baseFeePerGas + maxPriorityFeePerGas). */
maxFeePerGas: bigintType
/** Max priority fee per gas (in wei). */
maxPriorityFeePerGas: bigintType
}
export type FeeValuesEip4844Rpc = FeeValuesEip4844<Hex.Hex>
export type FeeValues<bigintType = bigint> = OneOf<
| FeeValuesLegacy<bigintType>
| FeeValuesEip1559<bigintType>
| FeeValuesEip4844<bigintType>
>
export type FeeValuesRpc = OneOf<
FeeValuesLegacyRpc | FeeValuesEip1559Rpc | FeeValuesEip4844Rpc
>
export type FeeValuesType = 'legacy' | 'eip1559' | 'eip4844'

136
node_modules/ox/core/Filter.ts generated vendored Normal file
View File

@@ -0,0 +1,136 @@
import type * as Address from './Address.js'
import type * as Block from './Block.js'
import type * as Errors from './Errors.js'
import * as Hex from './Hex.js'
import type { Compute } from './internal/types.js'
/** A Filter as defined in the [Execution API specification](https://github.com/ethereum/execution-apis/blob/main/src/schemas/filter.yaml). */
export type Filter<bigintType = bigint> = Compute<{
/** Address to filter for logs. */
address?: Address.Address | readonly Address.Address[] | null | undefined
/** Block number or tag to filter logs from. */
fromBlock?: Block.Number<bigintType> | Block.Tag | undefined
/** Block number or tag to filter logs to. */
toBlock?: Block.Number<bigintType> | Block.Tag | undefined
/** Topics to filter for logs. */
topics?: Topics | undefined
}>
/** RPC representation of a {@link ox#Filter.Filter}. */
export type Rpc = Filter<Hex.Hex>
/** Set of Filter topics. */
export type Topics = readonly Topic[]
/**
* A filter topic.
*
* - `null`: Matches any topic.
* - `Hex`: Matches if the topic is equal.
* - `Hex[]`: Matches if the topic is in the array.
*/
export type Topic = Hex.Hex | readonly Hex.Hex[] | null
/**
* Converts a {@link ox#Filter.Rpc} to an {@link ox#Filter.Filter}.
*
* @example
* ```ts twoslash
* import { Filter } from 'ox'
*
* const filter = Filter.fromRpc({
* address: '0xd3cda913deb6f67967b99d671a681250403edf27',
* fromBlock: 'latest',
* toBlock: '0x010f2c',
* topics: [
* '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
* null,
* '0x0000000000000000000000000c04d9e9278ec5e4d424476d3ebec70cb5d648d1',
* ],
* })
* // @log: {
* // @log: address: '0xd3cda913deb6f67967b99d671a681250403edf27',
* // @log: fromBlock: 'latest',
* // @log: toBlock: 69420n,
* // @log: topics: [
* // @log: '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
* // @log: null,
* // @log: '0x0000000000000000000000000c04d9e9278ec5e4d424476d3ebec70cb5d648d1',
* // @log: ],
* // @log: }
* ```
*
* @param filter - The RPC filter to convert.
* @returns An instantiated {@link ox#Filter.Filter}.
*/
export function fromRpc(filter: Rpc): Filter {
const { fromBlock, toBlock } = filter
return {
...filter,
...(fromBlock && {
fromBlock: Hex.validate(fromBlock, { strict: false })
? BigInt(fromBlock)
: fromBlock,
}),
...(toBlock && {
toBlock: Hex.validate(toBlock, { strict: false })
? BigInt(toBlock)
: toBlock,
}),
} as Filter
}
export declare namespace fromRpc {
type ErrorType = Errors.GlobalErrorType
}
/**
* Converts a {@link ox#Filter.Filter} to a {@link ox#Filter.Rpc}.
*
* @example
* ```ts twoslash
* import { AbiEvent, Filter } from 'ox'
*
* const transfer = AbiEvent.from('event Transfer(address indexed, address indexed, uint256)')
* const { topics } = AbiEvent.encode(transfer)
*
* const filter = Filter.toRpc({
* address: '0xfba3912ca04dd458c843e2ee08967fc04f3579c2',
* topics,
* })
* // @log: {
* // @log: address: '0xfba3912ca04dd458c843e2ee08967fc04f3579c2',
* // @log: topics: [
* // @log: '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
* // @log: ],
* // @log: }
* ```
*
* @param filter - The filter to convert.
* @returns An RPC filter.
*/
export function toRpc(filter: Filter): Rpc {
const { address, topics, fromBlock, toBlock } = filter
return {
...(address && { address }),
...(topics && { topics }),
...(typeof fromBlock !== 'undefined'
? {
fromBlock:
typeof fromBlock === 'bigint'
? Hex.fromNumber(fromBlock)
: fromBlock,
}
: {}),
...(typeof toBlock !== 'undefined'
? {
toBlock:
typeof toBlock === 'bigint' ? Hex.fromNumber(toBlock) : toBlock,
}
: {}),
}
}
export declare namespace toRpc {
type ErrorType = Errors.GlobalErrorType
}

198
node_modules/ox/core/Hash.ts generated vendored Normal file
View File

@@ -0,0 +1,198 @@
import { ripemd160 as noble_ripemd160 } from '@noble/hashes/ripemd160'
import { keccak_256 as noble_keccak256 } from '@noble/hashes/sha3'
import { sha256 as noble_sha256 } from '@noble/hashes/sha256'
import * as Bytes from './Bytes.js'
import type * as Errors from './Errors.js'
import * as Hex from './Hex.js'
/**
* Calculates the [Keccak256](https://en.wikipedia.org/wiki/SHA-3) hash of a {@link ox#Bytes.Bytes} or {@link ox#Hex.Hex} value.
*
* This function is a re-export of `keccak_256` from [`@noble/hashes`](https://github.com/paulmillr/noble-hashes), an audited & minimal JS hashing library.
*
* @example
* ```ts twoslash
* import { Hash } from 'ox'
*
* Hash.keccak256('0xdeadbeef')
* // @log: '0xd4fd4e189132273036449fc9e11198c739161b4c0116a9a2dccdfa1c492006f1'
* ```
*
* @example
* ### Calculate Hash of a String
*
* ```ts twoslash
* import { Hash, Hex } from 'ox'
*
* Hash.keccak256(Hex.fromString('hello world'))
* // @log: '0x3ea2f1d0abf3fc66cf29eebb70cbd4e7fe762ef8a09bcc06c8edf641230afec0'
* ```
*
* @example
* ### Configure Return Type
*
* ```ts twoslash
* import { Hash } from 'ox'
*
* Hash.keccak256('0xdeadbeef', { as: 'Bytes' })
* // @log: Uint8Array [...]
* ```
*
* @param value - {@link ox#Bytes.Bytes} or {@link ox#Hex.Hex} value.
* @param options - Options.
* @returns Keccak256 hash.
*/
export function keccak256<
value extends Hex.Hex | Bytes.Bytes,
as extends 'Hex' | 'Bytes' =
| (value extends Hex.Hex ? 'Hex' : never)
| (value extends Bytes.Bytes ? 'Bytes' : never),
>(
value: value | Hex.Hex | Bytes.Bytes,
options: keccak256.Options<as> = {},
): keccak256.ReturnType<as> {
const { as = typeof value === 'string' ? 'Hex' : 'Bytes' } = options
const bytes = noble_keccak256(Bytes.from(value))
if (as === 'Bytes') return bytes as never
return Hex.fromBytes(bytes) as never
}
export declare namespace keccak256 {
type Options<as extends 'Hex' | 'Bytes' = 'Hex' | 'Bytes'> = {
/** The return type. @default 'Hex' */
as?: as | 'Hex' | 'Bytes' | undefined
}
type ReturnType<as extends 'Hex' | 'Bytes' = 'Hex' | 'Bytes'> =
| (as extends 'Bytes' ? Bytes.Bytes : never)
| (as extends 'Hex' ? Hex.Hex : never)
type ErrorType =
| Bytes.from.ErrorType
| Hex.fromBytes.ErrorType
| Errors.GlobalErrorType
}
/**
* Calculates the [Ripemd160](https://en.wikipedia.org/wiki/RIPEMD) hash of a {@link ox#Bytes.Bytes} or {@link ox#Hex.Hex} value.
*
* This function is a re-export of `ripemd160` from [`@noble/hashes`](https://github.com/paulmillr/noble-hashes), an audited & minimal JS hashing library.
*
* @example
* ```ts twoslash
* import { Hash } from 'ox'
*
* Hash.ripemd160('0xdeadbeef')
* // '0x226821c2f5423e11fe9af68bd285c249db2e4b5a'
* ```
*
* @param value - {@link ox#Bytes.Bytes} or {@link ox#Hex.Hex} value.
* @param options - Options.
* @returns Ripemd160 hash.
*/
export function ripemd160<
value extends Hex.Hex | Bytes.Bytes,
as extends 'Hex' | 'Bytes' =
| (value extends Hex.Hex ? 'Hex' : never)
| (value extends Bytes.Bytes ? 'Bytes' : never),
>(
value: value | Hex.Hex | Bytes.Bytes,
options: ripemd160.Options<as> = {},
): ripemd160.ReturnType<as> {
const { as = typeof value === 'string' ? 'Hex' : 'Bytes' } = options
const bytes = noble_ripemd160(Bytes.from(value))
if (as === 'Bytes') return bytes as never
return Hex.fromBytes(bytes) as never
}
export declare namespace ripemd160 {
type Options<as extends 'Hex' | 'Bytes' = 'Hex' | 'Bytes'> = {
/** The return type. @default 'Hex' */
as?: as | 'Hex' | 'Bytes' | undefined
}
type ReturnType<as extends 'Hex' | 'Bytes' = 'Hex' | 'Bytes'> =
| (as extends 'Bytes' ? Bytes.Bytes : never)
| (as extends 'Hex' ? Hex.Hex : never)
type ErrorType =
| Bytes.from.ErrorType
| Hex.fromBytes.ErrorType
| Errors.GlobalErrorType
}
/**
* Calculates the [Sha256](https://en.wikipedia.org/wiki/SHA-256) hash of a {@link ox#Bytes.Bytes} or {@link ox#Hex.Hex} value.
*
* This function is a re-export of `sha256` from [`@noble/hashes`](https://github.com/paulmillr/noble-hashes), an audited & minimal JS hashing library.
*
* @example
* ```ts twoslash
* import { Hash } from 'ox'
*
* Hash.sha256('0xdeadbeef')
* // '0x5f78c33274e43fa9de5659265c1d917e25c03722dcb0b8d27db8d5feaa813953'
* ```
*
* @param value - {@link ox#Bytes.Bytes} or {@link ox#Hex.Hex} value.
* @param options - Options.
* @returns Sha256 hash.
*/
export function sha256<
value extends Hex.Hex | Bytes.Bytes,
as extends 'Hex' | 'Bytes' =
| (value extends Hex.Hex ? 'Hex' : never)
| (value extends Bytes.Bytes ? 'Bytes' : never),
>(
value: value | Hex.Hex | Bytes.Bytes,
options: sha256.Options<as> = {},
): sha256.ReturnType<as> {
const { as = typeof value === 'string' ? 'Hex' : 'Bytes' } = options
const bytes = noble_sha256(Bytes.from(value))
if (as === 'Bytes') return bytes as never
return Hex.fromBytes(bytes) as never
}
export declare namespace sha256 {
type Options<as extends 'Hex' | 'Bytes' = 'Hex'> = {
/** The return type. @default 'Hex' */
as?: as | 'Hex' | 'Bytes' | undefined
}
type ReturnType<as extends 'Hex' | 'Bytes' = 'Hex'> =
| (as extends 'Bytes' ? Bytes.Bytes : never)
| (as extends 'Hex' ? Hex.Hex : never)
type ErrorType =
| Bytes.from.ErrorType
| Hex.fromBytes.ErrorType
| Errors.GlobalErrorType
}
/**
* Checks if a string is a valid hash value.
*
* @example
* ```ts twoslash
* import { Hash } from 'ox'
*
* Hash.validate('0x')
* // @log: false
*
* Hash.validate('0x3ea2f1d0abf3fc66cf29eebb70cbd4e7fe762ef8a09bcc06c8edf641230afec0')
* // @log: true
* ```
*
* @param value - Value to check.
* @returns Whether the value is a valid hash.
*/
export function validate(value: string): value is Hex.Hex {
return Hex.validate(value) && Hex.size(value) === 32
}
export declare namespace validate {
type ErrorType =
| Hex.validate.ErrorType
| Hex.size.ErrorType
| Errors.GlobalErrorType
}

160
node_modules/ox/core/HdKey.ts generated vendored Normal file
View File

@@ -0,0 +1,160 @@
import { HDKey, type Versions } from '@scure/bip32'
import * as Bytes from './Bytes.js'
import type * as Errors from './Errors.js'
import type * as Hex from './Hex.js'
import type * as PublicKey from './PublicKey.js'
import * as internal from './internal/hdKey.js'
/** Root type for a Hierarchical Deterministic (HD) Key. */
export type HdKey = {
derive: (path: string) => HdKey
depth: number
index: number
identifier: Hex.Hex
privateKey: Hex.Hex
privateExtendedKey: string
publicKey: PublicKey.PublicKey<false>
publicExtendedKey: string
versions: Versions
}
/**
* Creates a HD Key from an extended private key.
*
* @example
* ```ts twoslash
* import { HdKey } from 'ox'
*
* const hdKey = HdKey.fromExtendedKey('...')
*
* console.log(hdKey.privateKey)
* // @log: '0x...'
* ```
*
* @param extendedKey - The extended private key.
* @returns The HD Key.
*/
export function fromExtendedKey(extendedKey: string): HdKey {
const key = HDKey.fromExtendedKey(extendedKey)
return internal.fromScure(key)
}
export declare namespace fromExtendedKey {
type ErrorType = internal.fromScure.ErrorType | Errors.GlobalErrorType
}
/**
* Creates a HD Key from a JSON object containing an extended private key (`xpriv`).
*
* @example
* ```ts twoslash
* import { HdKey } from 'ox'
*
* const hdKey = HdKey.fromJson({ xpriv: '...' })
*
* console.log(hdKey.privateKey)
* // @log: '0x...'
* ```
*
* @param json - The JSON object containing an extended private key (`xpriv`).
* @returns The HD Key.
*/
export function fromJson(json: { xpriv: string }): HdKey {
return internal.fromScure(HDKey.fromJSON(json))
}
export declare namespace fromJson {
type ErrorType = internal.fromScure.ErrorType | Errors.GlobalErrorType
}
/**
* Creates a HD Key from a master seed.
*
* @example
* ```ts twoslash
* import { HdKey, Mnemonic } from 'ox'
*
* const seed = Mnemonic.toSeed('test test test test test test test test test test test junk')
* const hdKey = HdKey.fromSeed(seed)
* ```
*
* @example
* ### Path Derivation
*
* You can derive a HD Key at a specific path using `derive`.
*
* ```ts twoslash
* import { HdKey, Mnemonic } from 'ox'
*
* const mnemonic = Mnemonic.toSeed('test test test test test test test test test test test junk')
* const hdKey = HdKey.fromSeed(mnemonic).derive(HdKey.path())
*
* console.log(hdKey.privateKey)
* // @log: '0x...'
* ```
*
* @param seed - The master seed to create the HD Key from.
* @param options - Creation options.
* @returns The HD Key.
*/
export function fromSeed(
seed: Hex.Hex | Bytes.Bytes,
options: fromSeed.Options = {},
): HdKey {
const { versions } = options
const key = HDKey.fromMasterSeed(Bytes.from(seed), versions)
return internal.fromScure(key)
}
export declare namespace fromSeed {
type Options = {
/** The versions to use for the HD Key. */
versions?: Versions | undefined
}
type ErrorType =
| Bytes.from.ErrorType
| internal.fromScure.ErrorType
| Errors.GlobalErrorType
}
/**
* Creates an Ethereum-based BIP-44 HD path.
*
* @example
* ```ts twoslash
* import { HdKey } from 'ox'
*
* const path = HdKey.path({ account: 1, index: 2 })
* // @log: "m/44'/60'/1'/0/2"
* ```
*
* @param options - Path options.
* @returns The path.
*/
export function path(options: path.Options = {}): string {
const { account = 0, change = 0, index = 0 } = options
return `m/44'/60'/${account}'/${change}/${index}`
}
export declare namespace path {
type Options = {
/**
* The account.
* @default 0
*/
account?: number | undefined
/**
* The change.
* @default 0
*/
change?: number | undefined
/**
* The address index.
* @default 0
*/
index?: number | undefined
}
type ErrorType = Errors.GlobalErrorType
}

970
node_modules/ox/core/Hex.ts generated vendored Normal file
View File

@@ -0,0 +1,970 @@
import { equalBytes } from '@noble/curves/abstract/utils'
import * as Bytes from './Bytes.js'
import * as Errors from './Errors.js'
import * as Json from './Json.js'
import * as internal_bytes from './internal/bytes.js'
import * as internal from './internal/hex.js'
const encoder = /*#__PURE__*/ new TextEncoder()
const hexes = /*#__PURE__*/ Array.from({ length: 256 }, (_v, i) =>
i.toString(16).padStart(2, '0'),
)
/** Root type for a Hex string. */
export type Hex = `0x${string}`
/**
* Asserts if the given value is {@link ox#Hex.Hex}.
*
* @example
* ```ts twoslash
* import { Hex } from 'ox'
*
* Hex.assert('abc')
* // @error: InvalidHexValueTypeError:
* // @error: Value `"abc"` of type `string` is an invalid hex type.
* // @error: Hex types must be represented as `"0x\${string}"`.
* ```
*
* @param value - The value to assert.
* @param options - Options.
*/
export function assert(
value: unknown,
options: assert.Options = {},
): asserts value is Hex {
const { strict = false } = options
if (!value) throw new InvalidHexTypeError(value)
if (typeof value !== 'string') throw new InvalidHexTypeError(value)
if (strict) {
if (!/^0x[0-9a-fA-F]*$/.test(value)) throw new InvalidHexValueError(value)
}
if (!value.startsWith('0x')) throw new InvalidHexValueError(value)
}
export declare namespace assert {
type Options = {
/** Checks if the {@link ox#Hex.Hex} value contains invalid hexadecimal characters. @default false */
strict?: boolean | undefined
}
type ErrorType =
| InvalidHexTypeError
| InvalidHexValueError
| Errors.GlobalErrorType
}
/**
* Concatenates two or more {@link ox#Hex.Hex}.
*
* @example
* ```ts twoslash
* import { Hex } from 'ox'
*
* Hex.concat('0x123', '0x456')
* // @log: '0x123456'
* ```
*
* @param values - The {@link ox#Hex.Hex} values to concatenate.
* @returns The concatenated {@link ox#Hex.Hex} value.
*/
export function concat(...values: readonly Hex[]): Hex {
return `0x${(values as Hex[]).reduce((acc, x) => acc + x.replace('0x', ''), '')}`
}
export declare namespace concat {
type ErrorType = Errors.GlobalErrorType
}
/**
* Instantiates a {@link ox#Hex.Hex} value from a hex string or {@link ox#Bytes.Bytes} value.
*
* :::tip
*
* To instantiate from a **Boolean**, **String**, or **Number**, use one of the following:
*
* - `Hex.fromBoolean`
*
* - `Hex.fromString`
*
* - `Hex.fromNumber`
*
* :::
*
* @example
* ```ts twoslash
* import { Bytes, Hex } from 'ox'
*
* Hex.from('0x48656c6c6f20576f726c6421')
* // @log: '0x48656c6c6f20576f726c6421'
*
* Hex.from(Bytes.from([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33]))
* // @log: '0x48656c6c6f20576f726c6421'
* ```
*
* @param value - The {@link ox#Bytes.Bytes} value to encode.
* @returns The encoded {@link ox#Hex.Hex} value.
*/
export function from(value: Hex | Bytes.Bytes | readonly number[]): Hex {
if (value instanceof Uint8Array) return fromBytes(value)
if (Array.isArray(value)) return fromBytes(new Uint8Array(value))
return value as never
}
export declare namespace from {
type Options = {
/** The size (in bytes) of the output hex value. */
size?: number | undefined
}
type ErrorType = fromBytes.ErrorType | Errors.GlobalErrorType
}
/**
* Encodes a boolean into a {@link ox#Hex.Hex} value.
*
* @example
* ```ts twoslash
* import { Hex } from 'ox'
*
* Hex.fromBoolean(true)
* // @log: '0x1'
*
* Hex.fromBoolean(false)
* // @log: '0x0'
*
* Hex.fromBoolean(true, { size: 32 })
* // @log: '0x0000000000000000000000000000000000000000000000000000000000000001'
* ```
*
* @param value - The boolean value to encode.
* @param options - Options.
* @returns The encoded {@link ox#Hex.Hex} value.
*/
export function fromBoolean(
value: boolean,
options: fromBoolean.Options = {},
): Hex {
const hex: Hex = `0x${Number(value)}`
if (typeof options.size === 'number') {
internal.assertSize(hex, options.size)
return padLeft(hex, options.size)
}
return hex
}
export declare namespace fromBoolean {
type Options = {
/** The size (in bytes) of the output hex value. */
size?: number | undefined
}
type ErrorType =
| internal.assertSize.ErrorType
| padLeft.ErrorType
| Errors.GlobalErrorType
}
/**
* Encodes a {@link ox#Bytes.Bytes} value into a {@link ox#Hex.Hex} value.
*
* @example
* ```ts twoslash
* import { Bytes, Hex } from 'ox'
*
* Hex.fromBytes(Bytes.from([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33]))
* // @log: '0x48656c6c6f20576f726c6421'
* ```
*
* @param value - The {@link ox#Bytes.Bytes} value to encode.
* @param options - Options.
* @returns The encoded {@link ox#Hex.Hex} value.
*/
export function fromBytes(
value: Bytes.Bytes,
options: fromBytes.Options = {},
): Hex {
let string = ''
for (let i = 0; i < value.length; i++) string += hexes[value[i]!]
const hex = `0x${string}` as const
if (typeof options.size === 'number') {
internal.assertSize(hex, options.size)
return padRight(hex, options.size)
}
return hex
}
export declare namespace fromBytes {
type Options = {
/** The size (in bytes) of the output hex value. */
size?: number | undefined
}
type ErrorType =
| internal.assertSize.ErrorType
| padRight.ErrorType
| Errors.GlobalErrorType
}
/**
* Encodes a number or bigint into a {@link ox#Hex.Hex} value.
*
* @example
* ```ts twoslash
* import { Hex } from 'ox'
*
* Hex.fromNumber(420)
* // @log: '0x1a4'
*
* Hex.fromNumber(420, { size: 32 })
* // @log: '0x00000000000000000000000000000000000000000000000000000000000001a4'
* ```
*
* @param value - The number or bigint value to encode.
* @param options - Options.
* @returns The encoded {@link ox#Hex.Hex} value.
*/
export function fromNumber(
value: number | bigint,
options: fromNumber.Options = {},
): Hex {
const { signed, size } = options
const value_ = BigInt(value)
let maxValue: bigint | number | undefined
if (size) {
if (signed) maxValue = (1n << (BigInt(size) * 8n - 1n)) - 1n
else maxValue = 2n ** (BigInt(size) * 8n) - 1n
} else if (typeof value === 'number') {
maxValue = BigInt(Number.MAX_SAFE_INTEGER)
}
const minValue = typeof maxValue === 'bigint' && signed ? -maxValue - 1n : 0
if ((maxValue && value_ > maxValue) || value_ < minValue) {
const suffix = typeof value === 'bigint' ? 'n' : ''
throw new IntegerOutOfRangeError({
max: maxValue ? `${maxValue}${suffix}` : undefined,
min: `${minValue}${suffix}`,
signed,
size,
value: `${value}${suffix}`,
})
}
const stringValue = (
signed && value_ < 0 ? (1n << BigInt(size * 8)) + BigInt(value_) : value_
).toString(16)
const hex = `0x${stringValue}` as Hex
if (size) return padLeft(hex, size) as Hex
return hex
}
export declare namespace fromNumber {
type Options =
| {
/** Whether or not the number of a signed representation. */
signed?: boolean | undefined
/** The size (in bytes) of the output hex value. */
size: number
}
| {
signed?: undefined
/** The size (in bytes) of the output hex value. */
size?: number | undefined
}
type ErrorType =
| IntegerOutOfRangeError
| padLeft.ErrorType
| Errors.GlobalErrorType
}
/**
* Encodes a string into a {@link ox#Hex.Hex} value.
*
* @example
* ```ts twoslash
* import { Hex } from 'ox'
* Hex.fromString('Hello World!')
* // '0x48656c6c6f20576f726c6421'
*
* Hex.fromString('Hello World!', { size: 32 })
* // '0x48656c6c6f20576f726c64210000000000000000000000000000000000000000'
* ```
*
* @param value - The string value to encode.
* @param options - Options.
* @returns The encoded {@link ox#Hex.Hex} value.
*/
export function fromString(
value: string,
options: fromString.Options = {},
): Hex {
return fromBytes(encoder.encode(value), options)
}
export declare namespace fromString {
type Options = {
/** The size (in bytes) of the output hex value. */
size?: number | undefined
}
type ErrorType = fromBytes.ErrorType | Errors.GlobalErrorType
}
/**
* Checks if two {@link ox#Hex.Hex} values are equal.
*
* @example
* ```ts twoslash
* import { Hex } from 'ox'
*
* Hex.isEqual('0xdeadbeef', '0xdeadbeef')
* // @log: true
*
* Hex.isEqual('0xda', '0xba')
* // @log: false
* ```
*
* @param hexA - The first {@link ox#Hex.Hex} value.
* @param hexB - The second {@link ox#Hex.Hex} value.
* @returns `true` if the two {@link ox#Hex.Hex} values are equal, `false` otherwise.
*/
export function isEqual(hexA: Hex, hexB: Hex) {
return equalBytes(Bytes.fromHex(hexA), Bytes.fromHex(hexB))
}
export declare namespace isEqual {
type ErrorType = Bytes.fromHex.ErrorType | Errors.GlobalErrorType
}
/**
* Pads a {@link ox#Hex.Hex} value to the left with zero bytes until it reaches the given `size` (default: 32 bytes).
*
* @example
* ```ts twoslash
* import { Hex } from 'ox'
*
* Hex.padLeft('0x1234', 4)
* // @log: '0x00001234'
* ```
*
* @param value - The {@link ox#Hex.Hex} value to pad.
* @param size - The size (in bytes) of the output hex value.
* @returns The padded {@link ox#Hex.Hex} value.
*/
export function padLeft(
value: Hex,
size?: number | undefined,
): padLeft.ReturnType {
return internal.pad(value, { dir: 'left', size })
}
export declare namespace padLeft {
type ReturnType = Hex
type ErrorType = internal.pad.ErrorType | Errors.GlobalErrorType
}
/**
* Pads a {@link ox#Hex.Hex} value to the right with zero bytes until it reaches the given `size` (default: 32 bytes).
*
* @example
* ```ts
* import { Hex } from 'ox'
*
* Hex.padRight('0x1234', 4)
* // @log: '0x12340000'
* ```
*
* @param value - The {@link ox#Hex.Hex} value to pad.
* @param size - The size (in bytes) of the output hex value.
* @returns The padded {@link ox#Hex.Hex} value.
*/
export function padRight(
value: Hex,
size?: number | undefined,
): padRight.ReturnType {
return internal.pad(value, { dir: 'right', size })
}
export declare namespace padRight {
type ReturnType = Hex
type ErrorType = internal.pad.ErrorType | Errors.GlobalErrorType
}
/**
* Generates a random {@link ox#Hex.Hex} value of the specified length.
*
* @example
* ```ts twoslash
* import { Hex } from 'ox'
*
* const hex = Hex.random(32)
* // @log: '0x...'
* ```
*
* @returns Random {@link ox#Hex.Hex} value.
*/
export function random(length: number): Hex {
return fromBytes(Bytes.random(length))
}
export declare namespace random {
type ErrorType = Errors.GlobalErrorType
}
/**
* Returns a section of a {@link ox#Bytes.Bytes} value given a start/end bytes offset.
*
* @example
* ```ts twoslash
* import { Hex } from 'ox'
*
* Hex.slice('0x0123456789', 1, 4)
* // @log: '0x234567'
* ```
*
* @param value - The {@link ox#Hex.Hex} value to slice.
* @param start - The start offset (in bytes).
* @param end - The end offset (in bytes).
* @param options - Options.
* @returns The sliced {@link ox#Hex.Hex} value.
*/
export function slice(
value: Hex,
start?: number | undefined,
end?: number | undefined,
options: slice.Options = {},
): Hex {
const { strict } = options
internal.assertStartOffset(value, start)
const value_ = `0x${value
.replace('0x', '')
.slice((start ?? 0) * 2, (end ?? value.length) * 2)}` as const
if (strict) internal.assertEndOffset(value_, start, end)
return value_
}
export declare namespace slice {
type Options = {
/** Asserts that the sliced value is the same size as the given start/end offsets. */
strict?: boolean | undefined
}
type ErrorType =
| internal.assertStartOffset.ErrorType
| internal.assertEndOffset.ErrorType
| Errors.GlobalErrorType
}
/**
* Retrieves the size of a {@link ox#Hex.Hex} value (in bytes).
*
* @example
* ```ts twoslash
* import { Hex } from 'ox'
*
* Hex.size('0xdeadbeef')
* // @log: 4
* ```
*
* @param value - The {@link ox#Hex.Hex} value to get the size of.
* @returns The size of the {@link ox#Hex.Hex} value (in bytes).
*/
export function size(value: Hex): number {
return Math.ceil((value.length - 2) / 2)
}
export declare namespace size {
export type ErrorType = Errors.GlobalErrorType
}
/**
* Trims leading zeros from a {@link ox#Hex.Hex} value.
*
* @example
* ```ts twoslash
* import { Hex } from 'ox'
*
* Hex.trimLeft('0x00000000deadbeef')
* // @log: '0xdeadbeef'
* ```
*
* @param value - The {@link ox#Hex.Hex} value to trim.
* @returns The trimmed {@link ox#Hex.Hex} value.
*/
export function trimLeft(value: Hex): trimLeft.ReturnType {
return internal.trim(value, { dir: 'left' })
}
export declare namespace trimLeft {
type ReturnType = Hex
type ErrorType = internal.trim.ErrorType | Errors.GlobalErrorType
}
/**
* Trims trailing zeros from a {@link ox#Hex.Hex} value.
*
* @example
* ```ts twoslash
* import { Hex } from 'ox'
*
* Hex.trimRight('0xdeadbeef00000000')
* // @log: '0xdeadbeef'
* ```
*
* @param value - The {@link ox#Hex.Hex} value to trim.
* @returns The trimmed {@link ox#Hex.Hex} value.
*/
export function trimRight(value: Hex): trimRight.ReturnType {
return internal.trim(value, { dir: 'right' })
}
export declare namespace trimRight {
type ReturnType = Hex
type ErrorType = internal.trim.ErrorType | Errors.GlobalErrorType
}
/**
* Decodes a {@link ox#Hex.Hex} value into a BigInt.
*
* @example
* ```ts twoslash
* import { Hex } from 'ox'
*
* Hex.toBigInt('0x1a4')
* // @log: 420n
*
* Hex.toBigInt('0x00000000000000000000000000000000000000000000000000000000000001a4', { size: 32 })
* // @log: 420n
* ```
*
* @param hex - The {@link ox#Hex.Hex} value to decode.
* @param options - Options.
* @returns The decoded BigInt.
*/
export function toBigInt(hex: Hex, options: toBigInt.Options = {}): bigint {
const { signed } = options
if (options.size) internal.assertSize(hex, options.size)
const value = BigInt(hex)
if (!signed) return value
const size = (hex.length - 2) / 2
const max_unsigned = (1n << (BigInt(size) * 8n)) - 1n
const max_signed = max_unsigned >> 1n
if (value <= max_signed) return value
return value - max_unsigned - 1n
}
export declare namespace toBigInt {
type Options = {
/** Whether or not the number of a signed representation. */
signed?: boolean | undefined
/** Size (in bytes) of the hex value. */
size?: number | undefined
}
type ErrorType = internal.assertSize.ErrorType | Errors.GlobalErrorType
}
/**
* Decodes a {@link ox#Hex.Hex} value into a boolean.
*
* @example
* ```ts twoslash
* import { Hex } from 'ox'
*
* Hex.toBoolean('0x01')
* // @log: true
*
* Hex.toBoolean('0x0000000000000000000000000000000000000000000000000000000000000001', { size: 32 })
* // @log: true
* ```
*
* @param hex - The {@link ox#Hex.Hex} value to decode.
* @param options - Options.
* @returns The decoded boolean.
*/
export function toBoolean(hex: Hex, options: toBoolean.Options = {}): boolean {
if (options.size) internal.assertSize(hex, options.size)
const hex_ = trimLeft(hex)
if (hex_ === '0x') return false
if (hex_ === '0x1') return true
throw new InvalidHexBooleanError(hex)
}
export declare namespace toBoolean {
type Options = {
/** Size (in bytes) of the hex value. */
size?: number | undefined
}
type ErrorType =
| internal.assertSize.ErrorType
| trimLeft.ErrorType
| InvalidHexBooleanError
| Errors.GlobalErrorType
}
/**
* Decodes a {@link ox#Hex.Hex} value into a {@link ox#Bytes.Bytes}.
*
* @example
* ```ts twoslash
* import { Hex } from 'ox'
*
* const data = Hex.toBytes('0x48656c6c6f20776f726c6421')
* // @log: Uint8Array([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33])
* ```
*
* @param hex - The {@link ox#Hex.Hex} value to decode.
* @param options - Options.
* @returns The decoded {@link ox#Bytes.Bytes}.
*/
export function toBytes(hex: Hex, options: toBytes.Options = {}): Bytes.Bytes {
return Bytes.fromHex(hex, options)
}
export declare namespace toBytes {
type Options = {
/** Size (in bytes) of the hex value. */
size?: number | undefined
}
type ErrorType = Bytes.fromHex.ErrorType | Errors.GlobalErrorType
}
/**
* Decodes a {@link ox#Hex.Hex} value into a number.
*
* @example
* ```ts twoslash
* import { Hex } from 'ox'
*
* Hex.toNumber('0x1a4')
* // @log: 420
*
* Hex.toNumber('0x00000000000000000000000000000000000000000000000000000000000001a4', { size: 32 })
* // @log: 420
* ```
*
* @param hex - The {@link ox#Hex.Hex} value to decode.
* @param options - Options.
* @returns The decoded number.
*/
export function toNumber(hex: Hex, options: toNumber.Options = {}): number {
const { signed, size } = options
if (!signed && !size) return Number(hex)
return Number(toBigInt(hex, options))
}
export declare namespace toNumber {
type Options = toBigInt.Options
type ErrorType = toBigInt.ErrorType | Errors.GlobalErrorType
}
/**
* Decodes a {@link ox#Hex.Hex} value into a string.
*
* @example
* ```ts twoslash
* import { Hex } from 'ox'
*
* Hex.toString('0x48656c6c6f20576f726c6421')
* // @log: 'Hello world!'
*
* Hex.toString('0x48656c6c6f20576f726c64210000000000000000000000000000000000000000', {
* size: 32,
* })
* // @log: 'Hello world'
* ```
*
* @param hex - The {@link ox#Hex.Hex} value to decode.
* @param options - Options.
* @returns The decoded string.
*/
export function toString(hex: Hex, options: toString.Options = {}): string {
const { size } = options
let bytes = Bytes.fromHex(hex)
if (size) {
internal_bytes.assertSize(bytes, size)
bytes = Bytes.trimRight(bytes)
}
return new TextDecoder().decode(bytes)
}
export declare namespace toString {
type Options = {
/** Size (in bytes) of the hex value. */
size?: number | undefined
}
type ErrorType =
| internal_bytes.assertSize.ErrorType
| Bytes.fromHex.ErrorType
| Bytes.trimRight.ErrorType
| Errors.GlobalErrorType
}
/**
* Checks if the given value is {@link ox#Hex.Hex}.
*
* @example
* ```ts twoslash
* import { Bytes, Hex } from 'ox'
*
* Hex.validate('0xdeadbeef')
* // @log: true
*
* Hex.validate(Bytes.from([1, 2, 3]))
* // @log: false
* ```
*
* @param value - The value to check.
* @param options - Options.
* @returns `true` if the value is a {@link ox#Hex.Hex}, `false` otherwise.
*/
export function validate(
value: unknown,
options: validate.Options = {},
): value is Hex {
const { strict = false } = options
try {
assert(value, { strict })
return true
} catch {
return false
}
}
export declare namespace validate {
type Options = {
/** Checks if the {@link ox#Hex.Hex} value contains invalid hexadecimal characters. @default false */
strict?: boolean | undefined
}
type ErrorType = Errors.GlobalErrorType
}
/**
* Thrown when the provided integer is out of range, and cannot be represented as a hex value.
*
* @example
* ```ts twoslash
* import { Hex } from 'ox'
*
* Hex.fromNumber(420182738912731283712937129)
* // @error: Hex.IntegerOutOfRangeError: Number \`4.2018273891273126e+26\` is not in safe unsigned integer range (`0` to `9007199254740991`)
* ```
*/
export class IntegerOutOfRangeError extends Errors.BaseError {
override readonly name = 'Hex.IntegerOutOfRangeError'
constructor({
max,
min,
signed,
size,
value,
}: {
max?: string | undefined
min: string
signed?: boolean | undefined
size?: number | undefined
value: string
}) {
super(
`Number \`${value}\` is not in safe${
size ? ` ${size * 8}-bit` : ''
}${signed ? ' signed' : ' unsigned'} integer range ${max ? `(\`${min}\` to \`${max}\`)` : `(above \`${min}\`)`}`,
)
}
}
/**
* Thrown when the provided hex value cannot be represented as a boolean.
*
* @example
* ```ts twoslash
* import { Hex } from 'ox'
*
* Hex.toBoolean('0xa')
* // @error: Hex.InvalidHexBooleanError: Hex value `"0xa"` is not a valid boolean.
* // @error: The hex value must be `"0x0"` (false) or `"0x1"` (true).
* ```
*/
export class InvalidHexBooleanError extends Errors.BaseError {
override readonly name = 'Hex.InvalidHexBooleanError'
constructor(hex: Hex) {
super(`Hex value \`"${hex}"\` is not a valid boolean.`, {
metaMessages: [
'The hex value must be `"0x0"` (false) or `"0x1"` (true).',
],
})
}
}
/**
* Thrown when the provided value is not a valid hex type.
*
* @example
* ```ts twoslash
* import { Hex } from 'ox'
*
* Hex.assert(1)
* // @error: Hex.InvalidHexTypeError: Value `1` of type `number` is an invalid hex type.
* ```
*/
export class InvalidHexTypeError extends Errors.BaseError {
override readonly name = 'Hex.InvalidHexTypeError'
constructor(value: unknown) {
super(
`Value \`${typeof value === 'object' ? Json.stringify(value) : value}\` of type \`${typeof value}\` is an invalid hex type.`,
{
metaMessages: ['Hex types must be represented as `"0x${string}"`.'],
},
)
}
}
/**
* Thrown when the provided hex value is invalid.
*
* @example
* ```ts twoslash
* import { Hex } from 'ox'
*
* Hex.assert('0x0123456789abcdefg')
* // @error: Hex.InvalidHexValueError: Value `0x0123456789abcdefg` is an invalid hex value.
* // @error: Hex values must start with `"0x"` and contain only hexadecimal characters (0-9, a-f, A-F).
* ```
*/
export class InvalidHexValueError extends Errors.BaseError {
override readonly name = 'Hex.InvalidHexValueError'
constructor(value: unknown) {
super(`Value \`${value}\` is an invalid hex value.`, {
metaMessages: [
'Hex values must start with `"0x"` and contain only hexadecimal characters (0-9, a-f, A-F).',
],
})
}
}
/**
* Thrown when the provided hex value is an odd length.
*
* @example
* ```ts twoslash
* import { Bytes } from 'ox'
*
* Bytes.fromHex('0xabcde')
* // @error: Hex.InvalidLengthError: Hex value `"0xabcde"` is an odd length (5 nibbles).
* ```
*/
export class InvalidLengthError extends Errors.BaseError {
override readonly name = 'Hex.InvalidLengthError'
constructor(value: Hex) {
super(
`Hex value \`"${value}"\` is an odd length (${value.length - 2} nibbles).`,
{
metaMessages: ['It must be an even length.'],
},
)
}
}
/**
* Thrown when the size of the value exceeds the expected max size.
*
* @example
* ```ts twoslash
* import { Hex } from 'ox'
*
* Hex.fromString('Hello World!', { size: 8 })
* // @error: Hex.SizeOverflowError: Size cannot exceed `8` bytes. Given size: `12` bytes.
* ```
*/
export class SizeOverflowError extends Errors.BaseError {
override readonly name = 'Hex.SizeOverflowError'
constructor({ givenSize, maxSize }: { givenSize: number; maxSize: number }) {
super(
`Size cannot exceed \`${maxSize}\` bytes. Given size: \`${givenSize}\` bytes.`,
)
}
}
/**
* Thrown when the slice offset exceeds the bounds of the value.
*
* @example
* ```ts twoslash
* import { Hex } from 'ox'
*
* Hex.slice('0x0123456789', 6)
* // @error: Hex.SliceOffsetOutOfBoundsError: Slice starting at offset `6` is out-of-bounds (size: `5`).
* ```
*/
export class SliceOffsetOutOfBoundsError extends Errors.BaseError {
override readonly name = 'Hex.SliceOffsetOutOfBoundsError'
constructor({
offset,
position,
size,
}: { offset: number; position: 'start' | 'end'; size: number }) {
super(
`Slice ${
position === 'start' ? 'starting' : 'ending'
} at offset \`${offset}\` is out-of-bounds (size: \`${size}\`).`,
)
}
}
/**
* Thrown when the size of the value exceeds the pad size.
*
* @example
* ```ts twoslash
* import { Hex } from 'ox'
*
* Hex.padLeft('0x1a4e12a45a21323123aaa87a897a897a898a6567a578a867a98778a667a85a875a87a6a787a65a675a6a9', 32)
* // @error: Hex.SizeExceedsPaddingSizeError: Hex size (`43`) exceeds padding size (`32`).
* ```
*/
export class SizeExceedsPaddingSizeError extends Errors.BaseError {
override readonly name = 'Hex.SizeExceedsPaddingSizeError'
constructor({
size,
targetSize,
type,
}: {
size: number
targetSize: number
type: 'Hex' | 'Bytes'
}) {
super(
`${type.charAt(0).toUpperCase()}${type
.slice(1)
.toLowerCase()} size (\`${size}\`) exceeds padding size (\`${targetSize}\`).`,
)
}
}

76
node_modules/ox/core/Json.ts generated vendored Normal file
View File

@@ -0,0 +1,76 @@
import type * as Errors from './Errors.js'
const bigIntSuffix = '#__bigint'
/**
* Parses a JSON string, with support for `bigint`.
*
* @example
* ```ts twoslash
* import { Json } from 'ox'
*
* const json = Json.parse('{"foo":"bar","baz":"69420694206942069420694206942069420694206942069420#__bigint"}')
* // @log: {
* // @log: foo: 'bar',
* // @log: baz: 69420694206942069420694206942069420694206942069420n
* // @log: }
* ```
*
* @param string - The value to parse.
* @param reviver - A function that transforms the results.
* @returns The parsed value.
*/
export function parse(
string: string,
reviver?: ((this: any, key: string, value: any) => any) | undefined,
) {
return JSON.parse(string, (key, value_) => {
const value = value_
if (typeof value === 'string' && value.endsWith(bigIntSuffix))
return BigInt(value.slice(0, -bigIntSuffix.length))
return typeof reviver === 'function' ? reviver(key, value) : value
})
}
export declare namespace parse {
type ErrorType = Errors.GlobalErrorType
}
/**
* Stringifies a value to its JSON representation, with support for `bigint`.
*
* @example
* ```ts twoslash
* import { Json } from 'ox'
*
* const json = Json.stringify({
* foo: 'bar',
* baz: 69420694206942069420694206942069420694206942069420n,
* })
* // @log: '{"foo":"bar","baz":"69420694206942069420694206942069420694206942069420#__bigint"}'
* ```
*
* @param value - The value to stringify.
* @param replacer - A function that transforms the results. It is passed the key and value of the property, and must return the value to be used in the JSON string. If this function returns `undefined`, the property is not included in the resulting JSON string.
* @param space - A string or number that determines the indentation of the JSON string. If it is a number, it indicates the number of spaces to use as indentation; if it is a string (e.g. `'\t'`), it uses the string as the indentation character.
* @returns The JSON string.
*/
export function stringify(
value: any,
replacer?: ((this: any, key: string, value: any) => any) | null | undefined,
space?: string | number | undefined,
) {
return JSON.stringify(
value,
(key, value) => {
if (typeof replacer === 'function') return replacer(key, value)
if (typeof value === 'bigint') return value.toString() + bigIntSuffix
return value
},
space,
)
}
export declare namespace stringify {
type ErrorType = Errors.GlobalErrorType
}

48
node_modules/ox/core/Kzg.ts generated vendored Normal file
View File

@@ -0,0 +1,48 @@
import type * as Bytes from './Bytes.js'
import type * as Errors from './Errors.js'
/** @see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-4844.md#parameters */
export const versionedHashVersion = 1
/** Root type for a KZG interface. */
export type Kzg = {
/**
* Convert a blob to a KZG commitment.
*/
blobToKzgCommitment(blob: Bytes.Bytes): Bytes.Bytes
/**
* Given a blob, return the KZG proof that is used to verify it against the
* commitment.
*/
computeBlobKzgProof(blob: Bytes.Bytes, commitment: Bytes.Bytes): Bytes.Bytes
}
/**
* Defines a KZG interface.
*
* @example
* ```ts twoslash
* // @noErrors
* import * as cKzg from 'c-kzg'
* import { Kzg } from 'ox'
* import { Paths } from 'ox/trusted-setups'
*
* cKzg.loadTrustedSetup(Paths.mainnet)
*
* const kzg = Kzg.from(cKzg)
* ```
*
* @param value - The KZG object to convert.
* @returns The KZG interface object.
*/
export function from(value: Kzg): Kzg {
const { blobToKzgCommitment, computeBlobKzgProof } = value
return {
blobToKzgCommitment,
computeBlobKzgProof,
}
}
export declare namespace from {
type ErrorType = Errors.GlobalErrorType
}

240
node_modules/ox/core/Log.ts generated vendored Normal file
View File

@@ -0,0 +1,240 @@
import type * as Address from './Address.js'
import type * as Errors from './Errors.js'
import * as Hex from './Hex.js'
import type { Compute } from './internal/types.js'
/** A Log as defined in the [Execution API specification](https://github.com/ethereum/execution-apis/blob/main/src/schemas/receipt.yaml). */
export type Log<
pending extends boolean = false,
bigintType = bigint,
numberType = number,
> = Compute<{
/** The address from which this log originated */
address: Address.Address
/** Hash of block containing this log or `null` if pending */
blockHash: pending extends true ? null : Hex.Hex
/** Number of block containing this log or `null` if pending */
blockNumber: pending extends true ? null : bigintType
/** Contains the non-integered arguments of the log */
data: Hex.Hex
/** Index of this log within its block or `null` if pending */
logIndex: pending extends true ? null : numberType
/** List of topics associated with this log */
topics: [Hex.Hex, ...(readonly Hex.Hex[])]
/** Hash of the transaction that created this log or `null` if pending */
transactionHash: pending extends true ? null : Hex.Hex
/** Index of the transaction that created this log or `null` if pending */
transactionIndex: pending extends true ? null : numberType
/** `true` if this filter has been destroyed and is invalid */
removed: boolean
}>
/** An RPC Log as defined in the [Execution API specification](https://github.com/ethereum/execution-apis/blob/main/src/schemas/receipt.yaml). */
export type Rpc<pending extends boolean = false> = Log<
pending,
Hex.Hex,
Hex.Hex
>
/**
* Converts a {@link ox#Log.Rpc} to an {@link ox#Log.Log}.
*
* @example
* ```ts twoslash
* import { Log } from 'ox'
*
* const log = Log.fromRpc({
* address: '0xfba3912ca04dd458c843e2ee08967fc04f3579c2',
* topics: [
* '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
* '0x0000000000000000000000000000000000000000000000000000000000000000',
* '0x0000000000000000000000000c04d9e9278ec5e4d424476d3ebec70cb5d648d1',
* '0x000000000000000000000000000000000000000000000000000000000000025b',
* ],
* data: '0x',
* blockHash:
* '0xabe69134e80a12f6a93d0aa18215b5b86c2fb338bae911790ca374a8716e01a4',
* blockNumber: '0x12d846c',
* transactionHash:
* '0xcfa52db0bc2cb5bdcb2c5bd8816df7a2f018a0e3964ab1ef4d794cf327966e93',
* transactionIndex: '0x91',
* logIndex: '0x10f',
* removed: false,
* })
* // @log: {
* // @log: address: '0xfba3912ca04dd458c843e2ee08967fc04f3579c2',
* // @log: blockHash: '0xabe69134e80a12f6a93d0aa18215b5b86c2fb338bae911790ca374a8716e01a4',
* // @log: blockNumber: 19760236n,
* // @log: data: '0x',
* // @log: logIndex: 271,
* // @log: removed: false,
* // @log: topics: [
* // @log: "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
* // @log: "0x0000000000000000000000000000000000000000000000000000000000000000",
* // @log: "0x0000000000000000000000000c04d9e9278ec5e4d424476d3ebec70cb5d648d1",
* // @log: "0x000000000000000000000000000000000000000000000000000000000000025b",
* // @log: transactionHash:
* // @log: '0xcfa52db0bc2cb5bdcb2c5bd8816df7a2f018a0e3964ab1ef4d794cf327966e93',
* // @log: transactionIndex: 145,
* // @log: }
* ```
*
* @example
* ### End-to-end
*
* Below is an example of how to use `Log.fromRpc` to instantiate a {@link ox#Log.Log} from an RPC log.
*
* ```ts twoslash
* import 'ox/window'
* import { AbiEvent, Hex, Log } from 'ox'
*
* const transfer = AbiEvent.from(
* 'event Transfer(address indexed from, address indexed to, uint256 indexed value)',
* )
*
* const { topics } = AbiEvent.encode(transfer)
*
* const logs = await window.ethereum!.request({
* method: 'eth_getLogs',
* params: [
* {
* address: '0xfba3912ca04dd458c843e2ee08967fc04f3579c2',
* fromBlock: Hex.fromNumber(19760235n),
* toBlock: Hex.fromNumber(19760240n),
* topics,
* },
* ],
* })
*
* const log = Log.fromRpc(logs[0]) // [!code focus]
* // @log: {
* // @log: address: '0xfba3912ca04dd458c843e2ee08967fc04f3579c2',
* // @log: blockHash: '0xabe69134e80a12f6a93d0aa18215b5b86c2fb338bae911790ca374a8716e01a4',
* // @log: blockNumber: 19760236n,
* // @log: data: '0x',
* // @log: logIndex: 271,
* // @log: removed: false,
* // @log: topics: [
* // @log: "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
* // @log: "0x0000000000000000000000000000000000000000000000000000000000000000",
* // @log: "0x0000000000000000000000000c04d9e9278ec5e4d424476d3ebec70cb5d648d1",
* // @log: "0x000000000000000000000000000000000000000000000000000000000000025b",
* // @log: transactionHash:
* // @log: '0xcfa52db0bc2cb5bdcb2c5bd8816df7a2f018a0e3964ab1ef4d794cf327966e93',
* // @log: transactionIndex: 145,
* // @log: }
* ```
*
* :::note
*
* For simplicity, the above example uses `window.ethereum.request`, but you can use any
* type of JSON-RPC interface.
*
* :::
*
* @param log - The RPC log to convert.
* @returns An instantiated {@link ox#Log.Log}.
*/
export function fromRpc<
const log extends Rpc<boolean>,
pending extends boolean = false,
>(
log: log | Rpc<boolean>,
_options: fromRpc.Options<pending> = {},
): Log<pending> {
return {
...log,
blockNumber: log.blockNumber ? BigInt(log.blockNumber) : null,
logIndex: log.logIndex ? Number(log.logIndex) : null,
transactionIndex: log.transactionIndex
? Number(log.transactionIndex)
: null,
} as Log<pending>
}
export declare namespace fromRpc {
type Options<pending extends boolean = false> = {
pending?: pending | boolean | undefined
}
type ErrorType = Errors.GlobalErrorType
}
/**
* Converts a {@link ox#Log.Log} to a {@link ox#Log.Rpc}.
*
* @example
* ```ts twoslash
* import { Log } from 'ox'
*
* const log = Log.toRpc({
* address: '0xfba3912ca04dd458c843e2ee08967fc04f3579c2',
* blockHash:
* '0xabe69134e80a12f6a93d0aa18215b5b86c2fb338bae911790ca374a8716e01a4',
* blockNumber: 19760236n,
* data: '0x',
* logIndex: 271,
* removed: false,
* topics: [
* '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
* '0x0000000000000000000000000000000000000000000000000000000000000000',
* '0x0000000000000000000000000c04d9e9278ec5e4d424476d3ebec70cb5d648d1',
* '0x000000000000000000000000000000000000000000000000000000000000025b',
* ],
* transactionHash:
* '0xcfa52db0bc2cb5bdcb2c5bd8816df7a2f018a0e3964ab1ef4d794cf327966e93',
* transactionIndex: 145,
* })
* // @log: {
* // @log: address: '0xfba3912ca04dd458c843e2ee08967fc04f3579c2',
* // @log: blockHash: '0xabe69134e80a12f6a93d0aa18215b5b86c2fb338bae911790ca374a8716e01a4',
* // @log: blockNumber: '0x012d846c',
* // @log: data: '0x',
* // @log: logIndex: '0x010f',
* // @log: removed: false,
* // @log: topics: [
* // @log: '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
* // @log: '0x0000000000000000000000000000000000000000000000000000000000000000',
* // @log: '0x0000000000000000000000000c04d9e9278ec5e4d424476d3ebec70cb5d648d1',
* // @log: '0x000000000000000000000000000000000000000000000000000000000000025b',
* // @log: ],
* // @log: transactionHash:
* // @log: '0xcfa52db0bc2cb5bdcb2c5bd8816df7a2f018a0e3964ab1ef4d794cf327966e93',
* // @log: transactionIndex: '0x91',
* // @log: }
* ```
*
* @param log - The log to convert.
* @returns An RPC log.
*/
export function toRpc<
const log extends Log<boolean>,
pending extends boolean = false,
>(log: log, _options: toRpc.Options<pending> = {}): Rpc<pending> {
return {
address: log.address,
blockHash: log.blockHash,
blockNumber:
typeof log.blockNumber === 'bigint'
? Hex.fromNumber(log.blockNumber)
: null,
data: log.data,
logIndex:
typeof log.logIndex === 'number' ? Hex.fromNumber(log.logIndex) : null,
topics: log.topics,
transactionHash: log.transactionHash,
transactionIndex:
typeof log.transactionIndex === 'number'
? Hex.fromNumber(log.transactionIndex)
: null,
removed: log.removed,
} as Rpc as never
}
export declare namespace toRpc {
type Options<pending extends boolean = false> = {
pending?: pending | boolean | undefined
}
type ErrorType = Errors.GlobalErrorType
}

229
node_modules/ox/core/Mnemonic.ts generated vendored Normal file
View File

@@ -0,0 +1,229 @@
import {
generateMnemonic,
mnemonicToSeedSync,
validateMnemonic,
} from '@scure/bip39'
import * as Bytes from './Bytes.js'
import type * as Errors from './Errors.js'
import * as HdKey from './HdKey.js'
import type * as Hex from './Hex.js'
export { path } from './HdKey.js'
export {
english,
czech,
french,
italian,
japanese,
korean,
portuguese,
simplifiedChinese,
spanish,
traditionalChinese,
} from './internal/mnemonic/wordlists.js'
/**
* Generates a random mnemonic.
*
* @example
* ```ts twoslash
* import { Mnemonic } from 'ox'
*
* const mnemonic = Mnemonic.random(Mnemonic.english)
* // @log: 'buyer zoo end danger ice capable shrug naive twist relief mass bonus'
* ```
*
* @param wordlist - The wordlist to use.
* @param options - Generation options.
* @returns The mnemonic.
*/
export function random(
wordlist: string[],
options: random.Options = {},
): string {
const { strength = 128 } = options
return generateMnemonic(wordlist, strength)
}
export declare namespace random {
type Options = {
/**
* The strength of the mnemonic to generate, in bits.
* @default 128
*/
strength?: number | undefined
}
type ErrorType = Errors.GlobalErrorType
}
/**
* Converts a mnemonic to a HD Key.
*
* @example
* ```ts twoslash
* import { Mnemonic } from 'ox'
*
* const mnemonic = Mnemonic.random(Mnemonic.english)
* const hdKey = Mnemonic.toHdKey(mnemonic)
* ```
*
* @example
* ### Path Derivation
*
* You can derive a HD Key at a specific path using `derive`:
*
* ```ts twoslash
* import { Mnemonic } from 'ox'
*
* const mnemonic = Mnemonic.random(Mnemonic.english)
* const hdKey = Mnemonic.toHdKey(mnemonic).derive(Mnemonic.path({ index: 1 }))
* ```
*
* @param mnemonic - The mnemonic to convert.
* @param options - Conversion options.
* @returns The HD Key.
*/
export function toHdKey(
mnemonic: string,
options: toHdKey.Options = {},
): HdKey.HdKey {
const { passphrase } = options
const seed = toSeed(mnemonic, { passphrase })
return HdKey.fromSeed(seed)
}
export declare namespace toHdKey {
type Options = {
/** An optional passphrase for additional protection to the seed. */
passphrase?: string | undefined
}
type ErrorType = Errors.GlobalErrorType
}
/**
* Converts a mnemonic to a private key.
*
* @example
* ```ts twoslash
* import { Mnemonic } from 'ox'
*
* const mnemonic = Mnemonic.random(Mnemonic.english)
* const privateKey = Mnemonic.toPrivateKey(mnemonic)
* // @log: '0x...'
* ```
*
* @example
* ### Paths
*
* You can derive a private key at a specific path using the `path` option.
*
* ```ts twoslash
* import { Mnemonic } from 'ox'
*
* const mnemonic = Mnemonic.random(Mnemonic.english)
* const privateKey = Mnemonic.toPrivateKey(mnemonic, {
* path: Mnemonic.path({ index: 1 }) // 'm/44'/60'/0'/0/1' // [!code focus]
* })
* // @log: '0x...'
* ```
*
* @param mnemonic - The mnemonic to convert.
* @param options - Conversion options.
* @returns The private key.
*/
export function toPrivateKey<as extends 'Bytes' | 'Hex' = 'Bytes'>(
mnemonic: string,
options: toPrivateKey.Options<as> = {},
): toPrivateKey.ReturnType<as> {
const { path = HdKey.path(), passphrase } = options
const hdKey = toHdKey(mnemonic, { passphrase }).derive(path)
if (options.as === 'Bytes') return Bytes.from(hdKey.privateKey) as never
return hdKey.privateKey as never
}
export declare namespace toPrivateKey {
type Options<as extends 'Bytes' | 'Hex' = 'Bytes'> = {
/** The output format. @default 'Bytes' */
as?: as | 'Bytes' | 'Hex' | undefined
/** An optional path to derive the private key from. @default `m/44'/60'/0'/0/0` */
path?: string | undefined
/** An optional passphrase for additional protection to the seed. */
passphrase?: string | undefined
}
type ReturnType<as extends 'Bytes' | 'Hex' = 'Bytes'> =
| (as extends 'Bytes' ? Bytes.Bytes : never)
| (as extends 'Hex' ? Hex.Hex : never)
type ErrorType = Errors.GlobalErrorType
}
/**
* Converts a mnemonic to a master seed.
*
* @example
* ```ts twoslash
* import { Mnemonic } from 'ox'
*
* const mnemonic = Mnemonic.random(Mnemonic.english)
* const seed = Mnemonic.toSeed(mnemonic)
* // @log: Uint8Array [...64 bytes]
* ```
*
* @param mnemonic - The mnemonic to convert.
* @param options - Conversion options.
* @returns The master seed.
*/
export function toSeed<as extends 'Bytes' | 'Hex' = 'Bytes'>(
mnemonic: string,
options: toSeed.Options<as> = {},
): toSeed.ReturnType<as> {
const { passphrase } = options
const seed = mnemonicToSeedSync(mnemonic, passphrase)
if (options.as === 'Hex') return Bytes.toHex(seed) as never
return seed as never
}
export declare namespace toSeed {
type Options<as extends 'Bytes' | 'Hex' = 'Bytes'> = {
/** The output format. @default 'Bytes' */
as?: as | 'Bytes' | 'Hex' | undefined
/** An optional passphrase for additional protection to the seed. */
passphrase?: string | undefined
}
type ReturnType<as extends 'Bytes' | 'Hex' = 'Bytes'> =
| (as extends 'Bytes' ? Bytes.Bytes : never)
| (as extends 'Hex' ? Hex.Hex : never)
type ErrorType = Errors.GlobalErrorType
}
/**
* Checks if a mnemonic is valid, given a wordlist.
*
* @example
* ```ts twoslash
* import { Mnemonic } from 'ox'
*
* const mnemonic = Mnemonic.validate(
* 'buyer zoo end danger ice capable shrug naive twist relief mass bonus',
* Mnemonic.english
* )
* // @log: true
* ```
*
* @param mnemonic - The mnemonic to validate.
* @param wordlist - The wordlist to use.
* @returns Whether the mnemonic is valid.
*/
export function validate(mnemonic: string, wordlist: string[]): boolean {
return validateMnemonic(mnemonic, wordlist)
}
export declare namespace validate {
type ErrorType = Errors.GlobalErrorType
}

244
node_modules/ox/core/P256.ts generated vendored Normal file
View File

@@ -0,0 +1,244 @@
import { secp256r1 } from '@noble/curves/p256'
import * as Bytes from './Bytes.js'
import type * as Errors from './Errors.js'
import * as Hex from './Hex.js'
import * as PublicKey from './PublicKey.js'
import type * as Signature from './Signature.js'
import * as Entropy from './internal/entropy.js'
/** Re-export of noble/curves P256 utilities. */
export const noble = secp256r1
/**
* Computes the P256 ECDSA public key from a provided private key.
*
* @example
* ```ts twoslash
* import { P256 } from 'ox'
*
* const publicKey = P256.getPublicKey({ privateKey: '0x...' })
* ```
*
* @param options - The options to compute the public key.
* @returns The computed public key.
*/
export function getPublicKey(
options: getPublicKey.Options,
): PublicKey.PublicKey {
const { privateKey } = options
const point = secp256r1.ProjectivePoint.fromPrivateKey(
typeof privateKey === 'string'
? privateKey.slice(2)
: Hex.fromBytes(privateKey).slice(2),
)
return PublicKey.from(point)
}
export declare namespace getPublicKey {
type Options = {
/**
* Private key to compute the public key from.
*/
privateKey: Hex.Hex | Bytes.Bytes
}
type ErrorType = Errors.GlobalErrorType
}
/**
* Generates a random P256 ECDSA private key.
*
* @example
* ```ts twoslash
* import { P256 } from 'ox'
*
* const privateKey = P256.randomPrivateKey()
* ```
*
* @param options - The options to generate the private key.
* @returns The generated private key.
*/
export function randomPrivateKey<as extends 'Hex' | 'Bytes' = 'Hex'>(
options: randomPrivateKey.Options<as> = {},
): randomPrivateKey.ReturnType<as> {
const { as = 'Hex' } = options
const bytes = secp256r1.utils.randomPrivateKey()
if (as === 'Hex') return Hex.fromBytes(bytes) as never
return bytes as never
}
export declare namespace randomPrivateKey {
type Options<as extends 'Hex' | 'Bytes' = 'Hex'> = {
/**
* Format of the returned private key.
* @default 'Hex'
*/
as?: as | 'Hex' | 'Bytes' | undefined
}
type ReturnType<as extends 'Hex' | 'Bytes'> =
| (as extends 'Bytes' ? Bytes.Bytes : never)
| (as extends 'Hex' ? Hex.Hex : never)
type ErrorType = Hex.fromBytes.ErrorType | Errors.GlobalErrorType
}
/**
* Recovers the signing public key from the signed payload and signature.
*
* @example
* ```ts twoslash
* import { P256 } from 'ox'
*
* const signature = P256.sign({ payload: '0xdeadbeef', privateKey: '0x...' })
*
* const publicKey = P256.recoverPublicKey({ // [!code focus]
* payload: '0xdeadbeef', // [!code focus]
* signature, // [!code focus]
* }) // [!code focus]
* ```
*
* @param options - The recovery options.
* @returns The recovered public key.
*/
export function recoverPublicKey(
options: recoverPublicKey.Options,
): PublicKey.PublicKey {
const { payload, signature } = options
const { r, s, yParity } = signature
const signature_ = new secp256r1.Signature(
BigInt(r),
BigInt(s),
).addRecoveryBit(yParity)
const payload_ =
payload instanceof Uint8Array ? Hex.fromBytes(payload) : payload
const point = signature_.recoverPublicKey(payload_.substring(2))
return PublicKey.from(point)
}
export declare namespace recoverPublicKey {
type Options = {
/** Payload that was signed. */
payload: Hex.Hex | Bytes.Bytes
/** Signature of the payload. */
signature: Signature.Signature
}
type ErrorType =
| PublicKey.from.ErrorType
| Hex.fromBytes.ErrorType
| Errors.GlobalErrorType
}
/**
* Signs the payload with the provided private key and returns a P256 signature.
*
* @example
* ```ts twoslash
* import { P256 } from 'ox'
*
* const signature = P256.sign({ // [!code focus]
* payload: '0xdeadbeef', // [!code focus]
* privateKey: '0x...' // [!code focus]
* }) // [!code focus]
* ```
*
* @param options - The signing options.
* @returns The ECDSA {@link ox#Signature.Signature}.
*/
export function sign(options: sign.Options): Signature.Signature {
const {
extraEntropy = Entropy.extraEntropy,
hash,
payload,
privateKey,
} = options
const { r, s, recovery } = secp256r1.sign(
payload instanceof Uint8Array ? payload : Bytes.fromHex(payload),
privateKey instanceof Uint8Array ? privateKey : Bytes.fromHex(privateKey),
{
extraEntropy:
typeof extraEntropy === 'boolean'
? extraEntropy
: Hex.from(extraEntropy).slice(2),
lowS: true,
...(hash ? { prehash: true } : {}),
},
)
return {
r,
s,
yParity: recovery,
}
}
export declare namespace sign {
type Options = {
/**
* Extra entropy to add to the signing process. Setting to `false` will disable it.
* @default true
*/
extraEntropy?: boolean | Hex.Hex | Bytes.Bytes | undefined
/**
* If set to `true`, the payload will be hashed (sha256) before being signed.
*/
hash?: boolean | undefined
/**
* Payload to sign.
*/
payload: Hex.Hex | Bytes.Bytes
/**
* ECDSA private key.
*/
privateKey: Hex.Hex | Bytes.Bytes
}
type ErrorType = Bytes.fromHex.ErrorType | Errors.GlobalErrorType
}
/**
* Verifies a payload was signed by the provided public key.
*
* @example
*
* ```ts twoslash
* import { P256 } from 'ox'
*
* const privateKey = P256.randomPrivateKey()
* const publicKey = P256.getPublicKey({ privateKey })
* const signature = P256.sign({ payload: '0xdeadbeef', privateKey })
*
* const verified = P256.verify({ // [!code focus]
* publicKey, // [!code focus]
* payload: '0xdeadbeef', // [!code focus]
* signature, // [!code focus]
* }) // [!code focus]
* ```
*
* @param options - The verification options.
* @returns Whether the payload was signed by the provided public key.
*/
export function verify(options: verify.Options): boolean {
const { hash, payload, publicKey, signature } = options
return secp256r1.verify(
signature,
payload instanceof Uint8Array ? payload : Bytes.fromHex(payload),
PublicKey.toHex(publicKey).substring(2),
...(hash ? [{ prehash: true, lowS: true }] : []),
)
}
export declare namespace verify {
type Options = {
/** If set to `true`, the payload will be hashed (sha256) before being verified. */
hash?: boolean | undefined
/** Payload that was signed. */
payload: Hex.Hex | Bytes.Bytes
/** Public key that signed the payload. */
publicKey: PublicKey.PublicKey<boolean>
/** Signature of the payload. */
signature: Signature.Signature<boolean>
}
type ErrorType = Errors.GlobalErrorType
}

63
node_modules/ox/core/PersonalMessage.ts generated vendored Normal file
View File

@@ -0,0 +1,63 @@
import type * as Bytes from './Bytes.js'
import type * as Errors from './Errors.js'
import * as Hash from './Hash.js'
import * as Hex from './Hex.js'
/**
* Encodes a personal sign message in [ERC-191 format](https://eips.ethereum.org/EIPS/eip-191#version-0x45-e): `0x19 ‖ "Ethereum Signed Message:\n" + message.length ‖ message`.
*
* @example
* ```ts twoslash
* import { Hex, PersonalMessage } from 'ox'
*
* const data = PersonalMessage.encode(Hex.fromString('hello world'))
* // @log: '0x19457468657265756d205369676e6564204d6573736167653a0a313168656c6c6f20776f726c64'
* // @log: (0x19 ‖ 'Ethereum Signed Message:\n11' ‖ 'hello world')
* ```
*
* @param data - The data to encode.
* @returns The encoded personal sign message.
*/
export function encode(data: Hex.Hex | Bytes.Bytes): Hex.Hex {
const message = Hex.from(data)
return Hex.concat(
// Personal Sign Format: `0x19 ‖ "Ethereum Signed Message:\n" ‖ message.length ‖ message`
'0x19',
Hex.fromString('Ethereum Signed Message:\n' + Hex.size(message)),
message,
)
}
export declare namespace encode {
type ErrorType =
| Hex.concat.ErrorType
| Hex.from.ErrorType
| Hex.fromString.ErrorType
| Errors.GlobalErrorType
}
/**
* Gets the payload to use for signing an [ERC-191 formatted](https://eips.ethereum.org/EIPS/eip-191#version-0x45-e) personal message.
*
* @example
* ```ts twoslash
* import { Hex, PersonalMessage, Secp256k1 } from 'ox'
*
* const payload = PersonalMessage.getSignPayload(Hex.fromString('hello world')) // [!code focus]
*
* const signature = Secp256k1.sign({ payload, privateKey: '0x...' })
* ```
*
* @param data - The data to get the sign payload for.
* @returns The payload to use for signing.
*/
export function getSignPayload(data: Hex.Hex | Bytes.Bytes): Hex.Hex {
return Hash.keccak256(encode(data))
}
export declare namespace getSignPayload {
type ErrorType =
| Hash.keccak256.ErrorType
| encode.ErrorType
| Errors.GlobalErrorType
}

504
node_modules/ox/core/Provider.ts generated vendored Normal file
View File

@@ -0,0 +1,504 @@
import { EventEmitter } from 'eventemitter3'
import type * as Address from './Address.js'
import * as Errors from './Errors.js'
import * as RpcResponse from './RpcResponse.js'
import type * as RpcSchema from './RpcSchema.js'
import type * as RpcSchema_internal from './internal/rpcSchema.js'
import type { Compute, IsNarrowable, IsNever } from './internal/types.js'
/** Options for a {@link ox#Provider.Provider}. */
export type Options = {
/**
* Whether to include event functions (`on`, `removeListener`) on the Provider.
*
* @default true
*/
includeEvents?: boolean | undefined
/**
* RPC Schema to use for the Provider's `request` function.
* See {@link ox#RpcSchema.(from:function)} for more.
*
* @default `RpcSchema.Generic`
*/
schema?: RpcSchema.Generic | undefined
}
/** Root type for an EIP-1193 Provider. */
export type Provider<
options extends Options | undefined = undefined,
///
_schema extends RpcSchema.Generic = options extends {
schema: infer schema extends RpcSchema.Generic
}
? schema
: RpcSchema.Default,
> = Compute<
{
request: RequestFn<_schema>
} & (options extends { includeEvents: true } | undefined
? {
on: EventListenerFn
removeListener: EventListenerFn
}
: {})
>
/** Type for an EIP-1193 Provider's event emitter. */
export type Emitter = Compute<EventEmitter<EventMap>>
/** EIP-1193 Provider's `request` function. */
export type RequestFn<schema extends RpcSchema.Generic = RpcSchema.Generic> = <
methodName extends RpcSchema.MethodNameGeneric,
>(
parameters: RpcSchema_internal.ExtractRequestOpaque<schema, methodName>,
) => Promise<RpcSchema.ExtractReturnType<schema, methodName>>
/** Type for an EIP-1193 Provider's event listener functions (`on`, `removeListener`, etc). */
export type EventListenerFn = <event extends keyof EventMap>(
event: event,
listener: EventMap[event],
) => void
export type ConnectInfo = {
chainId: string
}
export type Message = {
type: string
data: unknown
}
export class ProviderRpcError extends Error {
override name = 'ProviderRpcError'
code: number
details: string
constructor(code: number, message: string) {
super(message)
this.code = code
this.details = message
}
}
export type EventMap = {
accountsChanged: (accounts: readonly Address.Address[]) => void
chainChanged: (chainId: string) => void
connect: (connectInfo: ConnectInfo) => void
disconnect: (error: ProviderRpcError) => void
message: (message: Message) => void
}
/** The user rejected the request. */
export class UserRejectedRequestError extends ProviderRpcError {
static readonly code = 4001
override readonly code = 4001
override readonly name = 'Provider.UserRejectedRequestError'
constructor({
message = 'The user rejected the request.',
}: { message?: string | undefined } = {}) {
super(4001, message)
}
}
/** The requested method and/or account has not been authorized by the user. */
export class UnauthorizedError extends ProviderRpcError {
static readonly code = 4100
override readonly code = 4100
override readonly name = 'Provider.UnauthorizedError'
constructor({
message = 'The requested method and/or account has not been authorized by the user.',
}: { message?: string | undefined } = {}) {
super(4100, message)
}
}
/** The provider does not support the requested method. */
export class UnsupportedMethodError extends ProviderRpcError {
static readonly code = 4200
override readonly code = 4200
override readonly name = 'Provider.UnsupportedMethodError'
constructor({
message = 'The provider does not support the requested method.',
}: { message?: string | undefined } = {}) {
super(4200, message)
}
}
/** The provider is disconnected from all chains. */
export class DisconnectedError extends ProviderRpcError {
static readonly code = 4900
override readonly code = 4900
override readonly name = 'Provider.DisconnectedError'
constructor({
message = 'The provider is disconnected from all chains.',
}: { message?: string | undefined } = {}) {
super(4900, message)
}
}
/** The provider is not connected to the requested chain. */
export class ChainDisconnectedError extends ProviderRpcError {
static readonly code = 4901
override readonly code = 4901
override readonly name = 'Provider.ChainDisconnectedError'
constructor({
message = 'The provider is not connected to the requested chain.',
}: { message?: string | undefined } = {}) {
super(4901, message)
}
}
/**
* Creates an EIP-1193 flavored event emitter to be injected onto a Provider.
*
* @example
* ```ts twoslash
* // @noErrors
* import { Provider, RpcRequest, RpcResponse } from 'ox' // [!code focus]
*
* // 1. Instantiate a Provider Emitter. // [!code focus]
* const emitter = Provider.createEmitter() // [!code focus]
*
* const store = RpcRequest.createStore()
*
* const provider = Provider.from({
* // 2. Pass the Emitter to the Provider. // [!code focus]
* ...emitter, // [!code focus]
* async request(args) {
* return await fetch('https://1.rpc.thirdweb.com', {
* body: JSON.stringify(store.prepare(args)),
* method: 'POST',
* headers: {
* 'Content-Type': 'application/json',
* },
* })
* .then((res) => res.json())
* .then(RpcResponse.parse)
* },
* })
*
* // 3. Emit Provider Events. // [!code focus]
* emitter.emit('accountsChanged', ['0x...']) // [!code focus]
* ```
*
* @returns An event emitter.
*/
export function createEmitter(): Emitter {
const emitter = new EventEmitter<EventMap>()
return {
get eventNames() {
return emitter.eventNames.bind(emitter)
},
get listenerCount() {
return emitter.listenerCount.bind(emitter)
},
get listeners() {
return emitter.listeners.bind(emitter)
},
addListener: emitter.addListener.bind(emitter),
emit: emitter.emit.bind(emitter),
off: emitter.off.bind(emitter),
on: emitter.on.bind(emitter),
once: emitter.once.bind(emitter),
removeAllListeners: emitter.removeAllListeners.bind(emitter),
removeListener: emitter.removeListener.bind(emitter),
}
}
export declare namespace createEmitter {
type ErrorType = Errors.GlobalErrorType
}
/**
* Instantiates an [EIP-1193](https://eips.ethereum.org/EIPS/eip-1193) {@link ox#Provider.Provider}
* from an arbitrary [EIP-1193 Provider](https://eips.ethereum.org/EIPS/eip-1193) interface.
*
* @example
* ### Instantiating with RPC Transport
*
* Ox's {@link ox#RpcTransport} is EIP-1193 compliant, and can be used to instantiate an EIP-1193 Provider. This means you can use any HTTP RPC endpoint as an EIP-1193 Provider.
*
* ```ts twoslash
* import { Provider, RpcTransport } from 'ox'
*
* const transport = RpcTransport.fromHttp('https://1.rpc.thirdweb.com')
* const provider = Provider.from(transport)
* ```
*
* @example
* ### Instantiating with External Providers
*
* The example below demonstrates how we can instantiate a typed EIP-1193 Provider from an
* external EIP-1193 Provider like `window.ethereum`.
*
* ```ts twoslash
* import 'ox/window'
* import { Provider } from 'ox'
*
* const provider = Provider.from(window.ethereum)
*
* const blockNumber = await provider.request({ method: 'eth_blockNumber' })
* ```
*
* :::tip
*
* There are also libraries that distribute EIP-1193 Provider objects that you can use with `Provider.from`:
*
* - [`@walletconnect/ethereum-provider`](https://www.npmjs.com/package/\@walletconnect/ethereum-provider)
*
* - [`@coinbase/wallet-sdk`](https://www.npmjs.com/package/\@coinbase/wallet-sdk)
*
* - [`@metamask/detect-provider`](https://www.npmjs.com/package/\@metamask/detect-provider)
*
* - [`@safe-global/safe-apps-provider`](https://github.com/safe-global/safe-apps-sdk/tree/main/packages/safe-apps-provider)
*
* - [`mipd`](https://github.com/wevm/mipd): EIP-6963 Multi Injected Providers
*
* :::
*
* @example
* ### Instantiating a Custom Provider
*
* The example below demonstrates how we can instantiate a typed EIP-1193 Provider from a
* HTTP `fetch` JSON-RPC request. You can use this pattern to integrate with any asynchronous JSON-RPC
* transport, including WebSockets and IPC.
*
* ```ts twoslash
* // @noErrors
* import { Provider, RpcRequest, RpcResponse } from 'ox'
*
* const store = RpcRequest.createStore()
*
* const provider = Provider.from({
* async request(args) {
* return await fetch('https://1.rpc.thirdweb.com', {
* body: JSON.stringify(store.prepare(args)),
* method: 'POST',
* headers: {
* 'Content-Type': 'application/json',
* },
* })
* .then((res) => res.json())
* .then(RpcResponse.parse)
* },
* })
*
* const blockNumber = await provider.request({ method: 'eth_blockNumber' })
* ```
*
* @example
* ### Type-safe Custom Schemas
*
* It is possible to define your own type-safe schema by using the {@link ox#RpcSchema.(from:function)} type.
*
* ```ts twoslash
* // @noErrors
* import 'ox/window'
* import { Provider, RpcSchema } from 'ox'
*
* const schema = RpcSchema.from<
* | RpcSchema.Default
* | {
* Request: {
* method: 'abe_foo',
* params: [id: number],
* }
* ReturnType: string
* }
* | {
* Request: {
* method: 'abe_bar',
* params: [id: string],
* }
* ReturnType: string
* }
* >()
*
* const provider = Provider.from(window.ethereum, { schema })
*
* const blockNumber = await provider.request({ method: 'e' })
* // ^|
*
*
*
*
*
* ```
*
* @example
* ### Instantiating a Provider with Events
*
* The example below demonstrates how to instantiate a Provider with your own EIP-1193 flavored event emitter.
*
* This example is useful for Wallets that distribute an EIP-1193 Provider (e.g. webpage injection via `window.ethereum`).
*
* ```ts twoslash
* // @noErrors
* import { Provider, RpcRequest, RpcResponse } from 'ox'
*
* // 1. Instantiate a Provider Emitter.
* const emitter = Provider.createEmitter() // [!code ++]
*
* const store = RpcRequest.createStore()
*
* const provider = Provider.from({
* // 2. Pass the Emitter to the Provider.
* ...emitter, // [!code ++]
* async request(args) {
* return await fetch('https://1.rpc.thirdweb.com', {
* body: JSON.stringify(store.prepare(args)),
* method: 'POST',
* headers: {
* 'Content-Type': 'application/json',
* },
* })
* .then((res) => res.json())
* .then(RpcResponse.parse)
* },
* })
*
* // 3. Emit Provider Events.
* emitter.emit('accountsChanged', ['0x...']) // [!code ++]
* ```
*
* @param provider - The EIP-1193 provider to convert.
* @returns An typed EIP-1193 Provider.
*/
export function from<
const provider extends Provider | unknown,
options extends Options | undefined = undefined,
>(
provider: provider | Provider<{ schema: RpcSchema.Generic }>,
options?: options | Options,
): Provider<options>
// eslint-disable-next-line jsdoc/require-jsdoc
export function from(provider: any, options: Options = {}): Provider<Options> {
const { includeEvents = true } = options
if (!provider) throw new IsUndefinedError()
return {
...(includeEvents
? {
on: provider.on?.bind(provider),
removeListener: provider.removeListener?.bind(provider),
}
: {}),
async request(args) {
try {
const result = await provider.request(args)
if (
result &&
typeof result === 'object' &&
'jsonrpc' in (result as { jsonrpc?: unknown })
)
return RpcResponse.parse(result) as never
return result
} catch (error) {
throw parseError(error)
}
},
}
}
export declare namespace from {
type ErrorType = IsUndefinedError | Errors.GlobalErrorType
}
/**
* Parses an error object into an error instance.
*
* @example
* ```ts twoslash
* import { Provider } from 'ox'
*
* const error = Provider.parseError({ code: 4200, message: 'foo' })
*
* error
* // ^?
*
* ```
*
* @param errorObject - The error object to parse.
* @returns An error instance.
*/
export function parseError<
const errorObject extends RpcResponse.ErrorObject | unknown,
>(
errorObject: errorObject | RpcResponse.ErrorObject,
): parseError.ReturnType<errorObject> {
const errorObject_ = errorObject as RpcResponse.ErrorObject
const error = RpcResponse.parseError(errorObject_)
if (error instanceof RpcResponse.InternalError) {
if (!error.data) return error as never
const { code } = error.data as RpcResponse.ErrorObject
if (code === DisconnectedError.code)
return new DisconnectedError(errorObject_) as never
if (code === ChainDisconnectedError.code)
return new ChainDisconnectedError(errorObject_) as never
if (code === UserRejectedRequestError.code)
return new UserRejectedRequestError(errorObject_) as never
if (code === UnauthorizedError.code)
return new UnauthorizedError(errorObject_) as never
if (code === UnsupportedMethodError.code)
return new UnsupportedMethodError(errorObject_) as never
}
return error as never
}
export declare namespace parseError {
type ReturnType<
errorObject extends RpcResponse.ErrorObject | unknown,
//
error = errorObject extends RpcResponse.ErrorObject
?
| (errorObject['code'] extends DisconnectedError['code']
? DisconnectedError
: never)
| (IsNarrowable<errorObject['code'], number> extends false
? DisconnectedError
: never)
| (errorObject['code'] extends ChainDisconnectedError['code']
? ChainDisconnectedError
: never)
| (IsNarrowable<errorObject['code'], number> extends false
? ChainDisconnectedError
: never)
| (errorObject['code'] extends UserRejectedRequestError['code']
? UserRejectedRequestError
: never)
| (IsNarrowable<errorObject['code'], number> extends false
? UserRejectedRequestError
: never)
| (errorObject['code'] extends UnauthorizedError['code']
? UnauthorizedError
: never)
| (IsNarrowable<errorObject['code'], number> extends false
? UnauthorizedError
: never)
| (errorObject['code'] extends UnsupportedMethodError['code']
? UnsupportedMethodError
: never)
| (IsNarrowable<errorObject['code'], number> extends false
? UnsupportedMethodError
: never)
: RpcResponse.parseError.ReturnType<RpcResponse.ErrorObject>,
> = IsNever<error> extends true
? RpcResponse.parseError.ReturnType<errorObject>
: error
}
/** Thrown when the provider is undefined. */
export class IsUndefinedError extends Errors.BaseError {
override readonly name = 'Provider.IsUndefinedError'
constructor() {
super('`provider` is undefined.')
}
}

521
node_modules/ox/core/PublicKey.ts generated vendored Normal file
View File

@@ -0,0 +1,521 @@
import * as Bytes from './Bytes.js'
import * as Errors from './Errors.js'
import * as Hex from './Hex.js'
import * as Json from './Json.js'
import type { Compute, ExactPartial } from './internal/types.js'
/** Root type for an ECDSA Public Key. */
export type PublicKey<
compressed extends boolean = false,
bigintType = bigint,
numberType = number,
> = Compute<
compressed extends true
? {
prefix: numberType
x: bigintType
y?: undefined
}
: {
prefix: numberType
x: bigintType
y: bigintType
}
>
/**
* Asserts that a {@link ox#PublicKey.PublicKey} is valid.
*
* @example
* ```ts twoslash
* import { PublicKey } from 'ox'
*
* PublicKey.assert({
* prefix: 4,
* y: 49782753348462494199823712700004552394425719014458918871452329774910450607807n,
* })
* // @error: PublicKey.InvalidError: Value \`{"y":"1"}\` is not a valid public key.
* // @error: Public key must contain:
* // @error: - an `x` and `prefix` value (compressed)
* // @error: - an `x`, `y`, and `prefix` value (uncompressed)
* ```
*
* @param publicKey - The public key object to assert.
*/
export function assert(
publicKey: ExactPartial<PublicKey>,
options: assert.Options = {},
): asserts publicKey is PublicKey {
const { compressed } = options
const { prefix, x, y } = publicKey
// Uncompressed
if (
compressed === false ||
(typeof x === 'bigint' && typeof y === 'bigint')
) {
if (prefix !== 4)
throw new InvalidPrefixError({
prefix,
cause: new InvalidUncompressedPrefixError(),
})
return
}
// Compressed
if (
compressed === true ||
(typeof x === 'bigint' && typeof y === 'undefined')
) {
if (prefix !== 3 && prefix !== 2)
throw new InvalidPrefixError({
prefix,
cause: new InvalidCompressedPrefixError(),
})
return
}
// Unknown/invalid
throw new InvalidError({ publicKey })
}
export declare namespace assert {
type Options = {
/** Whether or not the public key should be compressed. */
compressed?: boolean
}
type ErrorType = InvalidError | InvalidPrefixError | Errors.GlobalErrorType
}
/**
* Compresses a {@link ox#PublicKey.PublicKey}.
*
* @example
* ```ts twoslash
* import { PublicKey } from 'ox'
*
* const publicKey = PublicKey.from({
* prefix: 4,
* x: 59295962801117472859457908919941473389380284132224861839820747729565200149877n,
* y: 24099691209996290925259367678540227198235484593389470330605641003500238088869n,
* })
*
* const compressed = PublicKey.compress(publicKey) // [!code focus]
* // @log: {
* // @log: prefix: 3,
* // @log: x: 59295962801117472859457908919941473389380284132224861839820747729565200149877n,
* // @log: }
* ```
*
* @param publicKey - The public key to compress.
* @returns The compressed public key.
*/
export function compress(publicKey: PublicKey<false>): PublicKey<true> {
const { x, y } = publicKey
return {
prefix: y % 2n === 0n ? 2 : 3,
x,
}
}
export declare namespace compress {
type ErrorType = Errors.GlobalErrorType
}
/**
* Instantiates a typed {@link ox#PublicKey.PublicKey} object from a {@link ox#PublicKey.PublicKey}, {@link ox#Bytes.Bytes}, or {@link ox#Hex.Hex}.
*
* @example
* ```ts twoslash
* import { PublicKey } from 'ox'
*
* const publicKey = PublicKey.from({
* prefix: 4,
* x: 59295962801117472859457908919941473389380284132224861839820747729565200149877n,
* y: 24099691209996290925259367678540227198235484593389470330605641003500238088869n,
* })
* // @log: {
* // @log: prefix: 4,
* // @log: x: 59295962801117472859457908919941473389380284132224861839820747729565200149877n,
* // @log: y: 24099691209996290925259367678540227198235484593389470330605641003500238088869n,
* // @log: }
* ```
*
* @example
* ### From Serialized
*
* ```ts twoslash
* import { PublicKey } from 'ox'
*
* const publicKey = PublicKey.from('0x048318535b54105d4a7aae60c08fc45f9687181b4fdfc625bd1a753fa7397fed753547f11ca8696646f2f3acb08e31016afac23e630c5d11f59f61fef57b0d2aa5')
* // @log: {
* // @log: prefix: 4,
* // @log: x: 59295962801117472859457908919941473389380284132224861839820747729565200149877n,
* // @log: y: 24099691209996290925259367678540227198235484593389470330605641003500238088869n,
* // @log: }
* ```
*
* @param value - The public key value to instantiate.
* @returns The instantiated {@link ox#PublicKey.PublicKey}.
*/
export function from<
const publicKey extends
| CompressedPublicKey
| UncompressedPublicKey
| Hex.Hex
| Bytes.Bytes,
>(value: from.Value<publicKey>): from.ReturnType<publicKey> {
const publicKey = (() => {
if (Hex.validate(value)) return fromHex(value)
if (Bytes.validate(value)) return fromBytes(value)
const { prefix, x, y } = value
if (typeof x === 'bigint' && typeof y === 'bigint')
return { prefix: prefix ?? 0x04, x, y }
return { prefix, x }
})()
assert(publicKey)
return publicKey as never
}
/** @internal */
type CompressedPublicKey = PublicKey<true>
/** @internal */
type UncompressedPublicKey = Omit<PublicKey<false>, 'prefix'> & {
prefix?: PublicKey['prefix'] | undefined
}
export declare namespace from {
type Value<
publicKey extends
| CompressedPublicKey
| UncompressedPublicKey
| Hex.Hex
| Bytes.Bytes = PublicKey,
> = publicKey | CompressedPublicKey | UncompressedPublicKey
type ReturnType<
publicKey extends
| CompressedPublicKey
| UncompressedPublicKey
| Hex.Hex
| Bytes.Bytes = PublicKey,
> = publicKey extends CompressedPublicKey | UncompressedPublicKey
? publicKey extends UncompressedPublicKey
? Compute<publicKey & { readonly prefix: 0x04 }>
: publicKey
: PublicKey
type ErrorType = assert.ErrorType | Errors.GlobalErrorType
}
/**
* Deserializes a {@link ox#PublicKey.PublicKey} from a {@link ox#Bytes.Bytes} value.
*
* @example
* ```ts twoslash
* // @noErrors
* import { PublicKey } from 'ox'
*
* const publicKey = PublicKey.fromBytes(new Uint8Array([128, 3, 131, ...]))
* // @log: {
* // @log: prefix: 4,
* // @log: x: 59295962801117472859457908919941473389380284132224861839820747729565200149877n,
* // @log: y: 24099691209996290925259367678540227198235484593389470330605641003500238088869n,
* // @log: }
* ```
*
* @param publicKey - The serialized public key.
* @returns The deserialized public key.
*/
export function fromBytes(publicKey: Bytes.Bytes): PublicKey {
return fromHex(Hex.fromBytes(publicKey))
}
export declare namespace fromBytes {
type ErrorType =
| fromHex.ErrorType
| Hex.fromBytes.ErrorType
| Errors.GlobalErrorType
}
/**
* Deserializes a {@link ox#PublicKey.PublicKey} from a {@link ox#Hex.Hex} value.
*
* @example
* ```ts twoslash
* import { PublicKey } from 'ox'
*
* const publicKey = PublicKey.fromHex('0x8318535b54105d4a7aae60c08fc45f9687181b4fdfc625bd1a753fa7397fed753547f11ca8696646f2f3acb08e31016afac23e630c5d11f59f61fef57b0d2aa5')
* // @log: {
* // @log: prefix: 4,
* // @log: x: 59295962801117472859457908919941473389380284132224861839820747729565200149877n,
* // @log: y: 24099691209996290925259367678540227198235484593389470330605641003500238088869n,
* // @log: }
* ```
*
* @example
* ### Deserializing a Compressed Public Key
*
* ```ts twoslash
* import { PublicKey } from 'ox'
*
* const publicKey = PublicKey.fromHex('0x038318535b54105d4a7aae60c08fc45f9687181b4fdfc625bd1a753fa7397fed75')
* // @log: {
* // @log: prefix: 3,
* // @log: x: 59295962801117472859457908919941473389380284132224861839820747729565200149877n,
* // @log: }
* ```
*
* @param publicKey - The serialized public key.
* @returns The deserialized public key.
*/
export function fromHex(publicKey: Hex.Hex): PublicKey {
if (
publicKey.length !== 132 &&
publicKey.length !== 130 &&
publicKey.length !== 68
)
throw new InvalidSerializedSizeError({ publicKey })
if (publicKey.length === 130) {
const x = BigInt(Hex.slice(publicKey, 0, 32))
const y = BigInt(Hex.slice(publicKey, 32, 64))
return {
prefix: 4,
x,
y,
} as never
}
if (publicKey.length === 132) {
const prefix = Number(Hex.slice(publicKey, 0, 1))
const x = BigInt(Hex.slice(publicKey, 1, 33))
const y = BigInt(Hex.slice(publicKey, 33, 65))
return {
prefix,
x,
y,
} as never
}
const prefix = Number(Hex.slice(publicKey, 0, 1))
const x = BigInt(Hex.slice(publicKey, 1, 33))
return {
prefix,
x,
} as never
}
export declare namespace fromHex {
type ErrorType = Hex.slice.ErrorType | Errors.GlobalErrorType
}
/**
* Serializes a {@link ox#PublicKey.PublicKey} to {@link ox#Bytes.Bytes}.
*
* @example
* ```ts twoslash
* import { PublicKey } from 'ox'
*
* const publicKey = PublicKey.from({
* prefix: 4,
* x: 59295962801117472859457908919941473389380284132224861839820747729565200149877n,
* y: 24099691209996290925259367678540227198235484593389470330605641003500238088869n,
* })
*
* const bytes = PublicKey.toBytes(publicKey) // [!code focus]
* // @log: Uint8Array [128, 3, 131, ...]
* ```
*
* @param publicKey - The public key to serialize.
* @returns The serialized public key.
*/
export function toBytes(
publicKey: PublicKey<boolean>,
options: toBytes.Options = {},
): Bytes.Bytes {
return Bytes.fromHex(toHex(publicKey, options))
}
export declare namespace toBytes {
type Options = {
/**
* Whether to include the prefix in the serialized public key.
* @default true
*/
includePrefix?: boolean | undefined
}
type ErrorType =
| Hex.fromNumber.ErrorType
| Bytes.fromHex.ErrorType
| Errors.GlobalErrorType
}
/**
* Serializes a {@link ox#PublicKey.PublicKey} to {@link ox#Hex.Hex}.
*
* @example
* ```ts twoslash
* import { PublicKey } from 'ox'
*
* const publicKey = PublicKey.from({
* prefix: 4,
* x: 59295962801117472859457908919941473389380284132224861839820747729565200149877n,
* y: 24099691209996290925259367678540227198235484593389470330605641003500238088869n,
* })
*
* const hex = PublicKey.toHex(publicKey) // [!code focus]
* // @log: '0x048318535b54105d4a7aae60c08fc45f9687181b4fdfc625bd1a753fa7397fed753547f11ca8696646f2f3acb08e31016afac23e630c5d11f59f61fef57b0d2aa5'
* ```
*
* @param publicKey - The public key to serialize.
* @returns The serialized public key.
*/
export function toHex(
publicKey: PublicKey<boolean>,
options: toHex.Options = {},
): Hex.Hex {
assert(publicKey)
const { prefix, x, y } = publicKey
const { includePrefix = true } = options
const publicKey_ = Hex.concat(
includePrefix ? Hex.fromNumber(prefix, { size: 1 }) : '0x',
Hex.fromNumber(x, { size: 32 }),
// If the public key is not compressed, add the y coordinate.
typeof y === 'bigint' ? Hex.fromNumber(y, { size: 32 }) : '0x',
)
return publicKey_
}
export declare namespace toHex {
type Options = {
/**
* Whether to include the prefix in the serialized public key.
* @default true
*/
includePrefix?: boolean | undefined
}
type ErrorType = Hex.fromNumber.ErrorType | Errors.GlobalErrorType
}
/**
* Validates a {@link ox#PublicKey.PublicKey}. Returns `true` if valid, `false` otherwise.
*
* @example
* ```ts twoslash
* import { PublicKey } from 'ox'
*
* const valid = PublicKey.validate({
* prefix: 4,
* y: 49782753348462494199823712700004552394425719014458918871452329774910450607807n,
* })
* // @log: false
* ```
*
* @param publicKey - The public key object to assert.
*/
export function validate(
publicKey: ExactPartial<PublicKey>,
options: validate.Options = {},
): boolean {
try {
assert(publicKey, options)
return true
} catch (error) {
return false
}
}
export declare namespace validate {
type Options = {
/** Whether or not the public key should be compressed. */
compressed?: boolean
}
type ErrorType = Errors.GlobalErrorType
}
/**
* Thrown when a public key is invalid.
*
* @example
* ```ts twoslash
* import { PublicKey } from 'ox'
*
* PublicKey.assert({ y: 1n })
* // @error: PublicKey.InvalidError: Value `{"y":1n}` is not a valid public key.
* // @error: Public key must contain:
* // @error: - an `x` and `prefix` value (compressed)
* // @error: - an `x`, `y`, and `prefix` value (uncompressed)
* ```
*/
export class InvalidError extends Errors.BaseError {
override readonly name = 'PublicKey.InvalidError'
constructor({ publicKey }: { publicKey: unknown }) {
super(`Value \`${Json.stringify(publicKey)}\` is not a valid public key.`, {
metaMessages: [
'Public key must contain:',
'- an `x` and `prefix` value (compressed)',
'- an `x`, `y`, and `prefix` value (uncompressed)',
],
})
}
}
/** Thrown when a public key has an invalid prefix. */
export class InvalidPrefixError<
cause extends InvalidCompressedPrefixError | InvalidUncompressedPrefixError =
| InvalidCompressedPrefixError
| InvalidUncompressedPrefixError,
> extends Errors.BaseError<cause> {
override readonly name = 'PublicKey.InvalidPrefixError'
constructor({ prefix, cause }: { prefix: number | undefined; cause: cause }) {
super(`Prefix "${prefix}" is invalid.`, {
cause,
})
}
}
/** Thrown when the public key has an invalid prefix for a compressed public key. */
export class InvalidCompressedPrefixError extends Errors.BaseError {
override readonly name = 'PublicKey.InvalidCompressedPrefixError'
constructor() {
super('Prefix must be 2 or 3 for compressed public keys.')
}
}
/** Thrown when the public key has an invalid prefix for an uncompressed public key. */
export class InvalidUncompressedPrefixError extends Errors.BaseError {
override readonly name = 'PublicKey.InvalidUncompressedPrefixError'
constructor() {
super('Prefix must be 4 for uncompressed public keys.')
}
}
/** Thrown when the public key has an invalid serialized size. */
export class InvalidSerializedSizeError extends Errors.BaseError {
override readonly name = 'PublicKey.InvalidSerializedSizeError'
constructor({ publicKey }: { publicKey: Hex.Hex | Bytes.Bytes }) {
super(`Value \`${publicKey}\` is an invalid public key size.`, {
metaMessages: [
'Expected: 33 bytes (compressed + prefix), 64 bytes (uncompressed) or 65 bytes (uncompressed + prefix).',
`Received ${Hex.size(Hex.from(publicKey))} bytes.`,
],
})
}
}

367
node_modules/ox/core/Rlp.ts generated vendored Normal file
View File

@@ -0,0 +1,367 @@
import * as Bytes from './Bytes.js'
import * as Errors from './Errors.js'
import * as Hex from './Hex.js'
import * as Cursor from './internal/cursor.js'
import type { ExactPartial, RecursiveArray } from './internal/types.js'
/**
* Decodes a Recursive-Length Prefix (RLP) value into a {@link ox#Bytes.Bytes} value.
*
* @example
* ```ts twoslash
* import { Rlp } from 'ox'
* Rlp.toBytes('0x8b68656c6c6f20776f726c64')
* // Uint8Array([139, 104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100])
* ```
*
* @param value - The value to decode.
* @returns The decoded {@link ox#Bytes.Bytes} value.
*/
export function toBytes(
value: Bytes.Bytes | Hex.Hex,
): RecursiveArray<Bytes.Bytes> {
return to(value, 'Bytes')
}
export declare namespace toBytes {
type ErrorType = to.ErrorType
}
/**
* Decodes a Recursive-Length Prefix (RLP) value into a {@link ox#Hex.Hex} value.
*
* @example
* ```ts twoslash
* import { Rlp } from 'ox'
* Rlp.toHex('0x8b68656c6c6f20776f726c64')
* // 0x68656c6c6f20776f726c64
* ```
*
* @param value - The value to decode.
* @returns The decoded {@link ox#Hex.Hex} value.
*/
export function toHex(value: Bytes.Bytes | Hex.Hex): RecursiveArray<Hex.Hex> {
return to(value, 'Hex')
}
export declare namespace toHex {
type ErrorType = to.ErrorType
}
/////////////////////////////////////////////////////////////////////////////////
// Internal
/////////////////////////////////////////////////////////////////////////////////
/** @internal */
export function to<
value extends Bytes.Bytes | Hex.Hex,
to extends 'Hex' | 'Bytes',
>(value: value, to: to | 'Hex' | 'Bytes'): to.ReturnType<to> {
const to_ = to ?? (typeof value === 'string' ? 'Hex' : 'Bytes')
const bytes = (() => {
if (typeof value === 'string') {
if (value.length > 3 && value.length % 2 !== 0)
throw new Hex.InvalidLengthError(value)
return Bytes.fromHex(value)
}
return value as Bytes.Bytes
})()
const cursor = Cursor.create(bytes, {
recursiveReadLimit: Number.POSITIVE_INFINITY,
})
const result = decodeRlpCursor(cursor, to_)
return result as to.ReturnType<to>
}
/** @internal */
export declare namespace to {
type ReturnType<to extends 'Hex' | 'Bytes' = 'Hex' | 'Bytes'> =
| (to extends 'Bytes' ? RecursiveArray<Bytes.Bytes> : never)
| (to extends 'Hex' ? RecursiveArray<Hex.Hex> : never)
type ErrorType =
| Bytes.fromHex.ErrorType
| decodeRlpCursor.ErrorType
| Cursor.create.ErrorType
| Hex.InvalidLengthError
| Errors.GlobalErrorType
}
/** @internal */
/** @internal */
export function decodeRlpCursor<to extends 'Hex' | 'Bytes' = 'Hex'>(
cursor: Cursor.Cursor,
to: to | 'Hex' | 'Bytes' | undefined = 'Hex',
): decodeRlpCursor.ReturnType<to> {
if (cursor.bytes.length === 0)
return (
to === 'Hex' ? Hex.fromBytes(cursor.bytes) : cursor.bytes
) as decodeRlpCursor.ReturnType<to>
const prefix = cursor.readByte()
if (prefix < 0x80) cursor.decrementPosition(1)
// bytes
if (prefix < 0xc0) {
const length = readLength(cursor, prefix, 0x80)
const bytes = cursor.readBytes(length)
return (
to === 'Hex' ? Hex.fromBytes(bytes) : bytes
) as decodeRlpCursor.ReturnType<to>
}
// list
const length = readLength(cursor, prefix, 0xc0)
return readList(cursor, length, to) as {} as decodeRlpCursor.ReturnType<to>
}
/** @internal */
export declare namespace decodeRlpCursor {
type ReturnType<to extends 'Hex' | 'Bytes' = 'Hex'> = to.ReturnType<to>
type ErrorType =
| Hex.fromBytes.ErrorType
| readLength.ErrorType
| readList.ErrorType
| Errors.GlobalErrorType
}
/** @internal */
export function readLength(
cursor: Cursor.Cursor,
prefix: number,
offset: number,
) {
if (offset === 0x80 && prefix < 0x80) return 1
if (prefix <= offset + 55) return prefix - offset
if (prefix === offset + 55 + 1) return cursor.readUint8()
if (prefix === offset + 55 + 2) return cursor.readUint16()
if (prefix === offset + 55 + 3) return cursor.readUint24()
if (prefix === offset + 55 + 4) return cursor.readUint32()
throw new Errors.BaseError('Invalid RLP prefix')
}
/** @internal */
export declare namespace readLength {
type ErrorType = Errors.BaseError | Errors.GlobalErrorType
}
/** @internal */
export function readList<to extends 'Hex' | 'Bytes'>(
cursor: Cursor.Cursor,
length: number,
to: to | 'Hex' | 'Bytes',
) {
const position = cursor.position
const value: decodeRlpCursor.ReturnType<to>[] = []
while (cursor.position - position < length)
value.push(decodeRlpCursor(cursor, to))
return value
}
/** @internal */
export declare namespace readList {
type ErrorType = Errors.GlobalErrorType
}
type Encodable = {
length: number
encode(cursor: Cursor.Cursor): void
}
/**
* Encodes a {@link ox#Bytes.Bytes} or {@link ox#Hex.Hex} value into a Recursive-Length Prefix (RLP) value.
*
* @example
* ```ts twoslash
* import { Bytes, Rlp } from 'ox'
*
* Rlp.from('0x68656c6c6f20776f726c64', { as: 'Hex' })
* // @log: 0x8b68656c6c6f20776f726c64
*
* Rlp.from(Bytes.from([139, 104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100]), { as: 'Bytes' })
* // @log: Uint8Array([104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100])
* ```
*
* @param value - The {@link ox#Bytes.Bytes} or {@link ox#Hex.Hex} value to encode.
* @param options - Options.
* @returns The RLP value.
*/
export function from<as extends 'Hex' | 'Bytes'>(
value: RecursiveArray<Bytes.Bytes> | RecursiveArray<Hex.Hex>,
options: from.Options<as>,
): from.ReturnType<as> {
const { as } = options
const encodable = getEncodable(value)
const cursor = Cursor.create(new Uint8Array(encodable.length))
encodable.encode(cursor)
if (as === 'Hex') return Hex.fromBytes(cursor.bytes) as from.ReturnType<as>
return cursor.bytes as from.ReturnType<as>
}
export declare namespace from {
type Options<as extends 'Hex' | 'Bytes'> = {
/** The type to convert the RLP value to. */
as: as | 'Hex' | 'Bytes'
}
type ReturnType<as extends 'Hex' | 'Bytes'> =
| (as extends 'Bytes' ? Bytes.Bytes : never)
| (as extends 'Hex' ? Hex.Hex : never)
type ErrorType =
| Cursor.create.ErrorType
| Hex.fromBytes.ErrorType
| Bytes.fromHex.ErrorType
| Errors.GlobalErrorType
}
/**
* Encodes a {@link ox#Bytes.Bytes} value into a Recursive-Length Prefix (RLP) value.
*
* @example
* ```ts twoslash
* import { Bytes, Rlp } from 'ox'
*
* Rlp.fromBytes(Bytes.from([139, 104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100]))
* // @log: Uint8Array([104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100])
* ```
*
* @param bytes - The {@link ox#Bytes.Bytes} value to encode.
* @param options - Options.
* @returns The RLP value.
*/
export function fromBytes<as extends 'Hex' | 'Bytes' = 'Bytes'>(
bytes: RecursiveArray<Bytes.Bytes>,
options: fromBytes.Options<as> = {},
): fromBytes.ReturnType<as> {
const { as = 'Bytes' } = options
return from(bytes, { as }) as never
}
export declare namespace fromBytes {
type Options<as extends 'Hex' | 'Bytes' = 'Bytes'> = ExactPartial<
from.Options<as>
>
type ReturnType<as extends 'Hex' | 'Bytes' = 'Bytes'> = from.ReturnType<as>
type ErrorType = from.ErrorType | Errors.GlobalErrorType
}
/**
* Encodes a {@link ox#Hex.Hex} value into a Recursive-Length Prefix (RLP) value.
*
* @example
* ```ts twoslash
* import { Rlp } from 'ox'
*
* Rlp.fromHex('0x68656c6c6f20776f726c64')
* // @log: 0x8b68656c6c6f20776f726c64
* ```
*
* @param hex - The {@link ox#Hex.Hex} value to encode.
* @param options - Options.
* @returns The RLP value.
*/
export function fromHex<as extends 'Hex' | 'Bytes' = 'Hex'>(
hex: RecursiveArray<Hex.Hex>,
options: fromHex.Options<as> = {},
): fromHex.ReturnType<as> {
const { as = 'Hex' } = options
return from(hex, { as }) as never
}
export declare namespace fromHex {
type Options<as extends 'Hex' | 'Bytes' = 'Hex'> = ExactPartial<
from.Options<as>
>
type ReturnType<as extends 'Hex' | 'Bytes' = 'Hex'> = from.ReturnType<as>
type ErrorType = from.ErrorType | Errors.GlobalErrorType
}
/////////////////////////////////////////////////////////////////////////////////
// Internal
/////////////////////////////////////////////////////////////////////////////////
function getEncodable(
bytes: RecursiveArray<Bytes.Bytes> | RecursiveArray<Hex.Hex>,
): Encodable {
if (Array.isArray(bytes))
return getEncodableList(bytes.map((x) => getEncodable(x)))
return getEncodableBytes(bytes as any)
}
function getEncodableList(list: Encodable[]): Encodable {
const bodyLength = list.reduce((acc, x) => acc + x.length, 0)
const sizeOfBodyLength = getSizeOfLength(bodyLength)
const length = (() => {
if (bodyLength <= 55) return 1 + bodyLength
return 1 + sizeOfBodyLength + bodyLength
})()
return {
length,
encode(cursor: Cursor.Cursor) {
if (bodyLength <= 55) {
cursor.pushByte(0xc0 + bodyLength)
} else {
cursor.pushByte(0xc0 + 55 + sizeOfBodyLength)
if (sizeOfBodyLength === 1) cursor.pushUint8(bodyLength)
else if (sizeOfBodyLength === 2) cursor.pushUint16(bodyLength)
else if (sizeOfBodyLength === 3) cursor.pushUint24(bodyLength)
else cursor.pushUint32(bodyLength)
}
for (const { encode } of list) {
encode(cursor)
}
},
}
}
function getEncodableBytes(bytesOrHex: Bytes.Bytes | Hex.Hex): Encodable {
const bytes =
typeof bytesOrHex === 'string' ? Bytes.fromHex(bytesOrHex) : bytesOrHex
const sizeOfBytesLength = getSizeOfLength(bytes.length)
const length = (() => {
if (bytes.length === 1 && bytes[0]! < 0x80) return 1
if (bytes.length <= 55) return 1 + bytes.length
return 1 + sizeOfBytesLength + bytes.length
})()
return {
length,
encode(cursor: Cursor.Cursor) {
if (bytes.length === 1 && bytes[0]! < 0x80) {
cursor.pushBytes(bytes)
} else if (bytes.length <= 55) {
cursor.pushByte(0x80 + bytes.length)
cursor.pushBytes(bytes)
} else {
cursor.pushByte(0x80 + 55 + sizeOfBytesLength)
if (sizeOfBytesLength === 1) cursor.pushUint8(bytes.length)
else if (sizeOfBytesLength === 2) cursor.pushUint16(bytes.length)
else if (sizeOfBytesLength === 3) cursor.pushUint24(bytes.length)
else cursor.pushUint32(bytes.length)
cursor.pushBytes(bytes)
}
},
}
}
function getSizeOfLength(length: number) {
if (length < 2 ** 8) return 1
if (length < 2 ** 16) return 2
if (length < 2 ** 24) return 3
if (length < 2 ** 32) return 4
throw new Errors.BaseError('Length is too large.')
}

184
node_modules/ox/core/RpcRequest.ts generated vendored Normal file
View File

@@ -0,0 +1,184 @@
import type { Errors } from '../index.js'
import type * as RpcSchema from './RpcSchema.js'
import type * as RpcSchema_internal from './internal/rpcSchema.js'
import type { Compute } from './internal/types.js'
/** A JSON-RPC request object as per the [JSON-RPC 2.0 specification](https://www.jsonrpc.org/specification#request_object). */
export type RpcRequest<schema extends RpcSchema.Generic = RpcSchema.Generic> =
Compute<
schema extends any
? schema['Request'] & {
id: number
jsonrpc: '2.0'
/** @deprecated internal */
_returnType: schema['ReturnType']
}
: never
>
/** JSON-RPC request store type. */
export type Store<schema extends RpcSchema.Generic = RpcSchema.Default> =
Compute<{
prepare: <methodName extends RpcSchema.MethodNameGeneric>(
parameters: Compute<
RpcSchema_internal.ExtractRequestOpaque<schema, methodName>
>,
) => Compute<RpcRequest<RpcSchema.ExtractItem<schema, methodName>>>
readonly id: number
}>
/**
* Creates a JSON-RPC request store to build requests with an incrementing `id`.
*
* Returns a type-safe `prepare` function to build a JSON-RPC request object as per the [JSON-RPC 2.0 specification](https://www.jsonrpc.org/specification#request_object).
*
* @example
* ```ts twoslash
* import { RpcRequest } from 'ox'
*
* const store = RpcRequest.createStore()
*
* const request_1 = store.prepare({
* method: 'eth_blockNumber',
* })
* // @log: { id: 0, jsonrpc: '2.0', method: 'eth_blockNumber' }
*
* const request_2 = store.prepare({
* method: 'eth_call',
* params: [
* {
* to: '0x0000000000000000000000000000000000000000',
* data: '0xdeadbeef',
* },
* ],
* })
* // @log: { id: 1, jsonrpc: '2.0', method: 'eth_call', params: [{ to: '0x0000000000000000000000000000000000000000', data: '0xdeadbeef' }] }
* ```
*
* @example
* ### Type-safe Custom Schemas
*
* It is possible to define your own type-safe schema by using the {@link ox#RpcSchema.From} type.
*
* ```ts twoslash
* import { RpcSchema, RpcRequest } from 'ox'
*
* type Schema = RpcSchema.From<{ // [!code focus]
* Request: { // [!code focus]
* method: 'eth_foobar' // [!code focus]
* params: [number] // [!code focus]
* } // [!code focus]
* ReturnType: string // [!code focus]
* } | { // [!code focus]
* Request: { // [!code focus]
* method: 'eth_foobaz' // [!code focus]
* params: [string] // [!code focus]
* } // [!code focus]
* ReturnType: string // [!code focus]
* }> // [!code focus]
*
* const store = RpcRequest.createStore<Schema>() // [!code focus]
*
* const request = store.prepare({
* method: 'eth_foobar', // [!code focus]
* // ^?
* params: [42],
* })
* ```
*
* @param options - Request store options.
* @returns The request store
*/
export function createStore<
schema extends RpcSchema.Generic = RpcSchema.Default,
>(options: createStore.Options = {}): createStore.ReturnType<schema> {
let id = options.id ?? 0
return {
prepare(options) {
return from({
id: id++,
...options,
} as never) as never
},
get id() {
return id
},
}
}
export declare namespace createStore {
type Options = {
/** The initial request ID. */
id?: number
}
type ReturnType<schema extends RpcSchema.Generic = RpcSchema.Default> =
Store<schema>
type ErrorType = Errors.GlobalErrorType
}
/**
* A type-safe interface to build a JSON-RPC request object as per the [JSON-RPC 2.0 specification](https://www.jsonrpc.org/specification#request_object).
*
* :::warning
*
* You will likely want to use {@link ox#RpcRequest.(createStore:function)} instead as it will also manage `id`s and uses this function internally.
*
* :::
*
* @example
* ```ts twoslash
* import { RpcRequest, RpcResponse } from 'ox'
*
* // 1. Build a request object.
* const request = RpcRequest.from({ // [!code focus]
* id: 0, // [!code focus]
* method: 'eth_estimateGas', // [!code focus]
* params: [ // [!code focus]
* { // [!code focus]
* from: '0xd2135CfB216b74109775236E36d4b433F1DF507B', // [!code focus]
* to: '0x0D44f617435088c947F00B31160f64b074e412B4', // [!code focus]
* value: '0x69420', // [!code focus]
* }, // [!code focus]
* ], // [!code focus]
* }) // [!code focus]
*
* // 2. Send the JSON-RPC request via HTTP.
* const gas = await fetch('https://1.rpc.thirdweb.com', {
* body: JSON.stringify(request),
* headers: {
* 'Content-Type': 'application/json',
* },
* method: 'POST',
* })
* .then((response) => response.json())
* // 3. Parse the JSON-RPC response into a type-safe result.
* .then((response) => RpcResponse.parse(response, { request }))
* ```
*
* @param options - JSON-RPC request options.
* @returns The fully-formed JSON-RPC request object.
*/
export function from<methodName extends RpcSchema.MethodNameGeneric>(
options: from.Options<methodName>,
): from.ReturnType<methodName> {
return {
...options,
jsonrpc: '2.0',
} as never
}
export declare namespace from {
type Options<methodName extends RpcSchema.MethodNameGeneric> = Compute<
RpcSchema_internal.ExtractRequestOpaque<RpcSchema.Default, methodName> & {
id: number
}
>
type ReturnType<methodName extends RpcSchema.MethodNameGeneric> = Compute<
RpcRequest<RpcSchema.ExtractItem<RpcSchema.Default, methodName>>
>
type ErrorType = Errors.GlobalErrorType
}

597
node_modules/ox/core/RpcResponse.ts generated vendored Normal file
View File

@@ -0,0 +1,597 @@
import type { Errors, RpcRequest } from '../index.js'
import type {
Compute,
IsNarrowable,
IsNever,
OneOf,
UnionPartialBy,
} from './internal/types.js'
/** A JSON-RPC response object as per the [JSON-RPC 2.0 specification](https://www.jsonrpc.org/specification#request_object). */
export type RpcResponse<
result = unknown,
error extends ErrorObject = ErrorObject,
> = Compute<
{
id: number
jsonrpc: '2.0'
} & OneOf<{ result: result } | { error: error }>
>
/** JSON-RPC error object as per the [JSON-RPC 2.0 specification](https://www.jsonrpc.org/specification#error_object). */
export type ErrorObject = {
code: number
message: string
data?: unknown | undefined
}
/**
* A type-safe interface to instantiate a JSON-RPC response object as per the [JSON-RPC 2.0 specification](https://www.jsonrpc.org/specification#response_object).
*
* @example
* ### Instantiating a Response Object
*
* ```ts twoslash
* import { RpcResponse } from 'ox'
*
* const response = RpcResponse.from({
* id: 0,
* jsonrpc: '2.0',
* result: '0x69420',
* })
* ```
*
* @example
* ### Type-safe Instantiation
*
* If you have a JSON-RPC request object, you can use it to strongly-type the response. If a `request` is provided,
* then the `id` and `jsonrpc` properties will be overridden with the values from the request.
*
* ```ts twoslash
* import { RpcRequest, RpcResponse } from 'ox'
*
* const request = RpcRequest.from({ id: 0, method: 'eth_blockNumber' })
*
* const response = RpcResponse.from(
* { result: '0x69420' },
* { request },
* )
* ```
*
* @param response - Opaque JSON-RPC response object.
* @param options - Parsing options.
* @returns Typed JSON-RPC result, or response object (if `raw` is `true`).
*/
export function from<
request extends RpcRequest.RpcRequest | undefined = undefined,
const response =
| (request extends RpcRequest.RpcRequest
? request['_returnType']
: RpcResponse)
| unknown,
>(
response: from.Response<request, response>,
options?: from.Options<request>,
): Compute<from.ReturnType<response>>
// eslint-disable-next-line jsdoc/require-jsdoc
export function from(response: RpcResponse, options: any = {}): RpcResponse {
const { request } = options
return {
...response,
id: response.id ?? request?.id,
jsonrpc: response.jsonrpc ?? request.jsonrpc,
}
}
export declare namespace from {
type Response<
request extends RpcRequest.RpcRequest | undefined = undefined,
response = unknown,
> = response &
(request extends RpcRequest.RpcRequest
? UnionPartialBy<RpcResponse<request['_returnType']>, 'id' | 'jsonrpc'>
: RpcResponse)
type Options<
request extends RpcRequest.RpcRequest | undefined =
| RpcRequest.RpcRequest
| undefined,
> = {
request?: request | RpcRequest.RpcRequest | undefined
}
type ReturnType<response> = IsNarrowable<response, RpcResponse> extends true
? RpcResponse
: response & Readonly<{ id: number; jsonrpc: '2.0' }>
}
/**
* A type-safe interface to parse a JSON-RPC response object as per the [JSON-RPC 2.0 specification](https://www.jsonrpc.org/specification#response_object), and extract the result.
*
* @example
* ```ts twoslash
* import { RpcRequest, RpcResponse } from 'ox'
*
* // 1. Create a request store.
* const store = RpcRequest.createStore()
*
* // 2. Get a request object.
* const request = store.prepare({
* method: 'eth_getBlockByNumber',
* params: ['0x1', false],
* })
*
* // 3. Send the JSON-RPC request via HTTP.
* const block = await fetch('https://1.rpc.thirdweb.com', {
* body: JSON.stringify(request),
* headers: {
* 'Content-Type': 'application/json',
* },
* method: 'POST',
* })
* .then((response) => response.json())
* // 4. Parse the JSON-RPC response into a type-safe result. // [!code focus]
* .then((response) => RpcResponse.parse(response, { request })) // [!code focus]
*
* block // [!code focus]
* // ^?
*
*
*
*
*
*
*
*
*
*
*
* ```
*
* :::tip
*
* If you don't need the return type, you can omit the options entirely.
*
* ```ts twoslash
* // @noErrors
* import { RpcResponse } from 'ox'
*
* const block = await fetch('https://1.rpc.thirdweb.com', {})
* .then((response) => response.json())
* .then((response) => RpcResponse.parse(response, { request })) // [!code --]
* .then(RpcResponse.parse) // [!code ++]
* ```
* :::
*
* @example
* ### Raw Mode
*
* If `raw` is `true`, the response will be returned as an object with `result` and `error` properties instead of returning the `result` directly and throwing errors.
*
* ```ts twoslash
* import { RpcRequest, RpcResponse } from 'ox'
*
* const store = RpcRequest.createStore()
*
* const request = store.prepare({
* method: 'eth_blockNumber',
* })
*
* const response = RpcResponse.parse({}, {
* request,
* raw: true, // [!code hl]
* })
*
* response.result
* // ^?
*
*
* response.error
* // ^?
*
*
* ```
*
* @param response - Opaque JSON-RPC response object.
* @param options - Parsing options.
* @returns Typed JSON-RPC result, or response object (if `raw` is `true`).
*/
export function parse<
const response extends RpcResponse | unknown,
returnType,
raw extends boolean = false,
>(
response: response,
options: parse.Options<returnType, raw> = {},
): parse.ReturnType<
unknown extends response
? returnType
: response extends RpcResponse
? response extends { result: infer result }
? result
: never
: returnType,
raw
> {
const { raw = false } = options
const response_ = response as RpcResponse
if (raw) return response as never
if (response_.error) throw parseError(response_.error)
return response_.result as never
}
export declare namespace parse {
type Options<returnType, raw extends boolean = false> = {
/**
* JSON-RPC Method that was used to make the request. Used for typing the response.
*/
request?:
| {
_returnType: returnType
}
| RpcRequest.RpcRequest
| undefined
/**
* Enables raw mode responses will return an object with `result` and `error` properties instead of returning the `result` directly and throwing errors.
*
* - `true`: a JSON-RPC response object will be returned with `result` and `error` properties.
* - `false`: the JSON-RPC response object's `result` property will be returned directly, and JSON-RPC Errors will be thrown.
*
* @default false
*/
raw?: raw | boolean | undefined
}
type ReturnType<returnType, raw extends boolean = false> = Compute<
raw extends true ? RpcResponse<returnType> : returnType
>
type ErrorType =
| ParseError
| InvalidInputError
| ResourceNotFoundError
| ResourceUnavailableError
| TransactionRejectedError
| MethodNotSupportedError
| LimitExceededError
| VersionNotSupportedError
| InvalidRequestError
| MethodNotFoundError
| InvalidParamsError
| InternalError
| BaseErrorType
| Errors.GlobalErrorType
}
/**
* Parses a JSON-RPC error object into an error instance.
*
* @example
* ```ts twoslash
* import { RpcResponse } from 'ox'
*
* const error = RpcResponse.parseError({ code: -32000, message: 'unsupported method' })
*
* error
* // ^?
*
* ```
*
* @param errorObject - JSON-RPC error object.
* @returns Error instance.
*/
export function parseError<const errorObject extends ErrorObject | unknown>(
errorObject: errorObject | ErrorObject,
): parseError.ReturnType<errorObject> {
const errorObject_ = errorObject as ErrorObject
const { code } = errorObject_
if (code === InternalError.code)
return new InternalError(errorObject_) as never
if (code === InvalidInputError.code)
return new InvalidInputError(errorObject_) as never
if (code === InvalidParamsError.code)
return new InvalidParamsError(errorObject_) as never
if (code === InvalidRequestError.code)
return new InvalidRequestError(errorObject_) as never
if (code === LimitExceededError.code)
return new LimitExceededError(errorObject_) as never
if (code === MethodNotFoundError.code)
return new MethodNotFoundError(errorObject_) as never
if (code === MethodNotSupportedError.code)
return new MethodNotSupportedError(errorObject_) as never
if (code === ParseError.code) return new ParseError(errorObject_) as never
if (code === ResourceNotFoundError.code)
return new ResourceNotFoundError(errorObject_) as never
if (code === ResourceUnavailableError.code)
return new ResourceUnavailableError(errorObject_) as never
if (code === TransactionRejectedError.code)
return new TransactionRejectedError(errorObject_) as never
if (code === VersionNotSupportedError.code)
return new VersionNotSupportedError(errorObject_) as never
return new InternalError({
data: errorObject_,
message: errorObject_.message,
}) as never
}
export declare namespace parseError {
type ReturnType<
errorObject extends ErrorObject | unknown,
//
error = errorObject extends ErrorObject
?
| (errorObject['code'] extends InternalError['code']
? InternalError
: never)
| (IsNarrowable<errorObject['code'], number> extends false
? InternalError
: never)
| (errorObject['code'] extends InvalidInputError['code']
? InvalidInputError
: never)
| (IsNarrowable<errorObject['code'], number> extends false
? InvalidInputError
: never)
| (errorObject['code'] extends ResourceNotFoundError['code']
? ResourceNotFoundError
: never)
| (IsNarrowable<errorObject['code'], number> extends false
? ResourceNotFoundError
: never)
| (errorObject['code'] extends ResourceUnavailableError['code']
? ResourceUnavailableError
: never)
| (IsNarrowable<errorObject['code'], number> extends false
? ResourceUnavailableError
: never)
| (errorObject['code'] extends TransactionRejectedError['code']
? TransactionRejectedError
: never)
| (IsNarrowable<errorObject['code'], number> extends false
? TransactionRejectedError
: never)
| (errorObject['code'] extends ParseError['code']
? ParseError
: never)
| (IsNarrowable<errorObject['code'], number> extends false
? ParseError
: never)
| (errorObject['code'] extends MethodNotSupportedError['code']
? MethodNotSupportedError
: never)
| (IsNarrowable<errorObject['code'], number> extends false
? MethodNotSupportedError
: never)
| (errorObject['code'] extends LimitExceededError['code']
? LimitExceededError
: never)
| (IsNarrowable<errorObject['code'], number> extends false
? LimitExceededError
: never)
| (errorObject['code'] extends VersionNotSupportedError['code']
? VersionNotSupportedError
: never)
| (IsNarrowable<errorObject['code'], number> extends false
? VersionNotSupportedError
: never)
| (errorObject['code'] extends InvalidRequestError['code']
? InvalidRequestError
: never)
| (IsNarrowable<errorObject['code'], number> extends false
? InvalidRequestError
: never)
| (errorObject['code'] extends MethodNotFoundError['code']
? MethodNotFoundError
: never)
| (IsNarrowable<errorObject['code'], number> extends false
? MethodNotFoundError
: never)
| (errorObject['code'] extends InvalidParamsError['code']
? InvalidParamsError
: never)
| (IsNarrowable<errorObject['code'], number> extends false
? InvalidParamsError
: never)
| (IsNarrowable<errorObject['code'], number> extends false
? BaseError
: never)
: parseError.ReturnType<ErrorObject>,
> = IsNever<error> extends true ? BaseError : error
}
export type BaseErrorType = BaseError & { name: 'BaseError' }
/** Thrown when a JSON-RPC error has occurred. */
export class BaseError extends Error {
override name = 'RpcResponse.BaseError'
readonly code: number
readonly data?: unknown | undefined
constructor(errorObject: ErrorObject) {
const { code, message, data } = errorObject
super(message)
this.code = code
this.data = data
}
}
/** Thrown when the input to a JSON-RPC method is invalid. */
export class InvalidInputError extends BaseError {
static readonly code = -32000
override readonly code = -32000
override readonly name = 'RpcResponse.InvalidInputError'
constructor(parameters: Partial<Omit<ErrorObject, 'code'>> = {}) {
super({
code: InvalidInputError.code,
data: parameters.data,
message: parameters.message ?? 'Missing or invalid parameters.',
})
}
}
/** Thrown when a JSON-RPC resource is not found. */
export class ResourceNotFoundError extends BaseError {
static readonly code = -32001
override readonly code = -32001
override readonly name = 'RpcResponse.ResourceNotFoundError'
constructor(parameters: Partial<Omit<ErrorObject, 'code'>> = {}) {
super({
code: ResourceNotFoundError.code,
data: parameters.data,
message: parameters.message ?? 'Requested resource not found.',
})
}
}
/** Thrown when a JSON-RPC resource is unavailable. */
export class ResourceUnavailableError extends BaseError {
static readonly code = -32002
override readonly code = -32002
override readonly name = 'RpcResponse.ResourceUnavailableError'
constructor(parameters: Partial<Omit<ErrorObject, 'code'>> = {}) {
super({
code: ResourceUnavailableError.code,
data: parameters.data,
message: parameters.message ?? 'Requested resource not available.',
})
}
}
/** Thrown when a JSON-RPC transaction is rejected. */
export class TransactionRejectedError extends BaseError {
static readonly code = -32003
override readonly code = -32003
override readonly name = 'RpcResponse.TransactionRejectedError'
constructor(parameters: Partial<Omit<ErrorObject, 'code'>> = {}) {
super({
code: TransactionRejectedError.code,
data: parameters.data,
message: parameters.message ?? 'Transaction creation failed.',
})
}
}
/** Thrown when a JSON-RPC method is not supported. */
export class MethodNotSupportedError extends BaseError {
static readonly code = -32004
override readonly code = -32004
override readonly name = 'RpcResponse.MethodNotSupportedError'
constructor(parameters: Partial<Omit<ErrorObject, 'code'>> = {}) {
super({
code: MethodNotSupportedError.code,
data: parameters.data,
message: parameters.message ?? 'Method is not implemented.',
})
}
}
/** Thrown when a rate-limit is exceeded. */
export class LimitExceededError extends BaseError {
static readonly code = -32005
override readonly code = -32005
override readonly name = 'RpcResponse.LimitExceededError'
constructor(parameters: Partial<Omit<ErrorObject, 'code'>> = {}) {
super({
code: LimitExceededError.code,
data: parameters.data,
message: parameters.message ?? 'Rate limit exceeded.',
})
}
}
/** Thrown when a JSON-RPC version is not supported. */
export class VersionNotSupportedError extends BaseError {
static readonly code = -32006
override readonly code = -32006
override readonly name = 'RpcResponse.VersionNotSupportedError'
constructor(parameters: Partial<Omit<ErrorObject, 'code'>> = {}) {
super({
code: VersionNotSupportedError.code,
data: parameters.data,
message: parameters.message ?? 'JSON-RPC version not supported.',
})
}
}
/** Thrown when a JSON-RPC request is invalid. */
export class InvalidRequestError extends BaseError {
static readonly code = -32600
override readonly code = -32600
override readonly name = 'RpcResponse.InvalidRequestError'
constructor(parameters: Partial<Omit<ErrorObject, 'code'>> = {}) {
super({
code: InvalidRequestError.code,
data: parameters.data,
message: parameters.message ?? 'Input is not a valid JSON-RPC request.',
})
}
}
/** Thrown when a JSON-RPC method is not found. */
export class MethodNotFoundError extends BaseError {
static readonly code = -32601
override readonly code = -32601
override readonly name = 'RpcResponse.MethodNotFoundError'
constructor(parameters: Partial<Omit<ErrorObject, 'code'>> = {}) {
super({
code: MethodNotFoundError.code,
data: parameters.data,
message: parameters.message ?? 'Method does not exist.',
})
}
}
/** Thrown when the parameters to a JSON-RPC method are invalid. */
export class InvalidParamsError extends BaseError {
static readonly code = -32602
override readonly code = -32602
override readonly name = 'RpcResponse.InvalidParamsError'
constructor(parameters: Partial<Omit<ErrorObject, 'code'>> = {}) {
super({
code: InvalidParamsError.code,
data: parameters.data,
message: parameters.message ?? 'Invalid method parameters.',
})
}
}
/** Thrown when an internal JSON-RPC error has occurred. */
export class InternalError extends BaseError {
static readonly code = -32603
override readonly code = -32603
override readonly name = 'RpcResponse.InternalError'
constructor(parameters: Partial<Omit<ErrorObject, 'code'>> = {}) {
super({
code: InternalError.code,
data: parameters.data,
message: parameters.message ?? 'Internal JSON-RPC error.',
})
}
}
/** Thrown when a JSON-RPC response is invalid. */
export class ParseError extends BaseError {
static readonly code = -32700
override readonly code = -32700
override readonly name = 'RpcResponse.ParseError'
constructor(parameters: Partial<Omit<ErrorObject, 'code'>> = {}) {
super({
code: ParseError.code,
data: parameters.data,
message: parameters.message ?? 'Failed to parse JSON-RPC response.',
})
}
}

273
node_modules/ox/core/RpcSchema.ts generated vendored Normal file
View File

@@ -0,0 +1,273 @@
import type { ResolvedRegister } from './internal/register.js'
import type { Compute, IsNarrowable } from './internal/types.js'
export type { Eth } from './internal/rpcSchemas/eth.js'
export type { Wallet } from './internal/rpcSchemas/wallet.js'
/**
* Instantiates a statically typed Schema. This is a runtime-noop function, and is purposed
* to be used as a type-level tag to be used with {@link ox#Provider.(from:function)} or
* {@link ox#RpcTransport.(fromHttp:function)}.
*
* @example
* ### Using with `Provider.from`
*
* ```ts twoslash
* // @noErrors
* import 'ox/window'
* import { Provider, RpcSchema } from 'ox'
*
* const schema = RpcSchema.from<
* | RpcSchema.Default
* | {
* Request: {
* method: 'abe_foo',
* params: [id: number],
* }
* ReturnType: string
* }
* | {
* Request: {
* method: 'abe_bar',
* params: [id: string],
* }
* ReturnType: string
* }
* >()
*
* const provider = Provider.from(window.ethereum, { schema })
*
* const blockNumber = await provider.request({ method: 'e' })
* // ^|
*
*
*
*
*
* ```
*/
export function from<schema extends Generic>(): schema {
return null as never
}
/**
* Extracts a schema item from a {@link ox#RpcSchema.Generic} or {@link ox#RpcSchema.MethodNameGeneric}.
*
* @example
* ```ts twoslash
* import { RpcSchema } from 'ox'
*
* type Item = RpcSchema.ExtractItem<RpcSchema.Eth, 'eth_getBlockByNumber'>
* // ^?
*
*
*
*
*
*
*
*
*
*
*
*
*
* ```
*/
export type ExtractItem<
schema extends Generic,
methodName extends MethodNameGeneric<schema> = MethodNameGeneric<schema>,
> = Compute<{
Request: ExtractRequest<schema, methodName>
ReturnType: ExtractReturnType<schema, methodName>
}>
/**
* Extracts request from a {@link ox#RpcSchema.Generic} or {@link ox#RpcSchema.MethodNameGeneric}.
*
* @example
* ```ts twoslash
* import { RpcSchema } from 'ox'
*
* type Request = RpcSchema.ExtractRequest<RpcSchema.Eth, 'eth_getBlockByNumber'>
* // ^?
*
*
*
*
*
*
*
*
*
*
*
* ```
*/
export type ExtractRequest<
schema extends Generic,
methodName extends MethodNameGeneric<schema> = MethodNameGeneric<schema>,
> = Extract<schema['Request'], { method: methodName }>
/**
* Type-safe union of all JSON-RPC Method Names.
*
* @example
* ```ts twoslash
* import { RpcSchema } from 'ox'
*
* type MethodName = RpcSchema.ExtractMethodName<RpcSchema.Default>
* // ^?
*
*
*
*
*
*
*
*
* ```
*/
export type ExtractMethodName<schema extends Generic> =
schema['Request']['method']
/**
* Extracts parameters from a {@link ox#RpcSchema.Generic} or {@link ox#RpcSchema.MethodNameGeneric}.
*
* @example
* ```ts twoslash
* import { RpcSchema } from 'ox'
*
* type Eth_GetBlockByNumber = RpcSchema.ExtractParams<RpcSchema.Eth, 'eth_getBlockByNumber'>
* // ^?
*
*
*
*
*
* ```
*/
export type ExtractParams<
schema extends Generic,
methodName extends MethodNameGeneric<schema> = MethodNameGeneric<schema>,
> = ExtractRequest<schema, methodName>['params']
/**
* Extracts return type from a {@link ox#RpcSchema.Generic} or {@link ox#RpcSchema.MethodNameGeneric}.
*
* @example
* ```ts twoslash
* import { RpcSchema } from 'ox'
*
* type ReturnType = RpcSchema.ExtractReturnType<RpcSchema.Eth, 'eth_getBlockByNumber'>
* // ^?
*
*
*
*
*
*
*
*
*
*
*
* ```
*/
export type ExtractReturnType<
schema extends Generic,
methodName extends MethodNameGeneric<schema> = MethodNameGeneric<schema>,
> = methodName extends schema['Request']['method']
? IsNarrowable<schema, Generic> extends true
? Extract<schema, { Request: { method: methodName } }>['ReturnType']
: unknown
: unknown
/**
* Type to define a custom type-safe JSON-RPC Schema.
*
* @example
* ```ts twoslash
* import { RpcSchema, RpcRequest } from 'ox'
*
* type Schema = RpcSchema.From<{
* Request: {
* method: 'eth_foobar',
* params: [id: number],
* }
* ReturnType: string
* }>
* ```
*/
export type From<schema extends Generic> = schema
/**
* Generic type to define a JSON-RPC Method.
*
* @example
* ```ts twoslash
* import { RpcSchema } from 'ox'
*
* type Schema = RpcSchema.Generic
* // ^?
*
*
*
*
*
*
* ```
*/
export type Generic<name extends string = string, params = unknown> = {
Request: {
method: name
params?: params | undefined
}
ReturnType?: unknown
}
/**
* Type-safe union of all JSON-RPC Methods.
*
* @example
* ```ts twoslash
* import { RpcSchema } from 'ox'
*
* type Schema = RpcSchema.Default
* // ^?
*
*
*
*
*
*
*
*
*
*
*
*
*
* ```
*/
export type Default = ResolvedRegister['RpcSchema']
/**
* Generic type to define a JSON-RPC Method Name.
*
* @example
* ```ts twoslash
* import { RpcSchema } from 'ox'
*
* type Name = RpcSchema.MethodNameGeneric
* // ^?
*
*
*
*
*
* ```
*/
export type MethodNameGeneric<schema extends Generic = Generic> =
| schema['Request']['method']
| (string & {})

194
node_modules/ox/core/RpcTransport.ts generated vendored Normal file
View File

@@ -0,0 +1,194 @@
import * as Errors from './Errors.js'
import type * as RpcResponse from './RpcResponse.js'
import type * as RpcSchema from './RpcSchema.js'
import { getUrl } from './internal/errors.js'
import * as promise from './internal/promise.js'
import type * as RpcSchema_internal from './internal/rpcSchema.js'
import * as internal from './internal/rpcTransport.js'
import type { Compute } from './internal/types.js'
/** Root type for an RPC Transport. */
export type RpcTransport<
raw extends boolean = false,
options extends Record<string, unknown> = {},
schema extends RpcSchema.Generic = RpcSchema.Default,
> = Compute<{
request: RequestFn<raw, options, schema>
}>
/** HTTP-based RPC Transport. */
export type Http<
raw extends boolean = false,
schema extends RpcSchema.Generic = RpcSchema.Default,
> = RpcTransport<raw, HttpOptions, schema>
export type HttpOptions = {
/** Request configuration to pass to `fetch`. */
fetchOptions?:
| Omit<RequestInit, 'body'>
| ((
method: RpcSchema.Generic['Request'],
) => Omit<RequestInit, 'body'> | Promise<Omit<RequestInit, 'body'>>)
| undefined
/** Function to use to make the request. @default fetch */
fetchFn?: typeof fetch | undefined
/** Timeout for the request in milliseconds. @default 10_000 */
timeout?: number | undefined
}
export type RequestFn<
raw extends boolean = false,
options extends Record<string, unknown> = {},
schema extends RpcSchema.Generic = RpcSchema.Default,
> = <
methodName extends RpcSchema.MethodNameGeneric,
raw_override extends boolean | undefined = undefined,
>(
parameters: Compute<
RpcSchema_internal.ExtractRequestOpaque<schema, methodName>
>,
options?: internal.Options<raw_override, options, schema> | undefined,
) => Promise<
raw_override extends boolean
? raw_override extends true
? RpcResponse.RpcResponse<RpcSchema.ExtractReturnType<schema, methodName>>
: RpcSchema.ExtractReturnType<schema, methodName>
: raw extends true
? RpcResponse.RpcResponse<RpcSchema.ExtractReturnType<schema, methodName>>
: RpcSchema.ExtractReturnType<schema, methodName>
>
/**
* Creates a HTTP JSON-RPC Transport from a URL.
*
* @example
* ```ts twoslash
* import { RpcTransport } from 'ox'
*
* const transport = RpcTransport.fromHttp('https://1.rpc.thirdweb.com')
*
* const blockNumber = await transport.request({ method: 'eth_blockNumber' })
* // @log: '0x1a2b3c'
* ```
*
* @param url - URL to perform the JSON-RPC requests to.
* @param options - Transport options.
* @returns HTTP JSON-RPC Transport.
*/
export function fromHttp<
raw extends boolean = false,
schema extends RpcSchema.Generic = RpcSchema.Default,
>(url: string, options: fromHttp.Options<raw, schema> = {}): Http<raw, schema> {
return internal.create<HttpOptions, schema, raw>(
{
async request(body_, options_) {
const {
fetchFn = options.fetchFn ?? fetch,
fetchOptions: fetchOptions_ = options.fetchOptions,
timeout = options.timeout ?? 10_000,
} = options_
const body = JSON.stringify(body_)
const fetchOptions =
typeof fetchOptions_ === 'function'
? await fetchOptions_(body_)
: fetchOptions_
const response = await promise.withTimeout(
({ signal }) => {
const init: RequestInit = {
...fetchOptions,
body,
headers: {
'Content-Type': 'application/json',
...fetchOptions?.headers,
},
method: fetchOptions?.method ?? 'POST',
signal: fetchOptions?.signal ?? (timeout > 0 ? signal : null),
}
const request = new Request(url, init)
return fetchFn(request)
},
{
timeout,
signal: true,
},
)
const data = await (async () => {
if (
response.headers.get('Content-Type')?.startsWith('application/json')
)
return response.json()
return response.text().then((data) => {
try {
return JSON.parse(data || '{}')
} catch (err) {
if (response.ok)
throw new MalformedResponseError({
response: data,
})
return { error: data }
}
})
})()
if (!response.ok)
throw new HttpError({
body,
details: JSON.stringify(data.error) ?? response.statusText,
response,
url,
})
return data as never
},
},
{ raw: options.raw },
)
}
export declare namespace fromHttp {
type Options<
raw extends boolean = false,
schema extends RpcSchema.Generic = RpcSchema.Default,
> = internal.Options<raw, HttpOptions, schema>
type ErrorType =
| promise.withTimeout.ErrorType
| HttpError
| Errors.GlobalErrorType
}
/** Thrown when a HTTP request fails. */
export class HttpError extends Errors.BaseError {
override readonly name = 'RpcTransport.HttpError'
constructor({
body,
details,
response,
url,
}: { body: unknown; details: string; response: Response; url: string }) {
super('HTTP request failed.', {
details,
metaMessages: [
`Status: ${response.status}`,
`URL: ${getUrl(url)}`,
body ? `Body: ${JSON.stringify(body)}` : undefined,
],
})
}
}
/** Thrown when a HTTP response is malformed. */
export class MalformedResponseError extends Errors.BaseError {
override readonly name = 'RpcTransport.MalformedResponseError'
constructor({ response }: { response: string }) {
super('HTTP Response could not be parsed as JSON.', {
metaMessages: [`Response: ${response}`],
})
}
}

312
node_modules/ox/core/Secp256k1.ts generated vendored Normal file
View File

@@ -0,0 +1,312 @@
import { secp256k1 } from '@noble/curves/secp256k1'
import * as Address from './Address.js'
import * as Bytes from './Bytes.js'
import type * as Errors from './Errors.js'
import * as Hex from './Hex.js'
import * as PublicKey from './PublicKey.js'
import type * as Signature from './Signature.js'
import * as Entropy from './internal/entropy.js'
import type { OneOf } from './internal/types.js'
/** Re-export of noble/curves secp256k1 utilities. */
export const noble = secp256k1
/**
* Computes the secp256k1 ECDSA public key from a provided private key.
*
* @example
* ```ts twoslash
* import { Secp256k1 } from 'ox'
*
* const publicKey = Secp256k1.getPublicKey({ privateKey: '0x...' })
* ```
*
* @param options - The options to compute the public key.
* @returns The computed public key.
*/
export function getPublicKey(
options: getPublicKey.Options,
): PublicKey.PublicKey {
const { privateKey } = options
const point = secp256k1.ProjectivePoint.fromPrivateKey(
Hex.from(privateKey).slice(2),
)
return PublicKey.from(point)
}
export declare namespace getPublicKey {
type Options = {
/**
* Private key to compute the public key from.
*/
privateKey: Hex.Hex | Bytes.Bytes
}
type ErrorType =
| Hex.from.ErrorType
| PublicKey.from.ErrorType
| Errors.GlobalErrorType
}
/**
* Generates a random ECDSA private key on the secp256k1 curve.
*
* @example
* ```ts twoslash
* import { Secp256k1 } from 'ox'
*
* const privateKey = Secp256k1.randomPrivateKey()
* ```
*
* @param options - The options to generate the private key.
* @returns The generated private key.
*/
export function randomPrivateKey<as extends 'Hex' | 'Bytes' = 'Hex'>(
options: randomPrivateKey.Options<as> = {},
): randomPrivateKey.ReturnType<as> {
const { as = 'Hex' } = options
const bytes = secp256k1.utils.randomPrivateKey()
if (as === 'Hex') return Hex.fromBytes(bytes) as never
return bytes as never
}
export declare namespace randomPrivateKey {
type Options<as extends 'Hex' | 'Bytes' = 'Hex'> = {
/**
* Format of the returned private key.
* @default 'Hex'
*/
as?: as | 'Hex' | 'Bytes' | undefined
}
type ReturnType<as extends 'Hex' | 'Bytes'> =
| (as extends 'Bytes' ? Bytes.Bytes : never)
| (as extends 'Hex' ? Hex.Hex : never)
type ErrorType = Hex.fromBytes.ErrorType | Errors.GlobalErrorType
}
/**
* Recovers the signing address from the signed payload and signature.
*
* @example
* ```ts twoslash
* import { Secp256k1 } from 'ox'
*
* const signature = Secp256k1.sign({ payload: '0xdeadbeef', privateKey: '0x...' })
*
* const address = Secp256k1.recoverAddress({ // [!code focus]
* payload: '0xdeadbeef', // [!code focus]
* signature, // [!code focus]
* }) // [!code focus]
* ```
*
* @param options - The recovery options.
* @returns The recovered address.
*/
export function recoverAddress(
options: recoverAddress.Options,
): recoverAddress.ReturnType {
return Address.fromPublicKey(recoverPublicKey(options))
}
export declare namespace recoverAddress {
type Options = {
/** Payload that was signed. */
payload: Hex.Hex | Bytes.Bytes
/** Signature of the payload. */
signature: Signature.Signature
}
type ReturnType = Address.Address
type ErrorType =
| Address.fromPublicKey.ErrorType
| recoverPublicKey.ErrorType
| Errors.GlobalErrorType
}
/**
* Recovers the signing public key from the signed payload and signature.
*
* @example
* ```ts twoslash
* import { Secp256k1 } from 'ox'
*
* const signature = Secp256k1.sign({ payload: '0xdeadbeef', privateKey: '0x...' })
*
* const publicKey = Secp256k1.recoverPublicKey({ // [!code focus]
* payload: '0xdeadbeef', // [!code focus]
* signature, // [!code focus]
* }) // [!code focus]
* ```
*
* @param options - The recovery options.
* @returns The recovered public key.
*/
export function recoverPublicKey(
options: recoverPublicKey.Options,
): PublicKey.PublicKey {
const { payload, signature } = options
const { r, s, yParity } = signature
const signature_ = new secp256k1.Signature(
BigInt(r),
BigInt(s),
).addRecoveryBit(yParity)
const point = signature_.recoverPublicKey(Hex.from(payload).substring(2))
return PublicKey.from(point)
}
export declare namespace recoverPublicKey {
type Options = {
/** Payload that was signed. */
payload: Hex.Hex | Bytes.Bytes
/** Signature of the payload. */
signature: Signature.Signature
}
type ErrorType =
| PublicKey.from.ErrorType
| Hex.from.ErrorType
| Errors.GlobalErrorType
}
/**
* Signs the payload with the provided private key.
*
* @example
* ```ts twoslash
* import { Secp256k1 } from 'ox'
*
* const signature = Secp256k1.sign({ // [!code focus]
* payload: '0xdeadbeef', // [!code focus]
* privateKey: '0x...' // [!code focus]
* }) // [!code focus]
* ```
*
* @param options - The signing options.
* @returns The ECDSA {@link ox#Signature.Signature}.
*/
export function sign(options: sign.Options): Signature.Signature {
const {
extraEntropy = Entropy.extraEntropy,
hash,
payload,
privateKey,
} = options
const { r, s, recovery } = secp256k1.sign(
Bytes.from(payload),
Bytes.from(privateKey),
{
extraEntropy:
typeof extraEntropy === 'boolean'
? extraEntropy
: Hex.from(extraEntropy).slice(2),
lowS: true,
...(hash ? { prehash: true } : {}),
},
)
return {
r,
s,
yParity: recovery,
}
}
export declare namespace sign {
type Options = {
/**
* Extra entropy to add to the signing process. Setting to `false` will disable it.
* @default true
*/
extraEntropy?: boolean | Hex.Hex | Bytes.Bytes | undefined
/**
* If set to `true`, the payload will be hashed (sha256) before being signed.
*/
hash?: boolean | undefined
/**
* Payload to sign.
*/
payload: Hex.Hex | Bytes.Bytes
/**
* ECDSA private key.
*/
privateKey: Hex.Hex | Bytes.Bytes
}
type ErrorType = Bytes.from.ErrorType | Errors.GlobalErrorType
}
/**
* Verifies a payload was signed by the provided address.
*
* @example
* ### Verify with Ethereum Address
*
* ```ts twoslash
* import { Secp256k1 } from 'ox'
*
* const signature = Secp256k1.sign({ payload: '0xdeadbeef', privateKey: '0x...' })
*
* const verified = Secp256k1.verify({ // [!code focus]
* address: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', // [!code focus]
* payload: '0xdeadbeef', // [!code focus]
* signature, // [!code focus]
* }) // [!code focus]
* ```
*
* @example
* ### Verify with Public Key
*
* ```ts twoslash
* import { Secp256k1 } from 'ox'
*
* const privateKey = '0x...'
* const publicKey = Secp256k1.getPublicKey({ privateKey })
* const signature = Secp256k1.sign({ payload: '0xdeadbeef', privateKey })
*
* const verified = Secp256k1.verify({ // [!code focus]
* publicKey, // [!code focus]
* payload: '0xdeadbeef', // [!code focus]
* signature, // [!code focus]
* }) // [!code focus]
* ```
*
* @param options - The verification options.
* @returns Whether the payload was signed by the provided address.
*/
export function verify(options: verify.Options): boolean {
const { address, hash, payload, publicKey, signature } = options
if (address)
return Address.isEqual(address, recoverAddress({ payload, signature }))
return secp256k1.verify(
signature,
Bytes.from(payload),
PublicKey.toBytes(publicKey),
...(hash ? [{ prehash: true, lowS: true }] : []),
)
}
export declare namespace verify {
type Options = {
/** If set to `true`, the payload will be hashed (sha256) before being verified. */
hash?: boolean | undefined
/** Payload that was signed. */
payload: Hex.Hex | Bytes.Bytes
} & OneOf<
| {
/** Address that signed the payload. */
address: Address.Address
/** Signature of the payload. */
signature: Signature.Signature
}
| {
/** Public key that signed the payload. */
publicKey: PublicKey.PublicKey<boolean>
/** Signature of the payload. */
signature: Signature.Signature<false>
}
>
type ErrorType = Errors.GlobalErrorType
}

843
node_modules/ox/core/Signature.ts generated vendored Normal file
View File

@@ -0,0 +1,843 @@
import { secp256k1 } from '@noble/curves/secp256k1'
import * as Bytes from './Bytes.js'
import * as Errors from './Errors.js'
import * as Hex from './Hex.js'
import * as Json from './Json.js'
import * as Solidity from './Solidity.js'
import type { Compute, ExactPartial, OneOf } from './internal/types.js'
/** Root type for an ECDSA signature. */
export type Signature<
recovered extends boolean = true,
bigintType = bigint,
numberType = number,
> = Compute<
recovered extends true
? {
r: bigintType
s: bigintType
yParity: numberType
}
: {
r: bigintType
s: bigintType
yParity?: numberType | undefined
}
>
/** RPC-formatted ECDSA signature. */
export type Rpc<recovered extends boolean = true> = Signature<
recovered,
Hex.Hex,
Hex.Hex
>
/** (Legacy) ECDSA signature. */
export type Legacy<bigintType = bigint, numberType = number> = {
r: bigintType
s: bigintType
v: numberType
}
/** RPC-formatted (Legacy) ECDSA signature. */
export type LegacyRpc = Legacy<Hex.Hex, Hex.Hex>
export type Tuple = readonly [yParity: Hex.Hex, r: Hex.Hex, s: Hex.Hex]
/**
* Asserts that a Signature is valid.
*
* @example
* ```ts twoslash
* import { Signature } from 'ox'
*
* Signature.assert({
* r: -49782753348462494199823712700004552394425719014458918871452329774910450607807n,
* s: 33726695977844476214676913201140481102225469284307016937915595756355928419768n,
* yParity: 1,
* })
* // @error: InvalidSignatureRError:
* // @error: Value `-549...n` is an invalid r value.
* // @error: r must be a positive integer less than 2^256.
* ```
*
* @param signature - The signature object to assert.
*/
export function assert(
signature: ExactPartial<Signature>,
options: assert.Options = {},
): asserts signature is Signature {
const { recovered } = options
if (typeof signature.r === 'undefined')
throw new MissingPropertiesError({ signature })
if (typeof signature.s === 'undefined')
throw new MissingPropertiesError({ signature })
if (recovered && typeof signature.yParity === 'undefined')
throw new MissingPropertiesError({ signature })
if (signature.r < 0n || signature.r > Solidity.maxUint256)
throw new InvalidRError({ value: signature.r })
if (signature.s < 0n || signature.s > Solidity.maxUint256)
throw new InvalidSError({ value: signature.s })
if (
typeof signature.yParity === 'number' &&
signature.yParity !== 0 &&
signature.yParity !== 1
)
throw new InvalidYParityError({ value: signature.yParity })
}
export declare namespace assert {
type Options = {
/** Whether or not the signature should be recovered (contain `yParity`). */
recovered?: boolean
}
type ErrorType =
| MissingPropertiesError
| InvalidRError
| InvalidSError
| InvalidYParityError
| Errors.GlobalErrorType
}
/**
* Deserializes a {@link ox#Bytes.Bytes} signature into a structured {@link ox#Signature.Signature}.
*
* @example
* ```ts twoslash
* // @noErrors
* import { Signature } from 'ox'
*
* Signature.fromBytes(new Uint8Array([128, 3, 131, ...]))
* // @log: { r: 5231...n, s: 3522...n, yParity: 0 }
* ```
*
* @param signature - The serialized signature.
* @returns The deserialized {@link ox#Signature.Signature}.
*/
export function fromBytes(signature: Bytes.Bytes): Signature {
return fromHex(Hex.fromBytes(signature))
}
export declare namespace fromBytes {
type ErrorType = Errors.GlobalErrorType
}
/**
* Deserializes a {@link ox#Hex.Hex} signature into a structured {@link ox#Signature.Signature}.
*
* @example
* ```ts twoslash
* import { Signature } from 'ox'
*
* Signature.fromHex('0x6e100a352ec6ad1b70802290e18aeed190704973570f3b8ed42cb9808e2ea6bf4a90a229a244495b41890987806fcbd2d5d23fc0dbe5f5256c2613c039d76db81c')
* // @log: { r: 5231...n, s: 3522...n, yParity: 0 }
* ```
*
* @param serialized - The serialized signature.
* @returns The deserialized {@link ox#Signature.Signature}.
*/
export function fromHex(signature: Hex.Hex): Signature {
if (signature.length !== 130 && signature.length !== 132)
throw new InvalidSerializedSizeError({ signature })
const r = BigInt(Hex.slice(signature, 0, 32))
const s = BigInt(Hex.slice(signature, 32, 64))
const yParity = (() => {
const yParity = Number(`0x${signature.slice(130)}`)
if (Number.isNaN(yParity)) return undefined
try {
return vToYParity(yParity)
} catch {
throw new InvalidYParityError({ value: yParity })
}
})()
if (typeof yParity === 'undefined')
return {
r,
s,
} as never
return {
r,
s,
yParity,
} as never
}
export declare namespace fromHex {
type ErrorType =
| Hex.from.ErrorType
| InvalidSerializedSizeError
| Errors.GlobalErrorType
}
/**
* Extracts a {@link ox#Signature.Signature} from an arbitrary object that may include signature properties.
*
* @example
* ```ts twoslash
* // @noErrors
* import { Signature } from 'ox'
*
* Signature.extract({
* baz: 'barry',
* foo: 'bar',
* r: 49782753348462494199823712700004552394425719014458918871452329774910450607807n,
* s: 33726695977844476214676913201140481102225469284307016937915595756355928419768n,
* yParity: 1,
* zebra: 'stripes',
* })
* // @log: {
* // @log: r: 49782753348462494199823712700004552394425719014458918871452329774910450607807n,
* // @log: s: 33726695977844476214676913201140481102225469284307016937915595756355928419768n,
* // @log: yParity: 1
* // @log: }
* ```
*
* @param value - The arbitrary object to extract the signature from.
* @returns The extracted {@link ox#Signature.Signature}.
*/
export function extract(value: extract.Value): Signature | undefined {
if (typeof value.r === 'undefined') return undefined
if (typeof value.s === 'undefined') return undefined
return from(value as any)
}
export declare namespace extract {
type Value = {
r?: bigint | Hex.Hex | undefined
s?: bigint | Hex.Hex | undefined
yParity?: number | Hex.Hex | undefined
v?: number | Hex.Hex | undefined
}
type ErrorType = Errors.GlobalErrorType
}
/**
* Instantiates a typed {@link ox#Signature.Signature} object from a {@link ox#Signature.Signature}, {@link ox#Signature.Legacy}, {@link ox#Bytes.Bytes}, or {@link ox#Hex.Hex}.
*
* @example
* ```ts twoslash
* import { Signature } from 'ox'
*
* Signature.from({
* r: 49782753348462494199823712700004552394425719014458918871452329774910450607807n,
* s: 33726695977844476214676913201140481102225469284307016937915595756355928419768n,
* yParity: 1,
* })
* // @log: {
* // @log: r: 49782753348462494199823712700004552394425719014458918871452329774910450607807n,
* // @log: s: 33726695977844476214676913201140481102225469284307016937915595756355928419768n,
* // @log: yParity: 1
* // @log: }
* ```
*
* @example
* ### From Serialized
*
* ```ts twoslash
* import { Signature } from 'ox'
*
* Signature.from('0x6e100a352ec6ad1b70802290e18aeed190704973570f3b8ed42cb9808e2ea6bf4a90a229a244495b41890987806fcbd2d5d23fc0dbe5f5256c2613c039d76db801')
* // @log: {
* // @log: r: 49782753348462494199823712700004552394425719014458918871452329774910450607807n,
* // @log: s: 33726695977844476214676913201140481102225469284307016937915595756355928419768n,
* // @log: yParity: 1,
* // @log: }
* ```
*
* @example
* ### From Legacy
*
* ```ts twoslash
* import { Signature } from 'ox'
*
* Signature.from({
* r: 47323457007453657207889730243826965761922296599680473886588287015755652701072n,
* s: 57228803202727131502949358313456071280488184270258293674242124340113824882788n,
* v: 27,
* })
* // @log: {
* // @log: r: 47323457007453657207889730243826965761922296599680473886588287015755652701072n,
* // @log: s: 57228803202727131502949358313456071280488184270258293674242124340113824882788n,
* // @log: yParity: 0
* // @log: }
* ```
*
* @param signature - The signature value to instantiate.
* @returns The instantiated {@link ox#Signature.Signature}.
*/
export function from<
const signature extends
| OneOf<Signature<boolean> | Rpc<boolean> | Legacy | LegacyRpc>
| Hex.Hex
| Bytes.Bytes,
>(
signature:
| signature
| OneOf<Signature<boolean> | Rpc<boolean> | Legacy | LegacyRpc>
| Hex.Hex
| Bytes.Bytes,
): from.ReturnType<signature> {
const signature_ = (() => {
if (typeof signature === 'string') return fromHex(signature)
if (signature instanceof Uint8Array) return fromBytes(signature)
if (typeof signature.r === 'string') return fromRpc(signature)
if (signature.v) return fromLegacy(signature)
return {
r: signature.r,
s: signature.s,
...(typeof signature.yParity !== 'undefined'
? { yParity: signature.yParity }
: {}),
}
})()
assert(signature_)
return signature_ as never
}
export declare namespace from {
type ReturnType<
signature extends
| OneOf<Signature<boolean> | Rpc<boolean> | Legacy | LegacyRpc>
| Hex.Hex
| Bytes.Bytes,
> = signature extends Signature<boolean> & { v?: undefined }
? signature
: Signature
type ErrorType =
| assert.ErrorType
| fromBytes.ErrorType
| fromHex.ErrorType
| vToYParity.ErrorType
| Errors.GlobalErrorType
}
/**
* Converts a DER-encoded signature to a {@link ox#Signature.Signature}.
*
* @example
* ```ts twoslash
* // @noErrors
* import { Signature } from 'ox'
*
* const signature = Signature.fromDerBytes(new Uint8Array([132, 51, 23, ...]))
* // @log: {
* // @log: r: 49782753348462494199823712700004552394425719014458918871452329774910450607807n,
* // @log: s: 33726695977844476214676913201140481102225469284307016937915595756355928419768n,
* // @log: }
* ```
*
* @param signature - The DER-encoded signature to convert.
* @returns The {@link ox#Signature.Signature}.
*/
export function fromDerBytes(signature: Bytes.Bytes): Signature<false> {
return fromDerHex(Hex.fromBytes(signature))
}
export declare namespace fromDerBytes {
type ErrorType = Errors.GlobalErrorType
}
/**
* Converts a DER-encoded signature to a {@link ox#Signature.Signature}.
*
* @example
* ```ts twoslash
* import { Signature } from 'ox'
*
* const signature = Signature.fromDerHex('0x304402206e100a352ec6ad1b70802290e18aeed190704973570f3b8ed42cb9808e2ea6bf02204a90a229a244495b41890987806fcbd2d5d23fc0dbe5f5256c2613c039d76db8')
* // @log: {
* // @log: r: 49782753348462494199823712700004552394425719014458918871452329774910450607807n,
* // @log: s: 33726695977844476214676913201140481102225469284307016937915595756355928419768n,
* // @log: }
* ```
*
* @param signature - The DER-encoded signature to convert.
* @returns The {@link ox#Signature.Signature}.
*/
export function fromDerHex(signature: Hex.Hex): Signature<false> {
const { r, s } = secp256k1.Signature.fromDER(Hex.from(signature).slice(2))
return { r, s }
}
export declare namespace fromDerHex {
type ErrorType = Errors.GlobalErrorType
}
/**
* Converts a {@link ox#Signature.Legacy} into a {@link ox#Signature.Signature}.
*
* @example
* ```ts twoslash
* import { Signature } from 'ox'
*
* const legacy = Signature.fromLegacy({ r: 1n, s: 2n, v: 28 })
* // @log: { r: 1n, s: 2n, yParity: 1 }
* ```
*
* @param signature - The {@link ox#Signature.Legacy} to convert.
* @returns The converted {@link ox#Signature.Signature}.
*/
export function fromLegacy(signature: Legacy): Signature {
return {
r: signature.r,
s: signature.s,
yParity: vToYParity(signature.v),
}
}
export declare namespace fromLegacy {
type ErrorType = vToYParity.ErrorType | Errors.GlobalErrorType
}
/**
* Converts a {@link ox#Signature.Rpc} into a {@link ox#Signature.Signature}.
*
* @example
* ```ts twoslash
* import { Signature } from 'ox'
*
* const signature = Signature.fromRpc({
* r: '0x635dc2033e60185bb36709c29c75d64ea51dfbd91c32ef4be198e4ceb169fb4d',
* s: '0x50c2667ac4c771072746acfdcf1f1483336dcca8bd2df47cd83175dbe60f0540',
* yParity: '0x0',
* })
* ```
*
* @param signature - The {@link ox#Signature.Rpc} to convert.
* @returns The converted {@link ox#Signature.Signature}.
*/
export function fromRpc(signature: {
r: Hex.Hex
s: Hex.Hex
yParity?: Hex.Hex | undefined
v?: Hex.Hex | undefined
}): Signature {
const yParity = (() => {
const v = signature.v ? Number(signature.v) : undefined
let yParity = signature.yParity ? Number(signature.yParity) : undefined
if (typeof v === 'number' && typeof yParity !== 'number')
yParity = vToYParity(v)
if (typeof yParity !== 'number')
throw new InvalidYParityError({ value: signature.yParity })
return yParity
})()
return {
r: BigInt(signature.r),
s: BigInt(signature.s),
yParity,
}
}
export declare namespace fromRpc {
type ErrorType = Errors.GlobalErrorType
}
/**
* Converts a {@link ox#Signature.Tuple} to a {@link ox#Signature.Signature}.
*
* @example
* ```ts twoslash
* import { Signature } from 'ox'
*
* const signature = Signature.fromTuple(['0x01', '0x7b', '0x1c8'])
* // @log: {
* // @log: r: 123n,
* // @log: s: 456n,
* // @log: yParity: 1,
* // @log: }
* ```
*
* @param tuple - The {@link ox#Signature.Tuple} to convert.
* @returns The {@link ox#Signature.Signature}.
*/
export function fromTuple(tuple: Tuple): Signature {
const [yParity, r, s] = tuple
return from({
r: r === '0x' ? 0n : BigInt(r),
s: s === '0x' ? 0n : BigInt(s),
yParity: yParity === '0x' ? 0 : Number(yParity),
})
}
export declare namespace fromTuple {
type ErrorType = from.ErrorType | Errors.GlobalErrorType
}
/**
* Serializes a {@link ox#Signature.Signature} to {@link ox#Bytes.Bytes}.
*
* @example
* ```ts twoslash
* import { Signature } from 'ox'
*
* const signature = Signature.toBytes({
* r: 49782753348462494199823712700004552394425719014458918871452329774910450607807n,
* s: 33726695977844476214676913201140481102225469284307016937915595756355928419768n,
* yParity: 1
* })
* // @log: Uint8Array [102, 16, 10, ...]
* ```
*
* @param signature - The signature to serialize.
* @returns The serialized signature.
*/
export function toBytes(signature: Signature<boolean>): Bytes.Bytes {
return Bytes.fromHex(toHex(signature))
}
export declare namespace toBytes {
type ErrorType =
| toHex.ErrorType
| Bytes.fromHex.ErrorType
| Errors.GlobalErrorType
}
/**
* Serializes a {@link ox#Signature.Signature} to {@link ox#Hex.Hex}.
*
* @example
* ```ts twoslash
* import { Signature } from 'ox'
*
* const signature = Signature.toHex({
* r: 49782753348462494199823712700004552394425719014458918871452329774910450607807n,
* s: 33726695977844476214676913201140481102225469284307016937915595756355928419768n,
* yParity: 1
* })
* // @log: '0x6e100a352ec6ad1b70802290e18aeed190704973570f3b8ed42cb9808e2ea6bf4a90a229a244495b41890987806fcbd2d5d23fc0dbe5f5256c2613c039d76db81c'
* ```
*
* @param signature - The signature to serialize.
* @returns The serialized signature.
*/
export function toHex(signature: Signature<boolean>): Hex.Hex {
assert(signature)
const r = signature.r
const s = signature.s
const signature_ = Hex.concat(
Hex.fromNumber(r, { size: 32 }),
Hex.fromNumber(s, { size: 32 }),
// If the signature is recovered, add the recovery byte to the signature.
typeof signature.yParity === 'number'
? Hex.fromNumber(yParityToV(signature.yParity), { size: 1 })
: '0x',
)
return signature_
}
export declare namespace toHex {
type ErrorType =
| Hex.concat.ErrorType
| Hex.fromNumber.ErrorType
| Errors.GlobalErrorType
}
/**
* Converts a {@link ox#Signature.Signature} to DER-encoded format.
*
* @example
* ```ts twoslash
* import { Signature } from 'ox'
*
* const signature = Signature.from({
* r: 49782753348462494199823712700004552394425719014458918871452329774910450607807n,
* s: 33726695977844476214676913201140481102225469284307016937915595756355928419768n,
* })
*
* const signature_der = Signature.toDerBytes(signature)
* // @log: Uint8Array [132, 51, 23, ...]
* ```
*
* @param signature - The signature to convert.
* @returns The DER-encoded signature.
*/
export function toDerBytes(signature: Signature<boolean>): Bytes.Bytes {
const sig = new secp256k1.Signature(signature.r, signature.s)
return sig.toDERRawBytes()
}
export declare namespace toDerBytes {
type ErrorType = Errors.GlobalErrorType
}
/**
* Converts a {@link ox#Signature.Signature} to DER-encoded format.
*
* @example
* ```ts twoslash
* import { Signature } from 'ox'
*
* const signature = Signature.from({
* r: 49782753348462494199823712700004552394425719014458918871452329774910450607807n,
* s: 33726695977844476214676913201140481102225469284307016937915595756355928419768n,
* })
*
* const signature_der = Signature.toDerHex(signature)
* // @log: '0x304402206e100a352ec6ad1b70802290e18aeed190704973570f3b8ed42cb9808e2ea6bf02204a90a229a244495b41890987806fcbd2d5d23fc0dbe5f5256c2613c039d76db8'
* ```
*
* @param signature - The signature to convert.
* @returns The DER-encoded signature.
*/
export function toDerHex(signature: Signature<boolean>): Hex.Hex {
const sig = new secp256k1.Signature(signature.r, signature.s)
return `0x${sig.toDERHex()}`
}
export declare namespace toDerHex {
type ErrorType = Errors.GlobalErrorType
}
/**
* Converts a {@link ox#Signature.Signature} into a {@link ox#Signature.Legacy}.
*
* @example
* ```ts twoslash
* import { Signature } from 'ox'
*
* const legacy = Signature.toLegacy({ r: 1n, s: 2n, yParity: 1 })
* // @log: { r: 1n, s: 2n, v: 28 }
* ```
*
* @param signature - The {@link ox#Signature.Signature} to convert.
* @returns The converted {@link ox#Signature.Legacy}.
*/
export function toLegacy(signature: Signature): Legacy {
return {
r: signature.r,
s: signature.s,
v: yParityToV(signature.yParity),
}
}
export declare namespace toLegacy {
type ErrorType = yParityToV.ErrorType | Errors.GlobalErrorType
}
/**
* Converts a {@link ox#Signature.Signature} into a {@link ox#Signature.Rpc}.
*
* @example
* ```ts twoslash
* import { Signature } from 'ox'
*
* const signature = Signature.toRpc({
* r: 49782753348462494199823712700004552394425719014458918871452329774910450607807n,
* s: 33726695977844476214676913201140481102225469284307016937915595756355928419768n,
* yParity: 1
* })
* ```
*
* @param signature - The {@link ox#Signature.Signature} to convert.
* @returns The converted {@link ox#Signature.Rpc}.
*/
export function toRpc(signature: Signature): Rpc {
const { r, s, yParity } = signature
return {
r: Hex.fromNumber(r, { size: 32 }),
s: Hex.fromNumber(s, { size: 32 }),
yParity: yParity === 0 ? '0x0' : '0x1',
}
}
export declare namespace toRpc {
type ErrorType = Errors.GlobalErrorType
}
/**
* Converts a {@link ox#Signature.Signature} to a serialized {@link ox#Signature.Tuple} to be used for signatures in Transaction Envelopes, EIP-7702 Authorization Lists, etc.
*
* @example
* ```ts twoslash
* import { Signature } from 'ox'
*
* const signatureTuple = Signature.toTuple({
* r: 123n,
* s: 456n,
* yParity: 1,
* })
* // @log: [yParity: '0x01', r: '0x7b', s: '0x1c8']
* ```
*
* @param signature - The {@link ox#Signature.Signature} to convert.
* @returns The {@link ox#Signature.Tuple}.
*/
export function toTuple(signature: Signature): Tuple {
const { r, s, yParity } = signature
return [
yParity ? '0x01' : '0x',
r === 0n ? '0x' : Hex.trimLeft(Hex.fromNumber(r!)),
s === 0n ? '0x' : Hex.trimLeft(Hex.fromNumber(s!)),
] as const
}
export declare namespace toTuple {
type ErrorType =
| Hex.trimLeft.ErrorType
| Hex.fromNumber.ErrorType
| Errors.GlobalErrorType
}
/**
* Validates a Signature. Returns `true` if the signature is valid, `false` otherwise.
*
* @example
* ```ts twoslash
* import { Signature } from 'ox'
*
* const valid = Signature.validate({
* r: -49782753348462494199823712700004552394425719014458918871452329774910450607807n,
* s: 33726695977844476214676913201140481102225469284307016937915595756355928419768n,
* yParity: 1,
* })
* // @log: false
* ```
*
* @param signature - The signature object to assert.
*/
export function validate(
signature: ExactPartial<Signature>,
options: validate.Options = {},
): boolean {
try {
assert(signature, options)
return true
} catch {
return false
}
}
export declare namespace validate {
type Options = {
/** Whether or not the signature should be recovered (contain `yParity`). */
recovered?: boolean
}
type ErrorType = Errors.GlobalErrorType
}
/**
* Converts a ECDSA `v` value to a `yParity` value.
*
* @example
* ```ts twoslash
* import { Signature } from 'ox'
*
* const yParity = Signature.vToYParity(28)
* // @log: 1
* ```
*
* @param v - The ECDSA `v` value to convert.
* @returns The `yParity` value.
*/
export function vToYParity(v: number): Signature['yParity'] {
if (v === 0 || v === 27) return 0
if (v === 1 || v === 28) return 1
if (v >= 35) return v % 2 === 0 ? 1 : 0
throw new InvalidVError({ value: v })
}
export declare namespace vToYParity {
type ErrorType = InvalidVError | Errors.GlobalErrorType
}
/**
* Converts a ECDSA `v` value to a `yParity` value.
*
* @example
* ```ts twoslash
* import { Signature } from 'ox'
*
* const v = Signature.yParityToV(1)
* // @log: 28
* ```
*
* @param yParity - The ECDSA `yParity` value to convert.
* @returns The `v` value.
*/
export function yParityToV(yParity: number): number {
if (yParity === 0) return 27
if (yParity === 1) return 28
throw new InvalidYParityError({ value: yParity })
}
export declare namespace yParityToV {
type ErrorType = InvalidVError | Errors.GlobalErrorType
}
/** Thrown when the serialized signature is of an invalid size. */
export class InvalidSerializedSizeError extends Errors.BaseError {
override readonly name = 'Signature.InvalidSerializedSizeError'
constructor({ signature }: { signature: Hex.Hex | Bytes.Bytes }) {
super(`Value \`${signature}\` is an invalid signature size.`, {
metaMessages: [
'Expected: 64 bytes or 65 bytes.',
`Received ${Hex.size(Hex.from(signature))} bytes.`,
],
})
}
}
/** Thrown when the signature is missing either an `r`, `s`, or `yParity` property. */
export class MissingPropertiesError extends Errors.BaseError {
override readonly name = 'Signature.MissingPropertiesError'
constructor({ signature }: { signature: unknown }) {
super(
`Signature \`${Json.stringify(signature)}\` is missing either an \`r\`, \`s\`, or \`yParity\` property.`,
)
}
}
/** Thrown when the signature has an invalid `r` value. */
export class InvalidRError extends Errors.BaseError {
override readonly name = 'Signature.InvalidRError'
constructor({ value }: { value: unknown }) {
super(
`Value \`${value}\` is an invalid r value. r must be a positive integer less than 2^256.`,
)
}
}
/** Thrown when the signature has an invalid `s` value. */
export class InvalidSError extends Errors.BaseError {
override readonly name = 'Signature.InvalidSError'
constructor({ value }: { value: unknown }) {
super(
`Value \`${value}\` is an invalid s value. s must be a positive integer less than 2^256.`,
)
}
}
/** Thrown when the signature has an invalid `yParity` value. */
export class InvalidYParityError extends Errors.BaseError {
override readonly name = 'Signature.InvalidYParityError'
constructor({ value }: { value: unknown }) {
super(
`Value \`${value}\` is an invalid y-parity value. Y-parity must be 0 or 1.`,
)
}
}
/** Thrown when the signature has an invalid `v` value. */
export class InvalidVError extends Errors.BaseError {
override readonly name = 'Signature.InvalidVError'
constructor({ value }: { value: number }) {
super(`Value \`${value}\` is an invalid v value. v must be 27, 28 or >=35.`)
}
}

512
node_modules/ox/core/Siwe.ts generated vendored Normal file
View File

@@ -0,0 +1,512 @@
import * as Address from './Address.js'
import * as Errors from './Errors.js'
import type { ExactPartial } from './internal/types.js'
import { uid } from './internal/uid.js'
export const domainRegex =
/^([a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}(:[0-9]{1,5})?$/
export const ipRegex =
/^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(:[0-9]{1,5})?$/
export const localhostRegex = /^localhost(:[0-9]{1,5})?$/
export const nonceRegex = /^[a-zA-Z0-9]{8,}$/
export const schemeRegex = /^([a-zA-Z][a-zA-Z0-9+-.]*)$/
// https://regexr.com/80gdj
export const prefixRegex =
/^(?:(?<scheme>[a-zA-Z][a-zA-Z0-9+-.]*):\/\/)?(?<domain>[a-zA-Z0-9+-.]*(?::[0-9]{1,5})?) (?:wants you to sign in with your Ethereum account:\n)(?<address>0x[a-fA-F0-9]{40})\n\n(?:(?<statement>.*)\n\n)?/
// https://regexr.com/80gf9
export const suffixRegex =
/(?:URI: (?<uri>.+))\n(?:Version: (?<version>.+))\n(?:Chain ID: (?<chainId>\d+))\n(?:Nonce: (?<nonce>[a-zA-Z0-9]+))\n(?:Issued At: (?<issuedAt>.+))(?:\nExpiration Time: (?<expirationTime>.+))?(?:\nNot Before: (?<notBefore>.+))?(?:\nRequest ID: (?<requestId>.+))?/
/** [EIP-4361](https://eips.ethereum.org/EIPS/eip-4361) message fields. */
export type Message = {
/**
* The Ethereum address performing the signing.
*/
address: Address.Address
/**
* The [EIP-155](https://eips.ethereum.org/EIPS/eip-155) Chain ID to which the session is bound,
*/
chainId: number
/**
* [RFC 3986](https://www.rfc-editor.org/rfc/rfc3986) authority that is requesting the signing.
*/
domain: string
/**
* Time when the signed authentication message is no longer valid.
*/
expirationTime?: Date | undefined
/**
* Time when the message was generated, typically the current time.
*/
issuedAt?: Date | undefined
/**
* A random string typically chosen by the relying party and used to prevent replay attacks.
*/
nonce: string
/**
* Time when the signed authentication message will become valid.
*/
notBefore?: Date | undefined
/**
* A system-specific identifier that may be used to uniquely refer to the sign-in request.
*/
requestId?: string | undefined
/**
* A list of information or references to information the user wishes to have resolved as part of authentication by the relying party.
*/
resources?: string[] | undefined
/**
* [RFC 3986](https://www.rfc-editor.org/rfc/rfc3986#section-3.1) URI scheme of the origin of the request.
*/
scheme?: string | undefined
/**
* A human-readable ASCII assertion that the user will sign.
*/
statement?: string | undefined
/**
* [RFC 3986](https://www.rfc-editor.org/rfc/rfc3986) URI referring to the resource that is the subject of the signing (as in the subject of a claim).
*/
uri: string
/**
* The current version of the SIWE Message.
*/
version: '1'
}
/**
* Creates [EIP-4361](https://eips.ethereum.org/EIPS/eip-4361) formatted message.
*
* @example
* ```ts twoslash
* import { Siwe } from 'ox'
*
* Siwe.createMessage({
* address: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e',
* chainId: 1,
* domain: 'example.com',
* nonce: 'foobarbaz',
* uri: 'https://example.com/path',
* version: '1',
* })
* // @log: "example.com wants you to sign in with your Ethereum account:
* // @log: 0xA0Cf798816D4b9b9866b5330EEa46a18382f251e
* // @log:
* // @log:
* // @log: URI: https://example.com/path
* // @log: Version: 1
* // @log: Chain ID: 1
* // @log: Nonce: foobarbaz
* // @log: Issued At: 2023-02-01T00:00:00.000Z"
* ```
*
* @param value - Values to use when creating EIP-4361 formatted message.
* @returns EIP-4361 formatted message.
*/
export function createMessage(value: Message): string {
const {
chainId,
domain,
expirationTime,
issuedAt = new Date(),
nonce,
notBefore,
requestId,
resources,
scheme,
uri,
version,
} = value
// Validate fields
{
// Required fields
if (chainId !== Math.floor(chainId))
throw new InvalidMessageFieldError({
field: 'chainId',
metaMessages: [
'- Chain ID must be a EIP-155 chain ID.',
'- See https://eips.ethereum.org/EIPS/eip-155',
'',
`Provided value: ${chainId}`,
],
})
if (
!(
domainRegex.test(domain) ||
ipRegex.test(domain) ||
localhostRegex.test(domain)
)
)
throw new InvalidMessageFieldError({
field: 'domain',
metaMessages: [
'- Domain must be an RFC 3986 authority.',
'- See https://www.rfc-editor.org/rfc/rfc3986',
'',
`Provided value: ${domain}`,
],
})
if (!nonceRegex.test(nonce))
throw new InvalidMessageFieldError({
field: 'nonce',
metaMessages: [
'- Nonce must be at least 8 characters.',
'- Nonce must be alphanumeric.',
'',
`Provided value: ${nonce}`,
],
})
if (!isUri(uri))
throw new InvalidMessageFieldError({
field: 'uri',
metaMessages: [
'- URI must be a RFC 3986 URI referring to the resource that is the subject of the signing.',
'- See https://www.rfc-editor.org/rfc/rfc3986',
'',
`Provided value: ${uri}`,
],
})
if (version !== '1')
throw new InvalidMessageFieldError({
field: 'version',
metaMessages: [
"- Version must be '1'.",
'',
`Provided value: ${version}`,
],
})
// Optional fields
if (scheme && !schemeRegex.test(scheme))
throw new InvalidMessageFieldError({
field: 'scheme',
metaMessages: [
'- Scheme must be an RFC 3986 URI scheme.',
'- See https://www.rfc-editor.org/rfc/rfc3986#section-3.1',
'',
`Provided value: ${scheme}`,
],
})
const statement = value.statement
if (statement?.includes('\n'))
throw new InvalidMessageFieldError({
field: 'statement',
metaMessages: [
"- Statement must not include '\\n'.",
'',
`Provided value: ${statement}`,
],
})
}
// Construct message
const address = Address.from(value.address, { checksum: true })
const origin = (() => {
if (scheme) return `${scheme}://${domain}`
return domain
})()
const statement = (() => {
if (!value.statement) return ''
return `${value.statement}\n`
})()
const prefix = `${origin} wants you to sign in with your Ethereum account:\n${address}\n\n${statement}`
let suffix = `URI: ${uri}\nVersion: ${version}\nChain ID: ${chainId}\nNonce: ${nonce}\nIssued At: ${issuedAt.toISOString()}`
if (expirationTime)
suffix += `\nExpiration Time: ${expirationTime.toISOString()}`
if (notBefore) suffix += `\nNot Before: ${notBefore.toISOString()}`
if (requestId) suffix += `\nRequest ID: ${requestId}`
if (resources) {
let content = '\nResources:'
for (const resource of resources) {
if (!isUri(resource))
throw new InvalidMessageFieldError({
field: 'resources',
metaMessages: [
'- Every resource must be a RFC 3986 URI.',
'- See https://www.rfc-editor.org/rfc/rfc3986',
'',
`Provided value: ${resource}`,
],
})
content += `\n- ${resource}`
}
suffix += content
}
return `${prefix}\n${suffix}`
}
export declare namespace createMessage {
type ErrorType =
| Address.from.ErrorType
| InvalidMessageFieldError
| Errors.GlobalErrorType
}
/**
* Generates random [EIP-4361](https://eips.ethereum.org/EIPS/eip-4361) nonce.
*
* @example
* ```ts twoslash
* import { Siwe } from 'ox'
*
* Siwe.generateNonce()
* // @log: '65ed4681d4efe0270b923ff5f4b097b1c95974dc33aeebecd5724c42fd86dfd25dc70b27ef836b2aa22e68f19ebcccc1'
* ```
*
* @returns Random nonce.
*/
export function generateNonce(): string {
return uid(96)
}
/**
* Check if the given URI is a valid [RFC 3986](https://www.rfc-editor.org/rfc/rfc3986) URI.
*
* @example
* ```ts twoslash
* import { Siwe } from 'ox'
*
* Siwe.isUri('https://example.com/foo')
* // @log: true
* ```
*
* @param value - Value to check.
* @returns `false` if invalid, otherwise the valid URI.
*/
// based on https://github.com/ogt/valid-url
export function isUri(value: string): false | string {
// check for illegal characters
if (/[^a-z0-9\:\/\?\#\[\]\@\!\$\&\'\(\)\*\+\,\;\=\.\-\_\~\%]/i.test(value))
return false
// check for hex escapes that aren't complete
if (/%[^0-9a-f]/i.test(value)) return false
if (/%[0-9a-f](:?[^0-9a-f]|$)/i.test(value)) return false
// from RFC 3986
const splitted = splitUri(value)
const scheme = splitted[1]
const authority = splitted[2]
const path = splitted[3]
const query = splitted[4]
const fragment = splitted[5]
// scheme and path are required, though the path can be empty
if (!(scheme?.length && path && path.length >= 0)) return false
// if authority is present, the path must be empty or begin with a /
if (authority?.length) {
if (!(path.length === 0 || /^\//.test(path))) return false
} else {
// if authority is not present, the path must not start with //
if (/^\/\//.test(path)) return false
}
// scheme must begin with a letter, then consist of letters, digits, +, ., or -
if (!/^[a-z][a-z0-9\+\-\.]*$/.test(scheme.toLowerCase())) return false
let out = ''
// re-assemble the URL per section 5.3 in RFC 3986
out += `${scheme}:`
if (authority?.length) out += `//${authority}`
out += path
if (query?.length) out += `?${query}`
if (fragment?.length) out += `#${fragment}`
return out
}
function splitUri(value: string) {
return value.match(
/(?:([^:\/?#]+):)?(?:\/\/([^\/?#]*))?([^?#]*)(?:\?([^#]*))?(?:#(.*))?/,
)!
}
/**
* [EIP-4361](https://eips.ethereum.org/EIPS/eip-4361) formatted message into message fields object.
*
* @example
* ```ts twoslash
* import { Siwe } from 'ox'
*
* Siwe.parseMessage(`example.com wants you to sign in with your Ethereum account:
* 0xA0Cf798816D4b9b9866b5330EEa46a18382f251e
*
* I accept the ExampleOrg Terms of Service: https://example.com/tos
*
* URI: https://example.com/path
* Version: 1
* Chain ID: 1
* Nonce: foobarbaz
* Issued At: 2023-02-01T00:00:00.000Z`)
* // @log: {
* // @log: address: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e',
* // @log: chainId: 1,
* // @log: domain: 'example.com',
* // @log: issuedAt: '2023-02-01T00:00:00.000Z',
* // @log: nonce: 'foobarbaz',
* // @log: statement: 'I accept the ExampleOrg Terms of Service: https://example.com/tos',
* // @log: uri: 'https://example.com/path',
* // @log: version: '1',
* // @log: }
* ```
*
* @param message - [EIP-4361](https://eips.ethereum.org/EIPS/eip-4361) formatted message.
* @returns Message fields object.
*/
export function parseMessage(message: string): ExactPartial<Message> {
const { scheme, statement, ...prefix } = (message.match(prefixRegex)
?.groups ?? {}) as {
address: Address.Address
domain: string
scheme?: string
statement?: string
}
const { chainId, expirationTime, issuedAt, notBefore, requestId, ...suffix } =
(message.match(suffixRegex)?.groups ?? {}) as {
chainId: string
expirationTime?: string
issuedAt?: string
nonce: string
notBefore?: string
requestId?: string
uri: string
version: '1'
}
const resources = message.split('Resources:')[1]?.split('\n- ').slice(1)
return {
...prefix,
...suffix,
...(chainId ? { chainId: Number(chainId) } : {}),
...(expirationTime ? { expirationTime: new Date(expirationTime) } : {}),
...(issuedAt ? { issuedAt: new Date(issuedAt) } : {}),
...(notBefore ? { notBefore: new Date(notBefore) } : {}),
...(requestId ? { requestId } : {}),
...(resources ? { resources } : {}),
...(scheme ? { scheme } : {}),
...(statement ? { statement } : {}),
}
}
/**
* Validates [EIP-4361](https://eips.ethereum.org/EIPS/eip-4361) message.
*
* @example
* ```ts twoslash
* import { Siwe } from 'ox'
*
* Siwe.validateMessage({
* address: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e',
* domain: 'example.com',
* message: {
* address: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e',
* chainId: 1,
* domain: 'example.com',
* nonce: 'foobarbaz',
* uri: 'https://example.com/path',
* version: '1',
* },
* nonce: 'foobarbaz',
* })
* // @log: true
* ```
*
* @param value - Values to use when validating EIP-4361 formatted message.
* @returns Whether the message is valid.
*/
export function validateMessage(value: validateMessage.Value): boolean {
const { address, domain, message, nonce, scheme, time = new Date() } = value
if (domain && message.domain !== domain) return false
if (nonce && message.nonce !== nonce) return false
if (scheme && message.scheme !== scheme) return false
if (message.expirationTime && time >= message.expirationTime) return false
if (message.notBefore && time < message.notBefore) return false
try {
if (!message.address) return false
if (address && !Address.isEqual(message.address, address)) return false
} catch {
return false
}
return true
}
export declare namespace validateMessage {
interface Value {
/**
* Ethereum address to check against.
*/
address?: Address.Address | undefined
/**
* [RFC 3986](https://www.rfc-editor.org/rfc/rfc3986) authority to check against.
*/
domain?: string | undefined
/**
* EIP-4361 message fields.
*/
message: ExactPartial<Message>
/**
* Random string to check against.
*/
nonce?: string | undefined
/**
* [RFC 3986](https://www.rfc-editor.org/rfc/rfc3986#section-3.1) URI scheme to check against.
*/
scheme?: string | undefined
/**
* Current time to check optional `expirationTime` and `notBefore` fields.
*
* @default new Date()
*/
time?: Date | undefined
}
}
/**
* Thrown when a field in a SIWE Message is invalid.
*
* @example
* ```ts twoslash
* import { Siwe } from 'ox'
*
* Siwe.createMessage({
* address: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e',
* chainId: 1.1,
* domain: 'example.com',
* nonce: 'foobarbaz',
* uri: 'https://example.com/path',
* version: '1',
* })
* // @error: Siwe.InvalidMessageFieldError: Invalid Sign-In with Ethereum message field "chainId".
* // @error: - Chain ID must be a EIP-155 chain ID.
* // @error: - See https://eips.ethereum.org/EIPS/eip-155
* // @error: Provided value: 1.1
* ```
*/
export class InvalidMessageFieldError extends Errors.BaseError {
override readonly name = 'Siwe.InvalidMessageFieldError'
constructor(parameters: {
field: string
metaMessages?: string[] | undefined
}) {
const { field, metaMessages } = parameters
super(`Invalid Sign-In with Ethereum message field "${field}".`, {
metaMessages,
})
}
}

109
node_modules/ox/core/Solidity.ts generated vendored Normal file
View File

@@ -0,0 +1,109 @@
export const arrayRegex = /^(.*)\[([0-9]*)\]$/
// `bytes<M>`: binary type of `M` bytes, `0 < M <= 32`
// https://regexr.com/6va55
export const bytesRegex = /^bytes([1-9]|1[0-9]|2[0-9]|3[0-2])?$/
// `(u)int<M>`: (un)signed integer type of `M` bits, `0 < M <= 256`, `M % 8 == 0`
// https://regexr.com/6v8hp
export const integerRegex =
/^(u?int)(8|16|24|32|40|48|56|64|72|80|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256)?$/
export const maxInt8 = 2n ** (8n - 1n) - 1n
export const maxInt16 = 2n ** (16n - 1n) - 1n
export const maxInt24 = 2n ** (24n - 1n) - 1n
export const maxInt32 = 2n ** (32n - 1n) - 1n
export const maxInt40 = 2n ** (40n - 1n) - 1n
export const maxInt48 = 2n ** (48n - 1n) - 1n
export const maxInt56 = 2n ** (56n - 1n) - 1n
export const maxInt64 = 2n ** (64n - 1n) - 1n
export const maxInt72 = 2n ** (72n - 1n) - 1n
export const maxInt80 = 2n ** (80n - 1n) - 1n
export const maxInt88 = 2n ** (88n - 1n) - 1n
export const maxInt96 = 2n ** (96n - 1n) - 1n
export const maxInt104 = 2n ** (104n - 1n) - 1n
export const maxInt112 = 2n ** (112n - 1n) - 1n
export const maxInt120 = 2n ** (120n - 1n) - 1n
export const maxInt128 = 2n ** (128n - 1n) - 1n
export const maxInt136 = 2n ** (136n - 1n) - 1n
export const maxInt144 = 2n ** (144n - 1n) - 1n
export const maxInt152 = 2n ** (152n - 1n) - 1n
export const maxInt160 = 2n ** (160n - 1n) - 1n
export const maxInt168 = 2n ** (168n - 1n) - 1n
export const maxInt176 = 2n ** (176n - 1n) - 1n
export const maxInt184 = 2n ** (184n - 1n) - 1n
export const maxInt192 = 2n ** (192n - 1n) - 1n
export const maxInt200 = 2n ** (200n - 1n) - 1n
export const maxInt208 = 2n ** (208n - 1n) - 1n
export const maxInt216 = 2n ** (216n - 1n) - 1n
export const maxInt224 = 2n ** (224n - 1n) - 1n
export const maxInt232 = 2n ** (232n - 1n) - 1n
export const maxInt240 = 2n ** (240n - 1n) - 1n
export const maxInt248 = 2n ** (248n - 1n) - 1n
export const maxInt256 = 2n ** (256n - 1n) - 1n
export const minInt8 = -(2n ** (8n - 1n))
export const minInt16 = -(2n ** (16n - 1n))
export const minInt24 = -(2n ** (24n - 1n))
export const minInt32 = -(2n ** (32n - 1n))
export const minInt40 = -(2n ** (40n - 1n))
export const minInt48 = -(2n ** (48n - 1n))
export const minInt56 = -(2n ** (56n - 1n))
export const minInt64 = -(2n ** (64n - 1n))
export const minInt72 = -(2n ** (72n - 1n))
export const minInt80 = -(2n ** (80n - 1n))
export const minInt88 = -(2n ** (88n - 1n))
export const minInt96 = -(2n ** (96n - 1n))
export const minInt104 = -(2n ** (104n - 1n))
export const minInt112 = -(2n ** (112n - 1n))
export const minInt120 = -(2n ** (120n - 1n))
export const minInt128 = -(2n ** (128n - 1n))
export const minInt136 = -(2n ** (136n - 1n))
export const minInt144 = -(2n ** (144n - 1n))
export const minInt152 = -(2n ** (152n - 1n))
export const minInt160 = -(2n ** (160n - 1n))
export const minInt168 = -(2n ** (168n - 1n))
export const minInt176 = -(2n ** (176n - 1n))
export const minInt184 = -(2n ** (184n - 1n))
export const minInt192 = -(2n ** (192n - 1n))
export const minInt200 = -(2n ** (200n - 1n))
export const minInt208 = -(2n ** (208n - 1n))
export const minInt216 = -(2n ** (216n - 1n))
export const minInt224 = -(2n ** (224n - 1n))
export const minInt232 = -(2n ** (232n - 1n))
export const minInt240 = -(2n ** (240n - 1n))
export const minInt248 = -(2n ** (248n - 1n))
export const minInt256 = -(2n ** (256n - 1n))
export const maxUint8 = 2n ** 8n - 1n
export const maxUint16 = 2n ** 16n - 1n
export const maxUint24 = 2n ** 24n - 1n
export const maxUint32 = 2n ** 32n - 1n
export const maxUint40 = 2n ** 40n - 1n
export const maxUint48 = 2n ** 48n - 1n
export const maxUint56 = 2n ** 56n - 1n
export const maxUint64 = 2n ** 64n - 1n
export const maxUint72 = 2n ** 72n - 1n
export const maxUint80 = 2n ** 80n - 1n
export const maxUint88 = 2n ** 88n - 1n
export const maxUint96 = 2n ** 96n - 1n
export const maxUint104 = 2n ** 104n - 1n
export const maxUint112 = 2n ** 112n - 1n
export const maxUint120 = 2n ** 120n - 1n
export const maxUint128 = 2n ** 128n - 1n
export const maxUint136 = 2n ** 136n - 1n
export const maxUint144 = 2n ** 144n - 1n
export const maxUint152 = 2n ** 152n - 1n
export const maxUint160 = 2n ** 160n - 1n
export const maxUint168 = 2n ** 168n - 1n
export const maxUint176 = 2n ** 176n - 1n
export const maxUint184 = 2n ** 184n - 1n
export const maxUint192 = 2n ** 192n - 1n
export const maxUint200 = 2n ** 200n - 1n
export const maxUint208 = 2n ** 208n - 1n
export const maxUint216 = 2n ** 216n - 1n
export const maxUint224 = 2n ** 224n - 1n
export const maxUint232 = 2n ** 232n - 1n
export const maxUint240 = 2n ** 240n - 1n
export const maxUint248 = 2n ** 248n - 1n
export const maxUint256 = 2n ** 256n - 1n

131
node_modules/ox/core/StateOverrides.ts generated vendored Normal file
View File

@@ -0,0 +1,131 @@
import type * as Address from './Address.js'
import * as Hex from './Hex.js'
import type { Compute, OneOf } from './internal/types.js'
/**
* State override set to specify state to be ephemerally overridden prior to executing a call.
*/
export type StateOverrides<bigintType = bigint> = Compute<{
[address: Address.Address]: AccountOverrides<bigintType>
}>
/**
* RPC state overrides.
*/
export type Rpc = StateOverrides<Hex.Hex>
/**
* Details of an account to be overridden.
*/
export type AccountOverrides<bigintType = bigint> = Compute<
{
/** Balance to set for the account. */
balance?: bigintType | undefined
/** Code to set for the account. */
code?: Hex.Hex | undefined
/** Address to move the precompile to. */
movePrecompileToAddress?: Address.Address | undefined
/** Nonce to set for the account. */
nonce?: bigintType | undefined
} & OneOf<
| {
/** Key-value mapping to override all slots in the account storage. */
state?: AccountStorage | undefined
}
| {
/** Key-value mapping to override individual slots in the account storage. */
stateDiff?: AccountStorage | undefined
}
>
>
/**
* RPC account overrides.
*/
export type RpcAccountOverrides = AccountOverrides<Hex.Hex>
/**
* Key-value mapping to override all slots in the account storage before executing the call.
*/
export type AccountStorage = Compute<{
[slot: Hex.Hex]: Hex.Hex
}>
/**
* Converts an {@link ox#StateOverrides.Rpc} to an {@link ox#StateOverrides.StateOverrides}.
*
* @example
* ```ts twoslash
* import { StateOverrides } from 'ox'
*
* const stateOverrides = StateOverrides.fromRpc({
* '0x0000000000000000000000000000000000000000': {
* balance: '0x1',
* },
* })
* ```
*
* @param rpcStateOverrides - The RPC state overrides to convert.
* @returns An instantiated {@link ox#StateOverrides.StateOverrides}.
*/
export function fromRpc(rpcStateOverrides: Rpc): StateOverrides {
const stateOverrides: StateOverrides = {}
for (const [address, accountOverridesRpc] of Object.entries(
rpcStateOverrides,
)) {
const accountOverrides: AccountOverrides = {}
if (accountOverridesRpc.balance)
accountOverrides.balance = BigInt(accountOverridesRpc.balance)
if (accountOverridesRpc.code)
accountOverrides.code = accountOverridesRpc.code
if (accountOverridesRpc.movePrecompileToAddress)
accountOverrides.movePrecompileToAddress =
accountOverridesRpc.movePrecompileToAddress
if (accountOverridesRpc.nonce)
accountOverrides.nonce = BigInt(accountOverridesRpc.nonce)
if (accountOverridesRpc.state)
accountOverrides.state = accountOverridesRpc.state
if (accountOverridesRpc.stateDiff)
accountOverrides.stateDiff = accountOverridesRpc.stateDiff
;(stateOverrides as any)[address] = accountOverrides
}
return stateOverrides
}
/**
* Converts an {@link ox#StateOverrides.StateOverrides} to an {@link ox#StateOverrides.Rpc}.
*
* @example
* ```ts twoslash
* import { StateOverrides } from 'ox'
*
* const stateOverrides = StateOverrides.toRpc({
* '0x0000000000000000000000000000000000000000': {
* balance: 1n,
* },
* })
* ```
*
* @param stateOverrides - The state overrides to convert.
* @returns An instantiated {@link ox#StateOverrides.Rpc}.
*/
export function toRpc(stateOverrides: StateOverrides): Rpc {
const rpcStateOverrides: Rpc = {}
for (const [address, accountOverrides] of Object.entries(stateOverrides)) {
const accountOverridesRpc: RpcAccountOverrides = {}
if (typeof accountOverrides.balance === 'bigint')
accountOverridesRpc.balance = Hex.fromNumber(accountOverrides.balance)
if (accountOverrides.code) accountOverridesRpc.code = accountOverrides.code
if (accountOverrides.movePrecompileToAddress)
accountOverridesRpc.movePrecompileToAddress =
accountOverrides.movePrecompileToAddress
if (typeof accountOverrides.nonce === 'bigint')
accountOverridesRpc.nonce = Hex.fromNumber(accountOverrides.nonce)
if (accountOverrides.state)
accountOverridesRpc.state = accountOverrides.state
if (accountOverrides.stateDiff)
accountOverridesRpc.stateDiff = accountOverrides.stateDiff
;(rpcStateOverrides as any)[address] = accountOverridesRpc
}
return rpcStateOverrides
}

421
node_modules/ox/core/Transaction.ts generated vendored Normal file
View File

@@ -0,0 +1,421 @@
import type * as AccessList from './AccessList.js'
import type * as Address from './Address.js'
import * as Authorization from './Authorization.js'
import type * as Errors from './Errors.js'
import * as Hex from './Hex.js'
import * as Signature from './Signature.js'
import type { Compute, UnionCompute } from './internal/types.js'
import type { OneOf } from './internal/types.js'
/**
* A Transaction as defined in the [Execution API specification](https://github.com/ethereum/execution-apis/blob/main/src/schemas/transaction.yaml).
*/
export type Transaction<
pending extends boolean = false,
bigintType = bigint,
numberType = number,
> = UnionCompute<
OneOf<
| Legacy<pending, bigintType, numberType>
| Eip1559<pending, bigintType, numberType>
| Eip2930<pending, bigintType, numberType>
| Eip4844<pending, bigintType, numberType>
| Eip7702<pending, bigintType, numberType>
| (Base & { type: Hex.Hex })
>
>
/**
* An RPC Transaction as defined in the [Execution API specification](https://github.com/ethereum/execution-apis/blob/main/src/schemas/transaction.yaml).
*/
export type Rpc<pending extends boolean = false> = UnionCompute<
OneOf<
| LegacyRpc<pending>
| Eip1559Rpc<pending>
| Eip2930Rpc<pending>
| Eip4844Rpc<pending>
| Eip7702Rpc<pending>
| (BaseRpc & { type: Hex.Hex })
>
>
/** Base properties of a Transaction as defined in the [Execution API specification](https://github.com/ethereum/execution-apis/blob/main/src/schemas/transaction.yaml). */
export type Base<
type extends string = string,
pending extends boolean = false,
bigintType = bigint,
numberType = number,
> = Compute<{
/** Hash of the block that contains this transaction, or `null` if pending. */
blockHash: pending extends true ? null : Hex.Hex
/** Number of block containing this transaction or `null` if pending */
blockNumber: pending extends true ? null : bigintType
/** Chain ID that this transaction is valid on. */
chainId: numberType
/** @alias `input` Added for TransactionEnvelope - Transaction compatibility. */
data?: Hex.Hex | undefined
/** Sender of this transaction */
from: Address.Address
/** Hash of this transaction */
hash: Hex.Hex
/** Contract code or a hashed method call with encoded args */
input: Hex.Hex
/** Gas provided for transaction execution */
gas: bigintType
/** Unique number identifying this transaction */
nonce: bigintType
/** Transaction recipient. `null` if the transaction is a contract creation. */
to: Address.Address | null
/** Index of this transaction in the block or `null` if pending */
transactionIndex: pending extends true ? null : numberType
/** Transaction type */
type: type
/** Value in wei sent with this transaction */
value: bigintType
/** ECDSA signature r. */
r: bigintType
/** ECDSA signature s. */
s: bigintType
/** ECDSA signature yParity. */
yParity: numberType
/** @deprecated ECDSA signature v (for backwards compatibility). */
v?: numberType | undefined
}>
/** Base properties of an RPC Transaction as defined in the [Execution API specification](https://github.com/ethereum/execution-apis/blob/main/src/schemas/transaction.yaml). */
export type BaseRpc<
type extends string = string,
pending extends boolean = false,
> = Base<type, pending, Hex.Hex, Hex.Hex>
/** An [EIP-1559](https://eips.ethereum.org/EIPS/eip-1559) Transaction as defined in the [Execution API specification](https://github.com/ethereum/execution-apis/blob/main/src/schemas/transaction.yaml). */
export type Eip1559<
pending extends boolean = false,
bigintType = bigint,
numberType = number,
type extends string = 'eip1559',
> = Compute<
Base<type, pending, bigintType, numberType> & {
/** EIP-2930 Access List. */
accessList: AccessList.AccessList
/** Effective gas price paid by the sender in wei. */
gasPrice?: bigintType | undefined
/** Total fee per gas in wei (gasPrice/baseFeePerGas + maxPriorityFeePerGas). */
maxFeePerGas: bigintType
/** Max priority fee per gas (in wei). */
maxPriorityFeePerGas: bigintType
}
>
/** An [EIP-1559](https://eips.ethereum.org/EIPS/eip-1559) RPC Transaction as defined in the [Execution API specification](https://github.com/ethereum/execution-apis/blob/main/src/schemas/transaction.yaml). */
export type Eip1559Rpc<pending extends boolean = false> = Compute<
Eip1559<pending, Hex.Hex, Hex.Hex, ToRpcType['eip1559']>
>
/** An [EIP-2930](https://eips.ethereum.org/EIPS/eip-2930) Transaction as defined in the [Execution API specification](https://github.com/ethereum/execution-apis/blob/main/src/schemas/transaction.yaml). */
export type Eip2930<
pending extends boolean = false,
bigintType = bigint,
numberType = number,
type extends string = 'eip2930',
> = Compute<
Base<type, pending, bigintType, numberType> & {
/** EIP-2930 Access List. */
accessList: AccessList.AccessList
/** The gas price willing to be paid by the sender (in wei). */
gasPrice: bigintType
}
>
/** An RPC [EIP-2930](https://eips.ethereum.org/EIPS/eip-2930) Transaction as defined in the [Execution API specification](https://github.com/ethereum/execution-apis/blob/main/src/schemas/transaction.yaml). */
export type Eip2930Rpc<pending extends boolean = false> = Compute<
Eip2930<pending, Hex.Hex, Hex.Hex, ToRpcType['eip2930']>
>
/** An [EIP-4844](https://eips.ethereum.org/EIPS/eip-4844) Transaction as defined in the [Execution API specification](https://github.com/ethereum/execution-apis/blob/main/src/schemas/transaction.yaml). */
export type Eip4844<
pending extends boolean = false,
bigintType = bigint,
numberType = number,
type extends string = 'eip4844',
> = Compute<
Base<type, pending, bigintType, numberType> & {
/** EIP-2930 Access List. */
accessList: AccessList.AccessList
/** List of versioned blob hashes associated with the transaction's blobs. */
blobVersionedHashes: readonly Hex.Hex[]
/** Total fee per blob gas in wei. */
maxFeePerBlobGas: bigintType
/** Total fee per gas in wei (gasPrice/baseFeePerGas + maxPriorityFeePerGas). */
maxFeePerGas: bigintType
/** Max priority fee per gas (in wei). */
maxPriorityFeePerGas: bigintType
}
>
/** An RPC [EIP-4844](https://eips.ethereum.org/EIPS/eip-4844) Transaction as defined in the [Execution API specification](https://github.com/ethereum/execution-apis/blob/main/src/schemas/transaction.yaml). */
export type Eip4844Rpc<pending extends boolean = false> = Compute<
Eip4844<pending, Hex.Hex, Hex.Hex, ToRpcType['eip4844']>
>
/** An [EIP-7702](https://eips.ethereum.org/EIPS/eip-7702) Transaction as defined in the [Execution API specification](https://github.com/ethereum/execution-apis/blob/main/src/schemas/transaction.yaml). */
export type Eip7702<
pending extends boolean = false,
bigintType = bigint,
numberType = number,
type extends string = 'eip7702',
> = Compute<
Base<type, pending, bigintType, numberType> & {
/** EIP-2930 Access List. */
accessList: AccessList.AccessList
/** EIP-7702 Authorization list for the transaction. */
authorizationList: Authorization.ListSigned<bigintType, numberType>
/** Total fee per gas in wei (gasPrice/baseFeePerGas + maxPriorityFeePerGas). */
maxFeePerGas: bigintType
/** Max priority fee per gas (in wei). */
maxPriorityFeePerGas: bigintType
}
>
/** An RPC [EIP-7702](https://eips.ethereum.org/EIPS/eip-7702) Transaction as defined in the [Execution API specification](https://github.com/ethereum/execution-apis/blob/main/src/schemas/transaction.yaml). */
export type Eip7702Rpc<pending extends boolean = false> = Compute<
Eip7702<pending, Hex.Hex, Hex.Hex, ToRpcType['eip7702']>
>
/** An legacy Transaction as defined in the [Execution API specification](https://github.com/ethereum/execution-apis/blob/main/src/schemas/transaction.yaml). */
export type Legacy<
pending extends boolean = false,
bigintType = bigint,
numberType = number,
type extends string = 'legacy',
> = Compute<
Omit<
Base<type, pending, bigintType, numberType>,
'chainId' | 'v' | 'yParity'
> & {
chainId?: numberType | undefined
/** The gas price willing to be paid by the sender (in wei). */
gasPrice: bigintType
/** ECDSA signature v. */
v: numberType
/** ECDSA signature yParity. */
yParity?: numberType | undefined
}
>
/** A legacy RPC Transaction as defined in the [Execution API specification](https://github.com/ethereum/execution-apis/blob/main/src/schemas/transaction.yaml). */
export type LegacyRpc<pending extends boolean = false> = Compute<
Legacy<pending, Hex.Hex, Hex.Hex, ToRpcType['legacy']>
>
/** Type to RPC Type mapping. */
export const toRpcType = {
legacy: '0x0',
eip2930: '0x1',
eip1559: '0x2',
eip4844: '0x3',
eip7702: '0x4',
} as const
/** Type to RPC Type mapping. */
export type ToRpcType = typeof toRpcType & {
[type: string]: `0x${string}`
}
/** RPC Type to Type mapping. */
export const fromRpcType = {
'0x0': 'legacy',
'0x1': 'eip2930',
'0x2': 'eip1559',
'0x3': 'eip4844',
'0x4': 'eip7702',
} as const
/** RPC Type to Type mapping. */
export type FromRpcType = typeof fromRpcType & {
[type: `0x${string}`]: string
}
/**
* Converts an {@link ox#Transaction.Rpc} to an {@link ox#Transaction.Transaction}.
*
* @example
* ```ts twoslash
* import { Transaction } from 'ox'
*
* const transaction = Transaction.fromRpc({
* hash: '0x353fdfc38a2f26115daadee9f5b8392ce62b84f410957967e2ed56b35338cdd0',
* nonce: '0x357',
* blockHash:
* '0xc350d807505fb835650f0013632c5515592987ba169bbc6626d9fc54d91f0f0b',
* blockNumber: '0x12f296f',
* transactionIndex: '0x2',
* from: '0x814e5e0e31016b9a7f138c76b7e7b2bb5c1ab6a6',
* to: '0x3fc91a3afd70395cd496c647d5a6cc9d4b2b7fad',
* value: '0x9b6e64a8ec60000',
* gas: '0x43f5d',
* maxFeePerGas: '0x2ca6ae494',
* maxPriorityFeePerGas: '0x41cc3c0',
* input:
* '0x3593564c000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000006643504700000000000000000000000000000000000000000000000000000000000000040b080604000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000009b6e64a8ec600000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000009b6e64a8ec60000000000000000000000000000000000000000000000000000019124bb5ae978c000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000c56c7a0eaa804f854b536a5f3d5f49d2ec4b12b80000000000000000000000000000000000000000000000000000000000000060000000000000000000000000c56c7a0eaa804f854b536a5f3d5f49d2ec4b12b8000000000000000000000000000000fee13a103a10d593b9ae06b3e05f2e7e1c00000000000000000000000000000000000000000000000000000000000000190000000000000000000000000000000000000000000000000000000000000060000000000000000000000000c56c7a0eaa804f854b536a5f3d5f49d2ec4b12b800000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000190240001b9872b',
* r: '0x635dc2033e60185bb36709c29c75d64ea51dfbd91c32ef4be198e4ceb169fb4d',
* s: '0x50c2667ac4c771072746acfdcf1f1483336dcca8bd2df47cd83175dbe60f0540',
* yParity: '0x0',
* chainId: '0x1',
* accessList: [],
* type: '0x2',
* })
* ```
*
* @param transaction - The RPC transaction to convert.
* @returns An instantiated {@link ox#Transaction.Transaction}.
*/
export function fromRpc<
const transaction extends Rpc | null,
pending extends boolean = false,
>(
transaction: transaction | Rpc<pending> | null,
_options: fromRpc.Options<pending> = {},
): transaction extends Rpc<pending> ? Transaction<pending> : null {
if (!transaction) return null as never
const signature = Signature.extract(transaction)
const transaction_ = {
...transaction,
...signature,
} as unknown as Transaction<boolean>
transaction_.blockNumber = transaction.blockNumber
? BigInt(transaction.blockNumber)
: null
transaction_.data = transaction.input
transaction_.gas = BigInt(transaction.gas ?? 0n)
transaction_.nonce = BigInt(transaction.nonce ?? 0n)
transaction_.transactionIndex = transaction.transactionIndex
? Number(transaction.transactionIndex)
: null
transaction_.value = BigInt(transaction.value ?? 0n)
if (transaction.authorizationList)
transaction_.authorizationList = Authorization.fromRpcList(
transaction.authorizationList,
)
if (transaction.chainId) transaction_.chainId = Number(transaction.chainId)
if (transaction.gasPrice) transaction_.gasPrice = BigInt(transaction.gasPrice)
if (transaction.maxFeePerBlobGas)
transaction_.maxFeePerBlobGas = BigInt(transaction.maxFeePerBlobGas)
if (transaction.maxFeePerGas)
transaction_.maxFeePerGas = BigInt(transaction.maxFeePerGas)
if (transaction.maxPriorityFeePerGas)
transaction_.maxPriorityFeePerGas = BigInt(transaction.maxPriorityFeePerGas)
if (transaction.type)
transaction_.type =
(fromRpcType as any)[transaction.type] ?? transaction.type
if (signature) transaction_.v = Signature.yParityToV(signature.yParity)
return transaction_ as never
}
export declare namespace fromRpc {
type Options<pending extends boolean = false> = {
pending?: pending | boolean | undefined
}
type ErrorType = Signature.extract.ErrorType | Errors.GlobalErrorType
}
/**
* Converts an {@link ox#Transaction.Transaction} to an {@link ox#Transaction.Rpc}.
*
* @example
* ```ts twoslash
* import { Transaction } from 'ox'
*
* const transaction = Transaction.toRpc({
* accessList: [],
* blockHash:
* '0xc350d807505fb835650f0013632c5515592987ba169bbc6626d9fc54d91f0f0b',
* blockNumber: 19868015n,
* chainId: 1,
* from: '0x814e5e0e31016b9a7f138c76b7e7b2bb5c1ab6a6',
* gas: 278365n,
* hash: '0x353fdfc38a2f26115daadee9f5b8392ce62b84f410957967e2ed56b35338cdd0',
* input:
* '0x3593564c000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000006643504700000000000000000000000000000000000000000000000000000000000000040b080604000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000009b6e64a8ec600000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000009b6e64a8ec60000000000000000000000000000000000000000000000000000019124bb5ae978c000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000c56c7a0eaa804f854b536a5f3d5f49d2ec4b12b80000000000000000000000000000000000000000000000000000000000000060000000000000000000000000c56c7a0eaa804f854b536a5f3d5f49d2ec4b12b8000000000000000000000000000000fee13a103a10d593b9ae06b3e05f2e7e1c00000000000000000000000000000000000000000000000000000000000000190000000000000000000000000000000000000000000000000000000000000060000000000000000000000000c56c7a0eaa804f854b536a5f3d5f49d2ec4b12b800000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000190240001b9872b',
* maxFeePerGas: 11985937556n,
* maxPriorityFeePerGas: 68993984n,
* nonce: 855n,
* r: 44944627813007772897391531230081695102703289123332187696115181104739239197517n,
* s: 36528503505192438307355164441104001310566505351980369085208178712678799181120n,
* to: '0x3fc91a3afd70395cd496c647d5a6cc9d4b2b7fad',
* transactionIndex: 2,
* type: 'eip1559',
* v: 27,
* value: 700000000000000000n,
* yParity: 0,
* })
* ```
*
* @param transaction - The transaction to convert.
* @returns An RPC-formatted transaction.
*/
export function toRpc<pending extends boolean = false>(
transaction: Transaction<pending>,
_options?: toRpc.Options<pending>,
): Rpc<pending> {
const rpc = {} as Rpc<boolean>
rpc.blockHash = transaction.blockHash
rpc.blockNumber =
typeof transaction.blockNumber === 'bigint'
? Hex.fromNumber(transaction.blockNumber)
: null
rpc.from = transaction.from
rpc.gas = Hex.fromNumber(transaction.gas ?? 0n)
rpc.hash = transaction.hash
rpc.input = transaction.input
rpc.nonce = Hex.fromNumber(transaction.nonce ?? 0n)
rpc.to = transaction.to
rpc.transactionIndex = transaction.transactionIndex
? Hex.fromNumber(transaction.transactionIndex)
: null
rpc.type = (toRpcType as any)[transaction.type] ?? transaction.type
rpc.value = Hex.fromNumber(transaction.value ?? 0n)
if (transaction.accessList) rpc.accessList = transaction.accessList
if (transaction.authorizationList)
rpc.authorizationList = Authorization.toRpcList(
transaction.authorizationList,
)
if (transaction.blobVersionedHashes)
rpc.blobVersionedHashes = transaction.blobVersionedHashes
if (transaction.chainId) rpc.chainId = Hex.fromNumber(transaction.chainId)
if (typeof transaction.gasPrice === 'bigint')
rpc.gasPrice = Hex.fromNumber(transaction.gasPrice)
if (typeof transaction.maxFeePerBlobGas === 'bigint')
rpc.maxFeePerBlobGas = Hex.fromNumber(transaction.maxFeePerBlobGas)
if (typeof transaction.maxFeePerGas === 'bigint')
rpc.maxFeePerGas = Hex.fromNumber(transaction.maxFeePerGas)
if (typeof transaction.maxPriorityFeePerGas === 'bigint')
rpc.maxPriorityFeePerGas = Hex.fromNumber(transaction.maxPriorityFeePerGas)
if (typeof transaction.r === 'bigint')
rpc.r = Hex.fromNumber(transaction.r, { size: 32 })
if (typeof transaction.s === 'bigint')
rpc.s = Hex.fromNumber(transaction.s, { size: 32 })
if (typeof transaction.v === 'number')
rpc.v = Hex.fromNumber(transaction.v, { size: 1 })
if (typeof transaction.yParity === 'number')
rpc.yParity = transaction.yParity === 0 ? '0x0' : '0x1'
return rpc as Rpc<pending>
}
export declare namespace toRpc {
type Options<pending extends boolean = false> = {
pending?: pending | boolean | undefined
}
type ErrorType = Signature.extract.ErrorType | Errors.GlobalErrorType
}

205
node_modules/ox/core/TransactionEnvelope.ts generated vendored Normal file
View File

@@ -0,0 +1,205 @@
import type * as Address from './Address.js'
import * as Errors from './Errors.js'
import type * as Hex from './Hex.js'
import * as Value from './Value.js'
import type { Compute } from './internal/types.js'
/** Base type for a Transaction Envelope. Transaction Envelopes inherit this type. */
export type Base<
type extends string = string,
signed extends boolean = boolean,
bigintType = bigint,
numberType = number,
> = Compute<
{
/** EIP-155 Chain ID. */
chainId: numberType
/** Contract code or a hashed method call with encoded args */
data?: Hex.Hex | undefined
/** @alias `data` added for TransactionEnvelope - Transaction compatibility. */
input?: Hex.Hex | undefined
/** Sender of the transaction. */
from?: Address.Address | undefined
/** Gas provided for transaction execution */
gas?: bigintType | undefined
/** Unique number identifying this transaction */
nonce?: bigintType | undefined
/** Transaction recipient */
to?: Address.Address | null | undefined
/** Transaction type */
type: type
/** Value in wei sent with this transaction */
value?: bigintType | undefined
/** ECDSA signature r. */
r?: bigintType | undefined
/** ECDSA signature s. */
s?: bigintType | undefined
/** ECDSA signature yParity. */
yParity?: numberType | undefined
/** @deprecated ECDSA signature v (for backwards compatibility). */
v?: numberType | undefined
} & (signed extends true ? { r: bigintType; s: bigintType } : {})
>
/** RPC representation of a {@link ox#(TransactionEnvelope:namespace).Base}. */
export type BaseRpc<
type extends string = string,
signed extends boolean = boolean,
> = Base<type, signed, Hex.Hex, Hex.Hex>
/** Signed representation of a {@link ox#(TransactionEnvelope:namespace).Base}. */
export type BaseSigned<type extends string = string> = Base<type, true>
/**
* Thrown when a fee cap is too high.
*
* @example
* ```ts twoslash
* import { TransactionEnvelopeEip1559 } from 'ox'
*
* TransactionEnvelopeEip1559.assert({
* maxFeePerGas: 2n ** 256n - 1n + 1n,
* chainId: 1,
* })
* // @error: TransactionEnvelope.FeeCapTooHighError: The fee cap (`maxFeePerGas`/`maxPriorityFeePerGas` = 115792089237316195423570985008687907853269984665640564039457584007913.129639936 gwei) cannot be higher than the maximum allowed value (2^256-1).
* ```
*/
export class FeeCapTooHighError extends Errors.BaseError {
override readonly name = 'TransactionEnvelope.FeeCapTooHighError'
constructor({
feeCap,
}: {
feeCap?: bigint | undefined
} = {}) {
super(
`The fee cap (\`maxFeePerGas\`/\`maxPriorityFeePerGas\`${
feeCap ? ` = ${Value.formatGwei(feeCap)} gwei` : ''
}) cannot be higher than the maximum allowed value (2^256-1).`,
)
}
}
/**
* Thrown when a gas price is too high.
*
* @example
* ```ts twoslash
* import { TransactionEnvelopeLegacy } from 'ox'
*
* TransactionEnvelopeLegacy.assert({
* gasPrice: 2n ** 256n - 1n + 1n,
* chainId: 1,
* })
* // @error: TransactionEnvelope.GasPriceTooHighError: The gas price (`gasPrice` = 115792089237316195423570985008687907853269984665640564039457584007913.129639936 gwei) cannot be higher than the maximum allowed value (2^256-1).
* ```
*/
export class GasPriceTooHighError extends Errors.BaseError {
override readonly name = 'TransactionEnvelope.GasPriceTooHighError'
constructor({
gasPrice,
}: {
gasPrice?: bigint | undefined
} = {}) {
super(
`The gas price (\`gasPrice\`${
gasPrice ? ` = ${Value.formatGwei(gasPrice)} gwei` : ''
}) cannot be higher than the maximum allowed value (2^256-1).`,
)
}
}
/**
* Thrown when a chain ID is invalid.
*
* @example
* ```ts twoslash
* import { TransactionEnvelopeEip1559 } from 'ox'
*
* TransactionEnvelopeEip1559.assert({ chainId: 0 })
* // @error: TransactionEnvelope.InvalidChainIdError: Chain ID "0" is invalid.
* ```
*/
export class InvalidChainIdError extends Errors.BaseError {
override readonly name = 'TransactionEnvelope.InvalidChainIdError'
constructor({ chainId }: { chainId?: number | undefined }) {
super(
typeof chainId !== 'undefined'
? `Chain ID "${chainId}" is invalid.`
: 'Chain ID is invalid.',
)
}
}
/**
* Thrown when a serialized transaction is invalid.
*
* @example
* ```ts twoslash
* import { TransactionEnvelopeEip1559 } from 'ox'
*
* TransactionEnvelopeEip1559.deserialize('0x02c0')
* // @error: TransactionEnvelope.InvalidSerializedError: Invalid serialized transaction of type "eip1559" was provided.
* // @error: Serialized Transaction: "0x02c0"
* // @error: Missing Attributes: chainId, nonce, maxPriorityFeePerGas, maxFeePerGas, gas, to, value, data, accessList
* ```
*/
export class InvalidSerializedError extends Errors.BaseError {
override readonly name = 'TransactionEnvelope.InvalidSerializedError'
constructor({
attributes,
serialized,
type,
}: {
attributes: Record<string, unknown>
serialized: Hex.Hex
type: string
}) {
const missing = Object.entries(attributes)
.map(([key, value]) => (typeof value === 'undefined' ? key : undefined))
.filter(Boolean)
super(`Invalid serialized transaction of type "${type}" was provided.`, {
metaMessages: [
`Serialized Transaction: "${serialized}"`,
missing.length > 0 ? `Missing Attributes: ${missing.join(', ')}` : '',
].filter(Boolean),
})
}
}
/**
* Thrown when a tip is higher than a fee cap.
*
* @example
* ```ts twoslash
* import { TransactionEnvelopeEip1559 } from 'ox'
*
* TransactionEnvelopeEip1559.assert({
* chainId: 1,
* maxFeePerGas: 10n,
* maxPriorityFeePerGas: 11n,
* })
* // @error: TransactionEnvelope.TipAboveFeeCapError: The provided tip (`maxPriorityFeePerGas` = 11 gwei) cannot be higher than the fee cap (`maxFeePerGas` = 10 gwei).
* ```
*/
export class TipAboveFeeCapError extends Errors.BaseError {
override readonly name = 'TransactionEnvelope.TipAboveFeeCapError'
constructor({
maxPriorityFeePerGas,
maxFeePerGas,
}: {
maxPriorityFeePerGas?: bigint | undefined
maxFeePerGas?: bigint | undefined
} = {}) {
super(
[
`The provided tip (\`maxPriorityFeePerGas\`${
maxPriorityFeePerGas
? ` = ${Value.formatGwei(maxPriorityFeePerGas)} gwei`
: ''
}) cannot be higher than the fee cap (\`maxFeePerGas\`${
maxFeePerGas ? ` = ${Value.formatGwei(maxFeePerGas)} gwei` : ''
}).`,
].join('\n'),
)
}
}

626
node_modules/ox/core/TransactionEnvelopeEip1559.ts generated vendored Normal file
View File

@@ -0,0 +1,626 @@
import * as AccessList from './AccessList.js'
import * as Address from './Address.js'
import type * as Errors from './Errors.js'
import * as Hash from './Hash.js'
import * as Hex from './Hex.js'
import * as Rlp from './Rlp.js'
import * as Signature from './Signature.js'
import * as TransactionEnvelope from './TransactionEnvelope.js'
import type {
Assign,
Compute,
PartialBy,
UnionPartialBy,
} from './internal/types.js'
export type TransactionEnvelopeEip1559<
signed extends boolean = boolean,
bigintType = bigint,
numberType = number,
type extends string = Type,
> = Compute<
TransactionEnvelope.Base<type, signed, bigintType, numberType> & {
/** EIP-2930 Access List. */
accessList?: AccessList.AccessList | undefined
/** Total fee per gas in wei (gasPrice/baseFeePerGas + maxPriorityFeePerGas). */
maxFeePerGas?: bigintType | undefined
/** Max priority fee per gas (in wei). */
maxPriorityFeePerGas?: bigintType | undefined
}
>
export type Rpc<signed extends boolean = boolean> = TransactionEnvelopeEip1559<
signed,
Hex.Hex,
Hex.Hex,
'0x2'
>
export type Serialized = `${SerializedType}${string}`
export const serializedType = '0x02' as const
export type SerializedType = typeof serializedType
export type Signed = TransactionEnvelopeEip1559<true>
export const type = 'eip1559' as const
export type Type = typeof type
/**
* Asserts a {@link ox#TransactionEnvelopeEip1559.TransactionEnvelopeEip1559} is valid.
*
* @example
* ```ts twoslash
* import { TransactionEnvelopeEip1559, Value } from 'ox'
*
* TransactionEnvelopeEip1559.assert({
* maxFeePerGas: 2n ** 256n - 1n + 1n,
* chainId: 1,
* to: '0x0000000000000000000000000000000000000000',
* value: Value.fromEther('1'),
* })
* // @error: FeeCapTooHighError:
* // @error: The fee cap (`masFeePerGas` = 115792089237316195423570985008687907853269984665640564039457584007913 gwei) cannot be
* // @error: higher than the maximum allowed value (2^256-1).
* ```
*
* @param envelope - The transaction envelope to assert.
*/
export function assert(
envelope: PartialBy<TransactionEnvelopeEip1559, 'type'>,
) {
const { chainId, maxPriorityFeePerGas, maxFeePerGas, to } = envelope
if (chainId <= 0)
throw new TransactionEnvelope.InvalidChainIdError({ chainId })
if (to) Address.assert(to, { strict: false })
if (maxFeePerGas && BigInt(maxFeePerGas) > 2n ** 256n - 1n)
throw new TransactionEnvelope.FeeCapTooHighError({ feeCap: maxFeePerGas })
if (
maxPriorityFeePerGas &&
maxFeePerGas &&
maxPriorityFeePerGas > maxFeePerGas
)
throw new TransactionEnvelope.TipAboveFeeCapError({
maxFeePerGas,
maxPriorityFeePerGas,
})
}
export declare namespace assert {
type ErrorType =
| Address.assert.ErrorType
| TransactionEnvelope.InvalidChainIdError
| TransactionEnvelope.FeeCapTooHighError
| TransactionEnvelope.TipAboveFeeCapError
| Errors.GlobalErrorType
}
/**
* Deserializes a {@link ox#TransactionEnvelopeEip1559.TransactionEnvelopeEip1559} from its serialized form.
*
* @example
* ```ts twoslash
* import { TransactionEnvelopeEip1559 } from 'ox'
*
* const envelope = TransactionEnvelopeEip1559.deserialize('0x02ef0182031184773594008477359400809470997970c51812dc3a010c7d01b50e0d17dc79c8880de0b6b3a764000080c0')
* // @log: {
* // @log: type: 'eip1559',
* // @log: nonce: 785n,
* // @log: maxFeePerGas: 2000000000n,
* // @log: gas: 1000000n,
* // @log: to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
* // @log: value: 1000000000000000000n,
* // @log: }
* ```
*
* @param serialized - The serialized transaction.
* @returns Deserialized Transaction Envelope.
*/
export function deserialize(
serialized: Serialized,
): Compute<TransactionEnvelopeEip1559> {
const transactionArray = Rlp.toHex(Hex.slice(serialized, 1))
const [
chainId,
nonce,
maxPriorityFeePerGas,
maxFeePerGas,
gas,
to,
value,
data,
accessList,
yParity,
r,
s,
] = transactionArray as readonly Hex.Hex[]
if (!(transactionArray.length === 9 || transactionArray.length === 12))
throw new TransactionEnvelope.InvalidSerializedError({
attributes: {
chainId,
nonce,
maxPriorityFeePerGas,
maxFeePerGas,
gas,
to,
value,
data,
accessList,
...(transactionArray.length > 9
? {
yParity,
r,
s,
}
: {}),
},
serialized,
type,
})
let transaction = {
chainId: Number(chainId),
type,
} as TransactionEnvelopeEip1559
if (Hex.validate(to) && to !== '0x') transaction.to = to
if (Hex.validate(gas) && gas !== '0x') transaction.gas = BigInt(gas)
if (Hex.validate(data) && data !== '0x') transaction.data = data
if (Hex.validate(nonce) && nonce !== '0x') transaction.nonce = BigInt(nonce)
if (Hex.validate(value) && value !== '0x') transaction.value = BigInt(value)
if (Hex.validate(maxFeePerGas) && maxFeePerGas !== '0x')
transaction.maxFeePerGas = BigInt(maxFeePerGas)
if (Hex.validate(maxPriorityFeePerGas) && maxPriorityFeePerGas !== '0x')
transaction.maxPriorityFeePerGas = BigInt(maxPriorityFeePerGas)
if (accessList!.length !== 0 && accessList !== '0x')
transaction.accessList = AccessList.fromTupleList(accessList as any)
const signature =
r && s && yParity ? Signature.fromTuple([yParity, r, s]) : undefined
if (signature)
transaction = {
...transaction,
...signature,
} as TransactionEnvelopeEip1559
assert(transaction)
return transaction
}
export declare namespace deserialize {
type ErrorType = Errors.GlobalErrorType
}
/**
* Converts an arbitrary transaction object into an EIP-1559 Transaction Envelope.
*
* @example
* ```ts twoslash
* import { TransactionEnvelopeEip1559, Value } from 'ox'
*
* const envelope = TransactionEnvelopeEip1559.from({
* chainId: 1,
* maxFeePerGas: Value.fromGwei('10'),
* maxPriorityFeePerGas: Value.fromGwei('1'),
* to: '0x0000000000000000000000000000000000000000',
* value: Value.fromEther('1'),
* })
* ```
*
* @example
* ### Attaching Signatures
*
* It is possible to attach a `signature` to the transaction envelope.
*
* ```ts twoslash
* import { Secp256k1, TransactionEnvelopeEip1559, Value } from 'ox'
*
* const envelope = TransactionEnvelopeEip1559.from({
* chainId: 1,
* maxFeePerGas: Value.fromGwei('10'),
* maxPriorityFeePerGas: Value.fromGwei('1'),
* to: '0x0000000000000000000000000000000000000000',
* value: Value.fromEther('1'),
* })
*
* const signature = Secp256k1.sign({
* payload: TransactionEnvelopeEip1559.getSignPayload(envelope),
* privateKey: '0x...',
* })
*
* const envelope_signed = TransactionEnvelopeEip1559.from(envelope, { // [!code focus]
* signature, // [!code focus]
* }) // [!code focus]
* // @log: {
* // @log: chainId: 1,
* // @log: maxFeePerGas: 10000000000n,
* // @log: maxPriorityFeePerGas: 1000000000n,
* // @log: to: '0x0000000000000000000000000000000000000000',
* // @log: type: 'eip1559',
* // @log: value: 1000000000000000000n,
* // @log: r: 125...n,
* // @log: s: 642...n,
* // @log: yParity: 0,
* // @log: }
* ```
*
* @example
* ### From Serialized
*
* It is possible to instantiate an EIP-1559 Transaction Envelope from a {@link ox#TransactionEnvelopeEip1559.Serialized} value.
*
* ```ts twoslash
* import { TransactionEnvelopeEip1559 } from 'ox'
*
* const envelope = TransactionEnvelopeEip1559.from('0x02f858018203118502540be4008504a817c800809470997970c51812dc3a010c7d01b50e0d17dc79c8880de0b6b3a764000080c08477359400e1a001627c687261b0e7f8638af1112efa8a77e23656f6e7945275b19e9deed80261')
* // @log: {
* // @log: chainId: 1,
* // @log: maxFeePerGas: 10000000000n,
* // @log: maxPriorityFeePerGas: 1000000000n,
* // @log: to: '0x0000000000000000000000000000000000000000',
* // @log: type: 'eip1559',
* // @log: value: 1000000000000000000n,
* // @log: }
* ```
*
* @param envelope - The transaction object to convert.
* @param options - Options.
* @returns An EIP-1559 Transaction Envelope.
*/
export function from<
const envelope extends
| UnionPartialBy<TransactionEnvelopeEip1559, 'type'>
| Serialized,
const signature extends Signature.Signature | undefined = undefined,
>(
envelope:
| envelope
| UnionPartialBy<TransactionEnvelopeEip1559, 'type'>
| Serialized,
options: from.Options<signature> = {},
): from.ReturnType<envelope, signature> {
const { signature } = options
const envelope_ = (
typeof envelope === 'string' ? deserialize(envelope) : envelope
) as TransactionEnvelopeEip1559
assert(envelope_)
return {
...envelope_,
...(signature ? Signature.from(signature) : {}),
type: 'eip1559',
} as never
}
export declare namespace from {
type Options<signature extends Signature.Signature | undefined = undefined> =
{
signature?: signature | Signature.Signature | undefined
}
type ReturnType<
envelope extends
| UnionPartialBy<TransactionEnvelopeEip1559, 'type'>
| Hex.Hex = TransactionEnvelopeEip1559 | Hex.Hex,
signature extends Signature.Signature | undefined = undefined,
> = Compute<
envelope extends Hex.Hex
? TransactionEnvelopeEip1559
: Assign<
envelope,
(signature extends Signature.Signature ? Readonly<signature> : {}) & {
readonly type: 'eip1559'
}
>
>
type ErrorType =
| deserialize.ErrorType
| assert.ErrorType
| Errors.GlobalErrorType
}
/**
* Returns the payload to sign for a {@link ox#TransactionEnvelopeEip1559.TransactionEnvelopeEip1559}.
*
* @example
* The example below demonstrates how to compute the sign payload which can be used
* with ECDSA signing utilities like {@link ox#Secp256k1.(sign:function)}.
*
* ```ts twoslash
* import { Secp256k1, TransactionEnvelopeEip1559 } from 'ox'
*
* const envelope = TransactionEnvelopeEip1559.from({
* chainId: 1,
* nonce: 0n,
* maxFeePerGas: 1000000000n,
* gas: 21000n,
* to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
* value: 1000000000000000000n,
* })
*
* const payload = TransactionEnvelopeEip1559.getSignPayload(envelope) // [!code focus]
* // @log: '0x...'
*
* const signature = Secp256k1.sign({ payload, privateKey: '0x...' })
* ```
*
* @param envelope - The transaction envelope to get the sign payload for.
* @returns The sign payload.
*/
export function getSignPayload(
envelope: TransactionEnvelopeEip1559,
): getSignPayload.ReturnType {
return hash(envelope, { presign: true })
}
export declare namespace getSignPayload {
type ReturnType = Hex.Hex
type ErrorType = hash.ErrorType | Errors.GlobalErrorType
}
/**
* Hashes a {@link ox#TransactionEnvelopeEip1559.TransactionEnvelopeEip1559}. This is the "transaction hash".
*
* @example
* ```ts twoslash
* import { Secp256k1, TransactionEnvelopeEip1559 } from 'ox'
*
* const envelope = TransactionEnvelopeEip1559.from({
* chainId: 1,
* nonce: 0n,
* maxFeePerGas: 1000000000n,
* gas: 21000n,
* to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
* value: 1000000000000000000n,
* })
*
* const signature = Secp256k1.sign({
* payload: TransactionEnvelopeEip1559.getSignPayload(envelope),
* privateKey: '0x...'
* })
*
* const envelope_signed = TransactionEnvelopeEip1559.from(envelope, { signature })
*
* const hash = TransactionEnvelopeEip1559.hash(envelope_signed) // [!code focus]
* ```
*
* @param envelope - The EIP-1559 Transaction Envelope to hash.
* @param options - Options.
* @returns The hash of the transaction envelope.
*/
export function hash<presign extends boolean = false>(
envelope: TransactionEnvelopeEip1559<presign extends true ? false : true>,
options: hash.Options<presign> = {},
): hash.ReturnType {
const { presign } = options
return Hash.keccak256(
serialize({
...envelope,
...(presign
? {
r: undefined,
s: undefined,
yParity: undefined,
v: undefined,
}
: {}),
}),
)
}
export declare namespace hash {
type Options<presign extends boolean = false> = {
/** Whether to hash this transaction for signing. @default false */
presign?: presign | boolean | undefined
}
type ReturnType = Hex.Hex
type ErrorType =
| Hash.keccak256.ErrorType
| serialize.ErrorType
| Errors.GlobalErrorType
}
/**
* Serializes a {@link ox#TransactionEnvelopeEip1559.TransactionEnvelopeEip1559}.
*
* @example
* ```ts twoslash
* import { TransactionEnvelopeEip1559, Value } from 'ox'
*
* const envelope = TransactionEnvelopeEip1559.from({
* chainId: 1,
* maxFeePerGas: Value.fromGwei('10'),
* maxPriorityFeePerGas: Value.fromGwei('1'),
* to: '0x0000000000000000000000000000000000000000',
* value: Value.fromEther('1'),
* })
*
* const serialized = TransactionEnvelopeEip1559.serialize(envelope) // [!code focus]
* ```
*
* @example
* ### Attaching Signatures
*
* It is possible to attach a `signature` to the serialized Transaction Envelope.
*
* ```ts twoslash
* import { Secp256k1, TransactionEnvelopeEip1559, Value } from 'ox'
*
* const envelope = TransactionEnvelopeEip1559.from({
* chainId: 1,
* maxFeePerGas: Value.fromGwei('10'),
* maxPriorityFeePerGas: Value.fromGwei('1'),
* to: '0x0000000000000000000000000000000000000000',
* value: Value.fromEther('1'),
* })
*
* const signature = Secp256k1.sign({
* payload: TransactionEnvelopeEip1559.getSignPayload(envelope),
* privateKey: '0x...',
* })
*
* const serialized = TransactionEnvelopeEip1559.serialize(envelope, { // [!code focus]
* signature, // [!code focus]
* }) // [!code focus]
*
* // ... send `serialized` transaction to JSON-RPC `eth_sendRawTransaction`
* ```
*
* @param envelope - The Transaction Envelope to serialize.
* @param options - Options.
* @returns The serialized Transaction Envelope.
*/
export function serialize(
envelope: PartialBy<TransactionEnvelopeEip1559, 'type'>,
options: serialize.Options = {},
): Serialized {
const {
chainId,
gas,
nonce,
to,
value,
maxFeePerGas,
maxPriorityFeePerGas,
accessList,
data,
input,
} = envelope
assert(envelope)
const accessTupleList = AccessList.toTupleList(accessList)
const signature = Signature.extract(options.signature || envelope)
const serialized = [
Hex.fromNumber(chainId),
nonce ? Hex.fromNumber(nonce) : '0x',
maxPriorityFeePerGas ? Hex.fromNumber(maxPriorityFeePerGas) : '0x',
maxFeePerGas ? Hex.fromNumber(maxFeePerGas) : '0x',
gas ? Hex.fromNumber(gas) : '0x',
to ?? '0x',
value ? Hex.fromNumber(value) : '0x',
data ?? input ?? '0x',
accessTupleList,
...(signature ? Signature.toTuple(signature) : []),
]
return Hex.concat(serializedType, Rlp.fromHex(serialized)) as Serialized
}
export declare namespace serialize {
type Options = {
/** Signature to append to the serialized Transaction Envelope. */
signature?: Signature.Signature | undefined
}
type ErrorType =
| assert.ErrorType
| Hex.fromNumber.ErrorType
| Signature.toTuple.ErrorType
| Hex.concat.ErrorType
| Rlp.fromHex.ErrorType
| Errors.GlobalErrorType
}
/**
* Converts an {@link ox#TransactionEnvelopeEip1559.TransactionEnvelopeEip1559} to an {@link ox#TransactionEnvelopeEip1559.Rpc}.
*
* @example
* ```ts twoslash
* import { RpcRequest, TransactionEnvelopeEip1559, Value } from 'ox'
*
* const envelope = TransactionEnvelopeEip1559.from({
* chainId: 1,
* nonce: 0n,
* gas: 21000n,
* to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
* value: Value.fromEther('1'),
* })
*
* const envelope_rpc = TransactionEnvelopeEip1559.toRpc(envelope) // [!code focus]
*
* const request = RpcRequest.from({
* id: 0,
* method: 'eth_sendTransaction',
* params: [envelope_rpc],
* })
* ```
*
* @param envelope - The EIP-1559 transaction envelope to convert.
* @returns An RPC-formatted EIP-1559 transaction envelope.
*/
export function toRpc(envelope: Omit<TransactionEnvelopeEip1559, 'type'>): Rpc {
const signature = Signature.extract(envelope)
return {
...envelope,
chainId: Hex.fromNumber(envelope.chainId),
data: envelope.data ?? envelope.input,
type: '0x2',
...(typeof envelope.gas === 'bigint'
? { gas: Hex.fromNumber(envelope.gas) }
: {}),
...(typeof envelope.nonce === 'bigint'
? { nonce: Hex.fromNumber(envelope.nonce) }
: {}),
...(typeof envelope.value === 'bigint'
? { value: Hex.fromNumber(envelope.value) }
: {}),
...(typeof envelope.maxFeePerGas === 'bigint'
? { maxFeePerGas: Hex.fromNumber(envelope.maxFeePerGas) }
: {}),
...(typeof envelope.maxPriorityFeePerGas === 'bigint'
? {
maxPriorityFeePerGas: Hex.fromNumber(envelope.maxPriorityFeePerGas),
}
: {}),
...(signature ? Signature.toRpc(signature) : {}),
} as never
}
export declare namespace toRpc {
export type ErrorType = Signature.extract.ErrorType | Errors.GlobalErrorType
}
/**
* Validates a {@link ox#TransactionEnvelopeEip1559.TransactionEnvelopeEip1559}. Returns `true` if the envelope is valid, `false` otherwise.
*
* @example
* ```ts twoslash
* import { TransactionEnvelopeEip1559, Value } from 'ox'
*
* const valid = TransactionEnvelopeEip1559.assert({
* maxFeePerGas: 2n ** 256n - 1n + 1n,
* chainId: 1,
* to: '0x0000000000000000000000000000000000000000',
* value: Value.fromEther('1'),
* })
* // @log: false
* ```
*
* @param envelope - The transaction envelope to validate.
*/
export function validate(
envelope: PartialBy<TransactionEnvelopeEip1559, 'type'>,
) {
try {
assert(envelope)
return true
} catch {
return false
}
}
export declare namespace validate {
type ErrorType = Errors.GlobalErrorType
}

593
node_modules/ox/core/TransactionEnvelopeEip2930.ts generated vendored Normal file
View File

@@ -0,0 +1,593 @@
import * as AccessList from './AccessList.js'
import * as Address from './Address.js'
import type * as Errors from './Errors.js'
import * as Hash from './Hash.js'
import * as Hex from './Hex.js'
import * as Rlp from './Rlp.js'
import * as Signature from './Signature.js'
import * as TransactionEnvelope from './TransactionEnvelope.js'
import type {
Assign,
Compute,
PartialBy,
UnionPartialBy,
} from './internal/types.js'
export type TransactionEnvelopeEip2930<
signed extends boolean = boolean,
bigintType = bigint,
numberType = number,
type extends string = Type,
> = Compute<
TransactionEnvelope.Base<type, signed, bigintType, numberType> & {
/** EIP-2930 Access List. */
accessList?: AccessList.AccessList | undefined
/** Base fee per gas. */
gasPrice?: bigintType | undefined
}
>
export type Rpc<signed extends boolean = boolean> = TransactionEnvelopeEip2930<
signed,
Hex.Hex,
Hex.Hex,
'0x1'
>
export type Serialized = `${SerializedType}${string}`
export const serializedType = '0x01' as const
export type SerializedType = typeof serializedType
export type Signed = TransactionEnvelopeEip2930<true>
export const type = 'eip2930' as const
export type Type = typeof type
/**
* Asserts a {@link ox#TransactionEnvelopeEip2930.TransactionEnvelopeEip2930} is valid.
*
* @example
* ```ts twoslash
* import { TransactionEnvelopeEip2930, Value } from 'ox'
*
* TransactionEnvelopeEip2930.assert({
* gasPrice: 2n ** 256n - 1n + 1n,
* chainId: 1,
* to: '0x0000000000000000000000000000000000000000',
* value: Value.fromEther('1'),
* })
* // @error: GasPriceTooHighError:
* // @error: The gas price (`gasPrice` = 115792089237316195423570985008687907853269984665640564039457584007913 gwei) cannot be
* // @error: higher than the maximum allowed value (2^256-1).
* ```
*
* @param envelope - The transaction envelope to assert.
*/
export function assert(
envelope: PartialBy<TransactionEnvelopeEip2930, 'type'>,
) {
const { chainId, gasPrice, to } = envelope
if (chainId <= 0)
throw new TransactionEnvelope.InvalidChainIdError({ chainId })
if (to) Address.assert(to, { strict: false })
if (gasPrice && BigInt(gasPrice) > 2n ** 256n - 1n)
throw new TransactionEnvelope.GasPriceTooHighError({ gasPrice })
}
export declare namespace assert {
type ErrorType =
| Address.assert.ErrorType
| TransactionEnvelope.InvalidChainIdError
| TransactionEnvelope.GasPriceTooHighError
| Errors.GlobalErrorType
}
/**
* Deserializes a {@link ox#TransactionEnvelopeEip2930.TransactionEnvelopeEip2930} from its serialized form.
*
* @example
* ```ts twoslash
* import { TransactionEnvelopeEip2930 } from 'ox'
*
* const envelope = TransactionEnvelopeEip2930.deserialize('0x01ef0182031184773594008477359400809470997970c51812dc3a010c7d01b50e0d17dc79c8880de0b6b3a764000080c0')
* // @log: {
* // @log: type: 'eip2930',
* // @log: nonce: 785n,
* // @log: gasPrice: 2000000000n,
* // @log: gas: 1000000n,
* // @log: to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
* // @log: value: 1000000000000000000n,
* // @log: }
* ```
*
* @param serialized - The serialized transaction.
* @returns Deserialized Transaction Envelope.
*/
export function deserialize(
serialized: Serialized,
): TransactionEnvelopeEip2930 {
const transactionArray = Rlp.toHex(Hex.slice(serialized, 1))
const [
chainId,
nonce,
gasPrice,
gas,
to,
value,
data,
accessList,
yParity,
r,
s,
] = transactionArray as readonly Hex.Hex[]
if (!(transactionArray.length === 8 || transactionArray.length === 11))
throw new TransactionEnvelope.InvalidSerializedError({
attributes: {
chainId,
nonce,
gasPrice,
gas,
to,
value,
data,
accessList,
...(transactionArray.length > 8
? {
yParity,
r,
s,
}
: {}),
},
serialized,
type,
})
let transaction = {
chainId: Number(chainId as Hex.Hex),
type,
} as TransactionEnvelopeEip2930
if (Hex.validate(to) && to !== '0x') transaction.to = to
if (Hex.validate(gas) && gas !== '0x') transaction.gas = BigInt(gas)
if (Hex.validate(data) && data !== '0x') transaction.data = data
if (Hex.validate(nonce) && nonce !== '0x') transaction.nonce = BigInt(nonce)
if (Hex.validate(value) && value !== '0x') transaction.value = BigInt(value)
if (Hex.validate(gasPrice) && gasPrice !== '0x')
transaction.gasPrice = BigInt(gasPrice)
if (accessList!.length !== 0 && accessList !== '0x')
transaction.accessList = AccessList.fromTupleList(accessList as any)
const signature =
r && s && yParity ? Signature.fromTuple([yParity, r, s]) : undefined
if (signature)
transaction = {
...transaction,
...signature,
} as TransactionEnvelopeEip2930
assert(transaction)
return transaction
}
export declare namespace deserialize {
type ErrorType = Errors.GlobalErrorType
}
/**
* Converts an arbitrary transaction object into an EIP-2930 Transaction Envelope.
*
* @example
* ```ts twoslash
* // @noErrors
* import { TransactionEnvelopeEip2930, Value } from 'ox'
*
* const envelope = TransactionEnvelopeEip2930.from({
* chainId: 1,
* accessList: [...],
* gasPrice: Value.fromGwei('10'),
* to: '0x0000000000000000000000000000000000000000',
* value: Value.fromEther('1'),
* })
* ```
*
* @example
* ### Attaching Signatures
*
* It is possible to attach a `signature` to the transaction envelope.
*
* ```ts twoslash
* import { Secp256k1, TransactionEnvelopeEip2930, Value } from 'ox'
*
* const envelope = TransactionEnvelopeEip2930.from({
* chainId: 1,
* gasPrice: Value.fromGwei('10'),
* to: '0x0000000000000000000000000000000000000000',
* value: Value.fromEther('1'),
* })
*
* const signature = Secp256k1.sign({
* payload: TransactionEnvelopeEip2930.getSignPayload(envelope),
* privateKey: '0x...',
* })
*
* const envelope_signed = TransactionEnvelopeEip2930.from(envelope, { // [!code focus]
* signature, // [!code focus]
* }) // [!code focus]
* // @log: {
* // @log: chainId: 1,
* // @log: gasPrice: 10000000000n,
* // @log: to: '0x0000000000000000000000000000000000000000',
* // @log: type: 'eip2930',
* // @log: value: 1000000000000000000n,
* // @log: r: 125...n,
* // @log: s: 642...n,
* // @log: yParity: 0,
* // @log: }
* ```
*
* @example
* ### From Serialized
*
* It is possible to instantiate an EIP-2930 Transaction Envelope from a {@link ox#TransactionEnvelopeEip2930.Serialized} value.
*
* ```ts twoslash
* import { TransactionEnvelopeEip2930 } from 'ox'
*
* const envelope = TransactionEnvelopeEip2930.from('0x01f858018203118502540be4008504a817c800809470997970c51812dc3a010c7d01b50e0d17dc79c8880de0b6b3a764000080c08477359400e1a001627c687261b0e7f8638af1112efa8a77e23656f6e7945275b19e9deed80261')
* // @log: {
* // @log: chainId: 1,
* // @log: gasPrice: 10000000000n,
* // @log: to: '0x0000000000000000000000000000000000000000',
* // @log: type: 'eip2930',
* // @log: value: 1000000000000000000n,
* // @log: }
* ```
*
* @param envelope - The transaction object to convert.
* @param options - Options.
* @returns A {@link ox#TransactionEnvelopeEip2930.TransactionEnvelopeEip2930}
*/
export function from<
const envelope extends
| UnionPartialBy<TransactionEnvelopeEip2930, 'type'>
| Serialized,
const signature extends Signature.Signature | undefined = undefined,
>(
envelope:
| envelope
| UnionPartialBy<TransactionEnvelopeEip2930, 'type'>
| Serialized,
options: from.Options<signature> = {},
): from.ReturnType<envelope, signature> {
const { signature } = options
const envelope_ = (
typeof envelope === 'string' ? deserialize(envelope) : envelope
) as TransactionEnvelopeEip2930
assert(envelope_)
return {
...envelope_,
...(signature ? Signature.from(signature) : {}),
type: 'eip2930',
} as never
}
export declare namespace from {
type Options<signature extends Signature.Signature | undefined = undefined> =
{
signature?: signature | Signature.Signature | undefined
}
type ReturnType<
envelope extends
| UnionPartialBy<TransactionEnvelopeEip2930, 'type'>
| Hex.Hex = TransactionEnvelopeEip2930 | Hex.Hex,
signature extends Signature.Signature | undefined = undefined,
> = Compute<
envelope extends Hex.Hex
? TransactionEnvelopeEip2930
: Assign<
envelope,
(signature extends Signature.Signature ? Readonly<signature> : {}) & {
readonly type: 'eip2930'
}
>
>
type ErrorType =
| deserialize.ErrorType
| assert.ErrorType
| Errors.GlobalErrorType
}
/**
* Returns the payload to sign for a {@link ox#TransactionEnvelopeEip2930.TransactionEnvelopeEip2930}.
*
* @example
* The example below demonstrates how to compute the sign payload which can be used
* with ECDSA signing utilities like {@link ox#Secp256k1.(sign:function)}.
*
* ```ts twoslash
* import { Secp256k1, TransactionEnvelopeEip2930 } from 'ox'
*
* const envelope = TransactionEnvelopeEip2930.from({
* chainId: 1,
* nonce: 0n,
* gasPrice: 1000000000n,
* gas: 21000n,
* to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
* value: 1000000000000000000n,
* })
*
* const payload = TransactionEnvelopeEip2930.getSignPayload(envelope) // [!code focus]
* // @log: '0x...'
*
* const signature = Secp256k1.sign({ payload, privateKey: '0x...' })
* ```
*
* @param envelope - The transaction envelope to get the sign payload for.
* @returns The sign payload.
*/
export function getSignPayload(
envelope: TransactionEnvelopeEip2930,
): getSignPayload.ReturnType {
return hash(envelope, { presign: true })
}
export declare namespace getSignPayload {
type ReturnType = Hex.Hex
type ErrorType = hash.ErrorType | Errors.GlobalErrorType
}
/**
* Hashes a {@link ox#TransactionEnvelopeEip2930.TransactionEnvelopeEip2930}. This is the "transaction hash".
*
* @example
* ```ts twoslash
* import { Secp256k1, TransactionEnvelopeEip2930 } from 'ox'
*
* const envelope = TransactionEnvelopeEip2930.from({
* chainId: 1,
* nonce: 0n,
* gasPrice: 1000000000n,
* gas: 21000n,
* to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
* value: 1000000000000000000n,
* })
*
* const signature = Secp256k1.sign({
* payload: TransactionEnvelopeEip2930.getSignPayload(envelope),
* privateKey: '0x...',
* })
*
* const envelope_signed = TransactionEnvelopeEip2930.from(envelope, {
* signature,
* })
*
* const hash = TransactionEnvelopeEip2930.hash(envelope_signed) // [!code focus]
* ```
*
* @param envelope - The EIP-2930 Transaction Envelope to hash.
* @param options - Options.
* @returns The hash of the transaction envelope.
*/
export function hash<presign extends boolean = false>(
envelope: TransactionEnvelopeEip2930<presign extends true ? false : true>,
options: hash.Options<presign> = {},
): hash.ReturnType {
const { presign } = options
return Hash.keccak256(
serialize({
...envelope,
...(presign
? {
r: undefined,
s: undefined,
yParity: undefined,
v: undefined,
}
: {}),
}),
)
}
export declare namespace hash {
type Options<presign extends boolean = false> = {
/** Whether to hash this transaction for signing. @default false */
presign?: presign | boolean | undefined
}
type ReturnType = Hex.Hex
type ErrorType =
| Hash.keccak256.ErrorType
| serialize.ErrorType
| Errors.GlobalErrorType
}
/**
* Serializes a {@link ox#TransactionEnvelopeEip2930.TransactionEnvelopeEip2930}.
*
* @example
* ```ts twoslash
* import { TransactionEnvelopeEip2930, Value } from 'ox'
*
* const envelope = TransactionEnvelopeEip2930.from({
* chainId: 1,
* gasPrice: Value.fromGwei('10'),
* to: '0x0000000000000000000000000000000000000000',
* value: Value.fromEther('1'),
* })
*
* const serialized = TransactionEnvelopeEip2930.serialize(envelope) // [!code focus]
* ```
*
* @example
* ### Attaching Signatures
*
* It is possible to attach a `signature` to the serialized Transaction Envelope.
*
* ```ts twoslash
* import { Secp256k1, TransactionEnvelopeEip2930, Value } from 'ox'
*
* const envelope = TransactionEnvelopeEip2930.from({
* chainId: 1,
* gasPrice: Value.fromGwei('10'),
* to: '0x0000000000000000000000000000000000000000',
* value: Value.fromEther('1'),
* })
*
* const signature = Secp256k1.sign({
* payload: TransactionEnvelopeEip2930.getSignPayload(envelope),
* privateKey: '0x...',
* })
*
* const serialized = TransactionEnvelopeEip2930.serialize(envelope, { // [!code focus]
* signature, // [!code focus]
* }) // [!code focus]
*
* // ... send `serialized` transaction to JSON-RPC `eth_sendRawTransaction`
* ```
*
* @param envelope - The Transaction Envelope to serialize.
* @param options - Options.
* @returns The serialized Transaction Envelope.
*/
export function serialize(
envelope: PartialBy<TransactionEnvelopeEip2930, 'type'>,
options: serialize.Options = {},
): Serialized {
const { chainId, gas, data, input, nonce, to, value, accessList, gasPrice } =
envelope
assert(envelope)
const accessTupleList = AccessList.toTupleList(accessList)
const signature = Signature.extract(options.signature || (envelope as any))
const serialized = [
Hex.fromNumber(chainId),
nonce ? Hex.fromNumber(nonce) : '0x',
gasPrice ? Hex.fromNumber(gasPrice) : '0x',
gas ? Hex.fromNumber(gas) : '0x',
to ?? '0x',
value ? Hex.fromNumber(value) : '0x',
data ?? input ?? '0x',
accessTupleList,
...(signature ? Signature.toTuple(signature) : []),
] as const
return Hex.concat('0x01', Rlp.fromHex(serialized)) as Serialized
}
export declare namespace serialize {
type Options = {
/** Signature to append to the serialized Transaction Envelope. */
signature?: Signature.Signature | undefined
}
type ErrorType =
| assert.ErrorType
| Hex.fromNumber.ErrorType
| Signature.toTuple.ErrorType
| Hex.concat.ErrorType
| Rlp.fromHex.ErrorType
| Errors.GlobalErrorType
}
/**
* Converts an {@link ox#TransactionEnvelopeEip2930.TransactionEnvelopeEip2930} to an {@link ox#TransactionEnvelopeEip2930.Rpc}.
*
* @example
* ```ts twoslash
* import { RpcRequest, TransactionEnvelopeEip2930, Value } from 'ox'
*
* const envelope = TransactionEnvelopeEip2930.from({
* chainId: 1,
* nonce: 0n,
* gas: 21000n,
* maxFeePerGas: Value.fromGwei('20'),
* to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
* value: Value.fromEther('1'),
* })
*
* const envelope_rpc = TransactionEnvelopeEip2930.toRpc(envelope) // [!code focus]
*
* const request = RpcRequest.from({
* id: 0,
* method: 'eth_sendTransaction',
* params: [envelope_rpc],
* })
* ```
*
* @param envelope - The EIP-2930 transaction envelope to convert.
* @returns An RPC-formatted EIP-2930 transaction envelope.
*/
export function toRpc(envelope: Omit<TransactionEnvelopeEip2930, 'type'>): Rpc {
const signature = Signature.extract(envelope)!
return {
...envelope,
chainId: Hex.fromNumber(envelope.chainId),
data: envelope.data ?? envelope.input,
...(typeof envelope.gas === 'bigint'
? { gas: Hex.fromNumber(envelope.gas) }
: {}),
...(typeof envelope.nonce === 'bigint'
? { nonce: Hex.fromNumber(envelope.nonce) }
: {}),
...(typeof envelope.value === 'bigint'
? { value: Hex.fromNumber(envelope.value) }
: {}),
...(typeof envelope.gasPrice === 'bigint'
? { gasPrice: Hex.fromNumber(envelope.gasPrice) }
: {}),
type: '0x1',
...(signature ? Signature.toRpc(signature) : {}),
} as never
}
export declare namespace toRpc {
export type ErrorType = Signature.extract.ErrorType | Errors.GlobalErrorType
}
/**
* Validates a {@link ox#TransactionEnvelopeEip2930.TransactionEnvelopeEip2930}. Returns `true` if the envelope is valid, `false` otherwise.
*
* @example
* ```ts twoslash
* import { TransactionEnvelopeEip2930, Value } from 'ox'
*
* const valid = TransactionEnvelopeEip2930.assert({
* gasPrice: 2n ** 256n - 1n + 1n,
* chainId: 1,
* to: '0x0000000000000000000000000000000000000000',
* value: Value.fromEther('1'),
* })
* // @log: false
* ```
*
* @param envelope - The transaction envelope to validate.
*/
export function validate(
envelope: PartialBy<TransactionEnvelopeEip2930, 'type'>,
) {
try {
assert(envelope)
return true
} catch {
return false
}
}
export declare namespace validate {
type ErrorType = Errors.GlobalErrorType
}

732
node_modules/ox/core/TransactionEnvelopeEip4844.ts generated vendored Normal file
View File

@@ -0,0 +1,732 @@
import * as AccessList from './AccessList.js'
import * as Blobs from './Blobs.js'
import type * 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 Rlp from './Rlp.js'
import * as Signature from './Signature.js'
import * as TransactionEnvelope from './TransactionEnvelope.js'
import * as TransactionEnvelopeEip1559 from './TransactionEnvelopeEip1559.js'
import type {
Assign,
Compute,
PartialBy,
UnionPartialBy,
} from './internal/types.js'
export type TransactionEnvelopeEip4844<
signed extends boolean = boolean,
bigintType = bigint,
numberType = number,
type extends string = Type,
> = Compute<
TransactionEnvelope.Base<type, signed, bigintType, numberType> & {
/** EIP-2930 Access List. */
accessList?: AccessList.AccessList | undefined
/** Versioned hashes of blobs to be included in the transaction. */
blobVersionedHashes: readonly Hex.Hex[]
/** Maximum total fee per gas sender is willing to pay for blob gas (in wei). */
maxFeePerBlobGas?: bigintType | undefined
/** Total fee per gas in wei (gasPrice/baseFeePerGas + maxPriorityFeePerGas). */
maxFeePerGas?: bigintType | undefined
/** Max priority fee per gas (in wei). */
maxPriorityFeePerGas?: bigintType | undefined
/** The sidecars associated with this transaction. When defined, the envelope is in the "network wrapper" format. */
sidecars?: readonly Blobs.BlobSidecar<Hex.Hex>[] | undefined
}
>
export type Rpc<signed extends boolean = boolean> = TransactionEnvelopeEip4844<
signed,
Hex.Hex,
Hex.Hex,
'0x3'
>
export type Serialized = `${SerializedType}${string}`
export const serializedType = '0x03' as const
export type SerializedType = typeof serializedType
export type Signed = TransactionEnvelopeEip4844<true>
export const type = 'eip4844' as const
export type Type = 'eip4844'
/**
* Asserts a {@link ox#TransactionEnvelopeEip4844.TransactionEnvelopeEip4844} is valid.
*
* @example
* ```ts twoslash
* import { TransactionEnvelopeEip4844, Value } from 'ox'
*
* TransactionEnvelopeEip4844.assert({
* blobVersionedHashes: [],
* chainId: 1,
* to: '0x0000000000000000000000000000000000000000',
* value: Value.fromEther('1'),
* })
* // @error: EmptyBlobVersionedHashesError: Blob versioned hashes must not be empty.
* ```
*
* @param envelope - The transaction envelope to assert.
*/
export function assert(
envelope: PartialBy<TransactionEnvelopeEip4844, 'type'>,
) {
const { blobVersionedHashes } = envelope
if (blobVersionedHashes) {
if (blobVersionedHashes.length === 0)
throw new Blobs.EmptyBlobVersionedHashesError()
for (const hash of blobVersionedHashes) {
const size = Hex.size(hash)
const version = Hex.toNumber(Hex.slice(hash, 0, 1))
if (size !== 32)
throw new Blobs.InvalidVersionedHashSizeError({ hash, size })
if (version !== Kzg.versionedHashVersion)
throw new Blobs.InvalidVersionedHashVersionError({
hash,
version,
})
}
}
TransactionEnvelopeEip1559.assert(
envelope as {} as TransactionEnvelopeEip1559.TransactionEnvelopeEip1559,
)
}
export declare namespace assert {
type ErrorType =
| TransactionEnvelopeEip1559.assert.ErrorType
| Hex.size.ErrorType
| Hex.toNumber.ErrorType
| Hex.slice.ErrorType
| Blobs.EmptyBlobVersionedHashesError
| Blobs.InvalidVersionedHashSizeError
| Blobs.InvalidVersionedHashVersionError
| Errors.GlobalErrorType
}
/**
* Deserializes a {@link ox#TransactionEnvelopeEip4844.TransactionEnvelopeEip4844} from its serialized form.
*
* @example
* ```ts twoslash
* import { TransactionEnvelopeEip4844 } from 'ox'
*
* const envelope = TransactionEnvelopeEip4844.deserialize('0x03ef0182031184773594008477359400809470997970c51812dc3a010c7d01b50e0d17dc79c8880de0b6b3a764000080c0')
* // @log: {
* // @log: blobVersionedHashes: [...],
* // @log: type: 'eip4844',
* // @log: nonce: 785n,
* // @log: maxFeePerGas: 2000000000n,
* // @log: gas: 1000000n,
* // @log: to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
* // @log: value: 1000000000000000000n,
* // @log: }
* ```
*
* @param serialized - The serialized transaction.
* @returns Deserialized Transaction Envelope.
*/
export function deserialize(
serialized: Serialized,
): Compute<TransactionEnvelopeEip4844> {
const transactionOrWrapperArray = Rlp.toHex(Hex.slice(serialized, 1))
const hasNetworkWrapper = transactionOrWrapperArray.length === 4
const transactionArray = hasNetworkWrapper
? transactionOrWrapperArray[0]!
: transactionOrWrapperArray
const wrapperArray = hasNetworkWrapper
? transactionOrWrapperArray.slice(1)
: []
const [
chainId,
nonce,
maxPriorityFeePerGas,
maxFeePerGas,
gas,
to,
value,
data,
accessList,
maxFeePerBlobGas,
blobVersionedHashes,
yParity,
r,
s,
] = transactionArray
const [blobs, commitments, proofs] = wrapperArray
if (!(transactionArray.length === 11 || transactionArray.length === 14))
throw new TransactionEnvelope.InvalidSerializedError({
attributes: {
chainId,
nonce,
maxPriorityFeePerGas,
maxFeePerGas,
gas,
to,
value,
data,
accessList,
...(transactionArray.length > 9
? {
yParity,
r,
s,
}
: {}),
},
serialized,
type,
})
let transaction = {
blobVersionedHashes: blobVersionedHashes as Hex.Hex[],
chainId: Number(chainId),
type,
} as TransactionEnvelopeEip4844
if (Hex.validate(to) && to !== '0x') transaction.to = to
if (Hex.validate(gas) && gas !== '0x') transaction.gas = BigInt(gas)
if (Hex.validate(data) && data !== '0x') transaction.data = data
if (Hex.validate(nonce) && nonce !== '0x') transaction.nonce = BigInt(nonce)
if (Hex.validate(value) && value !== '0x') transaction.value = BigInt(value)
if (Hex.validate(maxFeePerBlobGas) && maxFeePerBlobGas !== '0x')
transaction.maxFeePerBlobGas = BigInt(maxFeePerBlobGas)
if (Hex.validate(maxFeePerGas) && maxFeePerGas !== '0x')
transaction.maxFeePerGas = BigInt(maxFeePerGas)
if (Hex.validate(maxPriorityFeePerGas) && maxPriorityFeePerGas !== '0x')
transaction.maxPriorityFeePerGas = BigInt(maxPriorityFeePerGas)
if (accessList?.length !== 0 && accessList !== '0x')
transaction.accessList = AccessList.fromTupleList(accessList as any)
if (blobs && commitments && proofs)
transaction.sidecars = Blobs.toSidecars(blobs as Hex.Hex[], {
commitments: commitments as Hex.Hex[],
proofs: proofs as Hex.Hex[],
})
const signature =
r && s && yParity
? Signature.fromTuple([yParity as Hex.Hex, r as Hex.Hex, s as Hex.Hex])
: undefined
if (signature)
transaction = {
...transaction,
...signature,
} as TransactionEnvelopeEip4844
assert(transaction)
return transaction
}
export declare namespace deserialize {
type ErrorType = Errors.GlobalErrorType
}
/**
* Converts an arbitrary transaction object into an EIP-4844 Transaction Envelope.
*
* @example
* ```ts twoslash
* // @noErrors
* import { Blobs, TransactionEnvelopeEip4844, Value } from 'ox'
* import { kzg } from './kzg'
*
* const blobs = Blobs.from('0xdeadbeef')
* const blobVersionedHashes = Blobs.toVersionedHashes(blobs, { kzg })
*
* const envelope = TransactionEnvelopeEip4844.from({
* chainId: 1,
* blobVersionedHashes,
* maxFeePerBlobGas: Value.fromGwei('3'),
* maxFeePerGas: Value.fromGwei('10'),
* maxPriorityFeePerGas: Value.fromGwei('1'),
* to: '0x0000000000000000000000000000000000000000',
* value: Value.fromEther('1'),
* })
* ```
*
* @example
* ### Attaching Signatures
*
* It is possible to attach a `signature` to the transaction envelope.
*
* ```ts twoslash
* // @noErrors
* import { Blobs, Secp256k1, TransactionEnvelopeEip4844, Value } from 'ox'
* import { kzg } from './kzg'
*
* const blobs = Blobs.from('0xdeadbeef')
* const sidecars = Blobs.toSidecars(blobs, { kzg })
* const blobVersionedHashes = Blobs.sidecarsToVersionedHashes(sidecars)
*
* const envelope = TransactionEnvelopeEip4844.from({
* blobVersionedHashes,
* chainId: 1,
* maxFeePerBlobGas: Value.fromGwei('3'),
* maxFeePerGas: Value.fromGwei('10'),
* maxPriorityFeePerGas: Value.fromGwei('1'),
* to: '0x0000000000000000000000000000000000000000',
* value: Value.fromEther('1'),
* })
*
* const signature = Secp256k1.sign({
* payload: TransactionEnvelopeEip4844.getSignPayload(envelope),
* privateKey: '0x...',
* })
*
* const envelope_signed = TransactionEnvelopeEip4844.from(envelope, { // [!code focus]
* sidecars, // [!code focus]
* signature, // [!code focus]
* }) // [!code focus]
* // @log: {
* // @log: blobVersionedHashes: [...],
* // @log: chainId: 1,
* // @log: maxFeePerBlobGas: 3000000000n,
* // @log: maxFeePerGas: 10000000000n,
* // @log: maxPriorityFeePerGas: 1000000000n,
* // @log: to: '0x0000000000000000000000000000000000000000',
* // @log: type: 'eip4844',
* // @log: value: 1000000000000000000n,
* // @log: r: 125...n,
* // @log: s: 642...n,
* // @log: yParity: 0,
* // @log: }
* ```
*
* @example
* ### From Serialized
*
* It is possible to instantiate an EIP-4844 Transaction Envelope from a {@link ox#TransactionEnvelopeEip4844.Serialized} value.
*
* ```ts twoslash
* import { TransactionEnvelopeEip4844 } from 'ox'
*
* const envelope = TransactionEnvelopeEip4844.from('0x03f858018203118502540be4008504a817c800809470997970c51812dc3a010c7d01b50e0d17dc79c8880de0b6b3a764000080c08477359400e1a001627c687261b0e7f8638af1112efa8a77e23656f6e7945275b19e9deed80261')
* // @log: {
* // @log: blobVersionedHashes: [...],
* // @log: chainId: 1,
* // @log: maxFeePerGas: 10000000000n,
* // @log: to: '0x0000000000000000000000000000000000000000',
* // @log: type: 'eip4844',
* // @log: value: 1000000000000000000n,
* // @log: }
* ```
*
* @param envelope - The transaction object to convert.
* @param options - Options.
* @returns An EIP-4844 Transaction Envelope.
*/
export function from<
const envelope extends
| UnionPartialBy<TransactionEnvelopeEip4844, 'type'>
| Serialized,
const signature extends Signature.Signature | undefined = undefined,
>(
envelope:
| envelope
| UnionPartialBy<TransactionEnvelopeEip4844, 'type'>
| Serialized,
options: from.Options<signature> = {},
): from.ReturnType<envelope, signature> {
const { signature } = options
const envelope_ = (
typeof envelope === 'string' ? deserialize(envelope) : envelope
) as TransactionEnvelopeEip4844
assert(envelope_)
return {
...envelope_,
...(signature ? Signature.from(signature) : {}),
type: 'eip4844',
} as never
}
export declare namespace from {
type Options<signature extends Signature.Signature | undefined = undefined> =
{
signature?: signature | Signature.Signature | undefined
}
type ReturnType<
envelope extends
| UnionPartialBy<TransactionEnvelopeEip4844, 'type'>
| Hex.Hex = TransactionEnvelopeEip4844 | Hex.Hex,
signature extends Signature.Signature | undefined = undefined,
> = Compute<
envelope extends Hex.Hex
? TransactionEnvelopeEip4844
: Assign<
envelope,
(signature extends Signature.Signature ? Readonly<signature> : {}) & {
readonly type: 'eip4844'
}
>
>
type ErrorType =
| deserialize.ErrorType
| assert.ErrorType
| Errors.GlobalErrorType
}
/**
* Returns the payload to sign for a {@link ox#TransactionEnvelopeEip4844.TransactionEnvelopeEip4844}.
*
* @example
* The example below demonstrates how to compute the sign payload which can be used
* with ECDSA signing utilities like {@link ox#Secp256k1.(sign:function)}.
*
* ```ts twoslash
* // @noErrors
* import { Blobs, Secp256k1, TransactionEnvelopeEip4844 } from 'ox'
* import { kzg } from './kzg'
*
* const blobs = Blobs.from('0xdeadbeef')
* const blobVersionedHashes = Blobs.toVersionedHashes(blobs, { kzg })
*
* const envelope = TransactionEnvelopeEip4844.from({
* blobVersionedHashes,
* chainId: 1,
* nonce: 0n,
* maxFeePerGas: 1000000000n,
* gas: 21000n,
* to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
* value: 1000000000000000000n,
* })
*
* const payload = TransactionEnvelopeEip4844.getSignPayload(envelope) // [!code focus]
* // @log: '0x...'
*
* const signature = Secp256k1.sign({ payload, privateKey: '0x...' })
* ```
*
* @param envelope - The transaction envelope to get the sign payload for.
* @returns The sign payload.
*/
export function getSignPayload(
envelope: TransactionEnvelopeEip4844,
): getSignPayload.ReturnType {
return hash(envelope, { presign: true })
}
export declare namespace getSignPayload {
type ReturnType = Hex.Hex
type ErrorType = hash.ErrorType | Errors.GlobalErrorType
}
/**
* Hashes a {@link ox#TransactionEnvelopeEip4844.TransactionEnvelopeEip4844}. This is the "transaction hash".
*
* @example
* ```ts twoslash
* // @noErrors
* import { Blobs, TransactionEnvelopeEip4844 } from 'ox'
* import { kzg } from './kzg'
*
* const blobs = Blobs.from('0xdeadbeef')
* const blobVersionedHashes = Blobs.toVersionedHashes(blobs, { kzg })
*
* const envelope = TransactionEnvelopeEip4844.from({
* blobVersionedHashes,
* chainId: 1,
* nonce: 0n,
* maxFeePerGas: 1000000000n,
* gas: 21000n,
* to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
* value: 1000000000000000000n,
* })
*
* const hash = TransactionEnvelopeEip4844.hash(envelope) // [!code focus]
* ```
*
* @param envelope - The EIP-4844 Transaction Envelope to hash.
* @param options - Options.
* @returns The hash of the transaction envelope.
*/
export function hash<presign extends boolean = false>(
envelope: TransactionEnvelopeEip4844<presign extends true ? false : true>,
options: hash.Options<presign> = {},
): hash.ReturnType {
const { presign } = options
return Hash.keccak256(
serialize({
...envelope,
...(presign
? {
sidecars: undefined,
r: undefined,
s: undefined,
yParity: undefined,
v: undefined,
}
: {}),
}),
)
}
export declare namespace hash {
type Options<presign extends boolean = false> = {
/** Whether to hash this transaction for signing. @default false */
presign?: presign | boolean | undefined
}
type ReturnType = Hex.Hex
type ErrorType =
| Hash.keccak256.ErrorType
| serialize.ErrorType
| Errors.GlobalErrorType
}
/**
* Serializes a {@link ox#TransactionEnvelopeEip4844.TransactionEnvelopeEip4844}.
*
* @example
* ```ts twoslash
* // @noErrors
* import { Blobs, TransactionEnvelopeEip4844 } from 'ox'
* import { kzg } from './kzg'
*
* const blobs = Blobs.from('0xdeadbeef')
* const blobVersionedHashes = Blobs.toVersionedHashes(blobs, { kzg })
*
* const envelope = TransactionEnvelopeEip4844.from({
* blobVersionedHashes,
* chainId: 1,
* maxFeePerGas: Value.fromGwei('10'),
* to: '0x0000000000000000000000000000000000000000',
* value: Value.fromEther('1'),
* })
*
* const serialized = TransactionEnvelopeEip4844.serialize(envelope) // [!code focus]
* ```
*
* @example
* ### Attaching Signatures
*
* It is possible to attach a `signature` to the serialized Transaction Envelope.
*
* ```ts twoslash
* // @noErrors
* import { Blobs, Secp256k1, TransactionEnvelopeEip4844, Value } from 'ox'
* import { kzg } from './kzg'
*
* const blobs = Blobs.from('0xdeadbeef')
* const sidecars = Blobs.toSidecars(blobs, { kzg })
* const blobVersionedHashes = Blobs.sidecarsToVersionedHashes(blobs)
*
* const envelope = TransactionEnvelopeEip4844.from({
* blobVersionedHashes,
* chainId: 1,
* maxFeePerBlobGas: Value.fromGwei('3'),
* maxFeePerGas: Value.fromGwei('10'),
* maxPriorityFeePerGas: Value.fromGwei('1'),
* to: '0x0000000000000000000000000000000000000000',
* value: Value.fromEther('1'),
* })
*
* const signature = Secp256k1.sign({
* payload: TransactionEnvelopeEip4844.getSignPayload(envelope),
* privateKey: '0x...',
* })
*
* const serialized = TransactionEnvelopeEip4844.serialize(envelope, { // [!code focus]
* sidecars, // [!code focus]
* signature, // [!code focus]
* }) // [!code focus]
*
* // ... send `serialized` transaction to JSON-RPC `eth_sendRawTransaction`
* ```
*
* @param envelope - The Transaction Envelope to serialize.
* @param options - Options.
* @returns The serialized Transaction Envelope.
*/
export function serialize(
envelope: PartialBy<TransactionEnvelopeEip4844, 'type'>,
options: serialize.Options = {},
): Serialized {
const {
blobVersionedHashes,
chainId,
gas,
nonce,
to,
value,
maxFeePerBlobGas,
maxFeePerGas,
maxPriorityFeePerGas,
accessList,
data,
} = envelope
assert(envelope)
const accessTupleList = AccessList.toTupleList(accessList)
const signature = Signature.extract(options.signature || envelope)
const serialized = [
Hex.fromNumber(chainId),
nonce ? Hex.fromNumber(nonce) : '0x',
maxPriorityFeePerGas ? Hex.fromNumber(maxPriorityFeePerGas) : '0x',
maxFeePerGas ? Hex.fromNumber(maxFeePerGas) : '0x',
gas ? Hex.fromNumber(gas) : '0x',
to ?? '0x',
value ? Hex.fromNumber(value) : '0x',
data ?? '0x',
accessTupleList,
maxFeePerBlobGas ? Hex.fromNumber(maxFeePerBlobGas) : '0x',
blobVersionedHashes ?? [],
...(signature ? Signature.toTuple(signature) : []),
] as const
const sidecars = options.sidecars || envelope.sidecars
const blobs: Hex.Hex[] = []
const commitments: Hex.Hex[] = []
const proofs: Hex.Hex[] = []
if (sidecars)
for (let i = 0; i < sidecars.length; i++) {
const { blob, commitment, proof } = sidecars[i]!
blobs.push(blob)
commitments.push(commitment)
proofs.push(proof)
}
return Hex.concat(
'0x03',
sidecars
? // If sidecars are provided, envelope turns into a "network wrapper":
Rlp.fromHex([serialized, blobs, commitments, proofs])
: // Otherwise, standard envelope is used:
Rlp.fromHex(serialized),
) as Serialized
}
export declare namespace serialize {
type Options = {
/** Signature to append to the serialized Transaction Envelope. */
signature?: Signature.Signature | undefined
/** Sidecars to append to the serialized Transaction Envelope. */
sidecars?: Blobs.BlobSidecars<Hex.Hex> | undefined
}
type ErrorType =
| assert.ErrorType
| Hex.fromNumber.ErrorType
| Signature.toTuple.ErrorType
| Hex.concat.ErrorType
| Rlp.fromHex.ErrorType
| Errors.GlobalErrorType
}
/**
* Converts an {@link ox#TransactionEnvelopeEip4844.TransactionEnvelopeEip4844} to an {@link ox#TransactionEnvelopeEip4844.Rpc}.
*
* @example
* ```ts twoslash
* // @noErrors
* import { Blobs, RpcRequest, TransactionEnvelopeEip4844, Value } from 'ox'
* import { kzg } from './kzg'
*
* const blobs = Blobs.from('0xdeadbeef')
* const blobVersionedHashes = Blobs.toVersionedHashes(blobs, { kzg })
*
* const envelope = TransactionEnvelopeEip4844.from({
* blobVersionedHashes,
* chainId: 1,
* nonce: 0n,
* gas: 21000n,
* maxFeePerBlobGas: Value.fromGwei('20'),
* to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
* value: Value.fromEther('1'),
* })
*
* const envelope_rpc = TransactionEnvelopeEip4844.toRpc(envelope) // [!code focus]
*
* const request = RpcRequest.from({
* id: 0,
* method: 'eth_sendTransaction',
* params: [envelope_rpc],
* })
* ```
*
* @param envelope - The EIP-4844 transaction envelope to convert.
* @returns An RPC-formatted EIP-4844 transaction envelope.
*/
export function toRpc(envelope: Omit<TransactionEnvelopeEip4844, 'type'>): Rpc {
const signature = Signature.extract(envelope)
return {
...envelope,
chainId: Hex.fromNumber(envelope.chainId),
data: envelope.data ?? envelope.input,
...(typeof envelope.gas === 'bigint'
? { gas: Hex.fromNumber(envelope.gas) }
: {}),
...(typeof envelope.nonce === 'bigint'
? { nonce: Hex.fromNumber(envelope.nonce) }
: {}),
...(typeof envelope.value === 'bigint'
? { value: Hex.fromNumber(envelope.value) }
: {}),
...(typeof envelope.maxFeePerBlobGas === 'bigint'
? { maxFeePerBlobGas: Hex.fromNumber(envelope.maxFeePerBlobGas) }
: {}),
...(typeof envelope.maxFeePerGas === 'bigint'
? { maxFeePerGas: Hex.fromNumber(envelope.maxFeePerGas) }
: {}),
...(typeof envelope.maxPriorityFeePerGas === 'bigint'
? { maxPriorityFeePerGas: Hex.fromNumber(envelope.maxPriorityFeePerGas) }
: {}),
type: '0x3',
...(signature ? Signature.toRpc(signature) : {}),
} as never
}
export declare namespace toRpc {
export type ErrorType = Signature.extract.ErrorType | Errors.GlobalErrorType
}
/**
* Validates a {@link ox#TransactionEnvelopeEip4844.TransactionEnvelopeEip4844}. Returns `true` if the envelope is valid, `false` otherwise.
*
* @example
* ```ts twoslash
* import { TransactionEnvelopeEip4844, Value } from 'ox'
*
* const valid = TransactionEnvelopeEip4844.assert({
* blobVersionedHashes: [],
* chainId: 1,
* to: '0x0000000000000000000000000000000000000000',
* value: Value.fromEther('1'),
* })
* // @log: false
* ```
*
* @param envelope - The transaction envelope to validate.
*/
export function validate(
envelope: PartialBy<TransactionEnvelopeEip4844, 'type'>,
) {
try {
assert(envelope)
return true
} catch {
return false
}
}
export declare namespace validate {
type ErrorType = Errors.GlobalErrorType
}

611
node_modules/ox/core/TransactionEnvelopeEip7702.ts generated vendored Normal file
View File

@@ -0,0 +1,611 @@
import type { Assign } from './internal/types.js'
import type { PartialBy, UnionPartialBy } from './internal/types.js'
import * as AccessList from './AccessList.js'
import * as Address from './Address.js'
import * as Authorization from './Authorization.js'
import type * as Errors from './Errors.js'
import * as Hash from './Hash.js'
import * as Hex from './Hex.js'
import * as Rlp from './Rlp.js'
import * as Signature from './Signature.js'
import * as TransactionEnvelope from './TransactionEnvelope.js'
import * as TransactionEnvelopeEip1559 from './TransactionEnvelopeEip1559.js'
import type { Compute } from './internal/types.js'
export type TransactionEnvelopeEip7702<
signed extends boolean = boolean,
bigintType = bigint,
numberType = number,
type extends string = Type,
> = Compute<
TransactionEnvelope.Base<type, signed, bigintType, numberType> & {
/** EIP-2930 Access List. */
accessList?: AccessList.AccessList | undefined
/** EIP-7702 Authorization List. */
authorizationList: Authorization.ListSigned<bigintType, numberType>
/** Total fee per gas in wei (gasPrice/baseFeePerGas + maxPriorityFeePerGas). */
maxFeePerGas?: bigintType | undefined
/** Max priority fee per gas (in wei). */
maxPriorityFeePerGas?: bigintType | undefined
}
>
export type Rpc<signed extends boolean = boolean> = TransactionEnvelopeEip7702<
signed,
Hex.Hex,
Hex.Hex,
'0x4'
>
export type Serialized = `${SerializedType}${string}`
export type Signed = TransactionEnvelopeEip7702<true>
export const serializedType = '0x04' as const
export type SerializedType = typeof serializedType
export const type = 'eip7702' as const
export type Type = typeof type
/**
* Asserts a {@link ox#TransactionEnvelopeEip7702.TransactionEnvelopeEip7702} is valid.
*
* @example
* ```ts twoslash
* import { TransactionEnvelopeEip7702, Value } from 'ox'
*
* TransactionEnvelopeEip7702.assert({
* authorizationList: [],
* maxFeePerGas: 2n ** 256n - 1n + 1n,
* chainId: 1,
* to: '0x0000000000000000000000000000000000000000',
* value: Value.fromEther('1'),
* })
* // @error: FeeCapTooHighError:
* // @error: The fee cap (`masFeePerGas` = 115792089237316195423570985008687907853269984665640564039457584007913 gwei) cannot be
* // @error: higher than the maximum allowed value (2^256-1).
* ```
*
* @param envelope - The transaction envelope to assert.
*/
export function assert(
envelope: PartialBy<TransactionEnvelopeEip7702, 'type'>,
) {
const { authorizationList } = envelope
if (authorizationList) {
for (const authorization of authorizationList) {
const { address, chainId } = authorization
if (address) Address.assert(address, { strict: false })
if (Number(chainId) < 0)
throw new TransactionEnvelope.InvalidChainIdError({ chainId })
}
}
TransactionEnvelopeEip1559.assert(
envelope as {} as TransactionEnvelopeEip1559.TransactionEnvelopeEip1559,
)
}
export declare namespace assert {
type ErrorType =
| Address.assert.ErrorType
| TransactionEnvelope.InvalidChainIdError
| Errors.GlobalErrorType
}
/**
* Deserializes a {@link ox#TransactionEnvelopeEip7702.TransactionEnvelopeEip7702} from its serialized form.
*
* @example
* ```ts twoslash
* import { TransactionEnvelopeEip7702 } from 'ox'
*
* const envelope = TransactionEnvelopeEip7702.deserialize('0x04ef0182031184773594008477359400809470997970c51812dc3a010c7d01b50e0d17dc79c8880de0b6b3a764000080c0')
* // @log: {
* // @log: authorizationList: [...],
* // @log: type: 'eip7702',
* // @log: nonce: 785n,
* // @log: maxFeePerGas: 2000000000n,
* // @log: gas: 1000000n,
* // @log: to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
* // @log: value: 1000000000000000000n,
* // @log: }
* ```
*
* @param serialized - The serialized transaction.
* @returns Deserialized Transaction Envelope.
*/
export function deserialize(
serialized: Serialized,
): Compute<TransactionEnvelopeEip7702> {
const transactionArray = Rlp.toHex(Hex.slice(serialized, 1))
const [
chainId,
nonce,
maxPriorityFeePerGas,
maxFeePerGas,
gas,
to,
value,
data,
accessList,
authorizationList,
yParity,
r,
s,
] = transactionArray as readonly Hex.Hex[]
if (!(transactionArray.length === 10 || transactionArray.length === 13))
throw new TransactionEnvelope.InvalidSerializedError({
attributes: {
chainId,
nonce,
maxPriorityFeePerGas,
maxFeePerGas,
gas,
to,
value,
data,
accessList,
authorizationList,
...(transactionArray.length > 9
? {
yParity,
r,
s,
}
: {}),
},
serialized,
type,
})
let transaction = {
chainId: Number(chainId),
type,
} as TransactionEnvelopeEip7702
if (Hex.validate(to) && to !== '0x') transaction.to = to
if (Hex.validate(gas) && gas !== '0x') transaction.gas = BigInt(gas)
if (Hex.validate(data) && data !== '0x') transaction.data = data
if (Hex.validate(nonce) && nonce !== '0x') transaction.nonce = BigInt(nonce)
if (Hex.validate(value) && value !== '0x') transaction.value = BigInt(value)
if (Hex.validate(maxFeePerGas) && maxFeePerGas !== '0x')
transaction.maxFeePerGas = BigInt(maxFeePerGas)
if (Hex.validate(maxPriorityFeePerGas) && maxPriorityFeePerGas !== '0x')
transaction.maxPriorityFeePerGas = BigInt(maxPriorityFeePerGas)
if (accessList!.length !== 0 && accessList !== '0x')
transaction.accessList = AccessList.fromTupleList(accessList as never)
if (authorizationList !== '0x')
transaction.authorizationList = Authorization.fromTupleList(
authorizationList as never,
)
const signature =
r && s && yParity ? Signature.fromTuple([yParity, r, s]) : undefined
if (signature)
transaction = {
...transaction,
...signature,
} as TransactionEnvelopeEip7702
assert(transaction)
return transaction
}
export declare namespace deserialize {
type ErrorType = Errors.GlobalErrorType
}
/**
* Converts an arbitrary transaction object into an EIP-7702 Transaction Envelope.
*
* @example
* ```ts twoslash
* import { Authorization, Secp256k1, TransactionEnvelopeEip7702, Value } from 'ox'
*
* const authorization = Authorization.from({
* address: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
* chainId: 1,
* nonce: 0n,
* })
*
* const signature = Secp256k1.sign({
* payload: Authorization.getSignPayload(authorization),
* privateKey: '0x...',
* })
*
* const authorizationList = [Authorization.from(authorization, { signature })]
*
* const envelope = TransactionEnvelopeEip7702.from({ // [!code focus]
* authorizationList, // [!code focus]
* chainId: 1, // [!code focus]
* maxFeePerGas: Value.fromGwei('10'), // [!code focus]
* maxPriorityFeePerGas: Value.fromGwei('1'), // [!code focus]
* to: '0x0000000000000000000000000000000000000000', // [!code focus]
* value: Value.fromEther('1'), // [!code focus]
* }) // [!code focus]
* ```
*
* @example
* ### Attaching Signatures
*
* It is possible to attach a `signature` to the transaction envelope.
*
* ```ts twoslash
* // @noErrors
* import { Secp256k1, TransactionEnvelopeEip7702, Value } from 'ox'
*
* const envelope = TransactionEnvelopeEip7702.from({
* authorizationList: [...],
* chainId: 1,
* maxFeePerGas: Value.fromGwei('10'),
* maxPriorityFeePerGas: Value.fromGwei('1'),
* to: '0x0000000000000000000000000000000000000000',
* value: Value.fromEther('1'),
* })
*
* const signature = Secp256k1.sign({
* payload: TransactionEnvelopeEip7702.getSignPayload(envelope),
* privateKey: '0x...',
* })
*
* const envelope_signed = TransactionEnvelopeEip7702.from(envelope, { // [!code focus]
* signature, // [!code focus]
* }) // [!code focus]
* // @log: {
* // @log: authorizationList: [...],
* // @log: chainId: 1,
* // @log: maxFeePerGas: 10000000000n,
* // @log: maxPriorityFeePerGas: 1000000000n,
* // @log: to: '0x0000000000000000000000000000000000000000',
* // @log: type: 'eip7702',
* // @log: value: 1000000000000000000n,
* // @log: r: 125...n,
* // @log: s: 642...n,
* // @log: yParity: 0,
* // @log: }
* ```
*
* @example
* ### From Serialized
*
* It is possible to instantiate an EIP-7702 Transaction Envelope from a {@link ox#TransactionEnvelopeEip7702.Serialized} value.
*
* ```ts twoslash
* import { TransactionEnvelopeEip7702 } from 'ox'
*
* const envelope = TransactionEnvelopeEip7702.from('0x04f858018203118502540be4008504a817c800809470997970c51812dc3a010c7d01b50e0d17dc79c8880de0b6b3a764000080c08477359400e1a001627c687261b0e7f8638af1112efa8a77e23656f6e7945275b19e9deed80261')
* // @log: {
* // @log: authorizationList: [...],
* // @log: chainId: 1,
* // @log: maxFeePerGas: 10000000000n,
* // @log: to: '0x0000000000000000000000000000000000000000',
* // @log: type: 'eip7702',
* // @log: value: 1000000000000000000n,
* // @log: }
* ```
*
* @param envelope - The transaction object to convert.
* @param options - Options.
* @returns An EIP-7702 Transaction Envelope.
*/
export function from<
const envelope extends
| UnionPartialBy<TransactionEnvelopeEip7702, 'type'>
| Serialized,
const signature extends Signature.Signature | undefined = undefined,
>(
envelope:
| envelope
| UnionPartialBy<TransactionEnvelopeEip7702, 'type'>
| Serialized,
options: from.Options<signature> = {},
): from.ReturnType<envelope, signature> {
const { signature } = options
const envelope_ = (
typeof envelope === 'string' ? deserialize(envelope) : envelope
) as TransactionEnvelopeEip7702
assert(envelope_)
return {
...envelope_,
...(signature ? Signature.from(signature) : {}),
type: 'eip7702',
} as never
}
export declare namespace from {
type Options<signature extends Signature.Signature | undefined = undefined> =
{
signature?: signature | Signature.Signature | undefined
}
type ReturnType<
envelope extends
| UnionPartialBy<TransactionEnvelopeEip7702, 'type'>
| Hex.Hex = TransactionEnvelopeEip7702 | Hex.Hex,
signature extends Signature.Signature | undefined = undefined,
> = Compute<
envelope extends Hex.Hex
? TransactionEnvelopeEip7702
: Assign<
envelope,
(signature extends Signature.Signature ? Readonly<signature> : {}) & {
readonly type: 'eip7702'
}
>
>
type ErrorType =
| deserialize.ErrorType
| assert.ErrorType
| Errors.GlobalErrorType
}
/**
* Returns the payload to sign for a {@link ox#TransactionEnvelopeEip7702.TransactionEnvelopeEip7702}.
*
* @example
* The example below demonstrates how to compute the sign payload which can be used
* with ECDSA signing utilities like {@link ox#Secp256k1.(sign:function)}.
*
* ```ts twoslash
* // @noErrors
* import { Secp256k1, TransactionEnvelopeEip7702 } from 'ox'
*
* const envelope = TransactionEnvelopeEip7702.from({
* authorizationList: [...],
* chainId: 1,
* nonce: 0n,
* maxFeePerGas: 1000000000n,
* gas: 21000n,
* to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
* value: 1000000000000000000n,
* })
*
* const payload = TransactionEnvelopeEip7702.getSignPayload(envelope) // [!code focus]
* // @log: '0x...'
*
* const signature = Secp256k1.sign({ payload, privateKey: '0x...' })
* ```
*
* @param envelope - The transaction envelope to get the sign payload for.
* @returns The sign payload.
*/
export function getSignPayload(
envelope: TransactionEnvelopeEip7702,
): getSignPayload.ReturnType {
return hash(envelope, { presign: true })
}
export declare namespace getSignPayload {
type ReturnType = Hex.Hex
type ErrorType = hash.ErrorType | Errors.GlobalErrorType
}
/**
* Hashes a {@link ox#TransactionEnvelopeEip7702.TransactionEnvelopeEip7702}. This is the "transaction hash".
*
* @example
* ```ts twoslash
* // @noErrors
* import { Secp256k1, TransactionEnvelopeEip7702 } from 'ox'
*
* const envelope = TransactionEnvelopeEip7702.from({
* authorizationList: [...],
* chainId: 1,
* nonce: 0n,
* maxFeePerGas: 1000000000n,
* gas: 21000n,
* to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
* value: 1000000000000000000n,
* })
*
* const signature = Secp256k1.sign({
* payload: TransactionEnvelopeEip7702.getSignPayload(envelope),
* privateKey: '0x...'
* })
*
* const envelope_signed = TransactionEnvelopeEip7702.from(envelope, { signature })
*
* const hash = TransactionEnvelopeEip7702.hash(envelope_signed) // [!code focus]
* ```
*
* @param envelope - The EIP-7702 Transaction Envelope to hash.
* @param options - Options.
* @returns The hash of the transaction envelope.
*/
export function hash<presign extends boolean = false>(
envelope: TransactionEnvelopeEip7702<presign extends true ? false : true>,
options: hash.Options<presign> = {},
): hash.ReturnType {
const { presign } = options
return Hash.keccak256(
serialize({
...envelope,
...(presign
? {
r: undefined,
s: undefined,
yParity: undefined,
}
: {}),
}),
)
}
export declare namespace hash {
type Options<presign extends boolean = false> = {
/** Whether to hash this transaction for signing. @default false */
presign?: presign | boolean | undefined
}
type ReturnType = Hex.Hex
type ErrorType =
| Hash.keccak256.ErrorType
| serialize.ErrorType
| Errors.GlobalErrorType
}
/**
* Serializes a {@link ox#TransactionEnvelopeEip7702.TransactionEnvelopeEip7702}.
*
* @example
* ```ts twoslash
* // @noErrors
* import { Authorization, Secp256k1, TransactionEnvelopeEip7702, Value } from 'ox'
*
* const authorization = Authorization.from({
* address: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
* chainId: 1,
* nonce: 0n,
* })
*
* const signature = Secp256k1.sign({
* payload: Authorization.getSignPayload(authorization),
* privateKey: '0x...',
* })
*
* const authorizationList = [Authorization.from(authorization, { signature })]
*
* const envelope = TransactionEnvelopeEip7702.from({
* authorizationList,
* chainId: 1,
* maxFeePerGas: Value.fromGwei('10'),
* to: '0x0000000000000000000000000000000000000000',
* value: Value.fromEther('1'),
* })
*
* const serialized = TransactionEnvelopeEip7702.serialize(envelope) // [!code focus]
* ```
*
* @example
* ### Attaching Signatures
*
* It is possible to attach a `signature` to the serialized Transaction Envelope.
*
* ```ts twoslash
* // @noErrors
* import { Secp256k1, TransactionEnvelopeEip7702, Value } from 'ox'
*
* const envelope = TransactionEnvelopeEip7702.from({
* authorizationList: [...],
* chainId: 1,
* maxFeePerGas: Value.fromGwei('10'),
* to: '0x0000000000000000000000000000000000000000',
* value: Value.fromEther('1'),
* })
*
* const signature = Secp256k1.sign({
* payload: TransactionEnvelopeEip7702.getSignPayload(envelope),
* privateKey: '0x...',
* })
*
* const serialized = TransactionEnvelopeEip7702.serialize(envelope, { // [!code focus]
* signature, // [!code focus]
* }) // [!code focus]
*
* // ... send `serialized` transaction to JSON-RPC `eth_sendRawTransaction`
* ```
*
* @param envelope - The Transaction Envelope to serialize.
* @param options - Options.
* @returns The serialized Transaction Envelope.
*/
export function serialize(
envelope: PartialBy<TransactionEnvelopeEip7702, 'type'>,
options: serialize.Options = {},
): Serialized {
const {
authorizationList,
chainId,
gas,
nonce,
to,
value,
maxFeePerGas,
maxPriorityFeePerGas,
accessList,
data,
input,
} = envelope
assert(envelope)
const accessTupleList = AccessList.toTupleList(accessList)
const authorizationTupleList = Authorization.toTupleList(authorizationList)
const signature = Signature.extract(options.signature || envelope)
const serialized = [
Hex.fromNumber(chainId),
nonce ? Hex.fromNumber(nonce) : '0x',
maxPriorityFeePerGas ? Hex.fromNumber(maxPriorityFeePerGas) : '0x',
maxFeePerGas ? Hex.fromNumber(maxFeePerGas) : '0x',
gas ? Hex.fromNumber(gas) : '0x',
to ?? '0x',
value ? Hex.fromNumber(value) : '0x',
data ?? input ?? '0x',
accessTupleList,
authorizationTupleList,
...(signature ? Signature.toTuple(signature) : []),
]
return Hex.concat(serializedType, Rlp.fromHex(serialized)) as Serialized
}
export declare namespace serialize {
type Options = {
/** Signature to append to the serialized Transaction Envelope. */
signature?: Signature.Signature | undefined
}
type ErrorType =
| assert.ErrorType
| Hex.fromNumber.ErrorType
| Signature.toTuple.ErrorType
| Hex.concat.ErrorType
| Rlp.fromHex.ErrorType
| Errors.GlobalErrorType
}
/**
* Validates a {@link ox#TransactionEnvelopeEip7702.TransactionEnvelopeEip7702}. Returns `true` if the envelope is valid, `false` otherwise.
*
* @example
* ```ts twoslash
* import { TransactionEnvelopeEip7702, Value } from 'ox'
*
* const valid = TransactionEnvelopeEip7702.validate({
* authorizationList: [],
* maxFeePerGas: 2n ** 256n - 1n + 1n,
* chainId: 1,
* to: '0x0000000000000000000000000000000000000000',
* value: Value.fromEther('1'),
* })
* // @log: false
* ```
*
* @param envelope - The transaction envelope to validate.
*/
export function validate(
envelope: PartialBy<TransactionEnvelopeEip7702, 'type'>,
) {
try {
assert(envelope)
return true
} catch {
return false
}
}
export declare namespace validate {
type ErrorType = Errors.GlobalErrorType
}

642
node_modules/ox/core/TransactionEnvelopeLegacy.ts generated vendored Normal file
View File

@@ -0,0 +1,642 @@
import * as Address from './Address.js'
import type * as Errors from './Errors.js'
import * as Hash from './Hash.js'
import * as Hex from './Hex.js'
import * as Rlp from './Rlp.js'
import * as Signature from './Signature.js'
import * as TransactionEnvelope from './TransactionEnvelope.js'
import type {
Assign,
Branded,
Compute,
PartialBy,
UnionPartialBy,
} from './internal/types.js'
export type TransactionEnvelopeLegacy<
signed extends boolean = boolean,
bigintType = bigint,
numberType = number,
type extends string = Type,
> = Compute<
PartialBy<
TransactionEnvelope.Base<type, signed, bigintType, numberType>,
'chainId'
> & {
/** Base fee per gas. */
gasPrice?: bigintType | undefined
}
>
export type Rpc<signed extends boolean = boolean> = TransactionEnvelopeLegacy<
signed,
Hex.Hex,
Hex.Hex,
'0x0'
>
export type Serialized = Branded<`0x${string}`, 'legacy'>
export type Signed = TransactionEnvelopeLegacy<true>
export const type = 'legacy'
export type Type = typeof type
/**
* Asserts a {@link ox#TransactionEnvelopeLegacy.TransactionEnvelopeLegacy} is valid.
*
* @example
* ```ts twoslash
* import { TransactionEnvelopeLegacy, Value } from 'ox'
*
* TransactionEnvelopeLegacy.assert({
* gasPrice: 2n ** 256n - 1n + 1n,
* chainId: 1,
* to: '0x0000000000000000000000000000000000000000',
* value: Value.fromEther('1'),
* })
* // @error: GasPriceTooHighError:
* // @error: The gas price (`gasPrice` = 115792089237316195423570985008687907853269984665640564039457584007913 gwei) cannot be
* // @error: higher than the maximum allowed value (2^256-1).
* ```
*
* @param envelope - The transaction envelope to assert.
*/
export function assert(envelope: PartialBy<TransactionEnvelopeLegacy, 'type'>) {
const { chainId, gasPrice, to } = envelope
if (to) Address.assert(to, { strict: false })
if (typeof chainId !== 'undefined' && chainId <= 0)
throw new TransactionEnvelope.InvalidChainIdError({ chainId })
if (gasPrice && BigInt(gasPrice) > 2n ** 256n - 1n)
throw new TransactionEnvelope.GasPriceTooHighError({ gasPrice })
}
export declare namespace assert {
type ErrorType =
| Address.assert.ErrorType
| TransactionEnvelope.InvalidChainIdError
| TransactionEnvelope.GasPriceTooHighError
| Errors.GlobalErrorType
}
/**
* Deserializes a {@link ox#TransactionEnvelopeLegacy.TransactionEnvelopeLegacy} from its serialized form.
*
* @example
* ```ts twoslash
* import { TransactionEnvelopeLegacy } from 'ox'
*
* const envelope = TransactionEnvelopeLegacy.deserialize('0x01ef0182031184773594008477359400809470997970c51812dc3a010c7d01b50e0d17dc79c8880de0b6b3a764000080c0')
* // @log: {
* // @log: type: 'legacy',
* // @log: nonce: 785n,
* // @log: gasPrice: 2000000000n,
* // @log: gas: 1000000n,
* // @log: to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
* // @log: value: 1000000000000000000n,
* // @log: }
* ```
*
* @param serialized - The serialized transaction.
* @returns Deserialized Transaction Envelope.
*/
export function deserialize(
serialized: Hex.Hex,
): Compute<TransactionEnvelopeLegacy> {
const tuple = Rlp.toHex(serialized)
const [nonce, gasPrice, gas, to, value, data, chainIdOrV_, r, s] =
tuple as readonly Hex.Hex[]
if (!(tuple.length === 6 || tuple.length === 9))
throw new TransactionEnvelope.InvalidSerializedError({
attributes: {
nonce,
gasPrice,
gas,
to,
value,
data,
...(tuple.length > 6
? {
v: chainIdOrV_,
r,
s,
}
: {}),
},
serialized,
type,
})
const transaction = {
type,
} as TransactionEnvelopeLegacy
if (Hex.validate(to) && to !== '0x') transaction.to = to
if (Hex.validate(gas) && gas !== '0x') transaction.gas = BigInt(gas)
if (Hex.validate(data) && data !== '0x') transaction.data = data
if (Hex.validate(nonce) && nonce !== '0x') transaction.nonce = BigInt(nonce)
if (Hex.validate(value) && value !== '0x') transaction.value = BigInt(value)
if (Hex.validate(gasPrice) && gasPrice !== '0x')
transaction.gasPrice = BigInt(gasPrice)
if (tuple.length === 6) return transaction
const chainIdOrV =
Hex.validate(chainIdOrV_) && chainIdOrV_ !== '0x'
? Number(chainIdOrV_ as Hex.Hex)
: 0
if (s === '0x' && r === '0x') {
if (chainIdOrV > 0) transaction.chainId = Number(chainIdOrV)
return transaction
}
const v = chainIdOrV
const chainId: number | undefined = Math.floor((v - 35) / 2)
if (chainId > 0) transaction.chainId = chainId
else if (v !== 27 && v !== 28) throw new Signature.InvalidVError({ value: v })
transaction.yParity = Signature.vToYParity(v)
transaction.v = v
transaction.s = s === '0x' ? 0n : BigInt(s!)
transaction.r = r === '0x' ? 0n : BigInt(r!)
assert(transaction)
return transaction
}
export declare namespace deserialize {
type ErrorType = Errors.GlobalErrorType
}
/**
* Converts an arbitrary transaction object into a legacy Transaction Envelope.
*
* @example
* ```ts twoslash
* import { TransactionEnvelopeLegacy, Value } from 'ox'
*
* const envelope = TransactionEnvelopeLegacy.from({
* gasPrice: Value.fromGwei('10'),
* to: '0x0000000000000000000000000000000000000000',
* value: Value.fromEther('1'),
* })
* ```
*
* @example
* ### Attaching Signatures
*
* It is possible to attach a `signature` to the transaction envelope.
*
* ```ts twoslash
* import { Secp256k1, TransactionEnvelopeLegacy, Value } from 'ox'
*
* const envelope = TransactionEnvelopeLegacy.from({
* chainId: 1,
* gasPrice: Value.fromGwei('10'),
* to: '0x0000000000000000000000000000000000000000',
* value: Value.fromEther('1'),
* })
*
* const signature = Secp256k1.sign({
* payload: TransactionEnvelopeLegacy.getSignPayload(envelope),
* privateKey: '0x...',
* })
*
* const envelope_signed = TransactionEnvelopeLegacy.from(envelope, { // [!code focus]
* signature, // [!code focus]
* }) // [!code focus]
* // @log: {
* // @log: authorizationList: [...],
* // @log: chainId: 1,
* // @log: gasPrice: 10000000000n,
* // @log: to: '0x0000000000000000000000000000000000000000',
* // @log: type: 'eip7702',
* // @log: value: 1000000000000000000n,
* // @log: r: 125...n,
* // @log: s: 642...n,
* // @log: yParity: 0,
* // @log: }
* ```
*
* @example
* ### From Serialized
*
* It is possible to instantiate an legacy Transaction Envelope from a {@link ox#TransactionEnvelopeLegacy.Serialized} value.
*
* ```ts twoslash
* import { TransactionEnvelopeLegacy } from 'ox'
*
* const envelope = TransactionEnvelopeLegacy.from('0xf858018203118502540be4008504a817c800809470997970c51812dc3a010c7d01b50e0d17dc79c8880de0b6b3a764000080c08477359400e1a001627c687261b0e7f8638af1112efa8a77e23656f6e7945275b19e9deed80261')
* // @log: {
* // @log: chainId: 1,
* // @log: gasPrice: 10000000000n,
* // @log: to: '0x0000000000000000000000000000000000000000',
* // @log: type: 'legacy',
* // @log: value: 1000000000000000000n,
* // @log: }
* ```
*
* @param envelope - The transaction object to convert.
* @param options - Options.
* @returns A legacy Transaction Envelope.
*/
export function from<
const envelope extends
| UnionPartialBy<TransactionEnvelopeLegacy, 'type'>
| Hex.Hex,
const signature extends Signature.Signature | undefined = undefined,
>(
envelope:
| envelope
| UnionPartialBy<TransactionEnvelopeLegacy, 'type'>
| Hex.Hex,
options: from.Options<signature> = {},
): from.ReturnType<envelope, signature> {
const { signature } = options
const envelope_ = (
typeof envelope === 'string' ? deserialize(envelope) : envelope
) as TransactionEnvelopeLegacy
assert(envelope_)
const signature_ = (() => {
if (!signature) return {}
const s = Signature.from(signature) as any
s.v = Signature.yParityToV(s.yParity)
return s
})()
return {
...envelope_,
...signature_,
type: 'legacy',
} as never
}
export declare namespace from {
type Options<signature extends Signature.Signature | undefined = undefined> =
{
signature?: signature | Signature.Signature | undefined
}
type ReturnType<
envelope extends
| UnionPartialBy<TransactionEnvelopeLegacy, 'type'>
| Hex.Hex = TransactionEnvelopeLegacy | Hex.Hex,
signature extends Signature.Signature | undefined = undefined,
> = Compute<
envelope extends Hex.Hex
? TransactionEnvelopeLegacy
: Assign<
envelope,
(signature extends Signature.Signature
? Readonly<
signature & {
v: signature['yParity'] extends 0 ? 27 : 28
}
>
: {}) & {
readonly type: 'legacy'
}
>
>
type ErrorType =
| deserialize.ErrorType
| assert.ErrorType
| Errors.GlobalErrorType
}
/**
* Returns the payload to sign for a {@link ox#TransactionEnvelopeLegacy.TransactionEnvelopeLegacy}.
*
* @example
* The example below demonstrates how to compute the sign payload which can be used
* with ECDSA signing utilities like {@link ox#Secp256k1.(sign:function)}.
*
* ```ts twoslash
* // @noErrors
* import { Secp256k1, TransactionEnvelopeLegacy } from 'ox'
*
* const envelope = TransactionEnvelopeLegacy.from({
* nonce: 0n,
* gasPrice: 1000000000n,
* gas: 21000n,
* to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
* value: 1000000000000000000n,
* })
*
* const payload = TransactionEnvelopeLegacy.getSignPayload(envelope) // [!code focus]
* // @log: '0x...'
*
* const signature = Secp256k1.sign({ payload, privateKey: '0x...' })
* ```
*
* @param envelope - The transaction envelope to get the sign payload for.
* @returns The sign payload.
*/
export function getSignPayload(
envelope: TransactionEnvelopeLegacy<false>,
): getSignPayload.ReturnType {
return hash(envelope, { presign: true })
}
export declare namespace getSignPayload {
type ReturnType = Hex.Hex
type ErrorType = hash.ErrorType | Errors.GlobalErrorType
}
/**
* Hashes a {@link ox#TransactionEnvelopeLegacy.TransactionEnvelopeLegacy}. This is the "transaction hash".
*
* @example
* ```ts twoslash
* import { Secp256k1, TransactionEnvelopeLegacy } from 'ox'
*
* const envelope = TransactionEnvelopeLegacy.from({
* chainId: 1,
* nonce: 0n,
* gasPrice: 1000000000n,
* gas: 21000n,
* to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
* value: 1000000000000000000n,
* })
*
* const signature = Secp256k1.sign({
* payload: TransactionEnvelopeLegacy.getSignPayload(envelope),
* privateKey: '0x...'
* })
*
* const envelope_signed = TransactionEnvelopeLegacy.from(envelope, { signature })
*
* const hash = TransactionEnvelopeLegacy.hash(envelope_signed) // [!code focus]
* ```
*
* @param envelope - The Legacy Transaction Envelope to hash.
* @param options - Options.
* @returns The hash of the transaction envelope.
*/
export function hash<presign extends boolean = false>(
envelope: TransactionEnvelopeLegacy<presign extends true ? false : true>,
options: hash.Options<presign> = {},
): hash.ReturnType {
const { presign } = options
return Hash.keccak256(
serialize({
...envelope,
...(presign
? {
r: undefined,
s: undefined,
yParity: undefined,
v: undefined,
}
: {}),
}),
)
}
export declare namespace hash {
type Options<presign extends boolean = false> = {
/** Whether to hash this transaction for signing. @default false */
presign?: presign | boolean | undefined
}
type ReturnType = Hex.Hex
type ErrorType =
| Hash.keccak256.ErrorType
| serialize.ErrorType
| Errors.GlobalErrorType
}
/**
* Serializes a {@link ox#TransactionEnvelopeLegacy.TransactionEnvelopeLegacy}.
*
* @example
* ```ts twoslash
* // @noErrors
* import { TransactionEnvelopeLegacy } from 'ox'
*
* const envelope = TransactionEnvelopeLegacy.from({
* chainId: 1,
* gasPrice: Value.fromGwei('10'),
* to: '0x0000000000000000000000000000000000000000',
* value: Value.fromEther('1'),
* })
*
* const serialized = TransactionEnvelopeLegacy.serialize(envelope) // [!code focus]
* ```
*
* @example
* ### Attaching Signatures
*
* It is possible to attach a `signature` to the serialized Transaction Envelope.
*
* ```ts twoslash
* // @noErrors
* import { Secp256k1, TransactionEnvelopeLegacy, Value } from 'ox'
*
* const envelope = TransactionEnvelopeLegacy.from({
* chainId: 1,
* gasPrice: Value.fromGwei('10'),
* to: '0x0000000000000000000000000000000000000000',
* value: Value.fromEther('1'),
* })
*
* const signature = Secp256k1.sign({
* payload: TransactionEnvelopeLegacy.getSignPayload(envelope),
* privateKey: '0x...',
* })
*
* const serialized = TransactionEnvelopeLegacy.serialize(envelope, { // [!code focus]
* signature, // [!code focus]
* }) // [!code focus]
*
* // ... send `serialized` transaction to JSON-RPC `eth_sendRawTransaction`
* ```
*
* @param envelope - The Transaction Envelope to serialize.
* @param options - Options.
* @returns The serialized Transaction Envelope.
*/
export function serialize(
envelope: PartialBy<TransactionEnvelopeLegacy, 'type'>,
options: serialize.Options = {},
): Serialized {
const { chainId = 0, gas, data, input, nonce, to, value, gasPrice } = envelope
assert(envelope)
let serialized = [
nonce ? Hex.fromNumber(nonce) : '0x',
gasPrice ? Hex.fromNumber(gasPrice) : '0x',
gas ? Hex.fromNumber(gas) : '0x',
to ?? '0x',
value ? Hex.fromNumber(value) : '0x',
data ?? input ?? '0x',
]
const signature = (() => {
if (options.signature)
return {
r: options.signature.r,
s: options.signature.s,
v: Signature.yParityToV(options.signature.yParity),
}
if (typeof envelope.r === 'undefined' || typeof envelope.s === 'undefined')
return undefined
return {
r: envelope.r,
s: envelope.s,
v: envelope.v!,
}
})()
if (signature) {
const v = (() => {
// EIP-155 (inferred chainId)
if (signature.v >= 35) {
const inferredChainId = Math.floor((signature.v - 35) / 2)
if (inferredChainId > 0) return signature.v
return 27 + (signature.v === 35 ? 0 : 1)
}
// EIP-155 (explicit chainId)
if (chainId > 0) return chainId * 2 + 35 + signature.v - 27
// Pre-EIP-155 (no chainId)
const v = 27 + (signature.v === 27 ? 0 : 1)
if (signature.v !== v)
throw new Signature.InvalidVError({ value: signature.v })
return v
})()
serialized = [
...serialized,
Hex.fromNumber(v),
signature.r === 0n ? '0x' : Hex.trimLeft(Hex.fromNumber(signature.r)),
signature.s === 0n ? '0x' : Hex.trimLeft(Hex.fromNumber(signature.s)),
]
} else if (chainId > 0)
serialized = [...serialized, Hex.fromNumber(chainId), '0x', '0x']
return Rlp.fromHex(serialized) as never
}
export declare namespace serialize {
type Options = {
/** Signature to append to the serialized Transaction Envelope. */
signature?: Signature.Signature | undefined
}
type ErrorType =
| assert.ErrorType
| Hex.fromNumber.ErrorType
| Hex.trimLeft.ErrorType
| Rlp.fromHex.ErrorType
| Signature.InvalidVError
| Errors.GlobalErrorType
}
/**
* Converts an {@link ox#TransactionEnvelopeLegacy.TransactionEnvelopeLegacy} to an {@link ox#TransactionEnvelopeLegacy.Rpc}.
*
* @example
* ```ts twoslash
* import { RpcRequest, TransactionEnvelopeLegacy, Value } from 'ox'
*
* const envelope = TransactionEnvelopeLegacy.from({
* chainId: 1,
* nonce: 0n,
* gas: 21000n,
* to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
* value: Value.fromEther('1'),
* })
*
* const envelope_rpc = TransactionEnvelopeLegacy.toRpc(envelope) // [!code focus]
*
* const request = RpcRequest.from({
* id: 0,
* method: 'eth_sendTransaction',
* params: [envelope_rpc],
* })
* ```
*
* @param envelope - The legacy transaction envelope to convert.
* @returns An RPC-formatted legacy transaction envelope.
*/
export function toRpc(envelope: Omit<TransactionEnvelopeLegacy, 'type'>): Rpc {
const signature = Signature.extract(envelope)!
return {
...envelope,
chainId:
typeof envelope.chainId === 'number'
? Hex.fromNumber(envelope.chainId)
: undefined,
data: envelope.data ?? envelope.input,
type: '0x0',
...(typeof envelope.gas === 'bigint'
? { gas: Hex.fromNumber(envelope.gas) }
: {}),
...(typeof envelope.nonce === 'bigint'
? { nonce: Hex.fromNumber(envelope.nonce) }
: {}),
...(typeof envelope.value === 'bigint'
? { value: Hex.fromNumber(envelope.value) }
: {}),
...(typeof envelope.gasPrice === 'bigint'
? { gasPrice: Hex.fromNumber(envelope.gasPrice) }
: {}),
...(signature
? {
...Signature.toRpc(signature),
v: signature.yParity === 0 ? '0x1b' : '0x1c',
}
: {}),
} as never
}
export declare namespace toRpc {
export type ErrorType = Signature.extract.ErrorType | Errors.GlobalErrorType
}
/**
* Validates a {@link ox#TransactionEnvelopeLegacy.TransactionEnvelopeLegacy}. Returns `true` if the envelope is valid, `false` otherwise.
*
* @example
* ```ts twoslash
* import { TransactionEnvelopeLegacy, Value } from 'ox'
*
* const valid = TransactionEnvelopeLegacy.assert({
* gasPrice: 2n ** 256n - 1n + 1n,
* chainId: 1,
* to: '0x0000000000000000000000000000000000000000',
* value: Value.fromEther('1'),
* })
* // @log: false
* ```
*
* @param envelope - The transaction envelope to validate.
*/
export function validate(
envelope: PartialBy<TransactionEnvelopeLegacy, 'type'>,
) {
try {
assert(envelope)
return true
} catch {
return false
}
}
export declare namespace validate {
type ErrorType = Errors.GlobalErrorType
}

333
node_modules/ox/core/TransactionReceipt.ts generated vendored Normal file
View File

@@ -0,0 +1,333 @@
import type * as Address from './Address.js'
import type * as Errors from './Errors.js'
import * as Hex from './Hex.js'
import * as Log from './Log.js'
import type { Compute } from './internal/types.js'
/** An Transaction Receipt as defined in the [Execution API specification](https://github.com/ethereum/execution-apis/blob/main/src/schemas/receipt.yaml). */
export type TransactionReceipt<
status = Status,
type = Type,
bigintType = bigint,
numberType = number,
> = Compute<{
/** The actual value per gas deducted from the sender's account for blob gas. Only specified for blob transactions as defined by EIP-4844. */
blobGasPrice?: bigintType | undefined
/** The amount of blob gas used. Only specified for blob transactions as defined by EIP-4844. */
blobGasUsed?: bigintType | undefined
/** Hash of block containing this transaction */
blockHash: Hex.Hex
/** Number of block containing this transaction */
blockNumber: bigintType
/** Address of new contract or `null` if no contract was created */
contractAddress?: Address.Address | null | undefined
/** Gas used by this and all preceding transactions in this block */
cumulativeGasUsed: bigintType
/** Pre-London, it is equal to the transaction's gasPrice. Post-London, it is equal to the actual gas price paid for inclusion. */
effectiveGasPrice: bigintType
/** Transaction sender */
from: Address.Address
/** Gas used by this transaction */
gasUsed: bigintType
/** List of log objects generated by this transaction */
logs: Log.Log<false, bigintType, numberType>[]
/** Logs bloom filter */
logsBloom: Hex.Hex
/** The post-transaction state root. Only specified for transactions included before the Byzantium upgrade. */
root?: Hex.Hex | undefined
/** `success` if this transaction was successful or `reverted` if it failed */
status: status
/** Transaction recipient or `null` if deploying a contract */
to: Address.Address | null
/** Hash of this transaction */
transactionHash: Hex.Hex
/** Index of this transaction in the block */
transactionIndex: numberType
/** Transaction type */
type: type
}>
/** An RPC Transaction Receipt as defined in the [Execution API specification](https://github.com/ethereum/execution-apis/blob/main/src/schemas/receipt.yaml). */
export type Rpc = TransactionReceipt<RpcStatus, RpcType, Hex.Hex, Hex.Hex>
/**
* Union of Transaction Receipt statuses.
*
* - `success`
* - `reverted`
*/
export type Status = 'success' | 'reverted'
/**
* Union of RPC Transaction Receipt statuses.
*
* - `0x0`
* - `0x1`
*/
export type RpcStatus = '0x0' | '0x1'
/**
* Union of Transaction Receipt types.
*
* - `legacy`
* - `eip1559`
* - `eip2930`
* - `eip4844`
* - `eip7702`
* - any other string
*/
export type Type =
| 'legacy'
| 'eip1559'
| 'eip2930'
| 'eip4844'
| 'eip7702'
| (string & {})
/**
* Union of RPC Transaction Receipt types.
*
* - `0x0`: legacy transactions
* - `0x1`: EIP-1559 transactions
* - `0x2`: EIP-2930 transactions
* - `0x3`: EIP-4844 transactions
* - `0x4`: EIP-7702 transactions
* - any other string
*/
export type RpcType = '0x0' | '0x1' | '0x2' | '0x3' | '0x4' | (string & {})
/** RPC status to status mapping. */
export const fromRpcStatus = {
'0x0': 'reverted',
'0x1': 'success',
} as const
/** Status to RPC status mapping. */
export const toRpcStatus = {
reverted: '0x0',
success: '0x1',
} as const
/** RPC type to type mapping. */
export const fromRpcType = {
'0x0': 'legacy',
'0x1': 'eip2930',
'0x2': 'eip1559',
'0x3': 'eip4844',
'0x4': 'eip7702',
} as const
/** Type to RPC type mapping. */
export const toRpcType = {
legacy: '0x0',
eip2930: '0x1',
eip1559: '0x2',
eip4844: '0x3',
eip7702: '0x4',
} as const
/**
* Converts a {@link ox#TransactionReceipt.Rpc} to an {@link ox#TransactionReceipt.TransactionReceipt}.
*
* @example
* ```ts twoslash
* import { TransactionReceipt } from 'ox'
*
* const receipt = TransactionReceipt.fromRpc({
* blobGasPrice: '0x42069',
* blobGasUsed: '0x1337',
* blockHash:
* '0xc350d807505fb835650f0013632c5515592987ba169bbc6626d9fc54d91f0f0b',
* blockNumber: '0x12f296f',
* contractAddress: null,
* cumulativeGasUsed: '0x82515',
* effectiveGasPrice: '0x21c2f6c09',
* from: '0x814e5e0e31016b9a7f138c76b7e7b2bb5c1ab6a6',
* gasUsed: '0x2abba',
* logs: [],
* logsBloom:
* '0x00200000000000000000008080000000000000000040000000000000000000000000000000000000000000000000000022000000080000000000000000000000000000080000000000000008000000200000000000000000000200008020400000000000000000280000000000100000000000000000000000000010000000000000000000020000000000000020000000000001000000080000004000000000000000000000000000000000000000000000400000000000001000000000000000000002000000000000000020000000000000000000001000000000000000000000200000000000000000000000000000001000000000c00000000000000000',
* status: '0x1',
* to: '0x3fc91a3afd70395cd496c647d5a6cc9d4b2b7fad',
* transactionHash:
* '0x353fdfc38a2f26115daadee9f5b8392ce62b84f410957967e2ed56b35338cdd0',
* transactionIndex: '0x2',
* type: '0x2',
* })
* // @log: {
* // @log: blobGasPrice: 270441n,
* // @log: blobGasUsed: 4919n,
* // @log: blockHash: "0xc350d807505fb835650f0013632c5515592987ba169bbc6626d9fc54d91f0f0b",
* // @log: blockNumber: 19868015n,
* // @log: contractAddress: null,
* // @log: cumulativeGasUsed: 533781n,
* // @log: effectiveGasPrice: 9062804489n,
* // @log: from: "0x814e5e0e31016b9a7f138c76b7e7b2bb5c1ab6a6",
* // @log: gasUsed: 175034n,
* // @log: logs: [],
* // @log: logsBloom: "0x00200000000000000000008080000000000000000040000000000000000000000000000000000000000000000000000022000000080000000000000000000000000000080000000000000008000000200000000000000000000200008020400000000000000000280000000000100000000000000000000000000010000000000000000000020000000000000020000000000001000000080000004000000000000000000000000000000000000000000000400000000000001000000000000000000002000000000000000020000000000000000000001000000000000000000000200000000000000000000000000000001000000000c00000000000000000",
* // @log: root: undefined,
* // @log: status: "success",
* // @log: to: "0x3fc91a3afd70395cd496c647d5a6cc9d4b2b7fad",
* // @log: transactionHash: "0x353fdfc38a2f26115daadee9f5b8392ce62b84f410957967e2ed56b35338cdd0",
* // @log: transactionIndex: 2,
* // @log: type: "eip1559",
* // @log: }
* ```
*
* @example
* ### End-to-end
*
* Below is an example of how to use the `TransactionReceipt.fromRpc` method to convert an RPC transaction receipt to a {@link ox#TransactionReceipt.TransactionReceipt} object.
*
* ```ts twoslash
* import 'ox/window'
* import { TransactionReceipt } from 'ox'
*
* const receipt = await window.ethereum!
* .request({
* method: 'eth_getTransactionReceipt',
* params: [
* '0x353fdfc38a2f26115daadee9f5b8392ce62b84f410957967e2ed56b35338cdd0',
* ],
* })
* .then(TransactionReceipt.fromRpc) // [!code hl]
* // @log: {
* // @log: blobGasPrice: 270441n,
* // @log: blobGasUsed: 4919n,
* // @log: blockHash: "0xc350d807505fb835650f0013632c5515592987ba169bbc6626d9fc54d91f0f0b",
* // @log: blockNumber: 19868015n,
* // @log: contractAddress: null,
* // @log: cumulativeGasUsed: 533781n,
* // @log: effectiveGasPrice: 9062804489n,
* // @log: from: "0x814e5e0e31016b9a7f138c76b7e7b2bb5c1ab6a6",
* // @log: gasUsed: 175034n,
* // @log: logs: [],
* // @log: logsBloom: "0x00200000000000000000008080000000000000000040000000000000000000000000000000000000000000000000000022000000080000000000000000000000000000080000000000000008000000200000000000000000000200008020400000000000000000280000000000100000000000000000000000000010000000000000000000020000000000000020000000000001000000080000004000000000000000000000000000000000000000000000400000000000001000000000000000000002000000000000000020000000000000000000001000000000000000000000200000000000000000000000000000001000000000c00000000000000000",
* // @log: root: undefined,
* // @log: status: "success",
* // @log: to: "0x3fc91a3afd70395cd496c647d5a6cc9d4b2b7fad",
* // @log: transactionHash: "0x353fdfc38a2f26115daadee9f5b8392ce62b84f410957967e2ed56b35338cdd0",
* // @log: transactionIndex: 2,
* // @log: type: "eip1559",
* // @log: }
* ```
*
* :::note
*
* For simplicity, the above example uses `window.ethereum.request`, but you can use any
* type of JSON-RPC interface.
*
* :::
*
* @param receipt - The RPC receipt to convert.
* @returns An instantiated {@link ox#TransactionReceipt.TransactionReceipt}.
*/
export function fromRpc<const receipt extends Rpc | null>(
receipt: receipt | Rpc | null,
): receipt extends Rpc ? TransactionReceipt : null {
if (!receipt) return null as never
return {
...receipt,
blobGasPrice: receipt.blobGasPrice
? BigInt(receipt.blobGasPrice)
: undefined,
blobGasUsed: receipt.blobGasUsed ? BigInt(receipt.blobGasUsed) : undefined,
blockNumber: BigInt(receipt.blockNumber ?? 0n),
cumulativeGasUsed: BigInt(receipt.cumulativeGasUsed ?? 0n),
effectiveGasPrice: BigInt(receipt.effectiveGasPrice ?? 0n),
gasUsed: BigInt(receipt.gasUsed ?? 0n),
logs: receipt.logs.map((log) => Log.fromRpc(log, { pending: false })),
status: fromRpcStatus[receipt.status],
transactionIndex: Number(receipt.transactionIndex ?? 0),
type: (fromRpcType as any)[receipt.type] || receipt.type,
} as never
}
export declare namespace fromRpc {
export type ErrorType = Log.fromRpc.ErrorType | Errors.GlobalErrorType
}
/**
* Converts a {@link ox#TransactionReceipt.TransactionReceipt} to a {@link ox#TransactionReceipt.Rpc}.
*
* @example
* ```ts twoslash
* import { TransactionReceipt } from 'ox'
*
* const receipt = TransactionReceipt.toRpc({
* blobGasPrice: 270441n,
* blobGasUsed: 4919n,
* blockHash:
* '0xc350d807505fb835650f0013632c5515592987ba169bbc6626d9fc54d91f0f0b',
* blockNumber: 19868015n,
* contractAddress: null,
* cumulativeGasUsed: 533781n,
* effectiveGasPrice: 9062804489n,
* from: '0x814e5e0e31016b9a7f138c76b7e7b2bb5c1ab6a6',
* gasUsed: 175034n,
* logs: [],
* logsBloom:
* '0x00200000000000000000008080000000000000000040000000000000000000000000000000000000000000000000000022000000080000000000000000000000000000080000000000000008000000200000000000000000000200008020400000000000000000280000000000100000000000000000000000000010000000000000000000020000000000000020000000000001000000080000004000000000000000000000000000000000000000000000400000000000001000000000000000000002000000000000000020000000000000000000001000000000000000000000200000000000000000000000000000001000000000c00000000000000000',
* root: undefined,
* status: 'success',
* to: '0x3fc91a3afd70395cd496c647d5a6cc9d4b2b7fad',
* transactionHash:
* '0x353fdfc38a2f26115daadee9f5b8392ce62b84f410957967e2ed56b35338cdd0',
* transactionIndex: 2,
* type: 'eip1559',
* })
* // @log: {
* // @log: blobGasPrice: "0x042069",
* // @log: blobGasUsed: "0x1337",
* // @log: blockHash: "0xc350d807505fb835650f0013632c5515592987ba169bbc6626d9fc54d91f0f0b",
* // @log: blockNumber: "0x012f296f",
* // @log: contractAddress: null,
* // @log: cumulativeGasUsed: "0x082515",
* // @log: effectiveGasPrice: "0x021c2f6c09",
* // @log: from: "0x814e5e0e31016b9a7f138c76b7e7b2bb5c1ab6a6",
* // @log: gasUsed: "0x02abba",
* // @log: logs: [],
* // @log: logsBloom: "0x00200000000000000000008080000000000000000040000000000000000000000000000000000000000000000000000022000000080000000000000000000000000000080000000000000008000000200000000000000000000200008020400000000000000000280000000000100000000000000000000000000010000000000000000000020000000000000020000000000001000000080000004000000000000000000000000000000000000000000000400000000000001000000000000000000002000000000000000020000000000000000000001000000000000000000000200000000000000000000000000000001000000000c00000000000000000",
* // @log: root: undefined,
* // @log: status: "0x1",
* // @log: to: "0x3fc91a3afd70395cd496c647d5a6cc9d4b2b7fad",
* // @log: transactionHash: "0x353fdfc38a2f26115daadee9f5b8392ce62b84f410957967e2ed56b35338cdd0",
* // @log: transactionIndex: "0x02",
* // @log: type: "eip1559",
* // @log: }
* ```
*
* @param receipt - The receipt to convert.
* @returns An RPC receipt.
*/
export function toRpc(receipt: TransactionReceipt): Rpc {
return {
blobGasPrice: receipt.blobGasPrice
? Hex.fromNumber(receipt.blobGasPrice)
: undefined,
blobGasUsed: receipt.blobGasUsed
? Hex.fromNumber(receipt.blobGasUsed)
: undefined,
blockHash: receipt.blockHash,
blockNumber: Hex.fromNumber(receipt.blockNumber),
contractAddress: receipt.contractAddress,
cumulativeGasUsed: Hex.fromNumber(receipt.cumulativeGasUsed),
effectiveGasPrice: Hex.fromNumber(receipt.effectiveGasPrice),
from: receipt.from,
gasUsed: Hex.fromNumber(receipt.gasUsed),
logs: receipt.logs.map(Log.toRpc as never),
logsBloom: receipt.logsBloom,
root: receipt.root,
status: toRpcStatus[receipt.status],
to: receipt.to,
transactionHash: receipt.transactionHash,
transactionIndex: Hex.fromNumber(receipt.transactionIndex),
type: (toRpcType as any)[receipt.type] ?? receipt.type,
}
}
export declare namespace toRpc {
export type ErrorType = Hex.fromNumber.ErrorType | Errors.GlobalErrorType
}

147
node_modules/ox/core/TransactionRequest.ts generated vendored Normal file
View File

@@ -0,0 +1,147 @@
import type * as AccessList from './AccessList.js'
import type * as Address from './Address.js'
import * as Authorization from './Authorization.js'
import type * as Errors from './Errors.js'
import * as Hex from './Hex.js'
import type { Compute } from './internal/types.js'
/** A Transaction Request that is generic to all transaction types, as defined in the [Execution API specification](https://github.com/ethereum/execution-apis/blob/4aca1d7a3e5aab24c8f6437131289ad386944eaa/src/schemas/transaction.yaml#L358-L423). */
export type TransactionRequest<
bigintType = bigint,
numberType = number,
type extends string = string,
> = Compute<{
/** EIP-2930 Access List. */
accessList?: AccessList.AccessList | undefined
/** EIP-7702 Authorization List. */
authorizationList?:
| Authorization.ListSigned<bigintType, numberType>
| undefined
/** Versioned hashes of blobs to be included in the transaction. */
blobVersionedHashes?: readonly Hex.Hex[]
/** Raw blob data. */
blobs?: readonly Hex.Hex[] | undefined
/** EIP-155 Chain ID. */
chainId?: numberType | undefined
/** Contract code or a hashed method call with encoded args */
data?: Hex.Hex | undefined
/** @alias `data` added for TransactionEnvelope - Transaction compatibility. */
input?: Hex.Hex | undefined
/** Sender of the transaction. */
from?: Address.Address | undefined
/** Gas provided for transaction execution */
gas?: bigintType | undefined
/** Base fee per gas. */
gasPrice?: bigintType | undefined
/** Maximum total fee per gas sender is willing to pay for blob gas (in wei). */
maxFeePerBlobGas?: bigintType | undefined
/** Total fee per gas in wei (gasPrice/baseFeePerGas + maxPriorityFeePerGas). */
maxFeePerGas?: bigintType | undefined
/** Max priority fee per gas (in wei). */
maxPriorityFeePerGas?: bigintType | undefined
/** Unique number identifying this transaction */
nonce?: bigintType | undefined
/** Transaction recipient */
to?: Address.Address | null | undefined
/** Transaction type */
type?: type | undefined
/** Value in wei sent with this transaction */
value?: bigintType | undefined
}>
/** RPC representation of a {@link ox#TransactionRequest.TransactionRequest}. */
export type Rpc = TransactionRequest<Hex.Hex, Hex.Hex, string>
/**
* Converts a {@link ox#TransactionRequest.TransactionRequest} to a {@link ox#TransactionRequest.Rpc}.
*
* @example
* ```ts twoslash
* import { TransactionRequest, Value } from 'ox'
*
* const request = TransactionRequest.toRpc({
* to: '0x0000000000000000000000000000000000000000',
* value: Value.fromEther('0.01'),
* })
* ```
*
* @example
* ### Using with a Provider
*
* You can use {@link ox#Provider.(from:function)} to instantiate an EIP-1193 Provider and
* send a transaction to the Wallet using the `eth_sendTransaction` method.
*
* ```ts twoslash
* import 'ox/window'
* import { Provider, TransactionRequest, Value } from 'ox'
*
* const provider = Provider.from(window.ethereum!)
*
* const request = TransactionRequest.toRpc({
* to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
* value: Value.fromEther('0.01'),
* })
*
* const hash = await provider.request({ // [!code focus]
* method: 'eth_sendTransaction', // [!code focus]
* params: [request], // [!code focus]
* }) // [!code focus]
* ```
*
* @param request - The request to convert.
* @returns An RPC request.
*/
export function toRpc(request: TransactionRequest): Rpc {
const request_rpc: Rpc = {}
if (typeof request.accessList !== 'undefined')
request_rpc.accessList = request.accessList
if (typeof request.authorizationList !== 'undefined')
request_rpc.authorizationList = Authorization.toRpcList(
request.authorizationList,
)
if (typeof request.blobVersionedHashes !== 'undefined')
request_rpc.blobVersionedHashes = request.blobVersionedHashes
if (typeof request.blobs !== 'undefined') request_rpc.blobs = request.blobs
if (typeof request.chainId !== 'undefined')
request_rpc.chainId = Hex.fromNumber(request.chainId)
if (typeof request.data !== 'undefined') {
request_rpc.data = request.data
request_rpc.input = request.data
} else if (typeof request.input !== 'undefined') {
request_rpc.data = request.input
request_rpc.input = request.input
}
if (typeof request.from !== 'undefined') request_rpc.from = request.from
if (typeof request.gas !== 'undefined')
request_rpc.gas = Hex.fromNumber(request.gas)
if (typeof request.gasPrice !== 'undefined')
request_rpc.gasPrice = Hex.fromNumber(request.gasPrice)
if (typeof request.maxFeePerBlobGas !== 'undefined')
request_rpc.maxFeePerBlobGas = Hex.fromNumber(request.maxFeePerBlobGas)
if (typeof request.maxFeePerGas !== 'undefined')
request_rpc.maxFeePerGas = Hex.fromNumber(request.maxFeePerGas)
if (typeof request.maxPriorityFeePerGas !== 'undefined')
request_rpc.maxPriorityFeePerGas = Hex.fromNumber(
request.maxPriorityFeePerGas,
)
if (typeof request.maxPriorityFeePerGas !== 'undefined')
request_rpc.maxPriorityFeePerGas = Hex.fromNumber(
request.maxPriorityFeePerGas,
)
if (typeof request.nonce !== 'undefined')
request_rpc.nonce = Hex.fromNumber(request.nonce)
if (typeof request.to !== 'undefined') request_rpc.to = request.to
if (typeof request.type !== 'undefined') request_rpc.type = request.type
if (typeof request.value !== 'undefined')
request_rpc.value = Hex.fromNumber(request.value)
return request_rpc
}
export declare namespace toRpc {
export type ErrorType =
| Authorization.toRpcList.ErrorType
| Hex.fromNumber.ErrorType
| Errors.GlobalErrorType
}

910
node_modules/ox/core/TypedData.ts generated vendored Normal file
View File

@@ -0,0 +1,910 @@
import type * as abitype from 'abitype'
import * as AbiParameters from './AbiParameters.js'
import * as Address from './Address.js'
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 Json from './Json.js'
import * as Solidity from './Solidity.js'
import type { Compute } from './internal/types.js'
export type TypedData = abitype.TypedData
export type Domain = abitype.TypedDataDomain
export type Parameter = abitype.TypedDataParameter
// TODO: Make reusable for Viem?
export type Definition<
typedData extends TypedData | Record<string, unknown> = TypedData,
primaryType extends keyof typedData | 'EIP712Domain' = keyof typedData,
///
primaryTypes = typedData extends TypedData ? keyof typedData : string,
> = primaryType extends 'EIP712Domain'
? EIP712DomainDefinition<typedData, primaryType>
: MessageDefinition<typedData, primaryType, primaryTypes>
export type EIP712DomainDefinition<
typedData extends TypedData | Record<string, unknown> = TypedData,
primaryType extends 'EIP712Domain' = 'EIP712Domain',
///
schema extends Record<string, unknown> = typedData extends TypedData
? abitype.TypedDataToPrimitiveTypes<typedData>
: Record<string, unknown>,
> = {
types?: typedData | undefined
} & {
primaryType:
| 'EIP712Domain'
| (primaryType extends 'EIP712Domain' ? primaryType : never)
domain: schema extends { EIP712Domain: infer domain }
? domain
: Compute<Domain>
message?: undefined
}
export type MessageDefinition<
typedData extends TypedData | Record<string, unknown> = TypedData,
primaryType extends keyof typedData = keyof typedData,
///
primaryTypes = typedData extends TypedData ? keyof typedData : string,
schema extends Record<string, unknown> = typedData extends TypedData
? abitype.TypedDataToPrimitiveTypes<typedData>
: Record<string, unknown>,
message = schema[primaryType extends keyof schema
? primaryType
: keyof schema],
> = {
types: typedData
} & {
primaryType:
| primaryTypes // show all values
| (primaryType extends primaryTypes ? primaryType : never) // infer value
domain?:
| (schema extends { EIP712Domain: infer domain } ? domain : Compute<Domain>)
| undefined
message: { [_: string]: any } extends message // Check if message was inferred
? Record<string, unknown>
: message
}
/**
* Asserts that [EIP-712 Typed Data](https://eips.ethereum.org/EIPS/eip-712) is valid.
*
* @example
* ```ts twoslash
* import { TypedData } from 'ox'
*
* TypedData.assert({
* domain: {
* name: 'Ether!',
* version: '1',
* chainId: 1,
* verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC',
* },
* primaryType: 'Foo',
* types: {
* Foo: [
* { name: 'address', type: 'address' },
* { name: 'name', type: 'string' },
* { name: 'foo', type: 'string' },
* ],
* },
* message: {
* address: '0xb9CAB4F0E46F7F6b1024b5A7463734fa68E633f9',
* name: 'jxom',
* foo: '0xb9CAB4F0E46F7F6b1024b5A7463734fa68E633f9',
* },
* })
* ```
*
* @param value - The Typed Data to validate.
*/
export function assert<
const typedData extends TypedData | Record<string, unknown>,
primaryType extends keyof typedData | 'EIP712Domain',
>(value: assert.Value<typedData, primaryType>): void {
const { domain, message, primaryType, types } =
value as unknown as assert.Value
const validateData = (
struct: readonly Parameter[],
data: Record<string, unknown>,
) => {
for (const param of struct) {
const { name, type } = param
const value = data[name]
const integerMatch = type.match(Solidity.integerRegex)
if (
integerMatch &&
(typeof value === 'number' || typeof value === 'bigint')
) {
const [, base, size_] = integerMatch
// If number cannot be cast to a sized hex value, it is out of range
// and will throw.
Hex.fromNumber(value, {
signed: base === 'int',
size: Number.parseInt(size_ ?? '') / 8,
})
}
if (
type === 'address' &&
typeof value === 'string' &&
!Address.validate(value)
)
throw new Address.InvalidAddressError({
address: value,
cause: new Address.InvalidInputError(),
})
const bytesMatch = type.match(Solidity.bytesRegex)
if (bytesMatch) {
const [, size] = bytesMatch
if (size && Hex.size(value as Hex.Hex) !== Number.parseInt(size))
throw new BytesSizeMismatchError({
expectedSize: Number.parseInt(size),
givenSize: Hex.size(value as Hex.Hex),
})
}
const struct = types[type]
if (struct) {
validateReference(type)
validateData(struct, value as Record<string, unknown>)
}
}
}
// Validate domain types.
if (types.EIP712Domain && domain) {
if (typeof domain !== 'object') throw new InvalidDomainError({ domain })
validateData(types.EIP712Domain, domain)
}
// Validate message types.
if (primaryType !== 'EIP712Domain') {
if (types[primaryType]) validateData(types[primaryType], message)
else throw new InvalidPrimaryTypeError({ primaryType, types })
}
}
export declare namespace assert {
type Value<
typedData extends TypedData | Record<string, unknown> = TypedData,
primaryType extends keyof typedData | 'EIP712Domain' = keyof typedData,
> = Definition<typedData, primaryType>
type ErrorType =
| Address.InvalidAddressError
| BytesSizeMismatchError
| InvalidPrimaryTypeError
| Hex.fromNumber.ErrorType
| Hex.size.ErrorType
| Errors.GlobalErrorType
}
/**
* Creates [EIP-712 Typed Data](https://eips.ethereum.org/EIPS/eip-712) [`domainSeparator`](https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator) for the provided domain.
*
* @example
* ```ts twoslash
* import { TypedData } from 'ox'
*
* TypedData.domainSeparator({
* name: 'Ether!',
* version: '1',
* chainId: 1,
* verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC',
* })
* // @log: '0x9911ee4f58a7059a8f5385248040e6984d80e2c849500fe6a4d11c4fa98c2af3'
* ```
*
* @param domain - The domain for which to create the domain separator.
* @returns The domain separator.
*/
export function domainSeparator(domain: Domain): Hex.Hex {
return hashDomain({
domain,
})
}
export declare namespace domainSeparator {
type ErrorType = hashDomain.ErrorType | Errors.GlobalErrorType
}
/**
* Encodes typed data in [EIP-712 format](https://eips.ethereum.org/EIPS/eip-712): `0x19 ‖ 0x01 ‖ domainSeparator ‖ hashStruct(message)`.
*
* @example
* ```ts twoslash
* import { TypedData, Hash } from 'ox'
*
* const data = TypedData.encode({ // [!code focus:33]
* domain: {
* name: 'Ether Mail',
* version: '1',
* chainId: 1,
* verifyingContract: '0x0000000000000000000000000000000000000000',
* },
* types: {
* Person: [
* { name: 'name', type: 'string' },
* { name: 'wallet', type: 'address' },
* ],
* Mail: [
* { name: 'from', type: 'Person' },
* { name: 'to', type: 'Person' },
* { name: 'contents', type: 'string' },
* ],
* },
* primaryType: 'Mail',
* message: {
* from: {
* name: 'Cow',
* wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
* },
* to: {
* name: 'Bob',
* wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
* },
* contents: 'Hello, Bob!',
* },
* })
* // @log: '0x19012fdf3441fcaf4f30c7e16292b258a5d7054a4e2e00dbd7b7d2f467f2b8fb9413c52c0ee5d84264471806290a3f2c4cecfc5490626bf912d01f240d7a274b371e'
* // @log: (0x19 ‖ 0x01 ‖ domainSeparator ‖ hashStruct(message))
*
* const hash = Hash.keccak256(data)
* ```
*
* @param value - The Typed Data to encode.
* @returns The encoded Typed Data.
*/
export function encode<
const typedData extends TypedData | Record<string, unknown>,
primaryType extends keyof typedData | 'EIP712Domain',
>(value: encode.Value<typedData, primaryType>): Hex.Hex {
const { domain = {}, message, primaryType } = value as encode.Value
const types = {
EIP712Domain: extractEip712DomainTypes(domain),
...value.types,
} as TypedData
// Need to do a runtime validation check on addresses, byte ranges, integer ranges, etc
// as we can't statically check this with TypeScript.
assert({
domain,
message,
primaryType,
types,
})
// Typed Data Format: `0x19 ‖ 0x01 ‖ domainSeparator ‖ hashStruct(message)`
const parts: Hex.Hex[] = ['0x19', '0x01']
if (domain)
parts.push(
hashDomain({
domain,
types,
}),
)
if (primaryType !== 'EIP712Domain')
parts.push(
hashStruct({
data: message,
primaryType,
types,
}),
)
return Hex.concat(...parts)
}
export declare namespace encode {
type Value<
typedData extends TypedData | Record<string, unknown> = TypedData,
primaryType extends keyof typedData | 'EIP712Domain' = keyof typedData,
> = Definition<typedData, primaryType>
type ErrorType =
| extractEip712DomainTypes.ErrorType
| hashDomain.ErrorType
| hashStruct.ErrorType
| assert.ErrorType
| Errors.GlobalErrorType
}
/**
* Encodes [EIP-712 Typed Data](https://eips.ethereum.org/EIPS/eip-712) schema for the provided primaryType.
*
* @example
* ```ts twoslash
* import { TypedData } from 'ox'
*
* TypedData.encodeType({
* types: {
* Foo: [
* { name: 'address', type: 'address' },
* { name: 'name', type: 'string' },
* { name: 'foo', type: 'string' },
* ],
* },
* primaryType: 'Foo',
* })
* // @log: 'Foo(address address,string name,string foo)'
* ```
*
* @param value - The Typed Data schema.
* @returns The encoded type.
*/
export function encodeType(value: encodeType.Value): string {
const { primaryType, types } = value
let result = ''
const unsortedDeps = findTypeDependencies({ primaryType, types })
unsortedDeps.delete(primaryType)
const deps = [primaryType, ...Array.from(unsortedDeps).sort()]
for (const type of deps) {
result += `${type}(${(types[type] ?? [])
.map(({ name, type: t }) => `${t} ${name}`)
.join(',')})`
}
return result
}
export declare namespace encodeType {
type Value = {
primaryType: string
types: TypedData
}
type ErrorType = findTypeDependencies.ErrorType | Errors.GlobalErrorType
}
/**
* Gets [EIP-712 Typed Data](https://eips.ethereum.org/EIPS/eip-712) schema for EIP-721 domain.
*
* @example
* ```ts twoslash
* import { TypedData } from 'ox'
*
* TypedData.extractEip712DomainTypes({
* name: 'Ether!',
* version: '1',
* chainId: 1,
* verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC',
* })
* // @log: [
* // @log: { 'name': 'name', 'type': 'string' },
* // @log: { 'name': 'version', 'type': 'string' },
* // @log: { 'name': 'chainId', 'type': 'uint256' },
* // @log: { 'name': 'verifyingContract', 'type': 'address' },
* // @log: ]
* ```
*
* @param domain - The EIP-712 domain.
* @returns The EIP-712 domain schema.
*/
export function extractEip712DomainTypes(
domain: Domain | undefined,
): Parameter[] {
return [
typeof domain?.name === 'string' && { name: 'name', type: 'string' },
domain?.version && { name: 'version', type: 'string' },
typeof domain?.chainId === 'number' && {
name: 'chainId',
type: 'uint256',
},
domain?.verifyingContract && {
name: 'verifyingContract',
type: 'address',
},
domain?.salt && { name: 'salt', type: 'bytes32' },
].filter(Boolean) as Parameter[]
}
export declare namespace extractEip712DomainTypes {
type ErrorType = Errors.GlobalErrorType
}
/**
* Gets the payload to use for signing typed data in [EIP-712 format](https://eips.ethereum.org/EIPS/eip-712).
*
* @example
* ```ts twoslash
* import { Secp256k1, TypedData, Hash } from 'ox'
*
* const payload = TypedData.getSignPayload({ // [!code focus:99]
* domain: {
* name: 'Ether Mail',
* version: '1',
* chainId: 1,
* verifyingContract: '0x0000000000000000000000000000000000000000',
* },
* types: {
* Person: [
* { name: 'name', type: 'string' },
* { name: 'wallet', type: 'address' },
* ],
* Mail: [
* { name: 'from', type: 'Person' },
* { name: 'to', type: 'Person' },
* { name: 'contents', type: 'string' },
* ],
* },
* primaryType: 'Mail',
* message: {
* from: {
* name: 'Cow',
* wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
* },
* to: {
* name: 'Bob',
* wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
* },
* contents: 'Hello, Bob!',
* },
* })
*
* const signature = Secp256k1.sign({ payload, privateKey: '0x...' })
* ```
*
* @param value - The typed data to get the sign payload for.
* @returns The payload to use for signing.
*/
export function getSignPayload<
const typedData extends TypedData | Record<string, unknown>,
primaryType extends keyof typedData | 'EIP712Domain',
>(value: encode.Value<typedData, primaryType>): Hex.Hex {
return Hash.keccak256(encode(value))
}
export declare namespace getSignPayload {
type ErrorType =
| Hash.keccak256.ErrorType
| encode.ErrorType
| Errors.GlobalErrorType
}
/**
* Hashes [EIP-712 Typed Data](https://eips.ethereum.org/EIPS/eip-712) domain.
*
* @example
* ```ts twoslash
* import { TypedData } from 'ox'
*
* TypedData.hashDomain({
* domain: {
* name: 'Ether Mail',
* version: '1',
* chainId: 1,
* verifyingContract: '0x0000000000000000000000000000000000000000',
* },
* })
* // @log: '0x6192106f129ce05c9075d319c1fa6ea9b3ae37cbd0c1ef92e2be7137bb07baa1'
* ```
*
* @param value - The Typed Data domain and types.
* @returns The hashed domain.
*/
export function hashDomain(value: hashDomain.Value): Hex.Hex {
const { domain, types } = value
return hashStruct({
data: domain,
primaryType: 'EIP712Domain',
types: {
...types,
EIP712Domain: types?.EIP712Domain || extractEip712DomainTypes(domain),
},
})
}
export declare namespace hashDomain {
type Value = {
/** The Typed Data domain. */
domain: Domain
/** The Typed Data types. */
types?:
| {
EIP712Domain?: readonly Parameter[] | undefined
[key: string]: readonly Parameter[] | undefined
}
| undefined
}
type ErrorType = hashStruct.ErrorType | Errors.GlobalErrorType
}
/**
* Hashes [EIP-712 Typed Data](https://eips.ethereum.org/EIPS/eip-712) struct.
*
* @example
* ```ts twoslash
* import { TypedData } from 'ox'
*
* TypedData.hashStruct({
* types: {
* Foo: [
* { name: 'address', type: 'address' },
* { name: 'name', type: 'string' },
* { name: 'foo', type: 'string' },
* ],
* },
* primaryType: 'Foo',
* data: {
* address: '0xb9CAB4F0E46F7F6b1024b5A7463734fa68E633f9',
* name: 'jxom',
* foo: '0xb9CAB4F0E46F7F6b1024b5A7463734fa68E633f9',
* },
* })
* // @log: '0x996fb3b6d48c50312d69abdd4c1b6fb02057c85aa86bb8d04c6f023326a168ce'
* ```
*
* @param value - The Typed Data struct to hash.
* @returns The hashed Typed Data struct.
*/
export function hashStruct(value: hashStruct.Value): Hex.Hex {
const { data, primaryType, types } = value
const encoded = encodeData({
data,
primaryType,
types,
})
return Hash.keccak256(encoded)
}
export declare namespace hashStruct {
type Value = {
/** The Typed Data struct to hash. */
data: Record<string, unknown>
/** The primary type of the Typed Data struct. */
primaryType: string
/** The types of the Typed Data struct. */
types: TypedData
}
type ErrorType =
| encodeData.ErrorType
| Hash.keccak256.ErrorType
| Errors.GlobalErrorType
}
/**
* Serializes [EIP-712 Typed Data](https://eips.ethereum.org/EIPS/eip-712) schema into string.
*
* @example
* ```ts twoslash
* import { TypedData } from 'ox'
*
* TypedData.serialize({
* domain: {
* name: 'Ether!',
* version: '1',
* chainId: 1,
* verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC',
* },
* primaryType: 'Foo',
* types: {
* Foo: [
* { name: 'address', type: 'address' },
* { name: 'name', type: 'string' },
* { name: 'foo', type: 'string' },
* ],
* },
* message: {
* address: '0xb9CAB4F0E46F7F6b1024b5A7463734fa68E633f9',
* name: 'jxom',
* foo: '0xb9CAB4F0E46F7F6b1024b5A7463734fa68E633f9',
* },
* })
* // @log: "{"domain":{},"message":{"address":"0xb9cab4f0e46f7f6b1024b5a7463734fa68e633f9","name":"jxom","foo":"0xb9CAB4F0E46F7F6b1024b5A7463734fa68E633f9"},"primaryType":"Foo","types":{"Foo":[{"name":"address","type":"address"},{"name":"name","type":"string"},{"name":"foo","type":"string"}]}}"
* ```
*
* @param value - The Typed Data schema to serialize.
* @returns The serialized Typed Data schema. w
*/
export function serialize<
const typedData extends TypedData | Record<string, unknown>,
primaryType extends keyof typedData | 'EIP712Domain',
>(value: serialize.Value<typedData, primaryType>): string {
const {
domain: domain_,
message: message_,
primaryType,
types,
} = value as unknown as serialize.Value
const normalizeData = (
struct: readonly Parameter[],
value: Record<string, unknown>,
) => {
const data = { ...value }
for (const param of struct) {
const { name, type } = param
if (type === 'address') data[name] = (data[name] as string).toLowerCase()
}
return data
}
const domain = (() => {
if (!domain_) return {}
const type = types.EIP712Domain ?? extractEip712DomainTypes(domain_)
return normalizeData(type, domain_)
})()
const message = (() => {
if (primaryType === 'EIP712Domain') return undefined
if (!types[primaryType]) return {}
return normalizeData(types[primaryType], message_)
})()
return Json.stringify({ domain, message, primaryType, types }, (_, value) => {
if (typeof value === 'bigint') return value.toString()
return value
})
}
export declare namespace serialize {
type Value<
typedData extends TypedData | Record<string, unknown> = TypedData,
primaryType extends keyof typedData | 'EIP712Domain' = keyof typedData,
> = Definition<typedData, primaryType>
type ErrorType = Json.stringify.ErrorType | Errors.GlobalErrorType
}
/**
* Checks if [EIP-712 Typed Data](https://eips.ethereum.org/EIPS/eip-712) is valid.
*
* @example
* ```ts twoslash
* import { TypedData } from 'ox'
*
* const valid = TypedData.validate({
* domain: {
* name: 'Ether!',
* version: '1',
* chainId: 1,
* verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC',
* },
* primaryType: 'Foo',
* types: {
* Foo: [
* { name: 'address', type: 'address' },
* { name: 'name', type: 'string' },
* { name: 'foo', type: 'string' },
* ],
* },
* message: {
* address: '0xb9CAB4F0E46F7F6b1024b5A7463734fa68E633f9',
* name: 'jxom',
* foo: '0xb9CAB4F0E46F7F6b1024b5A7463734fa68E633f9',
* },
* })
* // @log: true
* ```
*
* @param value - The Typed Data to validate.
*/
export function validate<
const typedData extends TypedData | Record<string, unknown>,
primaryType extends keyof typedData | 'EIP712Domain',
>(value: assert.Value<typedData, primaryType>): boolean {
try {
assert(value)
return true
} catch {
return false
}
}
export declare namespace validate {
type ErrorType = assert.ErrorType | Errors.GlobalErrorType
}
/** Thrown when the bytes size of a typed data value does not match the expected size. */
export class BytesSizeMismatchError extends Errors.BaseError {
override readonly name = 'TypedData.BytesSizeMismatchError'
constructor({
expectedSize,
givenSize,
}: { expectedSize: number; givenSize: number }) {
super(`Expected bytes${expectedSize}, got bytes${givenSize}.`)
}
}
/** Thrown when the domain is invalid. */
export class InvalidDomainError extends Errors.BaseError {
override readonly name = 'TypedData.InvalidDomainError'
constructor({ domain }: { domain: unknown }) {
super(`Invalid domain "${Json.stringify(domain)}".`, {
metaMessages: ['Must be a valid EIP-712 domain.'],
})
}
}
/** Thrown when the primary type of a typed data value is invalid. */
export class InvalidPrimaryTypeError extends Errors.BaseError {
override readonly name = 'TypedData.InvalidPrimaryTypeError'
constructor({
primaryType,
types,
}: { primaryType: string; types: TypedData | Record<string, unknown> }) {
super(
`Invalid primary type \`${primaryType}\` must be one of \`${JSON.stringify(Object.keys(types))}\`.`,
{
metaMessages: ['Check that the primary type is a key in `types`.'],
},
)
}
}
/** Thrown when the struct type is not a valid type. */
export class InvalidStructTypeError extends Errors.BaseError {
override readonly name = 'TypedData.InvalidStructTypeError'
constructor({ type }: { type: string }) {
super(`Struct type "${type}" is invalid.`, {
metaMessages: ['Struct type must not be a Solidity type.'],
})
}
}
/** @internal */
export function encodeData(value: {
data: Record<string, unknown>
primaryType: string
types: TypedData
}): Hex.Hex {
const { data, primaryType, types } = value
const encodedTypes: AbiParameters.Parameter[] = [{ type: 'bytes32' }]
const encodedValues: unknown[] = [hashType({ primaryType, types })]
for (const field of types[primaryType] ?? []) {
const [type, value] = encodeField({
types,
name: field.name,
type: field.type,
value: data[field.name],
})
encodedTypes.push(type)
encodedValues.push(value)
}
return AbiParameters.encode(encodedTypes, encodedValues)
}
/** @internal */
export declare namespace encodeData {
type ErrorType =
| AbiParameters.encode.ErrorType
| encodeField.ErrorType
| hashType.ErrorType
| Errors.GlobalErrorType
}
/** @internal */
export function hashType(value: {
primaryType: string
types: TypedData
}): Hex.Hex {
const { primaryType, types } = value
const encodedHashType = Hex.fromString(encodeType({ primaryType, types }))
return Hash.keccak256(encodedHashType)
}
/** @internal */
export declare namespace hashType {
type ErrorType =
| Hex.fromString.ErrorType
| encodeType.ErrorType
| Hash.keccak256.ErrorType
| Errors.GlobalErrorType
}
/** @internal */
export function encodeField(properties: {
types: TypedData
name: string
type: string
value: any
}): [type: AbiParameters.Parameter, value: Hex.Hex] {
let { types, name, type, value } = properties
if (types[type] !== undefined)
return [
{ type: 'bytes32' },
Hash.keccak256(encodeData({ data: value, primaryType: type, types })),
]
if (type === 'bytes') {
const prepend = value.length % 2 ? '0' : ''
value = `0x${prepend + value.slice(2)}`
return [{ type: 'bytes32' }, Hash.keccak256(value, { as: 'Hex' })]
}
if (type === 'string')
return [
{ type: 'bytes32' },
Hash.keccak256(Bytes.fromString(value), { as: 'Hex' }),
]
if (type.lastIndexOf(']') === type.length - 1) {
const parsedType = type.slice(0, type.lastIndexOf('['))
const typeValuePairs = (value as [AbiParameters.Parameter, any][]).map(
(item) =>
encodeField({
name,
type: parsedType,
types,
value: item,
}),
)
return [
{ type: 'bytes32' },
Hash.keccak256(
AbiParameters.encode(
typeValuePairs.map(([t]) => t),
typeValuePairs.map(([, v]) => v),
),
),
]
}
return [{ type }, value]
}
/** @internal */
export declare namespace encodeField {
type ErrorType =
| AbiParameters.encode.ErrorType
| Hash.keccak256.ErrorType
| Bytes.fromString.ErrorType
| Errors.GlobalErrorType
}
/** @internal */
export function findTypeDependencies(
value: {
primaryType: string
types: TypedData
},
results: Set<string> = new Set(),
): Set<string> {
const { primaryType: primaryType_, types } = value
const match = primaryType_.match(/^\w*/u)
const primaryType = match?.[0]!
if (results.has(primaryType) || types[primaryType] === undefined)
return results
results.add(primaryType)
for (const field of types[primaryType])
findTypeDependencies({ primaryType: field.type, types }, results)
return results
}
/** @internal */
export declare namespace findTypeDependencies {
type ErrorType = Errors.GlobalErrorType
}
/** @internal */
function validateReference(type: string) {
// Struct type must not be a Solidity type.
if (
type === 'address' ||
type === 'bool' ||
type === 'string' ||
type.startsWith('bytes') ||
type.startsWith('uint') ||
type.startsWith('int')
)
throw new InvalidStructTypeError({ type })
}

80
node_modules/ox/core/ValidatorData.ts generated vendored Normal file
View File

@@ -0,0 +1,80 @@
import type * as Address from './Address.js'
import type * as Bytes from './Bytes.js'
import type * as Errors from './Errors.js'
import * as Hash from './Hash.js'
import * as Hex from './Hex.js'
/**
* Encodes data with a validator in [ERC-191 format](https://eips.ethereum.org/EIPS/eip-191#version-0x00): `0x19 ‖ 0x00 ‖ <intended validator address> ‖ <data to sign>`.
*
* @example
* ```ts twoslash
* import { Hex, ValidatorData } from 'ox'
*
* const encoded = ValidatorData.encode({
* data: Hex.fromString('hello world'),
* validator: '0xd8da6bf26964af9d7eed9e03e53415d37aa96045',
* })
* // @log: '0x1900d8da6bf26964af9d7eed9e03e53415d37aa9604568656c6c6f20776f726c64'
* // @log: '0x19 ‖ 0x00 ‖ 0xd8da6bf26964af9d7eed9e03e53415d37aa96045 ‖ "hello world"'
* ```
*
* @param value - The data to encode.
* @returns The encoded personal sign message.
*/
export function encode(value: encode.Value): Hex.Hex {
const { data, validator } = value
return Hex.concat(
// Validator Data Format: `0x19 ‖ 0x00 ‖ <intended validator address> ‖ <data to sign>`
'0x19',
'0x00',
validator,
Hex.from(data),
)
}
export declare namespace encode {
type Value = {
data: Hex.Hex | Bytes.Bytes
validator: Address.Address
}
type ErrorType =
| Hex.concat.ErrorType
| Hex.from.ErrorType
| Errors.GlobalErrorType
}
/**
* Gets the payload to use for signing [ERC-191 formatted](https://eips.ethereum.org/EIPS/eip-191#0x00) data with an intended validator.
*
* @example
* ```ts twoslash
* import { Hex, Secp256k1, ValidatorData } from 'ox'
*
* const payload = ValidatorData.getSignPayload({ // [!code focus]
* data: Hex.fromString('hello world'), // [!code focus]
* validator: '0xd8da6bf26964af9d7eed9e03e53415d37aa96045', // [!code focus]
* }) // [!code focus]
*
* const signature = Secp256k1.sign({ payload, privateKey: '0x...' })
* ```
*
* @param value - The data to get the sign payload for.
* @returns The payload to use for signing.
*/
export function getSignPayload(value: getSignPayload.Value): Hex.Hex {
return Hash.keccak256(encode(value))
}
export declare namespace getSignPayload {
type Value = {
data: Hex.Hex | Bytes.Bytes
validator: Address.Address
}
type ErrorType =
| Hash.keccak256.ErrorType
| encode.ErrorType
| Errors.GlobalErrorType
}

224
node_modules/ox/core/Value.ts generated vendored Normal file
View File

@@ -0,0 +1,224 @@
import * as Errors from './Errors.js'
/** @see https://ethereum.github.io/yellowpaper/paper.pdf */
export const exponents = {
wei: 0,
gwei: 9,
szabo: 12,
finney: 15,
ether: 18,
} as const
/**
* Formats a `bigint` Value to its string representation (divided by the given exponent).
*
* @example
* ```ts twoslash
* import { Value } from 'ox'
*
* Value.format(420_000_000_000n, 9)
* // @log: '420'
* ```
*
* @param value - The `bigint` Value to format.
* @param decimals - The exponent to divide the `bigint` Value by.
* @returns The string representation of the Value.
*/
export function format(value: bigint, decimals = 0) {
let display = value.toString()
const negative = display.startsWith('-')
if (negative) display = display.slice(1)
display = display.padStart(decimals, '0')
let [integer, fraction] = [
display.slice(0, display.length - decimals),
display.slice(display.length - decimals),
]
fraction = fraction.replace(/(0+)$/, '')
return `${negative ? '-' : ''}${integer || '0'}${
fraction ? `.${fraction}` : ''
}`
}
export declare namespace format {
type ErrorType = Errors.GlobalErrorType
}
/**
* Formats a `bigint` Value (default: wei) to a string representation of Ether.
*
* @example
* ```ts twoslash
* import { Value } from 'ox'
*
* Value.formatEther(1_000_000_000_000_000_000n)
* // @log: '1'
* ```
*
* @param wei - The Value to format.
* @param unit - The unit to format the Value in. @default 'wei'.
* @returns The Ether string representation of the Value.
*/
export function formatEther(
wei: bigint,
unit: 'wei' | 'gwei' | 'szabo' | 'finney' = 'wei',
) {
return format(wei, exponents.ether - exponents[unit])
}
export declare namespace formatEther {
type ErrorType = format.ErrorType | Errors.GlobalErrorType
}
/**
* Formats a `bigint` Value (default: wei) to a string representation of Gwei.
*
* @example
* ```ts twoslash
* import { Value } from 'ox'
*
* Value.formatGwei(1_000_000_000n)
* // @log: '1'
* ```
*
* @param wei - The Value to format.
* @param unit - The unit to format the Value in. @default 'wei'.
* @returns The Gwei string representation of the Value.
*/
export function formatGwei(wei: bigint, unit: 'wei' = 'wei') {
return format(wei, exponents.gwei - exponents[unit])
}
export declare namespace formatGwei {
type ErrorType = format.ErrorType | Errors.GlobalErrorType
}
/**
* Parses a `string` representation of a Value to `bigint` (multiplied by the given exponent).
*
* @example
* ```ts twoslash
* import { Value } from 'ox'
*
* Value.from('420', 9)
* // @log: 420000000000n
* ```
*
* @param value - The string representation of the Value.
* @param decimals - The exponent to multiply the Value by.
* @returns The `bigint` representation of the Value.
*/
export function from(value: string, decimals = 0) {
if (!/^(-?)([0-9]*)\.?([0-9]*)$/.test(value))
throw new InvalidDecimalNumberError({ value })
let [integer = '', fraction = '0'] = value.split('.')
const negative = integer.startsWith('-')
if (negative) integer = integer.slice(1)
// trim trailing zeros.
fraction = fraction.replace(/(0+)$/, '')
// round off if the fraction is larger than the number of decimals.
if (decimals === 0) {
if (Math.round(Number(`.${fraction}`)) === 1)
integer = `${BigInt(integer) + 1n}`
fraction = ''
} else if (fraction.length > decimals) {
const [left, unit, right] = [
fraction.slice(0, decimals - 1),
fraction.slice(decimals - 1, decimals),
fraction.slice(decimals),
]
const rounded = Math.round(Number(`${unit}.${right}`))
if (rounded > 9)
fraction = `${BigInt(left) + BigInt(1)}0`.padStart(left.length + 1, '0')
else fraction = `${left}${rounded}`
if (fraction.length > decimals) {
fraction = fraction.slice(1)
integer = `${BigInt(integer) + 1n}`
}
fraction = fraction.slice(0, decimals)
} else {
fraction = fraction.padEnd(decimals, '0')
}
return BigInt(`${negative ? '-' : ''}${integer}${fraction}`)
}
export declare namespace from {
type ErrorType = Errors.GlobalErrorType
}
/**
* Parses a string representation of Ether to a `bigint` Value (default: wei).
*
* @example
* ```ts twoslash
* import { Value } from 'ox'
*
* Value.fromEther('420')
* // @log: 420000000000000000000n
* ```
*
* @param ether - String representation of Ether.
* @param unit - The unit to parse to. @default 'wei'.
* @returns A `bigint` Value.
*/
export function fromEther(
ether: string,
unit: 'wei' | 'gwei' | 'szabo' | 'finney' = 'wei',
) {
return from(ether, exponents.ether - exponents[unit])
}
export declare namespace fromEther {
type ErrorType = from.ErrorType | Errors.GlobalErrorType
}
/**
* Parses a string representation of Gwei to a `bigint` Value (default: wei).
*
* @example
* ```ts twoslash
* import { Value } from 'ox'
*
* Value.fromGwei('420')
* // @log: 420000000000n
* ```
*
* @param gwei - String representation of Gwei.
* @param unit - The unit to parse to. @default 'wei'.
* @returns A `bigint` Value.
*/
export function fromGwei(gwei: string, unit: 'wei' = 'wei') {
return from(gwei, exponents.gwei - exponents[unit])
}
export declare namespace fromGwei {
type ErrorType = from.ErrorType | Errors.GlobalErrorType
}
/**
* Thrown when a value is not a valid decimal number.
*
* @example
* ```ts twoslash
* import { Value } from 'ox'
*
* Value.fromEther('123.456.789')
* // @error: Value.InvalidDecimalNumberError: Value `123.456.789` is not a valid decimal number.
* ```
*/
export class InvalidDecimalNumberError extends Errors.BaseError {
override readonly name = 'Value.InvalidDecimalNumberError'
constructor({ value }: { value: string }) {
super(`Value \`${value}\` is not a valid decimal number.`)
}
}

774
node_modules/ox/core/WebAuthnP256.ts generated vendored Normal file
View File

@@ -0,0 +1,774 @@
import * as Base64 from './Base64.js'
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 P256 from './P256.js'
import type * as PublicKey from './PublicKey.js'
import type * as Signature from './Signature.js'
import type { Compute, OneOf } from './internal/types.js'
import * as internal from './internal/webauthn.js'
/** A WebAuthn-flavored P256 credential. */
export type P256Credential = {
id: string
publicKey: PublicKey.PublicKey
raw: internal.PublicKeyCredential
}
/** Metadata for a WebAuthn P256 signature. */
export type SignMetadata = Compute<{
authenticatorData: Hex.Hex
challengeIndex: number
clientDataJSON: string
typeIndex: number
userVerificationRequired: boolean
}>
export const createChallenge = Uint8Array.from([
105, 171, 180, 181, 160, 222, 75, 198, 42, 42, 32, 31, 141, 37, 186, 233,
])
/**
* Creates a new WebAuthn P256 Credential, which can be stored and later used for signing.
*
* @example
* ```ts twoslash
* import { WebAuthnP256 } from 'ox'
*
* const credential = await WebAuthnP256.createCredential({ name: 'Example' }) // [!code focus]
* // @log: {
* // @log: id: 'oZ48...',
* // @log: publicKey: { x: 51421...5123n, y: 12345...6789n },
* // @log: raw: PublicKeyCredential {},
* // @log: }
*
* const { metadata, signature } = await WebAuthnP256.sign({
* credentialId: credential.id,
* challenge: '0xdeadbeef',
* })
* ```
*
* @param options - Credential creation options.
* @returns A WebAuthn P256 credential.
*/
export async function createCredential(
options: createCredential.Options,
): Promise<P256Credential> {
const {
createFn = window.navigator.credentials.create.bind(
window.navigator.credentials,
),
...rest
} = options
const creationOptions = getCredentialCreationOptions(rest)
try {
const credential = (await createFn(
creationOptions,
)) as internal.PublicKeyCredential
if (!credential) throw new CredentialCreationFailedError()
const response = credential.response as AuthenticatorAttestationResponse
const publicKey = await internal.parseCredentialPublicKey(response)
return {
id: credential.id,
publicKey,
raw: credential,
}
} catch (error) {
throw new CredentialCreationFailedError({
cause: error as Error,
})
}
}
export declare namespace createCredential {
type Options = getCredentialCreationOptions.Options & {
/**
* Credential creation function. Useful for environments that do not support
* the WebAuthn API natively (i.e. React Native or testing environments).
*
* @default window.navigator.credentials.create
*/
createFn?:
| ((
options?: internal.CredentialCreationOptions | undefined,
) => Promise<internal.Credential | null>)
| undefined
}
type ErrorType =
| getCredentialCreationOptions.ErrorType
| internal.parseCredentialPublicKey.ErrorType
| Errors.GlobalErrorType
}
/**
* Gets the authenticator data which contains information about the
* processing of an authenticator request (ie. from `WebAuthnP256.sign`).
*
* :::warning
*
* This function is mainly for testing purposes or for manually constructing
* autenticator data. In most cases you will not need this function.
* `authenticatorData` is typically returned as part of the
* {@link ox#WebAuthnP256.(sign:function)} response (ie. an authenticator response).
*
* :::
*
* @example
* ```ts twoslash
* import { WebAuthnP256 } from 'ox'
*
* const authenticatorData = WebAuthnP256.getAuthenticatorData({
* rpId: 'example.com',
* signCount: 420,
* })
* // @log: "0xa379a6f6eeafb9a55e378c118034e2751e682fab9f2d30ab13d2125586ce194705000001a4"
* ```
*
* @param options - Options to construct the authenticator data.
* @returns The authenticator data.
*/
export function getAuthenticatorData(
options: getAuthenticatorData.Options = {},
): Hex.Hex {
const { flag = 5, rpId = window.location.hostname, signCount = 0 } = options
const rpIdHash = Hash.sha256(Hex.fromString(rpId))
const flag_bytes = Hex.fromNumber(flag, { size: 1 })
const signCount_bytes = Hex.fromNumber(signCount, { size: 4 })
return Hex.concat(rpIdHash, flag_bytes, signCount_bytes)
}
export declare namespace getAuthenticatorData {
type Options = {
/** A bitfield that indicates various attributes that were asserted by the authenticator. [Read more](https://developer.mozilla.org/en-US/docs/Web/API/Web_Authentication_API/Authenticator_data#flags) */
flag?: number | undefined
/** The [Relying Party ID](https://w3c.github.io/webauthn/#relying-party-identifier) that the credential is scoped to. */
rpId?: internal.PublicKeyCredentialRequestOptions['rpId'] | undefined
/** A signature counter, if supported by the authenticator (set to 0 otherwise). */
signCount?: number | undefined
}
type ErrorType = Errors.GlobalErrorType
}
/**
* Constructs the Client Data in stringified JSON format which represents client data that
* was passed to `credentials.get()` in {@link ox#WebAuthnP256.(sign:function)}.
*
* :::warning
*
* This function is mainly for testing purposes or for manually constructing
* client data. In most cases you will not need this function.
* `clientDataJSON` is typically returned as part of the
* {@link ox#WebAuthnP256.(sign:function)} response (ie. an authenticator response).
*
* :::
*
* @example
* ```ts twoslash
* import { WebAuthnP256 } from 'ox'
*
* const clientDataJSON = WebAuthnP256.getClientDataJSON({
* challenge: '0xdeadbeef',
* origin: 'https://example.com',
* })
* // @log: "{"type":"webauthn.get","challenge":"3q2-7w","origin":"https://example.com","crossOrigin":false}"
* ```
*
* @param options - Options to construct the client data.
* @returns The client data.
*/
export function getClientDataJSON(options: getClientDataJSON.Options): string {
const {
challenge,
crossOrigin = false,
extraClientData,
origin = window.location.origin,
} = options
return JSON.stringify({
type: 'webauthn.get',
challenge: Base64.fromHex(challenge, { url: true, pad: false }),
origin,
crossOrigin,
...extraClientData,
})
}
export declare namespace getClientDataJSON {
type Options = {
/** The challenge to sign. */
challenge: Hex.Hex
/** If set to `true`, it means that the calling context is an `<iframe>` that is not same origin with its ancestor frames. */
crossOrigin?: boolean | undefined
/** Additional client data to include in the client data JSON. */
extraClientData?: Record<string, unknown> | undefined
/** The fully qualified origin of the relying party which has been given by the client/browser to the authenticator. */
origin?: string | undefined
}
type ErrorType = Errors.GlobalErrorType
}
/**
* Returns the creation options for a P256 WebAuthn Credential to be used with
* the Web Authentication API.
*
* @example
* ```ts twoslash
* import { WebAuthnP256 } from 'ox'
*
* const options = WebAuthnP256.getCredentialCreationOptions({ name: 'Example' })
*
* const credential = await window.navigator.credentials.create(options)
* ```
*
* @param options - Options.
* @returns The credential creation options.
*/
export function getCredentialCreationOptions(
options: getCredentialCreationOptions.Options,
): internal.CredentialCreationOptions {
const {
attestation = 'none',
authenticatorSelection = {
residentKey: 'preferred',
requireResidentKey: false,
userVerification: 'required',
},
challenge = createChallenge,
excludeCredentialIds,
name: name_,
rp = {
id: window.location.hostname,
name: window.document.title,
},
user,
extensions,
} = options
const name = (user?.name ?? name_)!
return {
publicKey: {
attestation,
authenticatorSelection,
challenge,
...(excludeCredentialIds
? {
excludeCredentials: excludeCredentialIds?.map((id) => ({
id: Base64.toBytes(id),
type: 'public-key',
})),
}
: {}),
pubKeyCredParams: [
{
type: 'public-key',
alg: -7, // p256
},
],
rp,
user: {
id: user?.id ?? Hash.keccak256(Bytes.fromString(name), { as: 'Bytes' }),
name,
displayName: user?.displayName ?? name,
},
extensions,
},
} as internal.CredentialCreationOptions
}
export declare namespace getCredentialCreationOptions {
type Options = {
/**
* A string specifying the relying party's preference for how the attestation statement
* (i.e., provision of verifiable evidence of the authenticity of the authenticator and its data)
* is conveyed during credential creation.
*/
attestation?:
| internal.PublicKeyCredentialCreationOptions['attestation']
| undefined
/**
* An object whose properties are criteria used to filter out the potential authenticators
* for the credential creation operation.
*/
authenticatorSelection?:
| internal.PublicKeyCredentialCreationOptions['authenticatorSelection']
| undefined
/**
* An `ArrayBuffer`, `TypedArray`, or `DataView` used as a cryptographic challenge.
*/
challenge?:
| internal.PublicKeyCredentialCreationOptions['challenge']
| undefined
/**
* List of credential IDs to exclude from the creation. This property can be used
* to prevent creation of a credential if it already exists.
*/
excludeCredentialIds?: readonly string[] | undefined
/**
* List of Web Authentication API credentials to use during creation or authentication.
*/
extensions?:
| internal.PublicKeyCredentialCreationOptions['extensions']
| undefined
/**
* An object describing the relying party that requested the credential creation
*/
rp?:
| {
id: string
name: string
}
| undefined
/**
* A numerical hint, in milliseconds, which indicates the time the calling web app is willing to wait for the creation operation to complete.
*/
timeout?: internal.PublicKeyCredentialCreationOptions['timeout'] | undefined
} & OneOf<
| {
/** Name for the credential (user.name). */
name: string
}
| {
/**
* An object describing the user account for which the credential is generated.
*/
user: {
displayName?: string
id?: BufferSource
name: string
}
}
>
type ErrorType =
| Base64.toBytes.ErrorType
| Hash.keccak256.ErrorType
| Bytes.fromString.ErrorType
| Errors.GlobalErrorType
}
/**
* Returns the request options to sign a challenge with the Web Authentication API.
*
* @example
* ```ts twoslash
* import { WebAuthnP256 } from 'ox'
*
* const options = WebAuthnP256.getCredentialRequestOptions({
* challenge: '0xdeadbeef',
* })
*
* const credential = await window.navigator.credentials.get(options)
* ```
*
* @param options - Options.
* @returns The credential request options.
*/
export function getCredentialRequestOptions(
options: getCredentialRequestOptions.Options,
): internal.CredentialRequestOptions {
const {
credentialId,
challenge,
rpId = window.location.hostname,
userVerification = 'required',
} = options
return {
publicKey: {
...(credentialId
? {
allowCredentials: [
{
id: Base64.toBytes(credentialId),
type: 'public-key',
},
],
}
: {}),
challenge: Bytes.fromHex(challenge),
rpId,
userVerification,
},
}
}
export declare namespace getCredentialRequestOptions {
type Options = {
/** The credential ID to use. */
credentialId?: string | undefined
/** The challenge to sign. */
challenge: Hex.Hex
/** The relying party identifier to use. */
rpId?: internal.PublicKeyCredentialRequestOptions['rpId'] | undefined
/** The user verification requirement. */
userVerification?:
| internal.PublicKeyCredentialRequestOptions['userVerification']
| undefined
}
type ErrorType =
| Bytes.fromHex.ErrorType
| Base64.toBytes.ErrorType
| Errors.GlobalErrorType
}
/**
* Constructs the final digest that was signed and computed by the authenticator. This payload includes
* the cryptographic `challenge`, as well as authenticator metadata (`authenticatorData` + `clientDataJSON`).
* This value can be also used with raw P256 verification (such as {@link ox#P256.(verify:function)} or
* {@link ox#WebCryptoP256.(verify:function)}).
*
* :::warning
*
* This function is mainly for testing purposes or for manually constructing
* signing payloads. In most cases you will not need this function and
* instead use {@link ox#WebAuthnP256.(sign:function)}.
*
* :::
*
* @example
* ```ts twoslash
* import { WebAuthnP256, WebCryptoP256 } from 'ox'
*
* const { metadata, payload } = WebAuthnP256.getSignPayload({ // [!code focus]
* challenge: '0xdeadbeef', // [!code focus]
* }) // [!code focus]
* // @log: {
* // @log: metadata: {
* // @log: authenticatorData: "0x49960de5880e8c687434170f6476605b8fe4aeb9a28632c7995cf3ba831d97630500000000",
* // @log: challengeIndex: 23,
* // @log: clientDataJSON: "{"type":"webauthn.get","challenge":"9jEFijuhEWrM4SOW-tChJbUEHEP44VcjcJ-Bqo1fTM8","origin":"http://localhost:5173","crossOrigin":false}",
* // @log: typeIndex: 1,
* // @log: userVerificationRequired: true,
* // @log: },
* // @log: payload: "0x49960de5880e8c687434170f6476605b8fe4aeb9a28632c7995cf3ba831d9763050000000045086dcb06a5f234db625bcdc94e657f86b76b6fd3eb9c30543eabc1e577a4b0",
* // @log: }
*
* const { publicKey, privateKey } = await WebCryptoP256.createKeyPair()
*
* const signature = await WebCryptoP256.sign({
* payload,
* privateKey,
* })
* ```
*
* @param options - Options to construct the signing payload.
* @returns The signing payload.
*/
export function getSignPayload(
options: getSignPayload.Options,
): getSignPayload.ReturnType {
const {
challenge,
crossOrigin,
extraClientData,
flag,
origin,
rpId,
signCount,
userVerification = 'required',
} = options
const authenticatorData = getAuthenticatorData({
flag,
rpId,
signCount,
})
const clientDataJSON = getClientDataJSON({
challenge,
crossOrigin,
extraClientData,
origin,
})
const clientDataJSONHash = Hash.sha256(Hex.fromString(clientDataJSON))
const challengeIndex = clientDataJSON.indexOf('"challenge"')
const typeIndex = clientDataJSON.indexOf('"type"')
const metadata = {
authenticatorData,
clientDataJSON,
challengeIndex,
typeIndex,
userVerificationRequired: userVerification === 'required',
}
const payload = Hex.concat(authenticatorData, clientDataJSONHash)
return { metadata, payload }
}
export declare namespace getSignPayload {
type Options = {
/** The challenge to sign. */
challenge: Hex.Hex
/** If set to `true`, it means that the calling context is an `<iframe>` that is not same origin with its ancestor frames. */
crossOrigin?: boolean | undefined
/** Additional client data to include in the client data JSON. */
extraClientData?: Record<string, unknown> | undefined
/** If set to `true`, the payload will be hashed before being returned. */
hash?: boolean | undefined
/** A bitfield that indicates various attributes that were asserted by the authenticator. [Read more](https://developer.mozilla.org/en-US/docs/Web/API/Web_Authentication_API/Authenticator_data#flags) */
flag?: number | undefined
/** The fully qualified origin of the relying party which has been given by the client/browser to the authenticator. */
origin?: string | undefined
/** The [Relying Party ID](https://w3c.github.io/webauthn/#relying-party-identifier) that the credential is scoped to. */
rpId?: internal.PublicKeyCredentialRequestOptions['rpId'] | undefined
/** A signature counter, if supported by the authenticator (set to 0 otherwise). */
signCount?: number | undefined
/** The user verification requirement that the authenticator will enforce. */
userVerification?:
| internal.PublicKeyCredentialRequestOptions['userVerification']
| undefined
}
type ReturnType = {
metadata: SignMetadata
payload: Hex.Hex
}
type ErrorType =
| Hash.sha256.ErrorType
| Hex.concat.ErrorType
| Hex.fromString.ErrorType
| getAuthenticatorData.ErrorType
| getClientDataJSON.ErrorType
| Errors.GlobalErrorType
}
/**
* Signs a challenge using a stored WebAuthn P256 Credential. If no Credential is provided,
* a prompt will be displayed for the user to select an existing Credential
* that was previously registered.
*
* @example
* ```ts twoslash
* import { WebAuthnP256 } from 'ox'
*
* const credential = await WebAuthnP256.createCredential({
* name: 'Example',
* })
*
* const { metadata, signature } = await WebAuthnP256.sign({ // [!code focus]
* credentialId: credential.id, // [!code focus]
* challenge: '0xdeadbeef', // [!code focus]
* }) // [!code focus]
* // @log: {
* // @log: metadata: {
* // @log: authenticatorData: '0x49960de5880e8c687434170f6476605b8fe4aeb9a28632c7995cf3ba831d97630500000000',
* // @log: clientDataJSON: '{"type":"webauthn.get","challenge":"9jEFijuhEWrM4SOW-tChJbUEHEP44VcjcJ-Bqo1fTM8","origin":"http://localhost:5173","crossOrigin":false}',
* // @log: challengeIndex: 23,
* // @log: typeIndex: 1,
* // @log: userVerificationRequired: true,
* // @log: },
* // @log: signature: { r: 51231...4215n, s: 12345...6789n },
* // @log: }
* ```
*
* @param options - Options.
* @returns The signature.
*/
export async function sign(options: sign.Options): Promise<sign.ReturnType> {
const {
getFn = window.navigator.credentials.get.bind(window.navigator.credentials),
...rest
} = options
const requestOptions = getCredentialRequestOptions(rest)
try {
const credential = (await getFn(
requestOptions,
)) as internal.PublicKeyCredential
if (!credential) throw new CredentialRequestFailedError()
const response = credential.response as AuthenticatorAssertionResponse
const clientDataJSON = String.fromCharCode(
...new Uint8Array(response.clientDataJSON),
)
const challengeIndex = clientDataJSON.indexOf('"challenge"')
const typeIndex = clientDataJSON.indexOf('"type"')
const signature = internal.parseAsn1Signature(
new Uint8Array(response.signature),
)
return {
metadata: {
authenticatorData: Hex.fromBytes(
new Uint8Array(response.authenticatorData),
),
clientDataJSON,
challengeIndex,
typeIndex,
userVerificationRequired:
requestOptions.publicKey!.userVerification === 'required',
},
signature,
raw: credential,
}
} catch (error) {
throw new CredentialRequestFailedError({
cause: error as Error,
})
}
}
export declare namespace sign {
type Options = getCredentialRequestOptions.Options & {
/**
* Credential request function. Useful for environments that do not support
* the WebAuthn API natively (i.e. React Native or testing environments).
*
* @default window.navigator.credentials.get
*/
getFn?:
| ((
options?: internal.CredentialRequestOptions | undefined,
) => Promise<internal.Credential | null>)
| undefined
}
type ReturnType = {
metadata: SignMetadata
raw: internal.PublicKeyCredential
signature: Signature.Signature<false>
}
type ErrorType =
| Hex.fromBytes.ErrorType
| getCredentialRequestOptions.ErrorType
| Errors.GlobalErrorType
}
/**
* Verifies a signature using the Credential's public key and the challenge which was signed.
*
* @example
* ```ts twoslash
* import { WebAuthnP256 } from 'ox'
*
* const credential = await WebAuthnP256.createCredential({
* name: 'Example',
* })
*
* const { metadata, signature } = await WebAuthnP256.sign({
* credentialId: credential.id,
* challenge: '0xdeadbeef',
* })
*
* const result = await WebAuthnP256.verify({ // [!code focus]
* metadata, // [!code focus]
* challenge: '0xdeadbeef', // [!code focus]
* publicKey: credential.publicKey, // [!code focus]
* signature, // [!code focus]
* }) // [!code focus]
* // @log: true
* ```
*
* @param options - Options.
* @returns Whether the signature is valid.
*/
export function verify(options: verify.Options): boolean {
const { challenge, hash = true, metadata, publicKey, signature } = options
const {
authenticatorData,
challengeIndex,
clientDataJSON,
typeIndex,
userVerificationRequired,
} = metadata
const authenticatorDataBytes = Bytes.fromHex(authenticatorData)
// Check length of `authenticatorData`.
if (authenticatorDataBytes.length < 37) return false
const flag = authenticatorDataBytes[32]!
// Verify that the UP bit of the flags in authData is set.
if ((flag & 0x01) !== 0x01) return false
// If user verification was determined to be required, verify that
// the UV bit of the flags in authData is set. Otherwise, ignore the
// value of the UV flag.
if (userVerificationRequired && (flag & 0x04) !== 0x04) return false
// If the BE bit of the flags in authData is not set, verify that
// the BS bit is not set.
if ((flag & 0x08) !== 0x08 && (flag & 0x10) === 0x10) return false
// Check that response is for an authentication assertion
const type = '"type":"webauthn.get"'
if (type !== clientDataJSON.slice(Number(typeIndex), type.length + 1))
return false
// Check that hash is in the clientDataJSON.
const match = clientDataJSON
.slice(Number(challengeIndex))
.match(/^"challenge":"(.*?)"/)
if (!match) return false
// Validate the challenge in the clientDataJSON.
const [_, challenge_extracted] = match
if (Hex.fromBytes(Base64.toBytes(challenge_extracted!)) !== challenge)
return false
const clientDataJSONHash = Hash.sha256(Bytes.fromString(clientDataJSON), {
as: 'Bytes',
})
const payload = Bytes.concat(authenticatorDataBytes, clientDataJSONHash)
return P256.verify({
hash,
payload,
publicKey,
signature,
})
}
export declare namespace verify {
type Options = {
/** The challenge to verify. */
challenge: Hex.Hex
/** If set to `true`, the payload will be hashed (sha256) before being verified. */
hash?: boolean | undefined
/** The public key to verify the signature with. */
publicKey: PublicKey.PublicKey
/** The signature to verify. */
signature: Signature.Signature<false>
/** The metadata to verify the signature with. */
metadata: SignMetadata
}
type ErrorType =
| Base64.toBytes.ErrorType
| Bytes.concat.ErrorType
| Bytes.fromHex.ErrorType
| P256.verify.ErrorType
| Errors.GlobalErrorType
}
/** Thrown when a WebAuthn P256 credential creation fails. */
export class CredentialCreationFailedError extends Errors.BaseError<Error> {
override readonly name = 'WebAuthnP256.CredentialCreationFailedError'
constructor({ cause }: { cause?: Error | undefined } = {}) {
super('Failed to create credential.', {
cause,
})
}
}
/** Thrown when a WebAuthn P256 credential request fails. */
export class CredentialRequestFailedError extends Errors.BaseError<Error> {
override readonly name = 'WebAuthnP256.CredentialRequestFailedError'
constructor({ cause }: { cause?: Error | undefined } = {}) {
super('Failed to request credential.', {
cause,
})
}
}

178
node_modules/ox/core/WebCryptoP256.ts generated vendored Normal file
View File

@@ -0,0 +1,178 @@
import { p256 } from '@noble/curves/p256'
import * as Bytes from './Bytes.js'
import type * as Errors from './Errors.js'
import type * as Hex from './Hex.js'
import * as PublicKey from './PublicKey.js'
import type * as Signature from './Signature.js'
import type { Compute } from './internal/types.js'
/**
* Generates an ECDSA P256 key pair that includes:
*
* - a `privateKey` of type [`CryptoKey`](https://developer.mozilla.org/en-US/docs/Web/API/CryptoKey)
*
* - a `publicKey` of type {@link ox#Hex.Hex} or {@link ox#Bytes.Bytes}
*
* @example
* ```ts twoslash
* import { WebCryptoP256 } from 'ox'
*
* const { publicKey, privateKey } = await WebCryptoP256.createKeyPair()
* // @log: {
* // @log: privateKey: CryptoKey {},
* // @log: publicKey: {
* // @log: x: 59295962801117472859457908919941473389380284132224861839820747729565200149877n,
* // @log: y: 24099691209996290925259367678540227198235484593389470330605641003500238088869n,
* // @log: prefix: 4,
* // @log: },
* // @log: }
* ```
*
* @param options - Options for creating the key pair.
* @returns The key pair.
*/
export async function createKeyPair(
options: createKeyPair.Options = {},
): Promise<createKeyPair.ReturnType> {
const { extractable = false } = options
const keypair = await globalThis.crypto.subtle.generateKey(
{
name: 'ECDSA',
namedCurve: 'P-256',
},
extractable,
['sign', 'verify'],
)
const publicKey_raw = await globalThis.crypto.subtle.exportKey(
'raw',
keypair.publicKey,
)
const publicKey = PublicKey.from(new Uint8Array(publicKey_raw))
return {
privateKey: keypair.privateKey,
publicKey,
}
}
export declare namespace createKeyPair {
type Options = {
/** A boolean value indicating whether it will be possible to export the private key using `globalThis.crypto.subtle.exportKey()`. */
extractable?: boolean | undefined
}
type ReturnType = Compute<{
privateKey: CryptoKey
publicKey: PublicKey.PublicKey
}>
type ErrorType = PublicKey.from.ErrorType | Errors.GlobalErrorType
}
/**
* Signs a payload with the provided `CryptoKey` private key and returns a P256 signature.
*
* @example
* ```ts twoslash
* import { WebCryptoP256 } from 'ox'
*
* const { privateKey } = await WebCryptoP256.createKeyPair()
*
* const signature = await WebCryptoP256.sign({ // [!code focus]
* payload: '0xdeadbeef', // [!code focus]
* privateKey, // [!code focus]
* }) // [!code focus]
* // @log: {
* // @log: r: 151231...4423n,
* // @log: s: 516123...5512n,
* // @log: }
* ```
*
* @param options - Options for signing the payload.
* @returns The P256 ECDSA {@link ox#Signature.Signature}.
*/
export async function sign(
options: sign.Options,
): Promise<Signature.Signature<false>> {
const { payload, privateKey } = options
const signature = await globalThis.crypto.subtle.sign(
{
name: 'ECDSA',
hash: 'SHA-256',
},
privateKey,
Bytes.from(payload),
)
const signature_bytes = Bytes.fromArray(new Uint8Array(signature))
const r = Bytes.toBigInt(Bytes.slice(signature_bytes, 0, 32))
let s = Bytes.toBigInt(Bytes.slice(signature_bytes, 32, 64))
if (s > p256.CURVE.n / 2n) s = p256.CURVE.n - s
return { r, s }
}
export declare namespace sign {
type Options = {
/** Payload to sign. */
payload: Hex.Hex | Bytes.Bytes
/** ECDSA private key. */
privateKey: CryptoKey
}
type ErrorType = Bytes.fromArray.ErrorType | Errors.GlobalErrorType
}
/**
* Verifies a payload was signed by the provided public key.
*
* @example
*
* ```ts twoslash
* import { WebCryptoP256 } from 'ox'
*
* const { privateKey, publicKey } = await WebCryptoP256.createKeyPair()
* const signature = await WebCryptoP256.sign({ payload: '0xdeadbeef', privateKey })
*
* const verified = await WebCryptoP256.verify({ // [!code focus]
* payload: '0xdeadbeef', // [!code focus]
* publicKey, // [!code focus]
* signature, // [!code focus]
* }) // [!code focus]
* // @log: true
* ```
*
* @param options - The verification options.
* @returns Whether the payload was signed by the provided public key.
*/
export async function verify(options: verify.Options): Promise<boolean> {
const { payload, signature } = options
const publicKey = await globalThis.crypto.subtle.importKey(
'raw',
PublicKey.toBytes(options.publicKey),
{ name: 'ECDSA', namedCurve: 'P-256' },
true,
['verify'],
)
return await globalThis.crypto.subtle.verify(
{
name: 'ECDSA',
hash: 'SHA-256',
},
publicKey,
Bytes.concat(Bytes.fromNumber(signature.r), Bytes.fromNumber(signature.s)),
Bytes.from(payload),
)
}
export declare namespace verify {
type Options = {
/** Public key that signed the payload. */
publicKey: PublicKey.PublicKey<boolean>
/** Signature of the payload. */
signature: Signature.Signature<false>
/** Payload that was signed. */
payload: Hex.Hex | Bytes.Bytes
}
type ErrorType = Errors.GlobalErrorType
}

87
node_modules/ox/core/Withdrawal.ts generated vendored Normal file
View File

@@ -0,0 +1,87 @@
import type * as Errors from './Errors.js'
import * as Hex from './Hex.js'
/** A Withdrawal as defined in the [Execution API specification](https://github.com/ethereum/execution-apis/blob/main/src/schemas/withdrawal.yaml). */
export type Withdrawal<bigintType = bigint, numberType = number> = {
address: Hex.Hex
amount: bigintType
index: numberType
validatorIndex: numberType
}
/** An RPC Withdrawal as defined in the [Execution API specification](https://github.com/ethereum/execution-apis/blob/main/src/schemas/withdrawal.yaml). */
export type Rpc = Withdrawal<Hex.Hex, Hex.Hex>
/**
* Converts a {@link ox#Withdrawal.Rpc} to an {@link ox#Withdrawal.Withdrawal}.
*
* @example
* ```ts twoslash
* import { Withdrawal } from 'ox'
*
* const withdrawal = Withdrawal.fromRpc({
* address: '0x00000000219ab540356cBB839Cbe05303d7705Fa',
* amount: '0x620323',
* index: '0x0',
* validatorIndex: '0x1',
* })
* // @log: {
* // @log: address: '0x00000000219ab540356cBB839Cbe05303d7705Fa',
* // @log: amount: 6423331n,
* // @log: index: 0,
* // @log: validatorIndex: 1
* // @log: }
* ```
*
* @param withdrawal - The RPC withdrawal to convert.
* @returns An instantiated {@link ox#Withdrawal.Withdrawal}.
*/
export function fromRpc(withdrawal: Rpc): Withdrawal {
return {
...withdrawal,
amount: BigInt(withdrawal.amount),
index: Number(withdrawal.index),
validatorIndex: Number(withdrawal.validatorIndex),
}
}
export declare namespace fromRpc {
export type ErrorType = Errors.GlobalErrorType
}
/**
* Converts a {@link ox#Withdrawal.Withdrawal} to an {@link ox#Withdrawal.Rpc}.
*
* @example
* ```ts twoslash
* import { Withdrawal } from 'ox'
*
* const withdrawal = Withdrawal.toRpc({
* address: '0x00000000219ab540356cBB839Cbe05303d7705Fa',
* amount: 6423331n,
* index: 0,
* validatorIndex: 1,
* })
* // @log: {
* // @log: address: '0x00000000219ab540356cBB839Cbe05303d7705Fa',
* // @log: amount: '0x620323',
* // @log: index: '0x0',
* // @log: validatorIndex: '0x1',
* // @log: }
* ```
*
* @param withdrawal - The Withdrawal to convert.
* @returns An RPC Withdrawal.
*/
export function toRpc(withdrawal: Withdrawal): Rpc {
return {
address: withdrawal.address,
amount: Hex.fromNumber(withdrawal.amount),
index: Hex.fromNumber(withdrawal.index),
validatorIndex: Hex.fromNumber(withdrawal.validatorIndex),
}
}
export declare namespace toRpc {
export type ErrorType = Errors.GlobalErrorType
}

11
node_modules/ox/core/internal/abi.ts generated vendored Normal file
View File

@@ -0,0 +1,11 @@
import type * as Abi from '../Abi.js'
/** @internal */
export function isSignatures(
value: Abi.Abi | readonly string[],
): value is readonly string[] {
for (const item of value) {
if (typeof item !== 'string') return false
}
return true
}

32
node_modules/ox/core/internal/abiConstructor.ts generated vendored Normal file
View File

@@ -0,0 +1,32 @@
import type * as AbiItem_internal from './abiItem.js'
import type { TypeErrorMessage } from './types.js'
/** @internal */
export type IsSignature<signature extends string> =
| (AbiItem_internal.IsConstructorSignature<signature> extends true
? true
: never)
| (AbiItem_internal.IsStructSignature<signature> extends true
? true
: never) extends infer condition
? [condition] extends [never]
? false
: true
: false
/** @internal */
export type Signature<
signature extends string,
key extends string | unknown = unknown,
> = IsSignature<signature> extends true
? signature
: string extends signature // if exactly `string` (not narrowed), then pass through as valid
? signature
: TypeErrorMessage<`Signature "${signature}" is invalid${key extends string
? ` at position ${key}`
: ''}.`>
/** @internal */
export type Signatures<signatures extends readonly string[]> = {
[key in keyof signatures]: Signature<signatures[key], key>
}

30
node_modules/ox/core/internal/abiError.ts generated vendored Normal file
View File

@@ -0,0 +1,30 @@
import type * as AbiItem_internal from './abiItem.js'
import type { TypeErrorMessage } from './types.js'
/** @internal */
export type IsSignature<signature extends string> =
| (AbiItem_internal.IsErrorSignature<signature> extends true ? true : never)
| (AbiItem_internal.IsStructSignature<signature> extends true
? true
: never) extends infer condition
? [condition] extends [never]
? false
: true
: false
/** @internal */
export type Signature<
signature extends string,
key extends string | unknown = unknown,
> = IsSignature<signature> extends true
? signature
: string extends signature // if exactly `string` (not narrowed), then pass through as valid
? signature
: TypeErrorMessage<`Signature "${signature}" is invalid${key extends string
? ` at position ${key}`
: ''}.`>
/** @internal */
export type Signatures<signatures extends readonly string[]> = {
[key in keyof signatures]: Signature<signatures[key], key>
}

154
node_modules/ox/core/internal/abiEvent.ts generated vendored Normal file
View File

@@ -0,0 +1,154 @@
import type * as abitype from 'abitype'
import type * as Filter from '../Filter.js'
import type * as Hex from '../Hex.js'
import type * as AbiItem_internal from './abiItem.js'
import type {
Compute,
Filter as Filter_internal,
MaybeRequired,
TypeErrorMessage,
UnionToIntersection,
} from './types.js'
/** @internal */
export type EventParameterOptions = {
EnableUnion?: boolean
IndexedOnly?: boolean
Required?: boolean
}
/** @internal */
export type DefaultEventParameterOptions = {
EnableUnion: true
IndexedOnly: true
Required: false
}
/** @internal */
export type IsSignature<signature extends string> =
| (AbiItem_internal.IsEventSignature<signature> extends true ? true : never)
| (AbiItem_internal.IsStructSignature<signature> extends true
? true
: never) extends infer condition
? [condition] extends [never]
? false
: true
: false
/** @internal */
export type Signature<
signature extends string,
key extends string | unknown = unknown,
> = IsSignature<signature> extends true
? signature
: string extends signature // if exactly `string` (not narrowed), then pass through as valid
? signature
: TypeErrorMessage<`Signature "${signature}" is invalid${key extends string
? ` at position ${key}`
: ''}.`>
/** @internal */
export type Signatures<signatures extends readonly string[]> = {
[key in keyof signatures]: Signature<signatures[key], key>
}
/** @internal */
export type ParametersToPrimitiveTypes<
abiParameters extends readonly abitype.AbiParameter[],
options extends EventParameterOptions = DefaultEventParameterOptions,
// Remove non-indexed parameters based on `Options['IndexedOnly']`
> = abiParameters extends readonly []
? readonly []
: Filter_internal<
abiParameters,
options['IndexedOnly'] extends true ? { indexed: true } : object
> extends infer Filtered extends readonly abitype.AbiParameter[]
? Filtered extends readonly []
? readonly []
: HasNamedAbiParameter<Filtered> extends true
? // All tuple parameters are named so return as object
UnionToIntersection<
{
[index in keyof Filtered]: Filtered[index] extends {
name: infer name extends string
}
? {
[key in name]?:
| ParameterToPrimitiveType<Filtered[index], options>
| undefined
}
: {
[key in index]?:
| ParameterToPrimitiveType<Filtered[index], options>
| undefined
}
}[number]
> extends infer Mapped
? Compute<
MaybeRequired<
Mapped,
options['Required'] extends boolean
? options['Required']
: false
>
>
: never
: // Has unnamed tuple parameters so return as array
| readonly [
...{
[K in keyof Filtered]: ParameterToPrimitiveType<
Filtered[K],
options
>
},
]
// Distribute over tuple to represent optional parameters
| (options['Required'] extends true
? never
: // Distribute over tuple to represent optional parameters
Filtered extends readonly [
...infer Head extends readonly abitype.AbiParameter[],
infer _,
]
? ParametersToPrimitiveTypes<
readonly [
...{ [K in keyof Head]: Omit<Head[K], 'name'> },
],
options
>
: never)
: never
/** @internal */
export type ParameterToPrimitiveType<
abiParameter extends abitype.AbiParameter,
//
options extends EventParameterOptions = DefaultEventParameterOptions,
_type = abitype.AbiParameterToPrimitiveType<abiParameter>,
> = options['EnableUnion'] extends true ? TopicType<_type> : _type
/** @internal */
export type TopicType<
primitiveType = Hex.Hex,
topic extends Filter.Topic = Filter.Topic,
> = topic extends Hex.Hex
? primitiveType
: topic extends readonly Hex.Hex[]
? primitiveType[]
: topic extends null
? null
: never
/** @internal */
export type HasNamedAbiParameter<
abiParameters extends readonly abitype.AbiParameter[],
> = abiParameters extends readonly [
infer Head extends abitype.AbiParameter,
...infer Tail extends readonly abitype.AbiParameter[],
]
? Head extends { name: string }
? Head['name'] extends ''
? HasNamedAbiParameter<Tail>
: true
: HasNamedAbiParameter<Tail>
: false

32
node_modules/ox/core/internal/abiFunction.ts generated vendored Normal file
View File

@@ -0,0 +1,32 @@
import type * as AbiItem_internal from './abiItem.js'
import type { TypeErrorMessage } from './types.js'
/** @internal */
export type IsSignature<signature extends string> =
| (AbiItem_internal.IsFunctionSignature<signature> extends true
? true
: never)
| (AbiItem_internal.IsStructSignature<signature> extends true
? true
: never) extends infer condition
? [condition] extends [never]
? false
: true
: false
/** @internal */
export type Signature<
signature extends string,
key extends string | unknown = unknown,
> = IsSignature<signature> extends true
? signature
: string extends signature // if exactly `string` (not narrowed), then pass through as valid
? signature
: TypeErrorMessage<`Signature "${signature}" is invalid${key extends string
? ` at position ${key}`
: ''}.`>
/** @internal */
export type Signatures<signatures extends readonly string[]> = {
[key in keyof signatures]: Signature<signatures[key], key>
}

593
node_modules/ox/core/internal/abiItem.ts generated vendored Normal file
View File

@@ -0,0 +1,593 @@
import type * as abitype from 'abitype'
import type * as Abi from '../Abi.js'
import type * as AbiItem from '../AbiItem.js'
import type * as AbiParameters from '../AbiParameters.js'
import * as Address from '../Address.js'
import * as Errors from '../Errors.js'
import type {
Compute,
IsNever,
IsUnion,
TypeErrorMessage,
UnionToTuple,
} from './types.js'
/** @internal */
export type ExtractArgs<
abi extends Abi.Abi | readonly unknown[] = Abi.Abi,
name extends AbiItem.Name<abi> = AbiItem.Name<abi>,
> = abitype.AbiParametersToPrimitiveTypes<
AbiItem.FromAbi<abi extends Abi.Abi ? abi : Abi.Abi, name>['inputs'],
'inputs'
> extends infer args
? [args] extends [never]
? readonly unknown[]
: args
: readonly unknown[]
/** @internal */
export type ExtractForArgs<
abi extends Abi.Abi,
name extends AbiItem.Name<abi>,
args extends ExtractArgs<abi, name>,
> = IsUnion<name> extends true
? {
[key in keyof abi]: abi[key] extends { name: name } ? abi[key] : never
}[number]
: AbiItem.FromAbi<abi, name> extends infer abiItem extends AbiItem.AbiItem & {
inputs: readonly abitype.AbiParameter[]
}
? IsUnion<abiItem> extends true // narrow overloads using `args` by converting to tuple and filtering out overloads that don't match
? UnionToTuple<abiItem> extends infer abiItems extends
readonly (AbiItem.AbiItem & {
inputs: readonly abitype.AbiParameter[]
})[]
? IsNever<TupleToUnion<abiItems, abi, name, args>> extends true
? Compute<
abiItems[0] & {
readonly overloads: UnionToTuple<
Exclude<abiItems[number], abiItems[0]>
>
}
>
: TupleToUnion<abiItems, abi, name, args> // convert back to union (removes `never` tuple entries: `['foo', never, 'bar'][number]` => `'foo' | 'bar'`)
: never
: abiItem
: never
/** @internal */
export type TupleToUnion<
abiItems extends readonly {
inputs: readonly abitype.AbiParameter[]
}[],
abi extends Abi.Abi,
name extends AbiItem.Name<abi>,
args extends ExtractArgs<abi, name>,
> = {
[k in keyof abiItems]: (
readonly [] extends args
? readonly [] // fallback to `readonly []` if `args` has no value (e.g. `args` property not provided)
: args
) extends abitype.AbiParametersToPrimitiveTypes<
abiItems[k]['inputs'],
'inputs'
>
? abiItems[k]
: never
}[number]
/** @internal */
export type ErrorSignature<
name extends string = string,
parameters extends string = string,
> = `error ${name}(${parameters})`
/** @internal */
export type IsErrorSignature<signature extends string> =
signature extends ErrorSignature<infer name> ? IsName<name> : false
/** @internal */
export type EventSignature<
name extends string = string,
parameters extends string = string,
> = `event ${name}(${parameters})`
/** @internal */
export type IsEventSignature<signature extends string> =
signature extends EventSignature<infer name> ? IsName<name> : false
/** @internal */
export type FunctionSignature<
name extends string = string,
tail extends string = string,
> = `function ${name}(${tail}`
export type IsFunctionSignature<signature> =
signature extends FunctionSignature<infer name>
? IsName<name> extends true
? signature extends ValidFunctionSignatures
? true
: // Check that `Parameters` is not absorbing other types (e.g. `returns`)
signature extends `function ${string}(${infer parameters})`
? parameters extends InvalidFunctionParameters
? false
: true
: false
: false
: false
/** @internal */
export type Scope = 'public' | 'external' // `internal` or `private` functions wouldn't make it to ABI so can ignore
/** @internal */
export type Returns = `returns (${string})` | `returns(${string})`
// Almost all valid function signatures, except `function ${string}(${infer parameters})` since `parameters` can absorb returns
/** @internal */
export type ValidFunctionSignatures =
| `function ${string}()`
// basic
| `function ${string}() ${Returns}`
| `function ${string}() ${abitype.AbiStateMutability}`
| `function ${string}() ${Scope}`
// combinations
| `function ${string}() ${abitype.AbiStateMutability} ${Returns}`
| `function ${string}() ${Scope} ${Returns}`
| `function ${string}() ${Scope} ${abitype.AbiStateMutability}`
| `function ${string}() ${Scope} ${abitype.AbiStateMutability} ${Returns}`
// Parameters
| `function ${string}(${string}) ${Returns}`
| `function ${string}(${string}) ${abitype.AbiStateMutability}`
| `function ${string}(${string}) ${Scope}`
| `function ${string}(${string}) ${abitype.AbiStateMutability} ${Returns}`
| `function ${string}(${string}) ${Scope} ${Returns}`
| `function ${string}(${string}) ${Scope} ${abitype.AbiStateMutability}`
| `function ${string}(${string}) ${Scope} ${abitype.AbiStateMutability} ${Returns}`
/** @internal */
export type StructSignature<
name extends string = string,
properties extends string = string,
> = `struct ${name} {${properties}}`
/** @internal */
export type IsStructSignature<signature extends string> =
signature extends StructSignature<infer name> ? IsName<name> : false
/** @internal */
export type ConstructorSignature<tail extends string = string> =
`constructor(${tail}`
/** @internal */
export type IsConstructorSignature<signature> =
signature extends ConstructorSignature
? signature extends ValidConstructorSignatures
? true
: false
: false
/** @internal */
export type ValidConstructorSignatures =
| `constructor(${string})`
| `constructor(${string}) payable`
/** @internal */
export type FallbackSignature<abiStateMutability extends '' | ' payable' = ''> =
`fallback() external${abiStateMutability}`
/** @internal */
export type ReceiveSignature = 'receive() external payable'
// TODO: Maybe use this for signature validation one day
// https://twitter.com/devanshj__/status/1610423724708343808
/** @internal */
export type IsSignature<type extends string> =
| (IsErrorSignature<type> extends true ? true : never)
| (IsEventSignature<type> extends true ? true : never)
| (IsFunctionSignature<type> extends true ? true : never)
| (IsStructSignature<type> extends true ? true : never)
| (IsConstructorSignature<type> extends true ? true : never)
| (type extends FallbackSignature ? true : never)
| (type extends ReceiveSignature ? true : never) extends infer condition
? [condition] extends [never]
? false
: true
: false
/** @internal */
export type Signature<
string1 extends string,
string2 extends string | unknown = unknown,
> = IsSignature<string1> extends true
? string1
: string extends string1 // if exactly `string` (not narrowed), then pass through as valid
? string1
: TypeErrorMessage<`Signature "${string1}" is invalid${string2 extends string
? ` at position ${string2}`
: ''}.`>
/** @internal */
export type Signatures<signatures extends readonly string[]> = {
[key in keyof signatures]: Signature<signatures[key], key>
}
/** @internal */
export type IsName<name extends string> = name extends ''
? false
: ValidateName<name> extends name
? true
: false
/** @internal */
export type ValidateName<
name extends string,
checkCharacters extends boolean = false,
> = name extends `${string}${' '}${string}`
? TypeErrorMessage<`Identifier "${name}" cannot contain whitespace.`>
: IsSolidityKeyword<name> extends true
? TypeErrorMessage<`"${name}" is a protected Solidity keyword.`>
: name extends `${number}`
? TypeErrorMessage<`Identifier "${name}" cannot be a number string.`>
: name extends `${number}${string}`
? TypeErrorMessage<`Identifier "${name}" cannot start with a number.`>
: checkCharacters extends true
? IsValidCharacter<name> extends true
? name
: TypeErrorMessage<`"${name}" contains invalid character.`>
: name
/** @internal */
export type IsSolidityKeyword<type extends string> =
type extends SolidityKeywords ? true : false
/** @internal */
export type SolidityKeywords =
| 'after'
| 'alias'
| 'anonymous'
| 'apply'
| 'auto'
| 'byte'
| 'calldata'
| 'case'
| 'catch'
| 'constant'
| 'copyof'
| 'default'
| 'defined'
| 'error'
| 'event'
| 'external'
| 'false'
| 'final'
| 'function'
| 'immutable'
| 'implements'
| 'in'
| 'indexed'
| 'inline'
| 'internal'
| 'let'
| 'mapping'
| 'match'
| 'memory'
| 'mutable'
| 'null'
| 'of'
| 'override'
| 'partial'
| 'private'
| 'promise'
| 'public'
| 'pure'
| 'reference'
| 'relocatable'
| 'return'
| 'returns'
| 'sizeof'
| 'static'
| 'storage'
| 'struct'
| 'super'
| 'supports'
| 'switch'
| 'this'
| 'true'
| 'try'
| 'typedef'
| 'typeof'
| 'var'
| 'view'
| 'virtual'
| `address${`[${string}]` | ''}`
| `bool${`[${string}]` | ''}`
| `string${`[${string}]` | ''}`
| `tuple${`[${string}]` | ''}`
| `bytes${number | ''}${`[${string}]` | ''}`
| `${'u' | ''}int${number | ''}${`[${string}]` | ''}`
/** @internal */
export type IsValidCharacter<character extends string> =
character extends `${ValidCharacters}${infer tail}`
? tail extends ''
? true
: IsValidCharacter<tail>
: false
// biome-ignore format: no formatting
/** @internal */
export type ValidCharacters =
// uppercase letters
| 'A' | 'B' | 'C' | 'D' | 'E' | 'F' | 'G' | 'H' | 'I' | 'J' | 'K' | 'L' | 'M' | 'N' | 'O' | 'P' | 'Q' | 'R' | 'S' | 'T' | 'U' | 'V' | 'W' | 'X' | 'Y' | 'Z'
// lowercase letters
| 'a' | 'b' | 'c' | 'd' | 'e' | 'f' | 'g' | 'h' | 'i' | 'j' | 'k' | 'l' | 'm' | 'n' | 'o' | 'p' | 'q' | 'r' | 's' | 't' | 'u' | 'v' | 'w' | 'x' | 'y' | 'z'
// numbers
| '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'
// special characters
| '_' | '$'
// Template string inference can absorb `returns`:
// type Result = `function foo(string) return s (uint256)` extends `function ${string}(${infer Parameters})` ? Parameters : never
// // ^? type Result = "string ) return s (uint256"
// So we need to validate against `returns` keyword with all combinations of whitespace
/** @internal */
export type InvalidFunctionParameters =
| `${string}${MangledReturns} (${string}`
| `${string}) ${MangledReturns}${string}`
| `${string})${string}${MangledReturns}${string}(${string}`
// r_e_t_u_r_n_s
/** @internal */
export type MangledReturns =
// Single
| `r${string}eturns`
| `re${string}turns`
| `ret${string}urns`
| `retu${string}rns`
| `retur${string}ns`
| `return${string}s`
// Double
// `r_e*`
| `r${string}e${string}turns`
| `r${string}et${string}urns`
| `r${string}etu${string}rns`
| `r${string}etur${string}ns`
| `r${string}eturn${string}s`
// `re_t*`
| `re${string}t${string}urns`
| `re${string}tu${string}rns`
| `re${string}tur${string}ns`
| `re${string}turn${string}s`
// `ret_u*`
| `ret${string}u${string}rns`
| `ret${string}ur${string}ns`
| `ret${string}urn${string}s`
// `retu_r*`
| `retu${string}r${string}ns`
| `retu${string}rn${string}s`
// `retur_n*`
| `retur${string}n${string}s`
// Triple
// `r_e_t*`
| `r${string}e${string}t${string}urns`
| `r${string}e${string}tu${string}rns`
| `r${string}e${string}tur${string}ns`
| `r${string}e${string}turn${string}s`
// `re_t_u*`
| `re${string}t${string}u${string}rns`
| `re${string}t${string}ur${string}ns`
| `re${string}t${string}urn${string}s`
// `ret_u_r*`
| `ret${string}u${string}r${string}ns`
| `ret${string}u${string}rn${string}s`
// `retu_r_n*`
| `retu${string}r${string}n${string}s`
// Quadruple
// `r_e_t_u*`
| `r${string}e${string}t${string}u${string}rns`
| `r${string}e${string}t${string}ur${string}ns`
| `r${string}e${string}t${string}urn${string}s`
// `re_t_u_r*`
| `re${string}t${string}u${string}r${string}ns`
| `re${string}t${string}u${string}rn${string}s`
// `ret_u_r_n*`
| `ret${string}u${string}r${string}n${string}s`
// Quintuple
// `r_e_t_u_r*`
| `r${string}e${string}t${string}u${string}r${string}ns`
| `r${string}e${string}t${string}u${string}rn${string}s`
// `re_t_u_r_n*`
| `re${string}t${string}u${string}r${string}n${string}s`
// Sextuple
// `r_e_t_u_r_n_s`
| `r${string}e${string}t${string}u${string}r${string}n${string}s`
/** @internal */
export type Widen<type> =
| ([unknown] extends [type] ? unknown : never)
| (type extends Function ? type : never)
| (type extends abitype.ResolvedRegister['bigIntType'] ? bigint : never)
| (type extends boolean ? boolean : never)
| (type extends abitype.ResolvedRegister['intType'] ? number : never)
| (type extends string
? type extends abitype.ResolvedRegister['addressType']
? abitype.ResolvedRegister['addressType']
: type extends abitype.ResolvedRegister['bytesType']['inputs']
? abitype.ResolvedRegister['bytesType']
: string
: never)
| (type extends readonly [] ? readonly [] : never)
| (type extends Record<string, unknown>
? { [K in keyof type]: Widen<type[K]> }
: never)
| (type extends { length: number }
? {
[K in keyof type]: Widen<type[K]>
} extends infer Val extends readonly unknown[]
? readonly [...Val]
: never
: never)
/** @internal */
export function normalizeSignature(signature: string): string {
let active = true
let current = ''
let level = 0
let result = ''
let valid = false
for (let i = 0; i < signature.length; i++) {
const char = signature[i]!
// If the character is a separator, we want to reactivate.
if (['(', ')', ','].includes(char)) active = true
// If the character is a "level" token, we want to increment/decrement.
if (char === '(') level++
if (char === ')') level--
// If we aren't active, we don't want to mutate the result.
if (!active) continue
// If level === 0, we are at the definition level.
if (level === 0) {
if (char === ' ' && ['event', 'function', 'error', ''].includes(result))
result = ''
else {
result += char
// If we are at the end of the definition, we must be finished.
if (char === ')') {
valid = true
break
}
}
continue
}
// Ignore spaces
if (char === ' ') {
// If the previous character is a separator, and the current section isn't empty, we want to deactivate.
if (signature[i - 1] !== ',' && current !== ',' && current !== ',(') {
current = ''
active = false
}
continue
}
result += char
current += char
}
if (!valid) throw new Errors.BaseError('Unable to normalize signature.')
return result
}
/** @internal */
export declare namespace normalizeSignature {
export type ErrorType = Errors.BaseError | Errors.GlobalErrorType
}
/** @internal */
export function isArgOfType(
arg: unknown,
abiParameter: AbiParameters.Parameter,
): boolean {
const argType = typeof arg
const abiParameterType = abiParameter.type
switch (abiParameterType) {
case 'address':
return Address.validate(arg as Address.Address, { strict: false })
case 'bool':
return argType === 'boolean'
case 'function':
return argType === 'string'
case 'string':
return argType === 'string'
default: {
if (abiParameterType === 'tuple' && 'components' in abiParameter)
return Object.values(abiParameter.components).every(
(component, index) => {
return isArgOfType(
Object.values(arg as unknown[] | Record<string, unknown>)[index],
component as AbiParameters.Parameter,
)
},
)
// `(u)int<M>`: (un)signed integer type of `M` bits, `0 < M <= 256`, `M % 8 == 0`
// https://regexr.com/6v8hp
if (
/^u?int(8|16|24|32|40|48|56|64|72|80|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256)?$/.test(
abiParameterType,
)
)
return argType === 'number' || argType === 'bigint'
// `bytes<M>`: binary type of `M` bytes, `0 < M <= 32`
// https://regexr.com/6va55
if (/^bytes([1-9]|1[0-9]|2[0-9]|3[0-2])?$/.test(abiParameterType))
return argType === 'string' || arg instanceof Uint8Array
// fixed-length (`<type>[M]`) and dynamic (`<type>[]`) arrays
// https://regexr.com/6va6i
if (/[a-z]+[1-9]{0,3}(\[[0-9]{0,}\])+$/.test(abiParameterType)) {
return (
Array.isArray(arg) &&
arg.every((x: unknown) =>
isArgOfType(x, {
...abiParameter,
// Pop off `[]` or `[M]` from end of type
type: abiParameterType.replace(/(\[[0-9]{0,}\])$/, ''),
} as AbiParameters.Parameter),
)
)
}
return false
}
}
}
/** @internal */
export function getAmbiguousTypes(
sourceParameters: readonly AbiParameters.Parameter[],
targetParameters: readonly AbiParameters.Parameter[],
args: ExtractArgs,
): AbiParameters.Parameter['type'][] | undefined {
for (const parameterIndex in sourceParameters) {
const sourceParameter = sourceParameters[parameterIndex]!
const targetParameter = targetParameters[parameterIndex]!
if (
sourceParameter.type === 'tuple' &&
targetParameter.type === 'tuple' &&
'components' in sourceParameter &&
'components' in targetParameter
)
return getAmbiguousTypes(
sourceParameter.components,
targetParameter.components,
(args as any)[parameterIndex],
)
const types = [sourceParameter.type, targetParameter.type]
const ambiguous = (() => {
if (types.includes('address') && types.includes('bytes20')) return true
if (types.includes('address') && types.includes('string'))
return Address.validate(args[parameterIndex] as Address.Address, {
strict: false,
})
if (types.includes('address') && types.includes('bytes'))
return Address.validate(args[parameterIndex] as Address.Address, {
strict: false,
})
return false
})()
if (ambiguous) return types
}
return
}

811
node_modules/ox/core/internal/abiParameters.ts generated vendored Normal file
View File

@@ -0,0 +1,811 @@
import type {
AbiParameter,
AbiParameterKind,
AbiParameterToPrimitiveType,
AbiParametersToPrimitiveTypes,
} from 'abitype'
import * as AbiParameters from '../AbiParameters.js'
import * as Address from '../Address.js'
import * as Bytes from '../Bytes.js'
import * as Errors from '../Errors.js'
import * as Hex from '../Hex.js'
import { integerRegex } from '../Solidity.js'
import type * as Cursor from './cursor.js'
import type { Compute, IsNarrowable, UnionToIntersection } from './types.js'
/** @internal */
export type ParameterToPrimitiveType<
abiParameter extends AbiParameter | { name: string; type: unknown },
abiParameterKind extends AbiParameterKind = AbiParameterKind,
> = AbiParameterToPrimitiveType<abiParameter, abiParameterKind>
/** @internal */
export type PreparedParameter = { dynamic: boolean; encoded: Hex.Hex }
/** @internal */
export type ToObject<
parameters extends readonly AbiParameter[],
kind extends AbiParameterKind = AbiParameterKind,
> = IsNarrowable<parameters, AbiParameters.AbiParameters> extends true
? Compute<
UnionToIntersection<
{
[index in keyof parameters]: parameters[index] extends {
name: infer name extends string
}
? {
[key in name]: AbiParameterToPrimitiveType<
parameters[index],
kind
>
}
: {
[key in index]: AbiParameterToPrimitiveType<
parameters[index],
kind
>
}
}[number]
>
>
: unknown
/** @internal */
export type ToPrimitiveTypes<
abiParameters extends readonly AbiParameter[],
abiParameterKind extends AbiParameterKind = AbiParameterKind,
> = AbiParametersToPrimitiveTypes<abiParameters, abiParameterKind>
/** @internal */
export type Tuple = ParameterToPrimitiveType<TupleAbiParameter>
/** @internal */
export function decodeParameter(
cursor: Cursor.Cursor,
param: AbiParameters.Parameter,
options: { checksumAddress?: boolean | undefined; staticPosition: number },
) {
const { checksumAddress, staticPosition } = options
const arrayComponents = getArrayComponents(param.type)
if (arrayComponents) {
const [length, type] = arrayComponents
return decodeArray(
cursor,
{ ...param, type },
{ checksumAddress, length, staticPosition },
)
}
if (param.type === 'tuple')
return decodeTuple(cursor, param as TupleAbiParameter, {
checksumAddress,
staticPosition,
})
if (param.type === 'address')
return decodeAddress(cursor, { checksum: checksumAddress })
if (param.type === 'bool') return decodeBool(cursor)
if (param.type.startsWith('bytes'))
return decodeBytes(cursor, param, { staticPosition })
if (param.type.startsWith('uint') || param.type.startsWith('int'))
return decodeNumber(cursor, param)
if (param.type === 'string') return decodeString(cursor, { staticPosition })
throw new AbiParameters.InvalidTypeError(param.type)
}
export declare namespace decodeParameter {
type ErrorType =
| decodeArray.ErrorType
| decodeTuple.ErrorType
| decodeAddress.ErrorType
| decodeBool.ErrorType
| decodeBytes.ErrorType
| decodeNumber.ErrorType
| decodeString.ErrorType
| AbiParameters.InvalidTypeError
| Errors.GlobalErrorType
}
const sizeOfLength = 32
const sizeOfOffset = 32
/** @internal */
export function decodeAddress(
cursor: Cursor.Cursor,
options: { checksum?: boolean | undefined } = {},
) {
const { checksum = false } = options
const value = cursor.readBytes(32)
const wrap = (address: Hex.Hex) =>
checksum ? Address.checksum(address) : address
return [wrap(Hex.fromBytes(Bytes.slice(value, -20))), 32]
}
export declare namespace decodeAddress {
type ErrorType =
| Hex.fromBytes.ErrorType
| Bytes.slice.ErrorType
| Errors.GlobalErrorType
}
/** @internal */
export function decodeArray(
cursor: Cursor.Cursor,
param: AbiParameters.Parameter,
options: {
checksumAddress?: boolean | undefined
length: number | null
staticPosition: number
},
) {
const { checksumAddress, length, staticPosition } = options
// If the length of the array is not known in advance (dynamic array),
// this means we will need to wonder off to the pointer and decode.
if (!length) {
// Dealing with a dynamic type, so get the offset of the array data.
const offset = Bytes.toNumber(cursor.readBytes(sizeOfOffset))
// Start is the static position of current slot + offset.
const start = staticPosition + offset
const startOfData = start + sizeOfLength
// Get the length of the array from the offset.
cursor.setPosition(start)
const length = Bytes.toNumber(cursor.readBytes(sizeOfLength))
// Check if the array has any dynamic children.
const dynamicChild = hasDynamicChild(param)
let consumed = 0
const value: unknown[] = []
for (let i = 0; i < length; ++i) {
// If any of the children is dynamic, then all elements will be offset pointer, thus size of one slot (32 bytes).
// Otherwise, elements will be the size of their encoding (consumed bytes).
cursor.setPosition(startOfData + (dynamicChild ? i * 32 : consumed))
const [data, consumed_] = decodeParameter(cursor, param, {
checksumAddress,
staticPosition: startOfData,
})
consumed += consumed_
value.push(data)
}
// As we have gone wondering, restore to the original position + next slot.
cursor.setPosition(staticPosition + 32)
return [value, 32]
}
// If the length of the array is known in advance,
// and the length of an element deeply nested in the array is not known,
// we need to decode the offset of the array data.
if (hasDynamicChild(param)) {
// Dealing with dynamic types, so get the offset of the array data.
const offset = Bytes.toNumber(cursor.readBytes(sizeOfOffset))
// Start is the static position of current slot + offset.
const start = staticPosition + offset
const value: unknown[] = []
for (let i = 0; i < length; ++i) {
// Move cursor along to the next slot (next offset pointer).
cursor.setPosition(start + i * 32)
const [data] = decodeParameter(cursor, param, {
checksumAddress,
staticPosition: start,
})
value.push(data)
}
// As we have gone wondering, restore to the original position + next slot.
cursor.setPosition(staticPosition + 32)
return [value, 32]
}
// If the length of the array is known in advance and the array is deeply static,
// then we can just decode each element in sequence.
let consumed = 0
const value: unknown[] = []
for (let i = 0; i < length; ++i) {
const [data, consumed_] = decodeParameter(cursor, param, {
checksumAddress,
staticPosition: staticPosition + consumed,
})
consumed += consumed_
value.push(data)
}
return [value, consumed]
}
export declare namespace decodeArray {
type ErrorType = Bytes.toNumber.ErrorType | Errors.GlobalErrorType
}
/** @internal */
export function decodeBool(cursor: Cursor.Cursor) {
return [Bytes.toBoolean(cursor.readBytes(32), { size: 32 }), 32]
}
export declare namespace decodeBool {
type ErrorType = Bytes.toBoolean.ErrorType | Errors.GlobalErrorType
}
/** @internal */
export function decodeBytes(
cursor: Cursor.Cursor,
param: AbiParameters.Parameter,
{ staticPosition }: { staticPosition: number },
) {
const [_, size] = param.type.split('bytes')
if (!size) {
// Dealing with dynamic types, so get the offset of the bytes data.
const offset = Bytes.toNumber(cursor.readBytes(32))
// Set position of the cursor to start of bytes data.
cursor.setPosition(staticPosition + offset)
const length = Bytes.toNumber(cursor.readBytes(32))
// If there is no length, we have zero data.
if (length === 0) {
// As we have gone wondering, restore to the original position + next slot.
cursor.setPosition(staticPosition + 32)
return ['0x', 32]
}
const data = cursor.readBytes(length)
// As we have gone wondering, restore to the original position + next slot.
cursor.setPosition(staticPosition + 32)
return [Hex.fromBytes(data), 32]
}
const value = Hex.fromBytes(cursor.readBytes(Number.parseInt(size), 32))
return [value, 32]
}
export declare namespace decodeBytes {
type ErrorType =
| Hex.fromBytes.ErrorType
| Bytes.toNumber.ErrorType
| Errors.GlobalErrorType
}
/** @internal */
export function decodeNumber(
cursor: Cursor.Cursor,
param: AbiParameters.Parameter,
) {
const signed = param.type.startsWith('int')
const size = Number.parseInt(param.type.split('int')[1] || '256')
const value = cursor.readBytes(32)
return [
size > 48
? Bytes.toBigInt(value, { signed })
: Bytes.toNumber(value, { signed }),
32,
]
}
export declare namespace decodeNumber {
type ErrorType =
| Bytes.toNumber.ErrorType
| Bytes.toBigInt.ErrorType
| Errors.GlobalErrorType
}
/** @internal */
export type TupleAbiParameter = AbiParameters.Parameter & {
components: readonly AbiParameters.Parameter[]
}
/** @internal */
export function decodeTuple(
cursor: Cursor.Cursor,
param: TupleAbiParameter,
options: { checksumAddress?: boolean | undefined; staticPosition: number },
) {
const { checksumAddress, staticPosition } = options
// Tuples can have unnamed components (i.e. they are arrays), so we must
// determine whether the tuple is named or unnamed. In the case of a named
// tuple, the value will be an object where each property is the name of the
// component. In the case of an unnamed tuple, the value will be an array.
const hasUnnamedChild =
param.components.length === 0 || param.components.some(({ name }) => !name)
// Initialize the value to an object or an array, depending on whether the
// tuple is named or unnamed.
const value: any = hasUnnamedChild ? [] : {}
let consumed = 0
// If the tuple has a dynamic child, we must first decode the offset to the
// tuple data.
if (hasDynamicChild(param)) {
// Dealing with dynamic types, so get the offset of the tuple data.
const offset = Bytes.toNumber(cursor.readBytes(sizeOfOffset))
// Start is the static position of referencing slot + offset.
const start = staticPosition + offset
for (let i = 0; i < param.components.length; ++i) {
const component = param.components[i]!
cursor.setPosition(start + consumed)
const [data, consumed_] = decodeParameter(cursor, component, {
checksumAddress,
staticPosition: start,
})
consumed += consumed_
value[hasUnnamedChild ? i : component?.name!] = data
}
// As we have gone wondering, restore to the original position + next slot.
cursor.setPosition(staticPosition + 32)
return [value, 32]
}
// If the tuple has static children, we can just decode each component
// in sequence.
for (let i = 0; i < param.components.length; ++i) {
const component = param.components[i]!
const [data, consumed_] = decodeParameter(cursor, component, {
checksumAddress,
staticPosition,
})
value[hasUnnamedChild ? i : component?.name!] = data
consumed += consumed_
}
return [value, consumed]
}
export declare namespace decodeTuple {
type ErrorType = Bytes.toNumber.ErrorType | Errors.GlobalErrorType
}
/** @internal */
export function decodeString(
cursor: Cursor.Cursor,
{ staticPosition }: { staticPosition: number },
) {
// Get offset to start of string data.
const offset = Bytes.toNumber(cursor.readBytes(32))
// Start is the static position of current slot + offset.
const start = staticPosition + offset
cursor.setPosition(start)
const length = Bytes.toNumber(cursor.readBytes(32))
// If there is no length, we have zero data (empty string).
if (length === 0) {
cursor.setPosition(staticPosition + 32)
return ['', 32]
}
const data = cursor.readBytes(length, 32)
const value = Bytes.toString(Bytes.trimLeft(data))
// As we have gone wondering, restore to the original position + next slot.
cursor.setPosition(staticPosition + 32)
return [value, 32]
}
export declare namespace decodeString {
type ErrorType =
| Bytes.toNumber.ErrorType
| Bytes.toString.ErrorType
| Bytes.trimLeft.ErrorType
| Errors.GlobalErrorType
}
/** @internal */
export function prepareParameters<
const parameters extends AbiParameters.AbiParameters,
>({
checksumAddress,
parameters,
values,
}: {
checksumAddress?: boolean | undefined
parameters: parameters
values: parameters extends AbiParameters.AbiParameters
? ToPrimitiveTypes<parameters>
: never
}) {
const preparedParameters: PreparedParameter[] = []
for (let i = 0; i < parameters.length; i++) {
preparedParameters.push(
prepareParameter({
checksumAddress,
parameter: parameters[i]!,
value: values[i],
}),
)
}
return preparedParameters
}
/** @internal */
export declare namespace prepareParameters {
type ErrorType = prepareParameter.ErrorType | Errors.GlobalErrorType
}
/** @internal */
export function prepareParameter<
const parameter extends AbiParameters.Parameter,
>({
checksumAddress = false,
parameter: parameter_,
value,
}: {
parameter: parameter
value: parameter extends AbiParameters.Parameter
? ParameterToPrimitiveType<parameter>
: never
checksumAddress?: boolean | undefined
}): PreparedParameter {
const parameter = parameter_ as AbiParameters.Parameter
const arrayComponents = getArrayComponents(parameter.type)
if (arrayComponents) {
const [length, type] = arrayComponents
return encodeArray(value, {
checksumAddress,
length,
parameter: {
...parameter,
type,
},
})
}
if (parameter.type === 'tuple') {
return encodeTuple(value as unknown as Tuple, {
checksumAddress,
parameter: parameter as TupleAbiParameter,
})
}
if (parameter.type === 'address') {
return encodeAddress(value as unknown as Hex.Hex, {
checksum: checksumAddress,
})
}
if (parameter.type === 'bool') {
return encodeBoolean(value as unknown as boolean)
}
if (parameter.type.startsWith('uint') || parameter.type.startsWith('int')) {
const signed = parameter.type.startsWith('int')
const [, , size = '256'] = integerRegex.exec(parameter.type) ?? []
return encodeNumber(value as unknown as number, {
signed,
size: Number(size),
})
}
if (parameter.type.startsWith('bytes')) {
return encodeBytes(value as unknown as Hex.Hex, { type: parameter.type })
}
if (parameter.type === 'string') {
return encodeString(value as unknown as string)
}
throw new AbiParameters.InvalidTypeError(parameter.type)
}
/** @internal */
export declare namespace prepareParameter {
type ErrorType =
| encodeArray.ErrorType
| encodeTuple.ErrorType
| encodeAddress.ErrorType
| encodeBoolean.ErrorType
| encodeBytes.ErrorType
| encodeString.ErrorType
| AbiParameters.InvalidTypeError
| Errors.GlobalErrorType
}
/** @internal */
export function encode(preparedParameters: PreparedParameter[]): Hex.Hex {
// 1. Compute the size of the static part of the parameters.
let staticSize = 0
for (let i = 0; i < preparedParameters.length; i++) {
const { dynamic, encoded } = preparedParameters[i]!
if (dynamic) staticSize += 32
else staticSize += Hex.size(encoded)
}
// 2. Split the parameters into static and dynamic parts.
const staticParameters: Hex.Hex[] = []
const dynamicParameters: Hex.Hex[] = []
let dynamicSize = 0
for (let i = 0; i < preparedParameters.length; i++) {
const { dynamic, encoded } = preparedParameters[i]!
if (dynamic) {
staticParameters.push(
Hex.fromNumber(staticSize + dynamicSize, { size: 32 }),
)
dynamicParameters.push(encoded)
dynamicSize += Hex.size(encoded)
} else {
staticParameters.push(encoded)
}
}
// 3. Concatenate static and dynamic parts.
return Hex.concat(...staticParameters, ...dynamicParameters)
}
/** @internal */
export declare namespace encode {
type ErrorType =
| Hex.concat.ErrorType
| Hex.fromNumber.ErrorType
| Hex.size.ErrorType
| Errors.GlobalErrorType
}
/** @internal */
export function encodeAddress(
value: Hex.Hex,
options: { checksum: boolean },
): PreparedParameter {
const { checksum = false } = options
Address.assert(value, { strict: checksum })
return {
dynamic: false,
encoded: Hex.padLeft(value.toLowerCase() as Hex.Hex),
}
}
/** @internal */
export declare namespace encodeAddress {
type ErrorType =
| Address.assert.ErrorType
| Hex.padLeft.ErrorType
| Errors.GlobalErrorType
}
/** @internal */
export function encodeArray<const parameter extends AbiParameters.Parameter>(
value: ParameterToPrimitiveType<parameter>,
options: {
checksumAddress?: boolean | undefined
length: number | null
parameter: parameter
},
): PreparedParameter {
const { checksumAddress, length, parameter } = options
const dynamic = length === null
if (!Array.isArray(value)) throw new AbiParameters.InvalidArrayError(value)
if (!dynamic && value.length !== length)
throw new AbiParameters.ArrayLengthMismatchError({
expectedLength: length!,
givenLength: value.length,
type: `${parameter.type}[${length}]`,
})
let dynamicChild = false
const preparedParameters: PreparedParameter[] = []
for (let i = 0; i < value.length; i++) {
const preparedParam = prepareParameter({
checksumAddress,
parameter,
value: value[i],
})
if (preparedParam.dynamic) dynamicChild = true
preparedParameters.push(preparedParam)
}
if (dynamic || dynamicChild) {
const data = encode(preparedParameters)
if (dynamic) {
const length = Hex.fromNumber(preparedParameters.length, { size: 32 })
return {
dynamic: true,
encoded:
preparedParameters.length > 0 ? Hex.concat(length, data) : length,
}
}
if (dynamicChild) return { dynamic: true, encoded: data }
}
return {
dynamic: false,
encoded: Hex.concat(...preparedParameters.map(({ encoded }) => encoded)),
}
}
/** @internal */
export declare namespace encodeArray {
type ErrorType =
| AbiParameters.InvalidArrayError
| AbiParameters.ArrayLengthMismatchError
| Hex.concat.ErrorType
| Hex.fromNumber.ErrorType
| Errors.GlobalErrorType
}
/** @internal */
export function encodeBytes(
value: Hex.Hex,
{ type }: { type: string },
): PreparedParameter {
const [, parametersize] = type.split('bytes')
const bytesSize = Hex.size(value)
if (!parametersize) {
let value_ = value
// If the size is not divisible by 32 bytes, pad the end
// with empty bytes to the ceiling 32 bytes.
if (bytesSize % 32 !== 0)
value_ = Hex.padRight(value_, Math.ceil((value.length - 2) / 2 / 32) * 32)
return {
dynamic: true,
encoded: Hex.concat(
Hex.padLeft(Hex.fromNumber(bytesSize, { size: 32 })),
value_,
),
}
}
if (bytesSize !== Number.parseInt(parametersize))
throw new AbiParameters.BytesSizeMismatchError({
expectedSize: Number.parseInt(parametersize),
value,
})
return { dynamic: false, encoded: Hex.padRight(value) }
}
/** @internal */
export declare namespace encodeBytes {
type ErrorType =
| Hex.padLeft.ErrorType
| Hex.padRight.ErrorType
| Hex.fromNumber.ErrorType
| Hex.slice.ErrorType
| Errors.GlobalErrorType
}
/** @internal */
export function encodeBoolean(value: boolean): PreparedParameter {
if (typeof value !== 'boolean')
throw new Errors.BaseError(
`Invalid boolean value: "${value}" (type: ${typeof value}). Expected: \`true\` or \`false\`.`,
)
return { dynamic: false, encoded: Hex.padLeft(Hex.fromBoolean(value)) }
}
/** @internal */
export declare namespace encodeBoolean {
type ErrorType =
| Hex.padLeft.ErrorType
| Hex.fromBoolean.ErrorType
| Errors.GlobalErrorType
}
/** @internal */
export function encodeNumber(
value: number,
{ signed, size }: { signed: boolean; size: number },
): PreparedParameter {
if (typeof size === 'number') {
const max = 2n ** (BigInt(size) - (signed ? 1n : 0n)) - 1n
const min = signed ? -max - 1n : 0n
if (value > max || value < min)
throw new Hex.IntegerOutOfRangeError({
max: max.toString(),
min: min.toString(),
signed,
size: size / 8,
value: value.toString(),
})
}
return {
dynamic: false,
encoded: Hex.fromNumber(value, {
size: 32,
signed,
}),
}
}
/** @internal */
export declare namespace encodeNumber {
type ErrorType = Hex.fromNumber.ErrorType | Errors.GlobalErrorType
}
/** @internal */
export function encodeString(value: string): PreparedParameter {
const hexValue = Hex.fromString(value)
const partsLength = Math.ceil(Hex.size(hexValue) / 32)
const parts: Hex.Hex[] = []
for (let i = 0; i < partsLength; i++) {
parts.push(Hex.padRight(Hex.slice(hexValue, i * 32, (i + 1) * 32)))
}
return {
dynamic: true,
encoded: Hex.concat(
Hex.padRight(Hex.fromNumber(Hex.size(hexValue), { size: 32 })),
...parts,
),
}
}
/** @internal */
export declare namespace encodeString {
type ErrorType =
| Hex.fromNumber.ErrorType
| Hex.padRight.ErrorType
| Hex.slice.ErrorType
| Hex.size.ErrorType
| Errors.GlobalErrorType
}
/** @internal */
export function encodeTuple<
const parameter extends AbiParameters.Parameter & {
components: readonly AbiParameters.Parameter[]
},
>(
value: ParameterToPrimitiveType<parameter>,
options: {
checksumAddress?: boolean | undefined
parameter: parameter
},
): PreparedParameter {
const { checksumAddress, parameter } = options
let dynamic = false
const preparedParameters: PreparedParameter[] = []
for (let i = 0; i < parameter.components.length; i++) {
const param_ = parameter.components[i]!
const index = Array.isArray(value) ? i : param_.name
const preparedParam = prepareParameter({
checksumAddress,
parameter: param_,
value: (value as any)[index!] as readonly unknown[],
})
preparedParameters.push(preparedParam)
if (preparedParam.dynamic) dynamic = true
}
return {
dynamic,
encoded: dynamic
? encode(preparedParameters)
: Hex.concat(...preparedParameters.map(({ encoded }) => encoded)),
}
}
/** @internal */
export declare namespace encodeTuple {
type ErrorType = Hex.concat.ErrorType | Errors.GlobalErrorType
}
/** @internal */
export function getArrayComponents(
type: string,
): [length: number | null, innerType: string] | undefined {
const matches = type.match(/^(.*)\[(\d+)?\]$/)
return matches
? // Return `null` if the array is dynamic.
[matches[2]! ? Number(matches[2]!) : null, matches[1]!]
: undefined
}
/** @internal */
export function hasDynamicChild(param: AbiParameters.Parameter) {
const { type } = param
if (type === 'string') return true
if (type === 'bytes') return true
if (type.endsWith('[]')) return true
if (type === 'tuple') return (param as any).components?.some(hasDynamicChild)
const arrayComponents = getArrayComponents(param.type)
if (
arrayComponents &&
hasDynamicChild({
...param,
type: arrayComponents[1],
} as AbiParameters.Parameter)
)
return true
return false
}

103
node_modules/ox/core/internal/base58.ts generated vendored Normal file
View File

@@ -0,0 +1,103 @@
import * as Bytes from '../Bytes.js'
import type * as Errors from '../Errors.js'
import * as Hex from '../Hex.js'
/** @internal */
export const integerToAlphabet =
'123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
/** @internal */
export const alphabetToInteger = /* __PURE__ */ Object.freeze<
Record<string, bigint>
>({
1: 0n,
2: 1n,
3: 2n,
4: 3n,
5: 4n,
6: 5n,
7: 6n,
8: 7n,
9: 8n,
A: 9n,
B: 10n,
C: 11n,
D: 12n,
E: 13n,
F: 14n,
G: 15n,
H: 16n,
J: 17n,
K: 18n,
L: 19n,
M: 20n,
N: 21n,
P: 22n,
Q: 23n,
R: 24n,
S: 25n,
T: 26n,
U: 27n,
V: 28n,
W: 29n,
X: 30n,
Y: 31n,
Z: 32n,
a: 33n,
b: 34n,
c: 35n,
d: 36n,
e: 37n,
f: 38n,
g: 39n,
h: 40n,
i: 41n,
j: 42n,
k: 43n,
m: 44n,
n: 45n,
o: 46n,
p: 47n,
q: 48n,
r: 49n,
s: 50n,
t: 51n,
u: 52n,
v: 53n,
w: 54n,
x: 55n,
y: 56n,
z: 57n,
})
/** @internal */
export function from(value: Hex.Hex | Bytes.Bytes) {
let bytes = Bytes.from(value)
let integer = (() => {
let hex = value
if (value instanceof Uint8Array) hex = Hex.fromBytes(bytes)
return BigInt(hex as string)
})()
let result = ''
while (integer > 0n) {
const remainder = Number(integer % 58n)
integer = integer / 58n
result = integerToAlphabet[remainder] + result
}
while (bytes.length > 1 && bytes[0] === 0) {
result = '1' + result
bytes = bytes.slice(1)
}
return result
}
/** @internal */
export declare namespace from {
type ErrorType = Errors.GlobalErrorType
}
/** @internal */

152
node_modules/ox/core/internal/bytes.ts generated vendored Normal file
View File

@@ -0,0 +1,152 @@
import * as Bytes from '../Bytes.js'
import type * as Errors from '../Errors.js'
/** @internal */
export function assertSize(bytes: Bytes.Bytes, size_: number): void {
if (Bytes.size(bytes) > size_)
throw new Bytes.SizeOverflowError({
givenSize: Bytes.size(bytes),
maxSize: size_,
})
}
/** @internal */
export declare namespace assertSize {
type ErrorType =
| Bytes.size.ErrorType
| Bytes.SizeOverflowError
| Errors.GlobalErrorType
}
/** @internal */
export function assertStartOffset(
value: Bytes.Bytes,
start?: number | undefined,
) {
if (typeof start === 'number' && start > 0 && start > Bytes.size(value) - 1)
throw new Bytes.SliceOffsetOutOfBoundsError({
offset: start,
position: 'start',
size: Bytes.size(value),
})
}
export declare namespace assertStartOffset {
export type ErrorType =
| Bytes.SliceOffsetOutOfBoundsError
| Bytes.size.ErrorType
| Errors.GlobalErrorType
}
/** @internal */
export function assertEndOffset(
value: Bytes.Bytes,
start?: number | undefined,
end?: number | undefined,
) {
if (
typeof start === 'number' &&
typeof end === 'number' &&
Bytes.size(value) !== end - start
) {
throw new Bytes.SliceOffsetOutOfBoundsError({
offset: end,
position: 'end',
size: Bytes.size(value),
})
}
}
/** @internal */
export declare namespace assertEndOffset {
type ErrorType =
| Bytes.SliceOffsetOutOfBoundsError
| Bytes.size.ErrorType
| Errors.GlobalErrorType
}
/** @internal */
export const charCodeMap = {
zero: 48,
nine: 57,
A: 65,
F: 70,
a: 97,
f: 102,
} as const
/** @internal */
export function charCodeToBase16(char: number) {
if (char >= charCodeMap.zero && char <= charCodeMap.nine)
return char - charCodeMap.zero
if (char >= charCodeMap.A && char <= charCodeMap.F)
return char - (charCodeMap.A - 10)
if (char >= charCodeMap.a && char <= charCodeMap.f)
return char - (charCodeMap.a - 10)
return undefined
}
/** @internal */
export function pad(bytes: Bytes.Bytes, options: pad.Options = {}) {
const { dir, size = 32 } = options
if (size === 0) return bytes
if (bytes.length > size)
throw new Bytes.SizeExceedsPaddingSizeError({
size: bytes.length,
targetSize: size,
type: 'Bytes',
})
const paddedBytes = new Uint8Array(size)
for (let i = 0; i < size; i++) {
const padEnd = dir === 'right'
paddedBytes[padEnd ? i : size - i - 1] =
bytes[padEnd ? i : bytes.length - i - 1]!
}
return paddedBytes
}
/** @internal */
export declare namespace pad {
type Options = {
dir?: 'left' | 'right' | undefined
size?: number | undefined
}
type ReturnType = Bytes.Bytes
type ErrorType = Bytes.SizeExceedsPaddingSizeError | Errors.GlobalErrorType
}
/** @internal */
export function trim(
value: Bytes.Bytes,
options: trim.Options = {},
): trim.ReturnType {
const { dir = 'left' } = options
let data = value
let sliceLength = 0
for (let i = 0; i < data.length - 1; i++) {
if (data[dir === 'left' ? i : data.length - i - 1]!.toString() === '0')
sliceLength++
else break
}
data =
dir === 'left'
? data.slice(sliceLength)
: data.slice(0, data.length - sliceLength)
return data as trim.ReturnType
}
/** @internal */
export declare namespace trim {
type Options = {
dir?: 'left' | 'right' | undefined
}
type ReturnType = Bytes.Bytes
type ErrorType = Errors.GlobalErrorType
}

252
node_modules/ox/core/internal/cursor.ts generated vendored Normal file
View File

@@ -0,0 +1,252 @@
import type { Bytes } from '../Bytes.js'
import * as Errors from '../Errors.js'
/** @internal */
export type Cursor = {
bytes: Bytes
dataView: DataView
position: number
positionReadCount: Map<number, number>
recursiveReadCount: number
recursiveReadLimit: number
remaining: number
assertReadLimit(position?: number): void
assertPosition(position: number): void
decrementPosition(offset: number): void
getReadCount(position?: number): number
incrementPosition(offset: number): void
inspectByte(position?: number): Bytes[number]
inspectBytes(length: number, position?: number): Bytes
inspectUint8(position?: number): number
inspectUint16(position?: number): number
inspectUint24(position?: number): number
inspectUint32(position?: number): number
pushByte(byte: Bytes[number]): void
pushBytes(bytes: Bytes): void
pushUint8(value: number): void
pushUint16(value: number): void
pushUint24(value: number): void
pushUint32(value: number): void
readByte(): Bytes[number]
readBytes(length: number, size?: number): Bytes
readUint8(): number
readUint16(): number
readUint24(): number
readUint32(): number
setPosition(position: number): () => void
_touch(): void
}
const staticCursor: Cursor = /*#__PURE__*/ {
bytes: new Uint8Array(),
dataView: new DataView(new ArrayBuffer(0)),
position: 0,
positionReadCount: new Map(),
recursiveReadCount: 0,
recursiveReadLimit: Number.POSITIVE_INFINITY,
assertReadLimit() {
if (this.recursiveReadCount >= this.recursiveReadLimit)
throw new RecursiveReadLimitExceededError({
count: this.recursiveReadCount + 1,
limit: this.recursiveReadLimit,
})
},
assertPosition(position) {
if (position < 0 || position > this.bytes.length - 1)
throw new PositionOutOfBoundsError({
length: this.bytes.length,
position,
})
},
decrementPosition(offset) {
if (offset < 0) throw new NegativeOffsetError({ offset })
const position = this.position - offset
this.assertPosition(position)
this.position = position
},
getReadCount(position) {
return this.positionReadCount.get(position || this.position) || 0
},
incrementPosition(offset) {
if (offset < 0) throw new NegativeOffsetError({ offset })
const position = this.position + offset
this.assertPosition(position)
this.position = position
},
inspectByte(position_) {
const position = position_ ?? this.position
this.assertPosition(position)
return this.bytes[position]!
},
inspectBytes(length, position_) {
const position = position_ ?? this.position
this.assertPosition(position + length - 1)
return this.bytes.subarray(position, position + length)
},
inspectUint8(position_) {
const position = position_ ?? this.position
this.assertPosition(position)
return this.bytes[position]!
},
inspectUint16(position_) {
const position = position_ ?? this.position
this.assertPosition(position + 1)
return this.dataView.getUint16(position)
},
inspectUint24(position_) {
const position = position_ ?? this.position
this.assertPosition(position + 2)
return (
(this.dataView.getUint16(position) << 8) +
this.dataView.getUint8(position + 2)
)
},
inspectUint32(position_) {
const position = position_ ?? this.position
this.assertPosition(position + 3)
return this.dataView.getUint32(position)
},
pushByte(byte: Bytes[number]) {
this.assertPosition(this.position)
this.bytes[this.position] = byte
this.position++
},
pushBytes(bytes: Bytes) {
this.assertPosition(this.position + bytes.length - 1)
this.bytes.set(bytes, this.position)
this.position += bytes.length
},
pushUint8(value: number) {
this.assertPosition(this.position)
this.bytes[this.position] = value
this.position++
},
pushUint16(value: number) {
this.assertPosition(this.position + 1)
this.dataView.setUint16(this.position, value)
this.position += 2
},
pushUint24(value: number) {
this.assertPosition(this.position + 2)
this.dataView.setUint16(this.position, value >> 8)
this.dataView.setUint8(this.position + 2, value & ~4294967040)
this.position += 3
},
pushUint32(value: number) {
this.assertPosition(this.position + 3)
this.dataView.setUint32(this.position, value)
this.position += 4
},
readByte() {
this.assertReadLimit()
this._touch()
const value = this.inspectByte()
this.position++
return value
},
readBytes(length, size) {
this.assertReadLimit()
this._touch()
const value = this.inspectBytes(length)
this.position += size ?? length
return value
},
readUint8() {
this.assertReadLimit()
this._touch()
const value = this.inspectUint8()
this.position += 1
return value
},
readUint16() {
this.assertReadLimit()
this._touch()
const value = this.inspectUint16()
this.position += 2
return value
},
readUint24() {
this.assertReadLimit()
this._touch()
const value = this.inspectUint24()
this.position += 3
return value
},
readUint32() {
this.assertReadLimit()
this._touch()
const value = this.inspectUint32()
this.position += 4
return value
},
get remaining() {
return this.bytes.length - this.position
},
setPosition(position) {
const oldPosition = this.position
this.assertPosition(position)
this.position = position
return () => (this.position = oldPosition)
},
_touch() {
if (this.recursiveReadLimit === Number.POSITIVE_INFINITY) return
const count = this.getReadCount()
this.positionReadCount.set(this.position, count + 1)
if (count > 0) this.recursiveReadCount++
},
}
/** @internal */
export function create(
bytes: Bytes,
{ recursiveReadLimit = 8_192 }: create.Config = {},
): Cursor {
const cursor: Cursor = Object.create(staticCursor)
cursor.bytes = bytes
cursor.dataView = new DataView(
bytes.buffer,
bytes.byteOffset,
bytes.byteLength,
)
cursor.positionReadCount = new Map()
cursor.recursiveReadLimit = recursiveReadLimit
return cursor
}
/** @internal */
export declare namespace create {
type Config = { recursiveReadLimit?: number | undefined }
type ErrorType = Errors.GlobalErrorType
}
/** @internal */
export class NegativeOffsetError extends Errors.BaseError {
override readonly name = 'Cursor.NegativeOffsetError'
constructor({ offset }: { offset: number }) {
super(`Offset \`${offset}\` cannot be negative.`)
}
}
/** @internal */
export class PositionOutOfBoundsError extends Errors.BaseError {
override readonly name = 'Cursor.PositionOutOfBoundsError'
constructor({ length, position }: { length: number; position: number }) {
super(
`Position \`${position}\` is out of bounds (\`0 < position < ${length}\`).`,
)
}
}
/** @internal */
export class RecursiveReadLimitExceededError extends Errors.BaseError {
override readonly name = 'Cursor.RecursiveReadLimitExceededError'
constructor({ count, limit }: { count: number; limit: number }) {
super(
`Recursive read limit of \`${limit}\` exceeded (recursive read count: \`${count}\`).`,
)
}
}

64
node_modules/ox/core/internal/ens.ts generated vendored Normal file
View File

@@ -0,0 +1,64 @@
import { Bytes } from '../../index.js'
import * as Ens from '../Ens.js'
import type * as Errors from '../Errors.js'
import * as Hex from '../Hex.js'
/**
* @internal
* Encodes a [DNS packet](https://docs.ens.domains/resolution/names#dns) into a ByteArray containing a UDP payload.
*/
export function packetToBytes(packet: string): Bytes.Bytes {
// strip leading and trailing `.`
const value = packet.replace(/^\.|\.$/gm, '')
if (value.length === 0) return new Uint8Array(1)
const bytes = new Uint8Array(Bytes.fromString(value).byteLength + 2)
let offset = 0
const list = value.split('.')
for (let i = 0; i < list.length; i++) {
let encoded = Bytes.fromString(list[i]!)
// if the length is > 255, make the encoded label value a labelhash
// this is compatible with the universal resolver
if (encoded.byteLength > 255)
encoded = Bytes.fromString(wrapLabelhash(Ens.labelhash(list[i]!)))
bytes[offset] = encoded.length
bytes.set(encoded, offset + 1)
offset += encoded.length + 1
}
if (bytes.byteLength !== offset + 1) return bytes.slice(0, offset + 1)
return bytes
}
export declare namespace packetToBytes {
type ErrorType =
| wrapLabelhash.ErrorType
| Ens.labelhash.ErrorType
| Bytes.fromString.ErrorType
| Errors.GlobalErrorType
}
/** @internal */
export function wrapLabelhash(hash: Hex.Hex): `[${string}]` {
return `[${hash.slice(2)}]`
}
export declare namespace wrapLabelhash {
type ErrorType = Errors.GlobalErrorType
}
/** @internal */
export function unwrapLabelhash(label: string): Hex.Hex | null {
if (label.length !== 66) return null
if (label.indexOf('[') !== 0) return null
if (label.indexOf(']') !== 65) return null
const hash = `0x${label.slice(1, 65)}`
if (!Hex.validate(hash, { strict: true })) return null
return hash
}
export declare namespace unwrapLabelhash {
type ErrorType = Hex.validate.ErrorType | Errors.GlobalErrorType
}

6
node_modules/ox/core/internal/entropy.ts generated vendored Normal file
View File

@@ -0,0 +1,6 @@
export let extraEntropy = false
/** @internal */
export function setExtraEntropy(entropy: boolean) {
extraEntropy = entropy
}

26
node_modules/ox/core/internal/errors.ts generated vendored Normal file
View File

@@ -0,0 +1,26 @@
import { version } from '../version.js'
/** @internal */
export function getUrl(url: string) {
return url
}
/** @internal */
export function getVersion() {
return version
}
/** @internal */
export function prettyPrint(args: unknown) {
if (!args) return ''
const entries = Object.entries(args)
.map(([key, value]) => {
if (value === undefined || value === false) return null
return [key, value]
})
.filter(Boolean) as [string, string][]
const maxLength = entries.reduce((acc, [key]) => Math.max(acc, key.length), 0)
return entries
.map(([key, value]) => ` ${`${key}:`.padEnd(maxLength + 1)} ${value}`)
.join('\n')
}

25
node_modules/ox/core/internal/hdKey.ts generated vendored Normal file
View File

@@ -0,0 +1,25 @@
import type { HDKey } from '@scure/bip32'
import type * as Errors from '../Errors.js'
import type * as HdKey from '../HdKey.js'
import * as Hex from '../Hex.js'
import * as Secp256k1 from '../Secp256k1.js'
/** @internal */
export function fromScure(key: HDKey): HdKey.HdKey {
return {
derive: (path) => fromScure(key.derive(path)),
depth: key.depth,
identifier: Hex.fromBytes(key.identifier!),
index: key.index,
privateKey: Hex.fromBytes(key.privateKey!),
privateExtendedKey: key.privateExtendedKey,
publicKey: Secp256k1.getPublicKey({ privateKey: key.privateKey! }),
publicExtendedKey: key.publicExtendedKey,
versions: key.versions,
}
}
/** @internal */
export declare namespace fromScure {
type ErrorType = Errors.GlobalErrorType
}

124
node_modules/ox/core/internal/hex.ts generated vendored Normal file
View File

@@ -0,0 +1,124 @@
import type * as Errors from '../Errors.js'
import * as Hex from '../Hex.js'
/** @internal */
export function assertSize(hex: Hex.Hex, size_: number): void {
if (Hex.size(hex) > size_)
throw new Hex.SizeOverflowError({
givenSize: Hex.size(hex),
maxSize: size_,
})
}
/** @internal */
export declare namespace assertSize {
type ErrorType =
| Hex.size.ErrorType
| Hex.SizeOverflowError
| Errors.GlobalErrorType
}
/** @internal */
export function assertStartOffset(value: Hex.Hex, start?: number | undefined) {
if (typeof start === 'number' && start > 0 && start > Hex.size(value) - 1)
throw new Hex.SliceOffsetOutOfBoundsError({
offset: start,
position: 'start',
size: Hex.size(value),
})
}
export declare namespace assertStartOffset {
type ErrorType =
| Hex.SliceOffsetOutOfBoundsError
| Hex.size.ErrorType
| Errors.GlobalErrorType
}
/** @internal */
export function assertEndOffset(
value: Hex.Hex,
start?: number | undefined,
end?: number | undefined,
) {
if (
typeof start === 'number' &&
typeof end === 'number' &&
Hex.size(value) !== end - start
) {
throw new Hex.SliceOffsetOutOfBoundsError({
offset: end,
position: 'end',
size: Hex.size(value),
})
}
}
export declare namespace assertEndOffset {
type ErrorType =
| Hex.SliceOffsetOutOfBoundsError
| Hex.size.ErrorType
| Errors.GlobalErrorType
}
/** @internal */
export function pad(hex_: Hex.Hex, options: pad.Options = {}) {
const { dir, size = 32 } = options
if (size === 0) return hex_
const hex = hex_.replace('0x', '')
if (hex.length > size * 2)
throw new Hex.SizeExceedsPaddingSizeError({
size: Math.ceil(hex.length / 2),
targetSize: size,
type: 'Hex',
})
return `0x${hex[dir === 'right' ? 'padEnd' : 'padStart'](size * 2, '0')}` as Hex.Hex
}
/** @internal */
export declare namespace pad {
type Options = {
dir?: 'left' | 'right' | undefined
size?: number | undefined
}
type ErrorType = Hex.SizeExceedsPaddingSizeError | Errors.GlobalErrorType
}
/** @internal */
export function trim(
value: Hex.Hex,
options: trim.Options = {},
): trim.ReturnType {
const { dir = 'left' } = options
let data = value.replace('0x', '')
let sliceLength = 0
for (let i = 0; i < data.length - 1; i++) {
if (data[dir === 'left' ? i : data.length - i - 1]!.toString() === '0')
sliceLength++
else break
}
data =
dir === 'left'
? data.slice(sliceLength)
: data.slice(0, data.length - sliceLength)
if (data === '0') return '0x'
if (dir === 'right' && data.length % 2 === 1) return `0x${data}0`
return `0x${data}` as trim.ReturnType
}
/** @internal */
export declare namespace trim {
type Options = {
dir?: 'left' | 'right' | undefined
}
type ReturnType = Hex.Hex
type ErrorType = Errors.GlobalErrorType
}

34
node_modules/ox/core/internal/lru.ts generated vendored Normal file
View File

@@ -0,0 +1,34 @@
/**
* @internal
*
* Map with a LRU (Least recently used) policy.
* @see https://en.wikipedia.org/wiki/Cache_replacement_policies#LRU
*/
export class LruMap<value = unknown> extends Map<string, value> {
maxSize: number
constructor(size: number) {
super()
this.maxSize = size
}
override get(key: string) {
const value = super.get(key)
if (super.has(key) && value !== undefined) {
this.delete(key)
super.set(key, value)
}
return value
}
override set(key: string, value: value) {
super.set(key, value)
if (this.maxSize && this.size > this.maxSize) {
const firstKey = this.keys().next().value
if (firstKey) this.delete(firstKey)
}
return this
}
}

10
node_modules/ox/core/internal/mnemonic/wordlists.ts generated vendored Normal file
View File

@@ -0,0 +1,10 @@
export { wordlist as czech } from '@scure/bip39/wordlists/czech'
export { wordlist as english } from '@scure/bip39/wordlists/english'
export { wordlist as french } from '@scure/bip39/wordlists/french'
export { wordlist as italian } from '@scure/bip39/wordlists/italian'
export { wordlist as japanese } from '@scure/bip39/wordlists/japanese'
export { wordlist as korean } from '@scure/bip39/wordlists/korean'
export { wordlist as portuguese } from '@scure/bip39/wordlists/portuguese'
export { wordlist as simplifiedChinese } from '@scure/bip39/wordlists/simplified-chinese'
export { wordlist as spanish } from '@scure/bip39/wordlists/spanish'
export { wordlist as traditionalChinese } from '@scure/bip39/wordlists/traditional-chinese'

63
node_modules/ox/core/internal/promise.ts generated vendored Normal file
View File

@@ -0,0 +1,63 @@
import * as Errors from '../Errors.js'
/** @internal */
export function withTimeout<data>(
fn: withTimeout.Fn<data>,
options: withTimeout.Options,
): Promise<data> {
const { errorInstance = new TimeoutError(), timeout, signal } = options
return new Promise((resolve, reject) => {
;(async () => {
let timeoutId: any
try {
const controller = new AbortController()
if (timeout > 0)
timeoutId = setTimeout(() => {
if (signal) {
controller.abort()
} else {
reject(errorInstance)
}
}, timeout) as any
resolve(await fn({ signal: controller.signal }))
} catch (err) {
if ((err as Error)?.name === 'AbortError') reject(errorInstance)
reject(err)
} finally {
clearTimeout(timeoutId)
}
})()
})
}
/** @internal */
export declare namespace withTimeout {
type Fn<data> = ({
signal,
}: { signal: AbortController['signal'] | null }) => Promise<data>
type Options = {
// The error instance to throw when the timeout is reached.
errorInstance?: Error | undefined
// The timeout (in ms).
timeout: number
// Whether or not the timeout should use an abort signal.
signal?: boolean | undefined
}
type ErrorType = TimeoutError | Errors.GlobalErrorType
}
/** @internal */
/**
* Thrown when an operation times out.
* @internal
*/
export class TimeoutError extends Errors.BaseError {
override readonly name = 'Promise.TimeoutError'
constructor() {
super('Operation timed out.')
}
}

15
node_modules/ox/core/internal/register.ts generated vendored Normal file
View File

@@ -0,0 +1,15 @@
import type * as RpcSchema from '../RpcSchema.js'
// biome-ignore lint/suspicious/noEmptyInterface:
export interface Register {}
export type ResolvedRegister = {
RpcSchema: Register extends { RpcSchema: infer schema }
? schema
: DefaultRegister['RpcSchema']
}
/** @internal */
export type DefaultRegister = {
RpcSchema: RpcSchema.Eth | RpcSchema.Wallet
}

20
node_modules/ox/core/internal/rpcSchema.ts generated vendored Normal file
View File

@@ -0,0 +1,20 @@
import type { Generic, MethodNameGeneric } from '../RpcSchema.js'
import type { Compute, IsNarrowable } from './types.js'
/** @internal */
export type ExtractRequestOpaque<
schema extends Generic,
methodName extends MethodNameGeneric<schema> = MethodNameGeneric<schema>,
> = Compute<
Omit<
{
method: methodName | schema['Request']['method']
params?: unknown
} & (methodName extends schema['Request']['method']
? IsNarrowable<schema, Generic> extends true
? Extract<schema, { Request: { method: methodName } }>['Request']
: {}
: {}),
''
>
>

802
node_modules/ox/core/internal/rpcSchemas/eth.ts generated vendored Normal file
View File

@@ -0,0 +1,802 @@
import type * as AccountProof from '../../AccountProof.js'
import type * as Address from '../../Address.js'
import type * as Block from '../../Block.js'
import type * as BlockOverrides from '../../BlockOverrides.js'
import type * as Fee from '../../Fee.js'
import type * as Filter from '../../Filter.js'
import type * as Hex from '../../Hex.js'
import type * as Log from '../../Log.js'
import type * as RpcSchema from '../../RpcSchema.js'
import type * as StateOverrides from '../../StateOverrides.js'
import type * as Transaction from '../../Transaction.js'
import type * as TransactionReceipt from '../../TransactionReceipt.js'
import type * as TransactionRequest from '../../TransactionRequest.js'
/**
* Union of all JSON-RPC Methods for the `eth_` namespace.
*
* @example
* ```ts twoslash
* import { RpcSchema } from 'ox'
*
* type Schema = RpcSchema.Eth
* // ^?
*
*
*
*
*
*
*
*
*
*
*
*
*
* ```
*/
export type Eth = RpcSchema.From<
/**
* Returns a list of addresses owned by this client
*
* @example
* ```
* request({ method: 'eth_accounts' })
* // => ['0x0fB69...']
* ```
*/
| {
Request: {
method: 'eth_accounts'
params?: undefined
}
ReturnType: readonly Address.Address[]
}
/**
* Returns the base fee per blob gas in wei.
*
* @example
* ```
* request({ method: 'eth_blobBaseFee' })
* // '0x09184e72a000'
* ```
*/
| {
Request: {
method: 'eth_blobBaseFee'
params?: undefined
}
ReturnType: Hex.Hex
}
/**
* Returns the number of the most recent block seen by this client
*
* @example
* ```
* request({ method: 'eth_blockNumber' })
* // '0x1b4'
* ```
*/
| {
Request: {
method: 'eth_blockNumber'
params?: undefined
}
ReturnType: Hex.Hex
}
/**
* Executes a new message call immediately without submitting a transaction to the network
*
* ```
* request({ method: 'eth_call', params: [{ to: '0x...', data: '0x...' }] })
* // '0x...'
* ```
*/
| {
Request: {
method: 'eth_call'
params:
| [transaction: TransactionRequest.Rpc]
| [
transaction: TransactionRequest.Rpc,
block:
| Block.Number<Hex.Hex>
| Block.Tag
| Block.Hash
| Block.Identifier,
]
| [
transaction: TransactionRequest.Rpc,
block:
| Block.Number<Hex.Hex>
| Block.Tag
| Block.Hash
| Block.Identifier,
stateOverrides: StateOverrides.Rpc,
]
}
ReturnType: Hex.Hex
}
/**
* Returns the chain ID associated with the current network
*
* @example
* ```
* request({ method: 'eth_chainId' })
* // => '0x1'
* ```
*/
| {
Request: {
method: 'eth_chainId'
params?: undefined
}
ReturnType: Hex.Hex
}
/**
* Returns the client coinbase address.
*
* @example
* ```
* request({ method: 'eth_coinbase' })
* // '0x...'
* ```
*/
| {
Request: {
method: 'eth_coinbase'
params?: undefined
}
ReturnType: Address.Address
}
/**
* Estimates the gas necessary to complete a transaction without submitting it to the network
*
* @example
* ```
* request({
* method: 'eth_estimateGas',
* params: [{ from: '0x...', to: '0x...', value: '0x...' }]
* })
* // '0x5208'
* ```
*/
| {
Request: {
method: 'eth_estimateGas'
params:
| [transaction: TransactionRequest.Rpc]
| [
transaction: TransactionRequest.Rpc,
block:
| Block.Number<Hex.Hex>
| Block.Tag
| Block.Hash
| Block.Identifier,
]
| [
transaction: TransactionRequest.Rpc,
block:
| Block.Number<Hex.Hex>
| Block.Tag
| Block.Hash
| Block.Identifier,
stateOverrides: StateOverrides.Rpc,
]
}
ReturnType: Hex.Hex
}
/**
* Returns a collection of historical gas information
*
* ```
* request({
* method: 'eth_feeHistory',
* params: ['4', 'latest', ['25', '75']]
* })
* // {
* // oldestBlock: '0x1',
* // baseFeePerGas: ['0x1', '0x2', '0x3', '0x4'],
* // gasUsedRatio: ['0x1', '0x2', '0x3', '0x4'],
* // reward: [['0x1', '0x2'], ['0x3', '0x4'], ['0x5', '0x6'], ['0x7', '0x8']]
* // }
* ```
* */
| {
Request: {
method: 'eth_feeHistory'
params: [
/** Number of blocks in the requested range. Between 1 and 1024 blocks can be requested in a single query. Less than requested may be returned if not all blocks are available. */
blockCount: Hex.Hex,
/** Highest number block of the requested range. */
newestBlock: Block.Number<Hex.Hex> | Block.Tag,
/** A monotonically increasing list of percentile values to sample from each block's effective priority fees per gas in ascending order, weighted by gas used. */
rewardPercentiles: number[] | undefined,
]
}
ReturnType: Fee.FeeHistoryRpc
}
/**
* Returns the current price of gas expressed in wei
*
* ```
* request({ method: 'eth_gasPrice' })
* // '0x09184e72a000'
* ```
*/
| {
Request: {
method: 'eth_gasPrice'
params?: undefined
}
ReturnType: Hex.Hex
}
/**
* Returns the balance of an address in wei
*
* @example
* ```
* request({ method: 'eth_getBalance', params: ['0x...', 'latest'] })
* // => '0x12a05...'
* ```
*/
| {
Request: {
method: 'eth_getBalance'
params: [
address: Address.Address,
block:
| Block.Number<Hex.Hex>
| Block.Tag
| Block.Hash
| Block.Identifier,
]
}
ReturnType: Hex.Hex
}
/**
* Returns information about a block specified by hash
*
* ```
* request({ method: 'eth_getBlockByHash', params: ['0x...', true] })
* // {
* // number: '0x1b4',
* // hash: '0x...',
* // parentHash: '0x...',
* // ...
* // }
* ```
*/
| {
Request: {
method: 'eth_getBlockByHash'
params: [
/** hash of a block */
hash: Hex.Hex,
/** true will pull full transaction objects, false will pull transaction hashes */
includeTransactionObjects: boolean,
]
}
ReturnType: Block.Rpc | null
}
/**
* Returns information about a block specified by number
*
* @example
* ```
* request({ method: 'eth_getBlockByNumber', params: ['0x1b4', true] })
* // {
* // number: '0x1b4',
* // hash: '0x...',
* // parentHash: '0x...',
* // ...
* // }
* ```
*/
| {
Request: {
method: 'eth_getBlockByNumber'
params: [
/** block number, or one of "latest", "safe", "finalized", "earliest" or "pending" */
block: Block.Number<Hex.Hex> | Block.Tag,
/** true will pull full transaction objects, false will pull transaction hashes */
includeTransactionObjects: boolean,
]
}
ReturnType: Block.Rpc | null
}
/**
* Returns the number of transactions in a block specified by block hash
*
* ```
* request({ method: 'eth_getBlockTransactionCountByHash', params: ['0x...'] })
* // '0x1'
* ```
*/
| {
Request: {
method: 'eth_getBlockTransactionCountByHash'
params: [hash: Hex.Hex]
}
ReturnType: Hex.Hex
}
/**
* Returns the number of transactions in a block specified by block number
*
* ```
* request({ method: 'eth_getBlockTransactionCountByNumber', params: ['0x1b4'] })
* // '0x1'
* ```
*/
| {
Request: {
method: 'eth_getBlockTransactionCountByNumber'
params: [block: Block.Number<Hex.Hex> | Block.Tag]
}
ReturnType: Hex.Hex
}
/**
* Returns the contract code stored at a given address
*
* @example
* ```
* request({ method: 'eth_getCode', params: ['0x...', 'latest'] })
* // '0x...'
* ```
*/
| {
Request: {
method: 'eth_getCode'
params: [
address: Address.Address,
block:
| Block.Number<Hex.Hex>
| Block.Tag
| Block.Hash
| Block.Identifier,
]
}
ReturnType: Hex.Hex
}
/**
* Returns a list of all logs based on filter ID since the last log retrieval
*
* @example
* ```
* request({ method: 'eth_getFilterChanges', params: ['0x...'] })
* // => [{ ... }| { ... }]
* ```
*/
| {
Request: {
method: 'eth_getFilterChanges'
params: [filterId: Hex.Hex]
}
ReturnType: readonly Log.Rpc[] | readonly Hex.Hex[]
}
/**
* Returns a list of all logs based on filter ID
*
* @example
* ```
* request({ method: 'eth_getFilterLogs', params: ['0x...'] })
* // => [{ ... }| { ... }]
* ```
*/
| {
Request: {
method: 'eth_getFilterLogs'
params: [filterId: Hex.Hex]
}
ReturnType: readonly Log.Rpc[]
}
/**
* Returns a list of all logs based on a filter object
*
* @example
* ```
* request({ method: 'eth_getLogs', params: [{ fromBlock: '0x...', toBlock: '0x...', address: '0x...', topics: ['0x...'] }] })
* // => [{ ... }| { ... }]
* ```
*/
| {
Request: {
method: 'eth_getLogs'
params: [filter: Filter.Rpc]
}
ReturnType: readonly Log.Rpc[]
}
/**
* Returns the account and storage values of the specified account including the Merkle-proof.
*
* @example
* ```
* request({ method: 'eth_getProof', params: ['0x...', ['0x...'], 'latest'] })
* // {
* // ...
* // }
* ```
*/
| {
Request: {
method: 'eth_getProof'
params: [
/** Address of the account. */
address: Address.Address,
/** An array of storage-keys that should be proofed and included. */
storageKeys: Hex.Hex[],
/** Block identifier to pull the proof from. */
block:
| Block.Number<Hex.Hex>
| Block.Tag
| Block.Hash
| Block.Identifier,
]
}
ReturnType: AccountProof.Rpc
}
/**
* Returns the value from a storage position at an address
*
* @example
* ```
* request({ method: 'eth_getStorageAt', params: ['0x...', '0x...', 'latest'] })
* // '0x...'
* ```
*/
| {
Request: {
method: 'eth_getStorageAt'
params: [
address: Address.Address,
index: Hex.Hex,
block:
| Block.Number<Hex.Hex>
| Block.Tag
| Block.Hash
| Block.Identifier,
]
}
ReturnType: Hex.Hex
}
/**
* Returns information about a transaction specified by block hash and transaction index
*
* @example
* ```
* request({ method: 'eth_getTransactionByBlockHashAndIndex', params: ['0x...', '0x...'] })
* // { ... }
* ```
*/
| {
Request: {
method: 'eth_getTransactionByBlockHashAndIndex'
params: [hash: Hex.Hex, index: Hex.Hex]
}
ReturnType: Transaction.Rpc | null
}
/**
* Returns information about a transaction specified by block number and transaction index
*
* @example
* ```
* request({ method: 'eth_getTransactionByBlockNumberAndIndex', params: ['0x...', '0x...'] })
* // { ... }
* ```
*/
| {
Request: {
method: 'eth_getTransactionByBlockNumberAndIndex'
params: [block: Block.Number<Hex.Hex> | Block.Tag, index: Hex.Hex]
}
ReturnType: Transaction.Rpc | null
}
/**
* Returns information about a transaction specified by hash
*
* @example
* ```
* request({ method: 'eth_getTransactionByHash', params: ['0x...'] })
* // { ... }
* ```
*/
| {
Request: {
method: 'eth_getTransactionByHash'
params: [hash: Hex.Hex]
}
ReturnType: Transaction.Rpc | null
}
/**
* Returns the number of transactions sent from an address
*
* @example
* ```
* request({ method: 'eth_getTransactionCount', params: ['0x...', 'latest'] })
* // '0x1'
* ```
*/
| {
Request: {
method: 'eth_getTransactionCount'
params: [
address: Address.Address,
block:
| Block.Number<Hex.Hex>
| Block.Tag
| Block.Hash
| Block.Identifier,
]
}
ReturnType: Hex.Hex
}
/**
* Returns the receipt of a transaction specified by hash
*
* @example
* ```
* request({ method: 'eth_getTransactionReceipt', params: ['0x...'] })
* // { ... }
* ```
*/
| {
Request: {
method: 'eth_getTransactionReceipt'
params: [hash: Hex.Hex]
}
ReturnType: TransactionReceipt.Rpc | null
}
/**
* Returns the number of uncles in a block specified by block hash
*
* @example
* ```
* request({ method: 'eth_getUncleCountByBlockHash', params: ['0x...'] })
* // => '0x1'
* ```
*/
| {
Request: {
method: 'eth_getUncleCountByBlockHash'
params: [hash: Hex.Hex]
}
ReturnType: Hex.Hex
}
/**
* Returns the number of uncles in a block specified by block number
*
* @example
* ```
* request({ method: 'eth_getUncleCountByBlockNumber', params: ['0x...'] })
* // '0x1'
* ```
*/
| {
Request: {
method: 'eth_getUncleCountByBlockNumber'
params: [block: Block.Number<Hex.Hex> | Block.Tag]
}
ReturnType: Hex.Hex
}
/**
* Returns the current maxPriorityFeePerGas in wei.
*
* @example
* ```
* request({ method: 'eth_maxPriorityFeePerGas' })
* // => '0x5f5e100'
* ```
*/
| {
Request: {
method: 'eth_maxPriorityFeePerGas'
params?: undefined
}
ReturnType: Hex.Hex
}
/**
* Creates a filter to listen for new blocks that can be used with `eth_getFilterChanges`
*
* @example
* ```
* request({ method: 'eth_newBlockFilter' })
* // => '0x1'
* ```
*/
| {
Request: {
method: 'eth_newBlockFilter'
params?: undefined
}
ReturnType: Hex.Hex
}
/**
* Creates a filter to listen for specific state changes that can then be used with `eth_getFilterChanges`
*
* @example
* ```
* request({ method: 'eth_newFilter', params: [{ fromBlock: '0x...', toBlock: '0x...', address: '0x...', topics: ['0x...'] }] })
* // => '0x1'
* ```
*/
| {
Request: {
method: 'eth_newFilter'
params: [filter: Filter.Rpc]
}
ReturnType: Hex.Hex
}
/**
* Creates a filter to listen for new pending transactions that can be used with `eth_getFilterChanges`
*
* @example
* ```
* request({ method: 'eth_newPendingTransactionFilter' })
* // '0x1'
* ```
*/
| {
Request: {
method: 'eth_newPendingTransactionFilter'
params?: undefined
}
ReturnType: Hex.Hex
}
/**
* Returns the current Ethereum protocol version
*
* @example
* ```
* request({ method: 'eth_protocolVersion' })
* // '54'
* ```
*/
| {
Request: {
method: 'eth_protocolVersion'
params?: undefined
}
ReturnType: string
}
/**
* Requests that the user provides an Ethereum address to be identified by. Typically causes a browser extension popup to appear.
*
* @example
* ```
* request({ method: 'eth_requestAccounts' })
* // => ['0x...', '0x...']
* ```
*/
| {
Request: {
method: 'eth_requestAccounts'
params?: undefined
}
ReturnType: readonly Address.Address[]
}
/**
* Sends a **signed** transaction to the network
*
* @example
* ```
* request({ method: 'eth_sendRawTransaction', params: ['0x...'] })
* // => '0x...'
* ```
*/
| {
Request: {
method: 'eth_sendRawTransaction'
params: [serializedTransaction: Hex.Hex]
}
ReturnType: Hex.Hex
}
/**
* Creates, signs, and sends a new transaction to the network
*
* @example
* ```
* request({ method: 'eth_sendTransaction', params: [{ from: '0x...', to: '0x...', value: '0x...' }] })
* // '0x...'
* ```
*/
| {
Request: {
method: 'eth_sendTransaction'
params: [transaction: TransactionRequest.Rpc]
}
ReturnType: Hex.Hex
}
| {
Request: {
method: 'eth_simulateV1'
params: [
{
blockStateCalls: readonly {
blockOverrides?: BlockOverrides.Rpc | undefined
calls?: readonly TransactionRequest.Rpc[] | undefined
stateOverrides?: StateOverrides.Rpc | undefined
}[]
returnFullTransactions?: boolean | undefined
traceTransfers?: boolean | undefined
validation?: boolean | undefined
},
block:
| Block.Number<Hex.Hex>
| Block.Tag
| Block.Hash
| Block.Identifier,
]
}
ReturnType: readonly (Block.Rpc & {
calls?:
| readonly {
error?:
| {
data?: Hex.Hex | undefined
code: number
message: string
}
| undefined
logs?: readonly Log.Rpc[] | undefined
gasUsed: Hex.Hex
returnData: Hex.Hex
status: Hex.Hex
}[]
| undefined
})[]
}
/**
* Signs a transaction that can be submitted to the network at a later time using with `eth_sendRawTransaction`
*
* @example
* ```
* request({ method: 'eth_signTransaction', params: [{ from: '0x...', to: '0x...', value: '0x...' }] })
* // '0x...'
* ```
*/
| {
Request: {
method: 'eth_signTransaction'
params: [request: TransactionRequest.Rpc]
}
ReturnType: Hex.Hex
}
/**
* Calculates an Ethereum-specific signature in the form of `keccak256("\x19Ethereum Signed Message:\n" + len(message) + message))`
*
* @example
* ```
* request({ method: 'eth_signTypedData_v4', params: [{ from: '0x...', data: [{ type: 'string', name: 'message', value: 'hello world' }] }] })
* // '0x...'
* ```
*/
| {
Request: {
method: 'eth_signTypedData_v4'
params: [
/** Address to use for signing */
address: Address.Address,
/** Message to sign containing type information, a domain separator, and data */
message: string,
]
}
ReturnType: Hex.Hex
}
/**
* Destroys a filter based on filter ID
*
* @example
* ```
* request({ method: 'eth_uninstallFilter', params: ['0x1'] })
* // true
* ```
*/
| {
Request: {
method: 'eth_uninstallFilter'
params: [filterId: Hex.Hex]
}
ReturnType: boolean
}
>

428
node_modules/ox/core/internal/rpcSchemas/wallet.ts generated vendored Normal file
View File

@@ -0,0 +1,428 @@
import type * as Address from '../../Address.js'
import type * as Hex from '../../Hex.js'
import type * as RpcSchema from '../../RpcSchema.js'
import type * as TransactionRequest from '../../TransactionRequest.js'
import type { Compute } from '../types.js'
/**
* Union of all JSON-RPC Methods for the `wallet_` namespace.
*
* @example
* ```ts twoslash
* import { RpcSchema } from 'ox'
*
* type Schema = RpcSchema.Wallet
* // ^?
*
*
*
*
*
*
*
*
*
*
*
* ```
*/
export type Wallet = RpcSchema.From<
/**
* Requests that the user provides an Ethereum address to be identified by.
*
* @see {@link https://eips.ethereum.org/EIPS/eip-1102}
*/
| {
Request: {
method: 'eth_requestAccounts'
params?: undefined
}
ReturnType: readonly Address.Address[]
}
/**
* Sends a **signed** transaction to the network
*
* @example
* ```
* request({ method: 'eth_sendRawTransaction', params: ['0x...'] })
* // => '0x...'
* ```
*/
| {
Request: {
method: 'eth_sendRawTransaction'
params: [serializedTransaction: Hex.Hex]
}
ReturnType: Hex.Hex
}
/**
* Creates, signs, and sends a new transaction to the network
*
* @example
* ```
* request({ method: 'eth_sendTransaction', params: [{ from: '0x...', to: '0x...', value: '0x...' }] })
* // '0x...'
* ```
*/
| {
Request: {
method: 'eth_sendTransaction'
params: [transaction: TransactionRequest.Rpc]
}
ReturnType: Hex.Hex
}
/**
* Signs a transaction that can be submitted to the network at a later time using with `eth_sendRawTransaction`
*
* @example
* ```
* request({ method: 'eth_signTransaction', params: [{ from: '0x...', to: '0x...', value: '0x...' }] })
* // '0x...'
* ```
*/
| {
Request: {
method: 'eth_signTransaction'
params: [request: TransactionRequest.Rpc]
}
ReturnType: Hex.Hex
}
/**
* Calculates an Ethereum-specific signature in the form of `keccak256("\x19Ethereum Signed Message:\n" + len(message) + message))`
*
* @example
* ```
* request({ method: 'eth_signTypedData_v4', params: [{ from: '0x...', data: [{ type: 'string', name: 'message', value: 'hello world' }] }] })
* // '0x...'
* ```
*/
| {
Request: {
method: 'eth_signTypedData_v4'
params: [
/** Address to use for signing */
address: Address.Address,
/** Message to sign containing type information, a domain separator, and data */
message: string,
]
}
ReturnType: Hex.Hex
}
/**
* Calculates an Ethereum-specific signature in the form of `keccak256("\x19Ethereum Signed Message:\n" + len(message) + message))`
*
* @see {@link https://eips.ethereum.org/EIPS/eip-1474}
*/
| {
Request: {
method: 'personal_sign'
params: [
/** Data to sign */
data: Hex.Hex,
/** Address to use for signing */
address: Address.Address,
]
}
ReturnType: Hex.Hex
}
/**
* Add an Ethereum chain to the wallet.
*
* @see {@link https://eips.ethereum.org/EIPS/eip-3085}
*/
| {
Request: {
method: 'wallet_addEthereumChain'
params: [chain: Compute<WalletAddEthereumChainParameters>]
}
ReturnType: null
}
/**
* Returns the status of a call batch that was sent via `wallet_sendCalls`.
*
* @see {@link https://eips.ethereum.org/EIPS/eip-5792}
*/
| {
Request: {
method: 'wallet_getCallsStatus'
params?: [string]
}
ReturnType: Compute<WalletGetCallsStatusReturnType>
}
/**
* Gets the connected wallet's capabilities.
*
* @see {@link https://eips.ethereum.org/EIPS/eip-5792}
*/
| {
Request: {
method: 'wallet_getCapabilities'
params?: [Address.Address]
}
ReturnType: Compute<WalletCapabilitiesMap>
}
/**
* Gets the wallets current permissions.
*
* @see {@link https://eips.ethereum.org/EIPS/eip-2255}
*/
| {
Request: {
method: 'wallet_getPermissions'
params?: undefined
}
ReturnType: readonly Compute<WalletPermission>[]
}
/**
* Requests permissions from a wallet.
*
* @see {@link https://eips.ethereum.org/EIPS/eip-7715}
*/
| {
Request: {
method: 'wallet_grantPermissions'
params?: [WalletGrantPermissionsParameters]
}
ReturnType: Compute<WalletGrantPermissionsReturnType>
}
/**
* Requests the given permissions from the user.
*
* @see {@link https://eips.ethereum.org/EIPS/eip-2255}
*/
| {
Request: {
method: 'wallet_requestPermissions'
params: [permissions: { eth_accounts: Record<string, any> }]
}
ReturnType: readonly Compute<WalletPermission>[]
}
/**
* Revokes the given permissions from the user.
*
* @see {@link https://github.com/MetaMask/metamask-improvement-proposals/blob/main/MIPs/mip-2.md}
*/
| {
Request: {
method: 'wallet_revokePermissions'
params: [permissions: { eth_accounts: Record<string, any> }]
}
ReturnType: null
}
/**
* Requests the connected wallet to send a batch of calls.
*
* @see {@link https://eips.ethereum.org/EIPS/eip-5792}
*/
| {
Request: {
method: 'wallet_sendCalls'
params: Compute<WalletSendCallsParameters>
}
ReturnType: string
}
/**
* Requests for the wallet to show information about a call batch
* that was sent via `wallet_sendCalls`.
*
* @see {@link https://eips.ethereum.org/EIPS/eip-5792}
*/
| {
Request: {
method: 'wallet_showCallsStatus'
params: [string]
}
ReturnType: undefined
}
/**
* Switch the wallet to the given Ethereum chain.
*
* @see {@link https://eips.ethereum.org/EIPS/eip-3326}
*/
| {
Request: {
method: 'wallet_switchEthereumChain'
params: [chain: { chainId: string }]
}
ReturnType: null
}
/**
* Requests that the user tracks the token in their wallet. Returns a boolean indicating if the token was successfully added.
*
* @see {@link https://eips.ethereum.org/EIPS/eip-747}
*/
| {
Request: {
method: 'wallet_watchAsset'
params: [Compute<WalletWatchAssetParameters>]
}
ReturnType: boolean
}
>
/**
* Parameters for `wallet_addEthereumChain`. [See more](https://eips.ethereum.org/EIPS/eip-3085).
* @internal
*/
type WalletAddEthereumChainParameters = {
/** A 0x-prefixed hexadecimal string */
chainId: string
/** The chain name. */
chainName: string
/** Native currency for the chain. */
nativeCurrency?:
| {
name: string
symbol: string
decimals: number
}
| undefined
rpcUrls: readonly string[]
blockExplorerUrls?: readonly string[] | undefined
iconUrls?: readonly string[] | undefined
}
/**
* Capabilities of a wallet. [See more](https://eips.ethereum.org/EIPS/eip-5792#wallet_getcapabilities).
* @internal
*/
type WalletCapabilities = {
[capability: string]: any
}
/**
* Capabilities of a wallet, mapped to chain IDs. [See more](https://eips.ethereum.org/EIPS/eip-5792#wallet_getcapabilities).
* @internal
*/
type WalletCapabilitiesMap = {
[chainId: Hex.Hex]: WalletCapabilities
}
/**
* Return type for `wallet_getCallsStatus`. [See more](https://eips.ethereum.org/EIPS/eip-5792#wallet_getcallsstatus).
* @internal
*/
type WalletGetCallsStatusReturnType = {
status: 'PENDING' | 'CONFIRMED'
receipts?:
| readonly {
logs: {
address: Hex.Hex
data: Hex.Hex
topics: readonly Hex.Hex[]
}[]
status: Hex.Hex
blockHash: Hex.Hex
blockNumber: Hex.Hex
gasUsed: Hex.Hex
transactionHash: Hex.Hex
}[]
| undefined
}
/**
* Caveat for a wallet permission. [See more](https://eips.ethereum.org/EIPS/eip-2255).
* @internal
*/
type WalletPermissionCaveat = {
type: string
value: any
}
/**
* A wallet permission. [See more](https://eips.ethereum.org/EIPS/eip-2255).
* @internal
*/
type WalletPermission = {
caveats: readonly WalletPermissionCaveat[]
date: number
id: string
invoker: `http://${string}` | `https://${string}`
parentCapability: 'eth_accounts' | string
}
/**
* Parameters for `wallet_grantPermissions`. [See more](https://eips.ethereum.org/EIPS/eip-7715).
* @internal
*/
type WalletGrantPermissionsParameters = {
signer?:
| {
type: string
data?: unknown | undefined
}
| undefined
permissions: readonly {
data: unknown
policies: readonly {
data: unknown
type: string
}[]
required?: boolean | undefined
type: string
}[]
expiry: number
}
/**
* Return type for `wallet_grantPermissions`. [See more](https://eips.ethereum.org/EIPS/eip-7715).
* @internal
*/
type WalletGrantPermissionsReturnType = {
expiry: number
factory?: `0x${string}` | undefined
factoryData?: string | undefined
grantedPermissions: readonly {
data: unknown
policies: readonly {
data: unknown
type: string
}[]
required?: boolean | undefined
type: string
}[]
permissionsContext: string
signerData?:
| {
userOpBuilder?: `0x${string}` | undefined
submitToAddress?: `0x${string}` | undefined
}
| undefined
}
/**
* Parameters for `wallet_sendCalls`. [See more](https://eips.ethereum.org/EIPS/eip-5792).
* @internal
*/
type WalletSendCallsParameters = [
{
calls: readonly {
to?: Address.Address | undefined
data?: Hex.Hex | undefined
value?: Hex.Hex | undefined
}[]
capabilities?: WalletCapabilities | undefined
chainId?: Hex.Hex | undefined
from: Address.Address
version: string
},
]
/**
* Parameters for `wallet_watchAsset`. [See more](https://eips.ethereum.org/EIPS/eip-747).
* @internal
*/
type WalletWatchAssetParameters = {
/** Token type. */
type: 'ERC20'
options: {
/** The address of the token contract */
address: string
/** A ticker symbol or shorthand, up to 11 characters */
symbol: string
/** The number of token decimals */
decimals: number
/** A string url of the token logo */
image?: string | undefined
}
}

69
node_modules/ox/core/internal/rpcTransport.ts generated vendored Normal file
View File

@@ -0,0 +1,69 @@
import type * as Errors from '../Errors.js'
import * as RpcRequest from '../RpcRequest.js'
import * as RpcResponse from '../RpcResponse.js'
import type * as RpcSchema from '../RpcSchema.js'
import type * as RpcTransport from '../RpcTransport.js'
import type { Compute } from './types.js'
/** @internal */
export type Options<
raw extends boolean | undefined = undefined,
options extends Record<string, unknown> = {},
schema extends RpcSchema.Generic = RpcSchema.Default,
> = {
/**
* Enables raw mode responses will return an object with `result` and `error` properties instead of returning the `result` directly and throwing errors.
*
* - `true`: a JSON-RPC response object will be returned with `result` and `error` properties.
* - `false`: the JSON-RPC response object's `result` property will be returned directly, and JSON-RPC Errors will be thrown.
*
* @default false
*/
raw?: raw | boolean | undefined
/**
* RPC Schema to use for the Transport's `request` function.
* See {@link ox#RpcSchema.(from:function)} for more.
*
* @default `RpcSchema.Default`
*/
schema?: schema | RpcSchema.Default | undefined
} & options
/** @internal */
export function create<
options extends Record<string, unknown> = {},
schema extends RpcSchema.Generic = RpcSchema.Default,
raw extends boolean = false,
>(
transport: create.Transport<options>,
options_root?: Options<raw, options, schema>,
): RpcTransport.RpcTransport<raw, options, schema> {
const requestStore = RpcRequest.createStore()
return {
request: async ({ method, params }, options: any = {}) => {
const body = requestStore.prepare({ method, params } as never)
const data = await transport.request(body as never, options as never)
return RpcResponse.parse(data, {
raw: options.raw ?? options_root?.raw,
}) as never
},
}
}
/** @internal */
export declare namespace create {
type Transport<options extends Record<string, unknown> = {}> = {
request: (
body: Compute<Omit<RpcRequest.RpcRequest, '_returnType'>>,
options: options,
) => Promise<RpcResponse.RpcResponse>
}
type ErrorType =
| RpcRequest.createStore.ErrorType
| RpcResponse.parse.ErrorType
| Errors.GlobalErrorType
}

414
node_modules/ox/core/internal/types.ts generated vendored Normal file
View File

@@ -0,0 +1,414 @@
/** Combines members of an intersection into a readable type. */
// https://twitter.com/mattpocockuk/status/1622730173446557697?s=20&t=NdpAcmEFXY01xkqU3KO0Mg
export type Compute<type> = { [key in keyof type]: type[key] } & unknown
declare const symbol: unique symbol
/**
* Creates a branded type of `T` with the brand `U`.
*
* @example
* ```ts
* type Result = Branded<string, 'foo'>
* // ^? type Result = string & { [symbol]: 'foo' }
* ```
*/
export type Branded<T, U> = T & { [symbol]: U }
/**
* Filters out all members of `T` that are not `P`
*
* @example
* ```ts
* type Result = Filter<['a', 'b', 'c'], 'b'>
* // ^? type Result = ['a', 'c']
* ```
*
* @internal
*/
export type Filter<
T extends readonly unknown[],
P,
Acc extends readonly unknown[] = [],
> = T extends readonly [infer F, ...infer Rest extends readonly unknown[]]
? [F] extends [P]
? Filter<Rest, P, [...Acc, F]>
: Filter<Rest, P, Acc>
: readonly [...Acc]
/**
* Checks if `T` can be narrowed further than `U`
*
* @example
* ```ts
* type Result = IsNarrowable<'foo', string>
* // ^? true
* ```
*/
export type IsNarrowable<T, U> = IsNever<
(T extends U ? true : false) & (U extends T ? false : true)
> extends true
? false
: true
/**
* Checks if `T` is `never`
*
* @example
* ```ts
* type Result = IsNever<never>
* // ^? type Result = true
* ```
*/
export type IsNever<T> = [T] extends [never] ? true : false
/**
* Removes `readonly` from all properties of an object.
*
* @internal
*/
export type Mutable<type extends object> = {
-readonly [key in keyof type]: type[key]
}
/**
* Evaluates boolean "or" condition for `T` properties.
*
* * @example
* ```ts
* type Result = Or<[false, true, false]>
* // ^? type Result = true
* ```
*
* @example
* ```ts
* type Result = Or<[false, false, false]>
* // ^? type Result = false
* ```
*
* @internal
*/
export type Or<T extends readonly unknown[]> = T extends readonly [
infer Head,
...infer Tail,
]
? Head extends true
? true
: Or<Tail>
: false
/**
* Checks if `T` is `undefined`
*
* @example
* ```ts
* type Result = IsUndefined<undefined>
* // ^? type Result = true
* ```
*
* @internal
*/
export type IsUndefined<T> = [undefined] extends [T] ? true : false
/**
* Checks if type `T` is the `unknown` type.
*
* @internal
*/
export type IsUnknown<T> = unknown extends T
? [T] extends [null]
? false
: true
: false
/** @internal */
export type MaybePromise<T> = T | Promise<T>
/**
* Makes attributes on the type T required if required is true.
*
* @example
* ```ts
* MaybeRequired<{ a: string, b?: number }, true>
* // { a: string, b: number }
*
* MaybeRequired<{ a: string, b?: number }, false>
* // { a: string, b?: number }
* ```
*
* @internal
*/
export type MaybeRequired<T, required extends boolean> = required extends true
? ExactRequired<T>
: T
/**
* Assigns the properties of U onto T.
*
* @example
* ```ts
* Assign<{ a: string, b: number }, { a: undefined, c: boolean }>
* // { a: undefined, b: number, c: boolean }
* ```
*
* @internal
*/
export type Assign<T, U> = Assign_inner<T, U> & U
/** @internal */
export type Assign_inner<T, U> = {
[K in keyof T as K extends keyof U
? U[K] extends void
? never
: K
: K]: K extends keyof U ? U[K] : T[K]
}
/**
* Constructs a type by excluding `undefined` from `T`.
*
* @example
* ```ts
* NoUndefined<string | undefined>
* // string
* ```
*
* @internal
*/
export type NoUndefined<T> = T extends undefined ? never : T
/**
* Strict version of built-in Omit type
*
* @internal
*/
export type Omit<type, keys extends keyof type> = Pick<
type,
Exclude<keyof type, keys>
>
/**
* Creates a type that is a partial of T, but with the required keys K.
*
* @example
* ```ts
* PartialBy<{ a: string, b: number }, 'a'>
* // { a?: string, b: number }
* ```
*
* @internal
*/
export type PartialBy<T, K extends keyof T> = Omit<T, K> &
ExactPartial<Pick<T, K>>
export type RecursiveArray<T> = T | readonly RecursiveArray<T>[]
/**
* Creates a type that is T with the required keys K.
*
* @example
* ```ts
* RequiredBy<{ a?: string, b: number }, 'a'>
* // { a: string, b: number }
* ```
*
* @internal
*/
export type RequiredBy<T, K extends keyof T> = Omit<T, K> &
ExactRequired<Pick<T, K>>
/**
* Returns truthy if `array` contains `value`.
*
* @example
* ```ts
* Some<[1, 2, 3], 2>
* // true
* ```
*
* @internal
*/
export type Some<
array extends readonly unknown[],
value,
> = array extends readonly [value, ...unknown[]]
? true
: array extends readonly [unknown, ...infer rest]
? Some<rest, value>
: false
/**
* Prints custom error message
*
* @param messages - Error message
* @returns Custom error message
*
* @example
* ```ts
* type Result = TypeErrorMessage<'Custom error message'>
* // ^? type Result = ['Error: Custom error message']
* ```
*/
export type TypeErrorMessage<messages extends string | string[]> =
messages extends string
? [
// Surrounding with array to prevent `messages` from being widened to `string`
`Error: ${messages}`,
]
: {
[key in keyof messages]: messages[key] extends infer message extends
string
? `Error: ${message}`
: never
}
/** @internal */
export type UnionToTuple<
union,
///
last = LastInUnion<union>,
> = [union] extends [never] ? [] : [...UnionToTuple<Exclude<union, last>>, last]
/** @internal */
export type LastInUnion<U> = UnionToIntersection<
U extends unknown ? (x: U) => 0 : never
> extends (x: infer l) => 0
? l
: never
/** @internal */
export type UnionToIntersection<union> = (
union extends unknown
? (arg: union) => 0
: never
) extends (arg: infer i) => 0
? i
: never
/** @internal */
export type IsUnion<
union,
///
union2 = union,
> = union extends union2 ? ([union2] extends [union] ? false : true) : never
/** @internal */
export type MaybePartial<
type,
enabled extends boolean | undefined,
> = enabled extends true ? Compute<ExactPartial<type>> : type
export type ExactPartial<type> = {
[key in keyof type]?: type[key] | undefined
}
/** @internal */
export type ExactRequired<type> = {
[key in keyof type]-?: Exclude<type[key], undefined>
}
export type OneOf<
union extends object,
fallback extends object | undefined = undefined,
///
keys extends KeyofUnion<union> = KeyofUnion<union>,
> = union extends infer item
? Compute<
item & {
[key in Exclude<keys, keyof item>]?: fallback extends object
? key extends keyof fallback
? fallback[key]
: undefined
: undefined
}
>
: never
/** @internal */
export type KeyofUnion<type> = type extends type ? keyof type : never
/** @internal */
export type Undefined<type> = {
[key in keyof type]?: undefined
}
///////////////////////////////////////////////////////////////////////////
// Loose types
/**
* Loose version of {@link Omit}
* @internal
*/
export type LooseOmit<type, keys extends string> = Pick<
type,
Exclude<keyof type, keys>
>
///////////////////////////////////////////////////////////////////////////
// Union types
/** @internal */
export type UnionCompute<type> = type extends object ? Compute<type> : type
/** @internal */
export type UnionLooseOmit<type, keys extends string> = type extends any
? LooseOmit<type, keys>
: never
/**
* Construct a type with the properties of union type T except for those in type K.
* @example
* ```ts
* type Result = UnionOmit<{ a: string, b: number } | { a: string, b: undefined, c: number }, 'a'>
* // { b: number } | { b: undefined, c: number }
* ```
*
* @internal
*/
export type UnionOmit<type, keys extends keyof type> = type extends any
? Omit<type, keys>
: never
/**
* Construct a type with the properties of union type T except for those in type K.
* @example
* ```ts
* type Result = UnionOmit<{ a: string, b: number } | { a: string, b: undefined, c: number }, 'a'>
* // { b: number } | { b: undefined, c: number }
* ```
*
* @internal
*/
export type UnionPick<type, keys extends keyof type> = type extends any
? Pick<type, keys>
: never
/**
* Creates a type that is a partial of T, but with the required keys K.
*
* @example
* ```ts
* PartialBy<{ a: string, b: number } | { a: string, b: undefined, c: number }, 'a'>
* // { a?: string, b: number } | { a?: string, b: undefined, c: number }
* ```
*
* @internal
*/
export type UnionPartialBy<T, K extends keyof T> = T extends any
? PartialBy<T, K>
: never
/**
* Creates a type that is T with the required keys K.
*
* @example
* ```ts
* RequiredBy<{ a?: string, b: number } | { a?: string, c?: number }, 'a'>
* // { a: string, b: number } | { a: string, c?: number }
* ```
*
* @internal
*/
export type UnionRequiredBy<T, K extends keyof T> = T extends any
? RequiredBy<T, K>
: never

15
node_modules/ox/core/internal/uid.ts generated vendored Normal file
View File

@@ -0,0 +1,15 @@
const size = 256
let index = size
let buffer: string
/** @internal */
export function uid(length = 11) {
if (!buffer || index + length > size * 2) {
buffer = ''
index = 0
for (let i = 0; i < size; i++) {
buffer += ((256 + Math.random() * 256) | 0).toString(16).substring(1)
}
}
return buffer.substring(index, index++ + length)
}

239
node_modules/ox/core/internal/webauthn.ts generated vendored Normal file
View File

@@ -0,0 +1,239 @@
import { p256 } from '@noble/curves/p256'
import type * as Errors from '../Errors.js'
import * as Hex from '../Hex.js'
import * as PublicKey from '../PublicKey.js'
import { CredentialCreationFailedError } from '../WebAuthnP256.js'
/** @internal */
export type AttestationConveyancePreference =
| 'direct'
| 'enterprise'
| 'indirect'
| 'none'
/** @internal */
export type AuthenticatorAttachment = 'cross-platform' | 'platform'
/** @internal */
export type AuthenticatorTransport =
| 'ble'
| 'hybrid'
| 'internal'
| 'nfc'
| 'usb'
/** @internal */
export type COSEAlgorithmIdentifier = number
/** @internal */
export type CredentialMediationRequirement =
| 'conditional'
| 'optional'
| 'required'
| 'silent'
/** @internal */
export type PublicKeyCredentialType = 'public-key'
/** @internal */
export type ResidentKeyRequirement = 'discouraged' | 'preferred' | 'required'
/** @internal */
export type UserVerificationRequirement =
| 'discouraged'
| 'preferred'
| 'required'
/** @internal */
export type LargeBlobSupport = {
support: 'required' | 'preferred'
}
/** @internal */
export type BufferSource = ArrayBufferView | ArrayBuffer
/** @internal */
export type PrfExtension = Record<'eval', Record<'first', Uint8Array>>
/** @internal */
export interface AuthenticationExtensionsClientInputs {
appid?: string
credProps?: boolean
hmacCreateSecret?: boolean
minPinLength?: boolean
prf?: PrfExtension
largeBlob?: LargeBlobSupport
}
/** @internal */
export interface AuthenticatorSelectionCriteria {
authenticatorAttachment?: AuthenticatorAttachment
requireResidentKey?: boolean
residentKey?: ResidentKeyRequirement
userVerification?: UserVerificationRequirement
}
/** @internal */
export interface Credential {
readonly id: string
readonly type: string
}
/** @internal */
export interface CredentialCreationOptions {
publicKey?: PublicKeyCredentialCreationOptions
signal?: AbortSignal
}
/** @internal */
export interface CredentialRequestOptions {
mediation?: CredentialMediationRequirement
publicKey?: PublicKeyCredentialRequestOptions
signal?: AbortSignal
}
/** @internal */
export interface PublicKeyCredential extends Credential {
readonly authenticatorAttachment: string | null
readonly rawId: ArrayBuffer
readonly response: AuthenticatorResponse
getClientExtensionResults(): AuthenticationExtensionsClientOutputs
}
/** @internal */
export interface PublicKeyCredentialCreationOptions {
attestation?: AttestationConveyancePreference
authenticatorSelection?: AuthenticatorSelectionCriteria
challenge: BufferSource
excludeCredentials?: PublicKeyCredentialDescriptor[]
extensions?: AuthenticationExtensionsClientInputs
pubKeyCredParams: PublicKeyCredentialParameters[]
rp: PublicKeyCredentialRpEntity
timeout?: number
user: PublicKeyCredentialUserEntity
}
/** @internal */
export interface PublicKeyCredentialDescriptor {
id: BufferSource
transports?: AuthenticatorTransport[]
type: PublicKeyCredentialType
}
/** @internal */
export interface PublicKeyCredentialEntity {
name: string
}
/** @internal */
export interface PublicKeyCredentialParameters {
alg: COSEAlgorithmIdentifier
type: PublicKeyCredentialType
}
/** @internal */
export interface PublicKeyCredentialRequestOptions {
allowCredentials?: PublicKeyCredentialDescriptor[]
challenge: BufferSource
extensions?: AuthenticationExtensionsClientInputs
rpId?: string
timeout?: number
userVerification?: UserVerificationRequirement
}
/** @internal */
export interface PublicKeyCredentialRpEntity extends PublicKeyCredentialEntity {
id?: string
}
/** @internal */
export interface PublicKeyCredentialUserEntity
extends PublicKeyCredentialEntity {
displayName: string
id: BufferSource
}
/**
* Parses an ASN.1 signature into a r and s value.
*
* @internal
*/
export function parseAsn1Signature(bytes: Uint8Array) {
const r_start = bytes[4] === 0 ? 5 : 4
const r_end = r_start + 32
const s_start = bytes[r_end + 2] === 0 ? r_end + 3 : r_end + 2
const r = BigInt(Hex.fromBytes(bytes.slice(r_start, r_end)))
const s = BigInt(Hex.fromBytes(bytes.slice(s_start)))
return {
r,
s: s > p256.CURVE.n / 2n ? p256.CURVE.n - s : s,
}
}
/**
* Parses a public key into x and y coordinates from the public key
* defined on the credential.
*
* @internal
*/
export async function parseCredentialPublicKey(
response: AuthenticatorAttestationResponse,
): Promise<PublicKey.PublicKey> {
try {
const publicKeyBuffer = response.getPublicKey()
if (!publicKeyBuffer) throw new CredentialCreationFailedError()
// Converting `publicKeyBuffer` throws when credential is created by 1Password Firefox Add-on
const publicKeyBytes = new Uint8Array(publicKeyBuffer)
const cryptoKey = await crypto.subtle.importKey(
'spki',
new Uint8Array(publicKeyBytes),
{
name: 'ECDSA',
namedCurve: 'P-256',
hash: 'SHA-256',
},
true,
['verify'],
)
const publicKey = new Uint8Array(
await crypto.subtle.exportKey('raw', cryptoKey),
)
return PublicKey.from(publicKey)
} catch (error) {
// Fallback for 1Password Firefox Add-on restricts access to certain credential properties
// so we need to use `attestationObject` to extract the public key.
// https://github.com/passwordless-id/webauthn/issues/50#issuecomment-2072902094
if ((error as Error).message !== 'Permission denied to access object')
throw error
const data = new Uint8Array(response.attestationObject)
const coordinateLength = 0x20
const cborPrefix = 0x58
const findStart = (key: number) => {
const coordinate = new Uint8Array([key, cborPrefix, coordinateLength])
for (let i = 0; i < data.length - coordinate.length; i++)
if (coordinate.every((byte, j) => data[i + j] === byte))
return i + coordinate.length
throw new CredentialCreationFailedError()
}
const xStart = findStart(0x21)
const yStart = findStart(0x22)
return PublicKey.from(
new Uint8Array([
0x04,
...data.slice(xStart, xStart + coordinateLength),
...data.slice(yStart, yStart + coordinateLength),
]),
)
}
}
export declare namespace parseCredentialPublicKey {
type ErrorType = CredentialCreationFailedError | Errors.GlobalErrorType
}

2
node_modules/ox/core/version.ts generated vendored Normal file
View File

@@ -0,0 +1,2 @@
/** @internal */
export const version = '0.1.1'