@metamask/utils
Version:
Various JavaScript/TypeScript utilities of wide relevance to the MetaMask codebase
366 lines • 14.8 kB
JavaScript
import { is } from "@metamask/superstruct";
import { definePattern } from "./superstruct.mjs";
export const CAIP_CHAIN_ID_REGEX = /^(?<namespace>[-a-z0-9]{3,8}):(?<reference>[-_a-zA-Z0-9]{1,32})$/u;
export const CAIP_NAMESPACE_REGEX = /^[-a-z0-9]{3,8}$/u;
export const CAIP_REFERENCE_REGEX = /^[-_a-zA-Z0-9]{1,32}$/u;
export const CAIP_ACCOUNT_ID_REGEX = /^(?<chainId>(?<namespace>[-a-z0-9]{3,8}):(?<reference>[-_a-zA-Z0-9]{1,32})):(?<accountAddress>[-.%a-zA-Z0-9]{1,128})$/u;
export const CAIP_ACCOUNT_ADDRESS_REGEX = /^[-.%a-zA-Z0-9]{1,128}$/u;
export const CAIP_ASSET_NAMESPACE_REGEX = /^[-a-z0-9]{3,8}$/u;
export const CAIP_ASSET_REFERENCE_REGEX = /^[-.%a-zA-Z0-9]{1,128}$/u;
export const CAIP_TOKEN_ID_REGEX = /^[-.%a-zA-Z0-9]{1,78}$/u;
export const CAIP_ASSET_TYPE_REGEX = /^(?<chainId>(?<namespace>[-a-z0-9]{3,8}):(?<reference>[-_a-zA-Z0-9]{1,32}))\/(?<assetNamespace>[-a-z0-9]{3,8}):(?<assetReference>[-.%a-zA-Z0-9]{1,128})$/u;
export const CAIP_ASSET_ID_REGEX = /^(?<chainId>(?<namespace>[-a-z0-9]{3,8}):(?<reference>[-_a-zA-Z0-9]{1,32}))\/(?<assetNamespace>[-a-z0-9]{3,8}):(?<assetReference>[-.%a-zA-Z0-9]{1,128})\/(?<tokenId>[-.%a-zA-Z0-9]{1,78})$/u;
const CAIP_ASSET_TYPE_OR_ID_REGEX = /^(?<chainId>(?<namespace>[-a-z0-9]{3,8}):(?<reference>[-_a-zA-Z0-9]{1,32}))\/(?<assetNamespace>[-a-z0-9]{3,8}):(?<assetReference>[-.%a-zA-Z0-9]{1,128})(\/(?<tokenId>[-.%a-zA-Z0-9]{1,78}))?$/u;
/**
* A CAIP-2 chain ID, i.e., a human-readable namespace and reference.
*/
export const CaipChainIdStruct = definePattern('CaipChainId', CAIP_CHAIN_ID_REGEX);
/**
* A CAIP-2 namespace, i.e., the first part of a CAIP chain ID.
*/
export const CaipNamespaceStruct = definePattern('CaipNamespace', CAIP_NAMESPACE_REGEX);
/**
* A CAIP-2 reference, i.e., the second part of a CAIP chain ID.
*/
export const CaipReferenceStruct = definePattern('CaipReference', CAIP_REFERENCE_REGEX);
/**
* A CAIP-10 account ID, i.e., a human-readable namespace, reference, and account address.
*/
export const CaipAccountIdStruct = definePattern('CaipAccountId', CAIP_ACCOUNT_ID_REGEX);
/**
* A CAIP-10 account address, i.e., the third part of the CAIP account ID.
*/
export const CaipAccountAddressStruct = definePattern('CaipAccountAddress', CAIP_ACCOUNT_ADDRESS_REGEX);
/**
* A CAIP-19 asset namespace, i.e., a namespace domain of an asset.
*/
export const CaipAssetNamespaceStruct = definePattern('CaipAssetNamespace', CAIP_ASSET_NAMESPACE_REGEX);
/**
* A CAIP-19 asset reference, i.e., an identifier for an asset within a given namespace.
*/
export const CaipAssetReferenceStruct = definePattern('CaipAssetReference', CAIP_ASSET_REFERENCE_REGEX);
/**
* A CAIP-19 asset token ID, i.e., a unique identifier for an addressable asset of a given type
*/
export const CaipTokenIdStruct = definePattern('CaipTokenId', CAIP_TOKEN_ID_REGEX);
/**
* A CAIP-19 asset type identifier, i.e., a human-readable type of asset identifier.
*/
export const CaipAssetTypeStruct = definePattern('CaipAssetType', CAIP_ASSET_TYPE_REGEX);
/**
* A CAIP-19 asset ID identifier, i.e., a human-readable type of asset ID.
*/
export const CaipAssetIdStruct = definePattern('CaipAssetId', CAIP_ASSET_ID_REGEX);
/**
* A CAIP-19 asset type or asset ID identifier, i.e., a human-readable type of asset identifier.
*/
export const CaipAssetTypeOrIdStruct = definePattern('CaipAssetTypeOrId', CAIP_ASSET_TYPE_OR_ID_REGEX);
/** Known CAIP namespaces. */
export var KnownCaipNamespace;
(function (KnownCaipNamespace) {
/** BIP-122 (Bitcoin) compatible chains. */
KnownCaipNamespace["Bip122"] = "bip122";
/** Solana compatible chains */
KnownCaipNamespace["Solana"] = "solana";
/** EIP-155 compatible chains. */
KnownCaipNamespace["Eip155"] = "eip155";
KnownCaipNamespace["Wallet"] = "wallet";
})(KnownCaipNamespace = KnownCaipNamespace || (KnownCaipNamespace = {}));
/**
* Check if the given value is a {@link CaipChainId}.
*
* @param value - The value to check.
* @returns Whether the value is a {@link CaipChainId}.
*/
export function isCaipChainId(value) {
return is(value, CaipChainIdStruct);
}
/**
* Check if the given value is a {@link CaipNamespace}.
*
* @param value - The value to check.
* @returns Whether the value is a {@link CaipNamespace}.
*/
export function isCaipNamespace(value) {
return is(value, CaipNamespaceStruct);
}
/**
* Check if the given value is a {@link CaipReference}.
*
* @param value - The value to check.
* @returns Whether the value is a {@link CaipReference}.
*/
export function isCaipReference(value) {
return is(value, CaipReferenceStruct);
}
/**
* Check if the given value is a {@link CaipAccountId}.
*
* @param value - The value to check.
* @returns Whether the value is a {@link CaipAccountId}.
*/
export function isCaipAccountId(value) {
return is(value, CaipAccountIdStruct);
}
/**
* Check if a value is a {@link CaipAccountAddress}.
*
* @param value - The value to validate.
* @returns True if the value is a valid {@link CaipAccountAddress}.
*/
export function isCaipAccountAddress(value) {
return is(value, CaipAccountAddressStruct);
}
/**
* Check if the given value is a {@link CaipAssetNamespace}.
*
* @param value - The value to check.
* @returns Whether the value is a {@link CaipAssetNamespace}.
*/
export function isCaipAssetNamespace(value) {
return is(value, CaipAssetNamespaceStruct);
}
/**
* Check if the given value is a {@link CaipAssetReference}.
*
* @param value - The value to check.
* @returns Whether the value is a {@link CaipAssetReference}.
*/
export function isCaipAssetReference(value) {
return is(value, CaipAssetReferenceStruct);
}
/**
* Check if the given value is a {@link CaipTokenId}.
*
* @param value - The value to check.
* @returns Whether the value is a {@link CaipTokenId}.
*/
export function isCaipTokenId(value) {
return is(value, CaipTokenIdStruct);
}
/**
* Check if the given value is a {@link CaipAssetType}.
*
* @param value - The value to check.
* @returns Whether the value is a {@link CaipAssetType}.
*/
export function isCaipAssetType(value) {
return is(value, CaipAssetTypeStruct);
}
/**
* Check if the given value is a {@link CaipAssetId}.
*
* @param value - The value to check.
* @returns Whether the value is a {@link CaipAssetId}.
*/
export function isCaipAssetId(value) {
return is(value, CaipAssetIdStruct);
}
/**
* Parse a CAIP-2 chain ID to an object containing the namespace and reference.
* This validates the CAIP-2 chain ID before parsing it.
*
* @param caipChainId - The CAIP-2 chain ID to validate and parse.
* @returns The parsed CAIP-2 chain ID.
*/
export function parseCaipChainId(caipChainId) {
const match = CAIP_CHAIN_ID_REGEX.exec(caipChainId);
if (!match?.groups) {
throw new Error('Invalid CAIP chain ID.');
}
return {
namespace: match.groups.namespace,
reference: match.groups.reference,
};
}
/**
* Parse an CAIP-10 account ID to an object containing the chain ID, parsed chain ID, and account address.
* This validates the CAIP-10 account ID before parsing it.
*
* @param caipAccountId - The CAIP-10 account ID to validate and parse.
* @returns The parsed CAIP-10 account ID.
*/
export function parseCaipAccountId(caipAccountId) {
const match = CAIP_ACCOUNT_ID_REGEX.exec(caipAccountId);
if (!match?.groups) {
throw new Error('Invalid CAIP account ID.');
}
return {
address: match.groups.accountAddress,
chainId: match.groups.chainId,
chain: {
namespace: match.groups.namespace,
reference: match.groups.reference,
},
};
}
/**
* Parse a CAIP-19 asset type to an object containing the chain ID, parsed chain ID,
* asset namespace, and asset reference
*
* This validates the CAIP-19 asset type before parsing it.
*
* @param caipAssetType - The CAIP-19 asset type to validate and parse.
* @returns The parsed CAIP-19 asset type.
*/
export function parseCaipAssetType(caipAssetType) {
const match = CAIP_ASSET_TYPE_REGEX.exec(caipAssetType);
if (!match?.groups) {
throw new Error('Invalid CAIP asset type.');
}
return {
assetNamespace: match.groups.assetNamespace,
assetReference: match.groups.assetReference,
chainId: match.groups.chainId,
chain: {
namespace: match.groups.namespace,
reference: match.groups.reference,
},
};
}
/**
* Parse a CAIP-19 asset ID to an object containing the chain ID, parsed chain ID,
* asset namespace, asset reference, and token ID.
*
* This validates the CAIP-19 asset ID before parsing it.
*
* @param caipAssetId - The CAIP-19 asset ID to validate and parse.
* @returns The parsed CAIP-19 asset ID.
*/
export function parseCaipAssetId(caipAssetId) {
const match = CAIP_ASSET_ID_REGEX.exec(caipAssetId);
if (!match?.groups) {
throw new Error('Invalid CAIP asset ID.');
}
return {
assetNamespace: match.groups.assetNamespace,
assetReference: match.groups.assetReference,
tokenId: match.groups.tokenId,
chainId: match.groups.chainId,
chain: {
namespace: match.groups.namespace,
reference: match.groups.reference,
},
};
}
/**
* Chain ID as defined per the CAIP-2
* {@link https://github.com/ChainAgnostic/CAIPs/blob/main/CAIPs/caip-2.md}.
*
* It defines a way to uniquely identify any blockchain in a human-readable
* way.
*
* @param namespace - The standard (ecosystem) of similar blockchains.
* @param reference - Identify of a blockchain within a given namespace.
* @throws {@link Error}
* This exception is thrown if the inputs does not comply with the CAIP-2
* syntax specification
* {@link https://github.com/ChainAgnostic/CAIPs/blob/main/CAIPs/caip-2.md#syntax}.
* @returns A CAIP chain ID.
*/
export function toCaipChainId(namespace, reference) {
if (!isCaipNamespace(namespace)) {
throw new Error(`Invalid "namespace", must match: ${CAIP_NAMESPACE_REGEX.toString()}`);
}
if (!isCaipReference(reference)) {
throw new Error(`Invalid "reference", must match: ${CAIP_REFERENCE_REGEX.toString()}`);
}
return `${namespace}:${reference}`;
}
/**
* Account ID as defined per the CAIP-10
* {@link https://github.com/ChainAgnostic/CAIPs/blob/main/CAIPs/caip-10.md}.
*
* It defines a way to uniquely identify any blockchain account in a human-readable
* way.
*
* @param namespace - The standard (ecosystem) of similar blockchains.
* @param reference - Identity of a blockchain within a given namespace.
* @param accountAddress - The address of the blockchain account.
* @throws {@link Error}
* This exception is thrown if the inputs do not comply with the CAIP-10
* syntax specification
* {@link https://github.com/ChainAgnostic/CAIPs/blob/main/CAIPs/caip-10.md#syntax}.
* @returns A CAIP account ID.
*/
export function toCaipAccountId(namespace, reference, accountAddress) {
if (!isCaipNamespace(namespace)) {
throw new Error(`Invalid "namespace", must match: ${CAIP_NAMESPACE_REGEX.toString()}`);
}
if (!isCaipReference(reference)) {
throw new Error(`Invalid "reference", must match: ${CAIP_REFERENCE_REGEX.toString()}`);
}
if (!isCaipAccountAddress(accountAddress)) {
throw new Error(`Invalid "accountAddress", must match: ${CAIP_ACCOUNT_ADDRESS_REGEX.toString()}`);
}
return `${namespace}:${reference}:${accountAddress}`;
}
/**
* Asset Type as defined per the CAIP-19
* {@link https://github.com/ChainAgnostic/CAIPs/blob/main/CAIPs/caip-19.md}.
*
* It defines a way to uniquely identify any blockchain asset in a human-readable
* way.
*
* @param namespace - The standard (ecosystem) of similar blockchains.
* @param reference - Identity of a blockchain within a given namespace.
* @param assetNamespace - The namespace domain of an asset.
* @param assetReference - The identity of an asset within a given namespace.
* @throws {@link Error}
* This exception is thrown if the inputs do not comply with the CAIP-19
* syntax specification
* {@link https://github.com/ChainAgnostic/CAIPs/blob/main/CAIPs/caip-19.md#syntax}.
* @returns A CAIP asset type.
*/
export function toCaipAssetType(namespace, reference, assetNamespace, assetReference) {
if (!isCaipNamespace(namespace)) {
throw new Error(`Invalid "namespace", must match: ${CAIP_NAMESPACE_REGEX.toString()}`);
}
if (!isCaipReference(reference)) {
throw new Error(`Invalid "reference", must match: ${CAIP_REFERENCE_REGEX.toString()}`);
}
if (!isCaipAssetNamespace(assetNamespace)) {
throw new Error(`Invalid "assetNamespace", must match: ${CAIP_ASSET_NAMESPACE_REGEX.toString()}`);
}
if (!isCaipAssetReference(assetReference)) {
throw new Error(`Invalid "assetReference", must match: ${CAIP_ASSET_REFERENCE_REGEX.toString()}`);
}
return `${namespace}:${reference}/${assetNamespace}:${assetReference}`;
}
/**
* Asset ID as defined per the CAIP-19
* {@link https://github.com/ChainAgnostic/CAIPs/blob/main/CAIPs/caip-19.md}.
*
* It defines a way to uniquely identify any blockchain asset in a human-readable
* way.
*
* @param namespace - The standard (ecosystem) of similar blockchains.
* @param reference - Identity of a blockchain within a given namespace.
* @param assetNamespace - The namespace domain of an asset.
* @param assetReference - The identity of an asset within a given namespace.
* @param tokenId - The unique identifier for an addressable asset of a given type.
* @throws {@link Error}
* This exception is thrown if the inputs do not comply with the CAIP-19
* syntax specification
* {@link https://github.com/ChainAgnostic/CAIPs/blob/main/CAIPs/caip-19.md#syntax}.
* @returns A CAIP asset ID.
*/
export function toCaipAssetId(namespace, reference, assetNamespace, assetReference, tokenId) {
if (!isCaipNamespace(namespace)) {
throw new Error(`Invalid "namespace", must match: ${CAIP_NAMESPACE_REGEX.toString()}`);
}
if (!isCaipReference(reference)) {
throw new Error(`Invalid "reference", must match: ${CAIP_REFERENCE_REGEX.toString()}`);
}
if (!isCaipAssetNamespace(assetNamespace)) {
throw new Error(`Invalid "assetNamespace", must match: ${CAIP_ASSET_NAMESPACE_REGEX.toString()}`);
}
if (!isCaipAssetReference(assetReference)) {
throw new Error(`Invalid "assetReference", must match: ${CAIP_ASSET_REFERENCE_REGEX.toString()}`);
}
if (!isCaipTokenId(tokenId)) {
throw new Error(`Invalid "tokenId", must match: ${CAIP_TOKEN_ID_REGEX.toString()}`);
}
return `${namespace}:${reference}/${assetNamespace}:${assetReference}/${tokenId}`;
}
//# sourceMappingURL=caip-types.mjs.map