PHP WebShell
Текущая директория: /usr/lib/node_modules/bitgo/node_modules/viem/actions/public
Просмотр файла: verifyHash.ts
import type { Address } from 'abitype'
import { SignatureErc6492 } from 'ox/erc6492'
import { SignatureErc8010 } from 'ox/erc8010'
import type { Client } from '../../clients/createClient.js'
import type { Transport } from '../../clients/transports/createTransport.js'
import {
erc1271Abi,
erc6492SignatureValidatorAbi,
multicall3Abi,
} from '../../constants/abis.js'
import {
erc6492SignatureValidatorByteCode,
multicall3Bytecode,
} from '../../constants/contracts.js'
import {
CallExecutionError,
ContractFunctionExecutionError,
} from '../../errors/contract.js'
import type { InvalidHexBooleanError } from '../../errors/encoding.js'
import type { ErrorType } from '../../errors/utils.js'
import type { Chain } from '../../types/chain.js'
import type { ByteArray, Hex, Signature } from '../../types/misc.js'
import type { OneOf } from '../../types/utils.js'
import {
type EncodeDeployDataErrorType,
encodeDeployData,
} from '../../utils/abi/encodeDeployData.js'
import {
type EncodeFunctionDataErrorType,
encodeFunctionData,
} from '../../utils/abi/encodeFunctionData.js'
import {
type GetAddressErrorType,
getAddress,
} from '../../utils/address/getAddress.js'
import {
type IsAddressEqualErrorType,
isAddressEqual,
} from '../../utils/address/isAddressEqual.js'
import { verifyAuthorization } from '../../utils/authorization/verifyAuthorization.js'
import { type ConcatHexErrorType, concatHex } from '../../utils/data/concat.js'
import { type IsHexErrorType, isHex } from '../../utils/data/isHex.js'
import { hexToBool } from '../../utils/encoding/fromHex.js'
import {
type BytesToHexErrorType,
bytesToHex,
type NumberToHexErrorType,
numberToHex,
} from '../../utils/encoding/toHex.js'
import { getAction } from '../../utils/getAction.js'
import {
type RecoverAddressErrorType,
recoverAddress,
} from '../../utils/signature/recoverAddress.js'
import {
type SerializeSignatureErrorType,
serializeSignature,
} from '../../utils/signature/serializeSignature.js'
import { type CallErrorType, type CallParameters, call } from './call.js'
import { type GetCodeErrorType, getCode } from './getCode.js'
import { type ReadContractErrorType, readContract } from './readContract.js'
export type VerifyHashParameters = Pick<
CallParameters,
'blockNumber' | 'blockTag'
> & {
/** The address that signed the original message. */
address: Address
/** The address of the ERC-6492 signature verifier contract. */
erc6492VerifierAddress?: Address | undefined
/** The hash to be verified. */
hash: Hex
/** Multicall3 address for ERC-8010 verification. */
multicallAddress?: Address | undefined
/** The signature that was generated by signing the message with the address's private key. */
signature: Hex | ByteArray | Signature
/** @deprecated use `erc6492VerifierAddress` instead. */
universalSignatureVerifierAddress?: Address | undefined
} & OneOf<{ factory: Address; factoryData: Hex } | {}>
export type VerifyHashReturnType = boolean
export type VerifyHashErrorType =
| BytesToHexErrorType
| CallErrorType
| ConcatHexErrorType
| EncodeDeployDataErrorType
| EncodeFunctionDataErrorType
| ErrorType
| GetAddressErrorType
| GetCodeErrorType
| InvalidHexBooleanError
| IsAddressEqualErrorType
| IsHexErrorType
| NumberToHexErrorType
| ReadContractErrorType
| RecoverAddressErrorType
| SerializeSignatureErrorType
/**
* Verifies a message hash onchain using ERC-6492.
*
* @param client - Client to use.
* @param parameters - {@link VerifyHashParameters}
* @returns Whether or not the signature is valid. {@link VerifyHashReturnType}
*/
export async function verifyHash<chain extends Chain | undefined>(
client: Client<Transport, chain>,
parameters: VerifyHashParameters,
): Promise<VerifyHashReturnType> {
const {
address,
hash,
erc6492VerifierAddress:
verifierAddress = parameters.universalSignatureVerifierAddress ??
client.chain?.contracts?.erc6492Verifier?.address,
multicallAddress = parameters.multicallAddress ??
client.chain?.contracts?.multicall3?.address,
} = parameters
const signature = (() => {
const signature = parameters.signature
if (isHex(signature)) return signature
if (typeof signature === 'object' && 'r' in signature && 's' in signature)
return serializeSignature(signature)
return bytesToHex(signature)
})()
try {
if (SignatureErc8010.validate(signature))
return await verifyErc8010(client, {
...parameters,
multicallAddress,
signature,
})
return await verifyErc6492(client, {
...parameters,
verifierAddress,
signature,
})
} catch (error) {
// Fallback attempt to verify the signature via ECDSA recovery.
try {
const verified = isAddressEqual(
getAddress(address),
await recoverAddress({ hash, signature }),
)
if (verified) return true
} catch {}
if (error instanceof VerificationError) {
// if the execution fails, the signature was not valid and an internal method inside of the validator reverted
// this can happen for many reasons, for example if signer can not be recovered from the signature
// or if the signature has no valid format
return false
}
throw error
}
}
/** @internal */
export async function verifyErc8010(
client: Client,
parameters: verifyErc8010.Parameters,
) {
const { address, blockNumber, blockTag, hash, multicallAddress } = parameters
const {
authorization: authorization_ox,
data: initData,
signature,
to,
} = SignatureErc8010.unwrap(parameters.signature)
// Check if already delegated
const code = await getCode(client, {
address,
blockNumber,
blockTag,
} as never)
// If already delegated, perform standard ERC-1271 verification.
if (code === concatHex(['0xef0100', authorization_ox.address]))
return await verifyErc1271(client, {
address,
blockNumber,
blockTag,
hash,
signature,
})
const authorization = {
address: authorization_ox.address,
chainId: Number(authorization_ox.chainId),
nonce: Number(authorization_ox.nonce),
r: numberToHex(authorization_ox.r, { size: 32 }),
s: numberToHex(authorization_ox.s, { size: 32 }),
yParity: authorization_ox.yParity,
} as const
const valid = await verifyAuthorization({
address,
authorization,
})
if (!valid) throw new VerificationError()
// Deployless verification.
const results = await getAction(
client,
readContract,
'readContract',
)({
...(multicallAddress
? { address: multicallAddress }
: { code: multicall3Bytecode }),
authorizationList: [authorization],
abi: multicall3Abi,
blockNumber,
blockTag: 'pending',
functionName: 'aggregate3',
args: [
[
...(initData
? [
{
allowFailure: true,
target: to ?? address,
callData: initData,
},
]
: []),
{
allowFailure: true,
target: address,
callData: encodeFunctionData({
abi: erc1271Abi,
functionName: 'isValidSignature',
args: [hash, signature],
}),
},
],
],
})
const data = results[results.length - 1]?.returnData
if (data?.startsWith('0x1626ba7e')) return true
throw new VerificationError()
}
export namespace verifyErc8010 {
export type Parameters = Pick<CallParameters, 'blockNumber' | 'blockTag'> & {
/** The address that signed the original message. */
address: Address
/** The hash to be verified. */
hash: Hex
/** Multicall3 address for ERC-8010 verification. */
multicallAddress?: Address | undefined
/** The signature that was generated by signing the message with the address's private key. */
signature: Hex
}
}
/** @internal */
// biome-ignore lint/correctness/noUnusedVariables: _
async function verifyErc6492(
client: Client,
parameters: verifyErc6492.Parameters,
) {
const {
address,
factory,
factoryData,
hash,
signature,
verifierAddress,
...rest
} = parameters
const wrappedSignature = await (async () => {
// If no `factory` or `factoryData` is provided, it is assumed that the
// address is not a Smart Account, or the Smart Account is already deployed.
if (!factory && !factoryData) return signature
// If the signature is already wrapped, return the signature.
if (SignatureErc6492.validate(signature)) return signature
// If the Smart Account is not deployed, wrap the signature with a 6492 wrapper
// to perform counterfactual validation.
return SignatureErc6492.wrap({
data: factoryData!,
signature,
to: factory!,
})
})()
const args = verifierAddress
? ({
to: verifierAddress,
data: encodeFunctionData({
abi: erc6492SignatureValidatorAbi,
functionName: 'isValidSig',
args: [address, hash, wrappedSignature],
}),
...rest,
} as unknown as CallParameters)
: ({
data: encodeDeployData({
abi: erc6492SignatureValidatorAbi,
args: [address, hash, wrappedSignature],
bytecode: erc6492SignatureValidatorByteCode,
}),
...rest,
} as unknown as CallParameters)
const { data } = await getAction(
client,
call,
'call',
)(args).catch((error) => {
if (error instanceof CallExecutionError) throw new VerificationError()
throw error
})
if (hexToBool(data ?? '0x0')) return true
throw new VerificationError()
}
export namespace verifyErc6492 {
export type Parameters = Pick<CallParameters, 'blockNumber' | 'blockTag'> & {
/** The address that signed the original message. */
address: Address
/** The hash to be verified. */
hash: Hex
/** The signature that was generated by signing the message with the address's private key. */
signature: Hex
/** The address of the ERC-6492 signature verifier contract. */
verifierAddress?: Address | undefined
} & OneOf<{ factory: Address; factoryData: Hex } | {}>
}
/** @internal */
export async function verifyErc1271(
client: Client,
parameters: verifyErc1271.Parameters,
) {
const { address, blockNumber, blockTag, hash, signature } = parameters
const result = await getAction(
client,
readContract,
'readContract',
)({
address,
abi: erc1271Abi,
args: [hash, signature],
blockNumber,
blockTag,
functionName: 'isValidSignature',
}).catch((error) => {
if (error instanceof ContractFunctionExecutionError)
throw new VerificationError()
throw error
})
if (result.startsWith('0x1626ba7e')) return true
throw new VerificationError()
}
export namespace verifyErc1271 {
export type Parameters = Pick<CallParameters, 'blockNumber' | 'blockTag'> & {
/** The address that signed the original message. */
address: Address
/** The hash to be verified. */
hash: Hex
/** The signature that was generated by signing the message with the address's private key. */
signature: Hex
}
}
class VerificationError extends Error {}
Выполнить команду
Для локальной разработки. Не используйте в интернете!