import { EvmChain } from '@axelar-network/axelarjs-sdk'; import { BigNumberish, ethers } from 'ethers'; import { normalizeChainId } from '.././utils/chainUtils'; import { DiamondCutFacet } from '../config/abi/common/facets/DiamondCutFacet'; import { DiamondLoupeFacet } from '../config/abi/common/facets/DiamondLoupeFacet'; import { ERC721AxelarBridgedableFacet } from '../config/abi/ERC721/common/facets/ERC721AxelarBridgedableFacet'; import { ERC721Facet } from '../config/abi/ERC721/common/facets/ERC721Facet'; import { ERC721LayerZeroBridgedableFacet } from '../config/abi/ERC721/common/facets/ERC721LayerZeroBridgedableFacet'; import { ERC721OmniteFacet } from '../config/abi/ERC721/common/facets/ERC721OmniteFacet'; import { ERC721Native as BaseContract, IDiamondCut, } from '../config/abi/ERC721/native/ERC721Native'; import { ERC721NativeMintableFacet } from '../config/abi/ERC721/native/facets/ERC721NativeMintableFacet'; import { ERC721NativeTokenURIFacet } from '../config/abi/ERC721/native/facets/ERC721NativeTokenURIFacet'; import { ERC721WithSlotsFacet } from '../config/abi/ERC721/native/facets/ERC721WithSlotsFacet'; import { DiamondCutFacet__factory } from '../config/abi/factories/common/facets/DiamondCutFacet__factory'; import { DiamondLoupeFacet__factory } from '../config/abi/factories/common/facets/DiamondLoupeFacet__factory'; import { ERC721AxelarBridgedableFacet__factory } from '../config/abi/factories/ERC721/common/facets/ERC721AxelarBridgedableFacet__factory'; import { ERC721Facet__factory } from '../config/abi/factories/ERC721/common/facets/ERC721Facet__factory'; import { ERC721LayerZeroBridgedableFacet__factory } from '../config/abi/factories/ERC721/common/facets/ERC721LayerZeroBridgedableFacet__factory'; import { ERC721OmniteFacet__factory } from '../config/abi/factories/ERC721/common/facets/ERC721OmniteFacet__factory'; import { ERC721Native__factory } from '../config/abi/factories/ERC721/native/ERC721Native__factory'; import { ERC721NativeMintableFacet__factory, ERC721NativeTokenURIFacet__factory, ERC721WithSlotsFacet__factory, } from '../config/abi/factories/ERC721/native/facets'; import config from '../config/config'; import { ChainId } from '../config/constants'; import { BridgeBroker } from '../types'; import { AxelarChainId, FacetCutAction, FacetId } from './constants'; import { DiamondContractInitializer } from './DiamondContractInitializer'; const iface = ERC721Native__factory.createInterface(); const diamonds = { layerZeroBridgeable: ERC721LayerZeroBridgedableFacet__factory.createInterface(), axelarBridgeable: ERC721AxelarBridgedableFacet__factory.createInterface(), withSlots: ERC721WithSlotsFacet__factory.createInterface(), common: ERC721Facet__factory.createInterface(), omnite: ERC721OmniteFacet__factory.createInterface(), nativeMintable: ERC721NativeMintableFacet__factory.createInterface(), nativeTokenURI: ERC721NativeTokenURIFacet__factory.createInterface(), diamondCut: DiamondCutFacet__factory.createInterface(), diamondLoupe: DiamondLoupeFacet__factory.createInterface(), }; export class ERC721Native extends DiamondContractInitializer< BaseContract, { layerZeroBridgeable: ERC721LayerZeroBridgedableFacet; axelarBridgeable: ERC721AxelarBridgedableFacet; withSlots: ERC721WithSlotsFacet; common: ERC721Facet; omnite: ERC721OmniteFacet; nativeMintable: ERC721NativeMintableFacet; nativeTokenURI: ERC721NativeTokenURIFacet; diamondCut: DiamondCutFacet; diamondLoupe: DiamondLoupeFacet; } > { className = ERC721Native.name; /** * Create contract instance for given signer * * @param {ethers.providers.JsonRpcSigner} signer * @param {string} address */ static async create( signer: ethers.providers.JsonRpcSigner, address: string ) { const chainId = normalizeChainId(await signer.getChainId()); if (!chainId) { throw new Error('Cannot fetch chainId from signer'); } const instance = new ERC721Native(chainId, iface, signer); instance.logCall('create', { address }); instance.address = address; instance.initialize(); instance.initializeDiamond(diamonds); return instance; } static _newInstance = (chainId: string, address: string) => { const selfInstance = new ERC721Native(chainId, iface); selfInstance.address = address; selfInstance.initialize(); selfInstance.initializeDiamond(diamonds); return selfInstance; }; static encode = async ( chainId: string, address: string, bridgeProviders: Array, name: string, symbol: string, ownerAddress: string, slotStart: number, slotEnd: number, baseTokenURI: string, contractURI: string ) => { const selfInstance = ERC721Native._newInstance(chainId, address); selfInstance.logCall('encode', { chainId, address, name, symbol, ownerAddress, slotStart, slotEnd, baseTokenURI, contractURI, }); const systemContextAddress = config.getChainConfig(chainId as ChainId) .contractAddress.systemContext; const diamondCuts: IDiamondCut.FacetCutStruct[] = [ ...(await selfInstance.getFacetCuts( FacetId.ERC721OmniteCoreFacetsPack )), ...(await selfInstance.getFacetCuts( FacetId.ERC721OmniteNativeFacetsPack )), ...(await selfInstance.getFacetCuts(FacetId.DiamondCutFacetsPack)), ]; if (bridgeProviders.includes(BridgeBroker.LayerZero)) { diamondCuts.push( ...(await selfInstance.getFacetCuts( FacetId.ERC721LayerZeroAdapterFacetsPack )) ); } if (bridgeProviders.includes(BridgeBroker.Axelar)) { diamondCuts.push( ...(await selfInstance.getFacetCuts( FacetId.ERC721AxelarAdapterFacetsPack )) ); } selfInstance.logCall('encode - result', { systemContextAddress, name, symbol, ownerAddress, contractURI, baseTokenURI, slotStart, slotEnd, diamondCuts, }); return selfInstance.contractInstance.encode( systemContextAddress, name, symbol, ownerAddress, contractURI, baseTokenURI, slotStart, slotEnd, diamondCuts ); }; static encodeRaw = async ( chainId: string, address: string, systemContextAddress: string, name: string, symbol: string, ownerAddress: string, slotStart: number, slotEnd: number, baseTokenURI: string, contractURI: string, diamondCuts: IDiamondCut.FacetCutStruct[] ) => { const selfInstance = ERC721Native._newInstance(chainId, address); selfInstance.logCall('encodeRaw', { chainId, address, systemContextAddress, name, symbol, ownerAddress, contractURI, baseTokenURI, slotStart, slotEnd, diamondCuts, }); return selfInstance.contractInstance.encode( systemContextAddress, name, symbol, ownerAddress, contractURI, baseTokenURI, slotStart, slotEnd, diamondCuts ); }; approve = async (to: string, tokenId: BigNumberish) => { return this.facets.common.approve(to, tokenId); }; /** * Move token using layer zero broker * * @param {BigNumberish} layerZeroChainId * @param {string} destinationBridge * @param {BigNumberish} tokenId * @param {BigNumberish} gasAmount * @param {BigNumberish} value */ moveToViaLayerZero = async ( layerZeroChainId: BigNumberish, destinationBridge: string, tokenId: BigNumberish, gasAmount: BigNumberish, value: BigNumberish ) => { this.logCall('moveToViaLayerZero', { layerZeroChainId, destinationBridge, tokenId, gasAmount, value, }); return this.facets.layerZeroBridgeable.moveToViaLayerZero( layerZeroChainId, destinationBridge, tokenId, gasAmount, { value } ); }; moveToViaAxelar = async ( axelarChainId: EvmChain, destinationBridge: string, tokenId: BigNumberish, value: BigNumberish ) => { this.logCall('moveToViaAxelar', { axelarChainId, destinationBridge, tokenId, value, }); return this.facets.axelarBridgeable.moveToViaAxelar( axelarChainId, destinationBridge, tokenId, { value } ); }; populateMoveToViaLayerZero = async ( layerZeroChainId: BigNumberish, destinationBridge: string, tokenId: BigNumberish, gasAmount: BigNumberish ) => { this.logCall('populateMoveToViaLayerZero', { layerZeroChainId, destinationBridge, tokenId, gasAmount, }); return this.facets.layerZeroBridgeable.populateTransaction.moveToViaLayerZero( layerZeroChainId, destinationBridge, tokenId, gasAmount ); }; mintToWithUri = async ( to: string, tokenId: BigNumberish, tokenURI: string ) => { this.logCall('mintToWithUri', { to, tokenId, tokenURI }); return this.facets.nativeMintable.mintToWithUri(to, tokenId, tokenURI, { gasLimit: 1000000, }); }; addFacet = async (facet: FacetId) => { const facetCut = await this.getFacetCuts(facet); return this.facets.diamondCut.diamondCutWithoutInit(facetCut); }; removeFacet = async (facet: FacetId) => { const facetCut = await this.getFacetCuts(facet, FacetCutAction.Remove); return this.facets.diamondCut.diamondCutWithoutInit( facetCut.map((v) => ({ ...v, facetAddress: ethers.constants.AddressZero, })) ); }; replaceFacet = async (facet: FacetId) => { const facetCut = await this.getFacetCuts(facet, FacetCutAction.Replace); return this.facets.diamondCut.diamondCutWithoutInit(facetCut); }; transfer = async (from: string, to: string, tokenId: BigNumberish) => { return this.facets.common.transferFrom(from, to, tokenId); }; /** * Mint token on another chain using layer zero * * @param {BigNumberish} layerZeroChainId * @param {string} destinationBridge * @param {BigNumberish} tokenId * @param {string} mintTo * @param {BigNumberish} gasAmount * @param {BigNumberish} value */ mintOnViaLayerZero = async ( layerZeroChainId: BigNumberish, destinationBridge: string, tokenId: BigNumberish, mintTo: string, gasAmount: BigNumberish, value: BigNumberish ) => { this.logCall('mintOnViaLayerZero', { layerZeroChainId, destinationBridge, tokenId, mintTo, gasAmount, value, }); return this.facets.layerZeroBridgeable.mintOnViaLayerZero( layerZeroChainId, destinationBridge, tokenId, mintTo, gasAmount, { value } ); }; /** * Mint token on another chain using axelar * * @param {AxelarChainId|EvmChain} axelarChainId * @param {string} destinationBridge * @param {BigNumberish} tokenId * @param {string} mintTo * @param {BigNumberish} value */ mintOnViaAxelar = async ( axelarChainId: AxelarChainId | EvmChain, destinationBridge: string, tokenId: BigNumberish, mintTo: string, value: BigNumberish ) => { this.logCall('mintOnViaLayerZero', { axelarChainId, destinationBridge, tokenId, mintTo, value, }); return this.facets.axelarBridgeable.mintOnViaAxelar( axelarChainId, destinationBridge, tokenId, mintTo, { value } ); }; /** * Returns current facet cuts for the given contract. * * @param {string} chainId * @param {string} address */ static getFacets = async (chainId: string, address: string) => { const selfInstance = ERC721Native._newInstance(chainId, address); return selfInstance.facets.diamondLoupe.facets(); }; static getSlots = async (chainId: string, address: string) => { const selfInstance = ERC721Native._newInstance(chainId, address); const [slotStart, slotEnd] = await selfInstance.facets.withSlots.getSlots(); selfInstance.logCall('slotEnd', { chainId, address, slotStart, slotEnd, }); return { slotStart, slotEnd }; }; /** * Returns collection name of the ERC721 token. * * @param {string} chainId * @param {string} address */ static getName = async (chainId: string, address: string) => { const selfInstance = ERC721Native._newInstance(chainId, address); return selfInstance.facets.common.name(); }; /** * Returns contract URI of the ERC721 token. * * @param {string} chainId * @param {string} address */ static contractURI = async (chainId: string, address: string) => { const selfInstance = ERC721Native._newInstance(chainId, address); return selfInstance.facets.omnite.contractURI(); }; /** * Returns owner of the ERC721 token id. * * @param {string} chainId * @param {string} address * @param {string} tokenId */ static ownerOf = async ( chainId: string, address: string, tokenId: string ) => { const selfInstance = ERC721Native._newInstance(chainId, address); selfInstance.logCall('ownerOf', { chainId, address, tokenId }); return selfInstance.facets.common.ownerOf(tokenId); }; static tokenURI = async ( chainId: string, address: string, tokenId: string ): Promise => { const selfInstance = ERC721Native._newInstance(chainId, address); return selfInstance.facets.nativeTokenURI.tokenURI(tokenId); }; /** * Returns collection id of the ERC721 token. * * @param {string} chainId * @param {string} address */ static collectionId = async (chainId: string, address: string) => { const selfInstance = ERC721Native._newInstance(chainId, address); selfInstance.logCall('collectionId', { chainId, address }); return selfInstance.facets.omnite.collectionId(); }; }