import {COLLECTION_ADDRESS_PREFIX, NESTING_PREFIX} from './constants' import { addressToEvm, compareSubstrateAddresses, decodeSubstrateAddress, encodeSubstrateAddress, evmToAddress, normalizeSubstrateAddress } from './substrate' import { collectionIdAndTokenIdToNestingAddress, collectionIdToEthAddress, compareEthereumAddresses, ethAddressToCollectionId, nestingAddressToCollectionIdAndTokenId, normalizeEthereumAddress } from './ethereum' import { CrossAccountId, CrossAccountIdUncapitalized, EthAddressObj, EthAddressObjUncapitalized, SubAddressObj, SubAddressObjUncapitalized, } from "../../types"; import { substrateNormalizedWithMirrorIfEthereum, addressToCrossAccountId, addressToCrossAccountIdNormalized, guessAddressAndExtractItNormalized, guessAddressAndExtractItNormalizedSafe } from "./crossAccountId"; import * as StringUtils from './stringUtils' import * as algorithms from './imports' import * as constants from './constants' export {constants, algorithms, StringUtils} const ETH_ADDRESS_REGEX = /^0x[a-fA-F0-9]{40}$/ export type DecodeSubstrateAddressResult = { u8a: Uint8Array, hex: string, bigint: bigint } export const validate = { substrateAddress: (address: string) => { decodeSubstrateAddress(address) return true }, ethereumAddress: (address: string) => { if (!is.ethereumAddress(address)) { throw new Error(`address "${address}" is not valid ethereum address`) } return true }, collectionAddress: (address: string) => { if (!is.collectionAddress(address)) { throw new Error(`address ${address} is not a collection address`) } return true }, nestingAddress: (address: string) => { if (!is.nestingAddress(address)) { throw new Error(`address ${address} is not a nesting address`) } return true }, collectionId: (collectionId: number) => { if (!is.collectionId(collectionId)) { throw new Error(`collectionId should be a number between 0 and 0xffffffff`) } return true }, tokenId: (tokenId: number) => { if (!is.tokenId(tokenId)) { throw new Error(`collectionId should be a number between 0 and 0xffffffff`) } return true }, } export const is = { substrateAddress: (address: string): boolean => { try { decodeSubstrateAddress(address) return true } catch { return false } }, ethereumAddress: (address: string): boolean => { return typeof address === 'string' && address.length === 42 && !!address.match(ETH_ADDRESS_REGEX) }, collectionAddress: (address: string): boolean => { return is.ethereumAddress(address) && address.toLowerCase().startsWith(COLLECTION_ADDRESS_PREFIX) }, nestingAddress: (address: string): boolean => { return is.ethereumAddress(address) && address.toLowerCase().startsWith(NESTING_PREFIX) }, collectionId: (collectionId: number): boolean => { return !(typeof collectionId !== 'number' || isNaN(collectionId) || collectionId < 0 || collectionId > 0xffffffff) }, tokenId: (tokenId: number): boolean => { return !(typeof tokenId !== 'number' || isNaN(tokenId) || tokenId < 0 || tokenId > 0xffffffff) }, crossAccountId(obj: any): obj is CrossAccountId { return is.substrateAddressObject(obj) || is.ethereumAddressObject(obj) }, crossAccountIdUncapitalized(obj: any): obj is CrossAccountIdUncapitalized { return is.substrateAddressObjectUncapitalized(obj) || is.ethereumAddressObjectUncapitalized(obj) }, substrateAddressObject(obj: any): obj is SubAddressObj { return typeof obj === 'object' && typeof obj?.Substrate === 'string' && is.substrateAddress(obj.Substrate) }, ethereumAddressObject(obj: any): obj is EthAddressObj { return typeof obj === 'object' && typeof obj?.Ethereum === 'string' && is.ethereumAddress(obj.Ethereum) }, substrateAddressObjectUncapitalized(obj: any): obj is SubAddressObjUncapitalized { return typeof obj === 'object' && typeof obj?.substrate === 'string' && is.substrateAddress(obj.substrate) }, ethereumAddressObjectUncapitalized(obj: any): obj is EthAddressObjUncapitalized { return typeof obj === 'object' && typeof obj?.ethereum === 'string' && is.ethereumAddress(obj.ethereum) }, } export const collection = { idToAddress: collectionIdToEthAddress, addressToId: ethAddressToCollectionId, } export const nesting = { idsToAddress: collectionIdAndTokenIdToNestingAddress, addressToIds: nestingAddressToCollectionIdAndTokenId, } export const to = { crossAccountId: addressToCrossAccountId, crossAccountIdNormalized: addressToCrossAccountIdNormalized, substrateNormalizedOrMirrorIfEthereum: substrateNormalizedWithMirrorIfEthereum, } export const extract = { normalizedAddressFromObject: guessAddressAndExtractItNormalized, normalizedAddressFromObjectSafe: guessAddressAndExtractItNormalizedSafe, crossAccountIdFromObject: (obj: any): CrossAccountId => { return addressToCrossAccountId(guessAddressAndExtractItNormalized(obj)) }, crossAccountIdFromObjectNormalized: (obj: any): CrossAccountId => { return addressToCrossAccountId(guessAddressAndExtractItNormalized(obj)) }, } export const mirror = { substrateToEthereum: addressToEvm, ethereumToSubstrate: evmToAddress, } export const normalize = { substrateAddress: normalizeSubstrateAddress, ethereumAddress: normalizeEthereumAddress, } export const compare = { substrateAddresses: compareSubstrateAddresses, ethereumAddresses: compareEthereumAddresses, } export const substrate = { encode: encodeSubstrateAddress, decode: decodeSubstrateAddress, compare: compareSubstrateAddresses, } export const Address = { constants, is, validate, collection, nesting, to, extract, mirror, normalize, compare, substrate, algorithms, StringUtils, }