- 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>
263 lines
9.9 KiB
TypeScript
263 lines
9.9 KiB
TypeScript
import type * as Abi from '../core/Abi.js'
|
|
import * as AbiParameters from '../core/AbiParameters.js'
|
|
import type * as Address from '../core/Address.js'
|
|
import * as Errors from '../core/Errors.js'
|
|
import * as Hex from '../core/Hex.js'
|
|
import * as Signature from '../core/Signature.js'
|
|
|
|
/** ERC-6492 Wrapped Signature. */
|
|
export type WrappedSignature = {
|
|
/** Calldata to pass to the target address for counterfactual verification. */
|
|
data: Hex.Hex
|
|
/** The original signature. */
|
|
signature: Signature.Signature
|
|
/** The target address to use for counterfactual verification. */
|
|
to: Address.Address
|
|
}
|
|
|
|
/**
|
|
* Magic bytes used to identify ERC-6492 wrapped signatures.
|
|
*/
|
|
export const magicBytes =
|
|
'0x6492649264926492649264926492649264926492649264926492649264926492' as const
|
|
|
|
/**
|
|
* Deployless ERC-6492 signature verification bytecode.
|
|
*/
|
|
export const universalSignatureValidatorBytecode =
|
|
'0x608060405234801561001057600080fd5b5060405161069438038061069483398101604081905261002f9161051e565b600061003c848484610048565b9050806000526001601ff35b60007f64926492649264926492649264926492649264926492649264926492649264926100748361040c565b036101e7576000606080848060200190518101906100929190610577565b60405192955090935091506000906001600160a01b038516906100b69085906105dd565b6000604051808303816000865af19150503d80600081146100f3576040519150601f19603f3d011682016040523d82523d6000602084013e6100f8565b606091505b50509050876001600160a01b03163b60000361016057806101605760405162461bcd60e51b815260206004820152601e60248201527f5369676e617475726556616c696461746f723a206465706c6f796d656e74000060448201526064015b60405180910390fd5b604051630b135d3f60e11b808252906001600160a01b038a1690631626ba7e90610190908b9087906004016105f9565b602060405180830381865afa1580156101ad573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101d19190610633565b6001600160e01b03191614945050505050610405565b6001600160a01b0384163b1561027a57604051630b135d3f60e11b808252906001600160a01b03861690631626ba7e9061022790879087906004016105f9565b602060405180830381865afa158015610244573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102689190610633565b6001600160e01b031916149050610405565b81516041146102df5760405162461bcd60e51b815260206004820152603a602482015260008051602061067483398151915260448201527f3a20696e76616c6964207369676e6174757265206c656e6774680000000000006064820152608401610157565b6102e7610425565b5060208201516040808401518451859392600091859190811061030c5761030c61065d565b016020015160f81c9050601b811480159061032b57508060ff16601c14155b1561038c5760405162461bcd60e51b815260206004820152603b602482015260008051602061067483398151915260448201527f3a20696e76616c6964207369676e617475726520762076616c756500000000006064820152608401610157565b60408051600081526020810180835289905260ff83169181019190915260608101849052608081018390526001600160a01b0389169060019060a0016020604051602081039080840390855afa1580156103ea573d6000803e3d6000fd5b505050602060405103516001600160a01b0316149450505050505b9392505050565b600060208251101561041d57600080fd5b508051015190565b60405180606001604052806003906020820280368337509192915050565b6001600160a01b038116811461045857600080fd5b50565b634e487b7160e01b600052604160045260246000fd5b60005b8381101561048c578181015183820152602001610474565b50506000910152565b600082601f8301126104a657600080fd5b81516001600160401b038111156104bf576104bf61045b565b604051601f8201601f19908116603f011681016001600160401b03811182821017156104ed576104ed61045b565b60405281815283820160200185101561050557600080fd5b610516826020830160208701610471565b949350505050565b60008060006060848603121561053357600080fd5b835161053e81610443565b6020850151604086015191945092506001600160401b0381111561056157600080fd5b61056d86828701610495565b9150509250925092565b60008060006060848603121561058c57600080fd5b835161059781610443565b60208501519093506001600160401b038111156105b357600080fd5b6105bf86828701610495565b604086015190935090506001600160401b0381111561056157600080fd5b600082516105ef818460208701610471565b9190910192915050565b828152604060208201526000825180604084015261061e816060850160208701610471565b601f01601f1916919091016060019392505050565b60006020828403121561064557600080fd5b81516001600160e01b03198116811461040557600080fd5b634e487b7160e01b600052603260045260246000fdfe5369676e617475726556616c696461746f72237265636f7665725369676e6572'
|
|
|
|
/**
|
|
* ABI for the ERC-6492 universal deployless signature validator contract.
|
|
*
|
|
* Constructor return value is `0x1` (valid) or `0x0` (invalid).
|
|
*/
|
|
export const universalSignatureValidatorAbi = [
|
|
{
|
|
inputs: [
|
|
{
|
|
name: '_signer',
|
|
type: 'address',
|
|
},
|
|
{
|
|
name: '_hash',
|
|
type: 'bytes32',
|
|
},
|
|
{
|
|
name: '_signature',
|
|
type: 'bytes',
|
|
},
|
|
],
|
|
stateMutability: 'nonpayable',
|
|
type: 'constructor',
|
|
},
|
|
{
|
|
inputs: [
|
|
{
|
|
name: '_signer',
|
|
type: 'address',
|
|
},
|
|
{
|
|
name: '_hash',
|
|
type: 'bytes32',
|
|
},
|
|
{
|
|
name: '_signature',
|
|
type: 'bytes',
|
|
},
|
|
],
|
|
outputs: [
|
|
{
|
|
type: 'bool',
|
|
},
|
|
],
|
|
stateMutability: 'nonpayable',
|
|
type: 'function',
|
|
name: 'isValidSig',
|
|
},
|
|
] as const satisfies Abi.Abi
|
|
|
|
/**
|
|
* Asserts that the wrapped signature is valid.
|
|
*
|
|
* @example
|
|
* ```ts twoslash
|
|
* import { WrappedSignature } from 'ox/erc6492'
|
|
*
|
|
* WrappedSignature.assert('0xdeadbeef')
|
|
* // @error: InvalidWrappedSignatureError: Value `0xdeadbeef` is an invalid ERC-6492 wrapped signature.
|
|
* ```
|
|
*
|
|
* @param wrapped - The wrapped signature to assert.
|
|
*/
|
|
export function assert(wrapped: Hex.Hex) {
|
|
if (Hex.slice(wrapped, -32) !== magicBytes)
|
|
throw new InvalidWrappedSignatureError(wrapped)
|
|
}
|
|
|
|
export declare namespace assert {
|
|
type ErrorType =
|
|
| InvalidWrappedSignatureError
|
|
| Hex.slice.ErrorType
|
|
| Errors.GlobalErrorType
|
|
}
|
|
|
|
/**
|
|
* Parses an [ERC-6492 wrapped signature](https://eips.ethereum.org/EIPS/eip-6492#specification) into its constituent parts.
|
|
*
|
|
* @example
|
|
* ```ts twoslash
|
|
* // @noErrors
|
|
* import { Secp256k1 } from 'ox'
|
|
* import { WrappedSignature } from 'ox/erc6492' // [!code focus]
|
|
*
|
|
* const signature = Secp256k1.sign({
|
|
* payload: '0x...',
|
|
* privateKey: '0x...',
|
|
* })
|
|
*
|
|
* // Instantiate from serialized format. // [!code focus]
|
|
* const wrapped = WrappedSignature.from('0x...') // [!code focus]
|
|
* // @log: { data: '0x...', signature: { ... }, to: '0x...', } // [!code focus]
|
|
*
|
|
* // Instantiate from constituent parts. // [!code focus]
|
|
* const wrapped = WrappedSignature.from({ // [!code focus]
|
|
* data: '0x...', // [!code focus]
|
|
* signature, // [!code focus]
|
|
* to: '0x...', // [!code focus]
|
|
* })
|
|
* // @log: { data: '0x...', signature: { ... }, to: '0x...', }
|
|
* ```
|
|
*
|
|
* @param wrapped - Wrapped signature to parse.
|
|
* @returns Wrapped signature.
|
|
*/
|
|
export function from(wrapped: WrappedSignature | Hex.Hex): WrappedSignature {
|
|
if (typeof wrapped === 'string') return fromHex(wrapped)
|
|
return wrapped
|
|
}
|
|
|
|
export declare namespace from {
|
|
type ReturnType = WrappedSignature
|
|
|
|
type ErrorType =
|
|
| AbiParameters.from.ErrorType
|
|
| AbiParameters.decode.ErrorType
|
|
| Signature.fromHex.ErrorType
|
|
| Errors.GlobalErrorType
|
|
}
|
|
|
|
/**
|
|
* Parses an [ERC-6492 wrapped signature](https://eips.ethereum.org/EIPS/eip-6492#specification) into its constituent parts.
|
|
*
|
|
* @example
|
|
* ```ts twoslash
|
|
* import { WrappedSignature } from 'ox/erc6492'
|
|
*
|
|
* const { data, signature, to } = WrappedSignature.fromHex('0x...')
|
|
* ```
|
|
*
|
|
* @param wrapped - Wrapped signature to parse.
|
|
* @returns Wrapped signature.
|
|
*/
|
|
export function fromHex(wrapped: Hex.Hex): WrappedSignature {
|
|
assert(wrapped)
|
|
|
|
const [to, data, signature_hex] = AbiParameters.decode(
|
|
AbiParameters.from('address, bytes, bytes'),
|
|
wrapped,
|
|
)
|
|
|
|
const signature = Signature.fromHex(signature_hex)
|
|
|
|
return { data, signature, to }
|
|
}
|
|
|
|
export declare namespace fromHex {
|
|
type ErrorType =
|
|
| AbiParameters.from.ErrorType
|
|
| AbiParameters.decode.ErrorType
|
|
| Signature.fromHex.ErrorType
|
|
| Errors.GlobalErrorType
|
|
}
|
|
|
|
/**
|
|
* Serializes an [ERC-6492 wrapped signature](https://eips.ethereum.org/EIPS/eip-6492#specification).
|
|
*
|
|
* @example
|
|
* ```ts twoslash
|
|
* import { Secp256k1 } from 'ox'
|
|
* import { WrappedSignature } from 'ox/erc6492' // [!code focus]
|
|
*
|
|
* const signature = Secp256k1.sign({
|
|
* payload: '0x...',
|
|
* privateKey: '0x...',
|
|
* })
|
|
*
|
|
* const wrapped = WrappedSignature.toHex({ // [!code focus]
|
|
* data: '0xdeadbeef', // [!code focus]
|
|
* signature, // [!code focus]
|
|
* to: '0x00000000219ab540356cBB839Cbe05303d7705Fa', // [!code focus]
|
|
* }) // [!code focus]
|
|
* ```
|
|
*
|
|
* @param value - Wrapped signature to serialize.
|
|
* @returns Serialized wrapped signature.
|
|
*/
|
|
export function toHex(value: WrappedSignature): Hex.Hex {
|
|
const { data, signature, to } = value
|
|
|
|
return Hex.concat(
|
|
AbiParameters.encode(AbiParameters.from('address, bytes, bytes'), [
|
|
to,
|
|
data,
|
|
Signature.toHex(signature),
|
|
]),
|
|
magicBytes,
|
|
)
|
|
}
|
|
|
|
export declare namespace toHex {
|
|
type ErrorType =
|
|
| AbiParameters.encode.ErrorType
|
|
| Hex.concat.ErrorType
|
|
| Signature.toHex.ErrorType
|
|
| Errors.GlobalErrorType
|
|
}
|
|
|
|
/**
|
|
* Validates a wrapped signature. Returns `true` if the wrapped signature is valid, `false` otherwise.
|
|
*
|
|
* @example
|
|
* ```ts twoslash
|
|
* import { WrappedSignature } from 'ox/erc6492'
|
|
*
|
|
* const valid = WrappedSignature.validate('0xdeadbeef')
|
|
* // @log: false
|
|
* ```
|
|
*
|
|
* @param wrapped - The wrapped signature to validate.
|
|
* @returns `true` if the wrapped signature is valid, `false` otherwise.
|
|
*/
|
|
export function validate(wrapped: Hex.Hex): boolean {
|
|
try {
|
|
assert(wrapped)
|
|
return true
|
|
} catch {
|
|
return false
|
|
}
|
|
}
|
|
|
|
export declare namespace validate {
|
|
type ErrorType = Errors.GlobalErrorType
|
|
}
|
|
|
|
/** Thrown when the ERC-6492 wrapped signature is invalid. */
|
|
export class InvalidWrappedSignatureError extends Errors.BaseError {
|
|
override readonly name = 'WrappedSignature.InvalidWrappedSignatureError'
|
|
|
|
constructor(wrapped: Hex.Hex) {
|
|
super(`Value \`${wrapped}\` is an invalid ERC-6492 wrapped signature.`)
|
|
}
|
|
}
|