diff --git a/contracts/.gitignore b/contracts/.gitignore index b9e5676..3eed1df 100644 --- a/contracts/.gitignore +++ b/contracts/.gitignore @@ -2,6 +2,7 @@ cache artifacts deployments/hardhat +deployments/local gas-report # Foundry diff --git a/contracts/contracts/FleekApps.sol b/contracts/contracts/FleekApps.sol new file mode 100644 index 0000000..a100dc1 --- /dev/null +++ b/contracts/contracts/FleekApps.sol @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.7; + +import "@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol"; +import "@openzeppelin/contracts/utils/Base64.sol"; +import "./util/FleekSVG.sol"; +import "./FleekERC721.sol"; + +contract FleekApps is Initializable, ERC721Upgradeable { + using Strings for address; + using Base64 for bytes; + + uint256 public bindCount; + mapping(uint256 => uint256) public bindings; + + FleekERC721 private main; + + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + function initialize(string memory _name, string memory _symbol, address _mainAddress) public initializer { + __ERC721_init(_name, _symbol); + main = FleekERC721(_mainAddress); + } + + modifier _requireMainMinted(uint256 _tokenId) { + require(main.ownerOf(_tokenId) != address(0), "Main token does not exist"); + _; + } + + function mint(address _to, uint256 _tokenId) public _requireMainMinted(_tokenId) { + _mint(_to, bindCount); + bindings[bindCount] = _tokenId; + bindCount++; + } + + function tokenURI(uint256 _bindId) public view virtual override(ERC721Upgradeable) returns (string memory) { + (string memory name, string memory ens, string memory logo, string memory color, string memory ipfsHash) = main + .getAppData(bindings[_bindId]); + + // prettier-ignore + return string(abi.encodePacked(_baseURI(), + abi.encodePacked('{', + '"owner":"', ownerOf(_bindId).toHexString(), '",', + '"name":"', name, '",', + '"image":"', FleekSVG.generateBase64(name, ens, logo, color), '",', + '"external_url":"ipfs://', ipfsHash, '"', + '}').encode() + )); + } + + function _baseURI() internal view virtual override returns (string memory) { + return "data:application/json;base64,"; + } +} diff --git a/contracts/contracts/FleekERC721.sol b/contracts/contracts/FleekERC721.sol index ccd5c5c..d5cee47 100644 --- a/contracts/contracts/FleekERC721.sol +++ b/contracts/contracts/FleekERC721.sol @@ -202,6 +202,15 @@ contract FleekERC721 is return (app.name, app.description, app.externalURL, app.ENS, app.currentBuild, app.logo, app.color); } + function getAppData( + uint256 tokenId + ) public view returns (string memory, string memory, string memory, string memory, string memory) { + _requireMinted(tokenId); + Token storage app = _apps[tokenId]; + + return (app.name, app.ENS, app.logo, app.color.toColorString(), app.builds[app.currentBuild].ipfsHash); + } + /** * @dev Returns the last minted tokenId. */ diff --git a/contracts/hardhat.config.ts b/contracts/hardhat.config.ts index 702398e..64173ad 100644 --- a/contracts/hardhat.config.ts +++ b/contracts/hardhat.config.ts @@ -9,7 +9,8 @@ import '@openzeppelin/hardhat-upgrades'; import * as dotenv from 'dotenv'; import { HardhatUserConfig } from 'hardhat/types'; import { task, types } from 'hardhat/config'; -import deploy from './scripts/deploy'; +import deployFleekERC721 from './scripts/deploy/deploy-fleek-erc721'; +import deployFleekApps from './scripts/deploy/deploy-fleek-apps'; dotenv.config(); @@ -26,7 +27,7 @@ const { } = process.env; const config: HardhatUserConfig = { - defaultNetwork: 'hardhat', + defaultNetwork: 'local', networks: { hardhat: { chainId: 31337, @@ -57,6 +58,10 @@ const config: HardhatUserConfig = { accounts: PRIVATE_KEY ? [PRIVATE_KEY] : [], chainId: 1, }, + local: { + url: 'http://localhost:8545', + accounts: PRIVATE_KEY ? [PRIVATE_KEY] : [], + }, }, gasReporter: { enabled: REPORT_GAS === 'true' || false, @@ -97,9 +102,9 @@ export default config; // Use the following command to deploy where the network flag can be replaced with the network you choose: // npx hardhat deploy --network goerli --new-proxy-instance --name "FleekNFAs" --symbol "FLKNFA" --billing "[10000, 20000]" -task('deploy', 'Deploy the contracts') +task('deploy:FleekERC721', 'Deploy the FleekERC721 contract') .addFlag('newProxyInstance', 'Force to deploy a new proxy instance') - .addOptionalParam('name', 'The collection name', 'FleekNFAs', types.string) + .addOptionalParam('name', 'The collection name', 'Fleek NFAs', types.string) .addOptionalParam('symbol', 'The collection symbol', 'FLKNFA', types.string) .addOptionalParam( 'billing', @@ -107,4 +112,10 @@ task('deploy', 'Deploy the contracts') [], types.json ) - .setAction(deploy); + .setAction(deployFleekERC721); + +task('deploy:FleekApps', 'Deploy the FleekApps contract') + .addFlag('newProxyInstance', 'Force to deploy a new proxy instance') + .addOptionalParam('name', 'The collection name', 'NFA - Apps', types.string) + .addOptionalParam('symbol', 'The collection symbol', 'NFAA', types.string) + .setAction(deployFleekApps); diff --git a/contracts/package.json b/contracts/package.json index 4fbc8cb..327db0d 100644 --- a/contracts/package.json +++ b/contracts/package.json @@ -6,13 +6,11 @@ "scripts": { "test": "yarn test:hardhat && yarn test:foundry", "test:foundry": "forge test -vvv --fork-url mainnet --fork-block-number 16876149", - "test:hardhat": "hardhat test", + "test:hardhat": "hardhat test --network hardhat", "format": "prettier --write \"./**/*.{js,json,sol,ts}\"", "node:hardhat": "hardhat node", - "deploy:hardhat": "hardhat deploy --network hardhat", - "deploy:mumbai": "hardhat deploy --network mumbai", - "deploy:sepolia": "hardhat deploy --network sepolia", - "deploy:goerli": "hardhat deploy --network goerli", + "deploy:FleekERC721": "hardhat deploy:FleekERC721", + "deploy:FleekApps": "hardhat deploy:FleekApps", "compile": "hardhat compile", "verify:mumbai": "npx hardhat run ./scripts/verify.js --network mumbai", "verify:goerli": "npx hardhat run ./scripts/verify.js --network goerli", diff --git a/contracts/scripts/deploy.js b/contracts/scripts/deploy.js deleted file mode 100644 index 20a7917..0000000 --- a/contracts/scripts/deploy.js +++ /dev/null @@ -1,105 +0,0 @@ -const { - deployStore, - getCurrentAddressIfSameBytecode, -} = require('./utils/deploy-store'); -const { getProxyAddress, proxyStore } = require('./utils/proxy-store'); - -// --- Script Settings --- -const CONTRACT_NAME = 'FleekERC721'; -const DEFAULT_PROXY_SETTINGS = { - unsafeAllow: ['external-library-linking'], -}; -const LIBRARIES_TO_DEPLOY = ['FleekSVG']; - -const libraryDeployment = async (hre) => { - console.log('Deploying Libraries...'); - const libraries = {}; - - for (const lib of LIBRARIES_TO_DEPLOY) { - const libAddress = await getCurrentAddressIfSameBytecode(lib); - if (libAddress) { - console.log(`Library "${lib}" already deployed at ${libAddress}`); - libraries[lib] = libAddress; - continue; - } - const libContract = await hre.ethers.getContractFactory(lib); - const libInstance = await libContract.deploy(); - await libInstance.deployed(); - await deployStore(hre.network.name, lib, libInstance, false); - console.log(`Library "${lib}" deployed at ${libInstance.address}`); - libraries[lib] = libInstance.address; - } - - return libraries; -}; - -module.exports = async (taskArgs, hre) => { - const { newProxyInstance, name, symbol, billing } = taskArgs; - const network = hre.network.name; - - console.log(':: Starting Deployment ::'); - console.log('Network:', network); - console.log('Contract:', CONTRACT_NAME); - console.log(':: Arguments ::'); - console.log(taskArgs); - console.log(); - - const deployArguments = [name, symbol, billing]; - - const libraries = await libraryDeployment(hre); - - const Contract = await ethers.getContractFactory(CONTRACT_NAME, { - libraries, - }); - const proxyAddress = await getProxyAddress(CONTRACT_NAME, network); - - let deployResult; - - try { - if (!proxyAddress || newProxyInstance) - throw new Error('new-proxy-instance'); - console.log(`Trying to upgrade proxy contract at: "${proxyAddress}"`); - deployResult = await upgrades.upgradeProxy( - proxyAddress, - Contract, - DEFAULT_PROXY_SETTINGS - ); - - console.log('\x1b[32m'); - console.log( - `Contract ${CONTRACT_NAME} upgraded at "${deployResult.address}" by account "${deployResult.signer.address}"` - ); - console.log('\x1b[0m'); - } catch (e) { - if ( - e.message === 'new-proxy-instance' || - e.message.includes("doesn't look like an ERC 1967 proxy") - ) { - console.log(`Failed to upgrade proxy contract: "${e.message?.trim()}"`); - console.log('Creating new proxy contract...'); - deployResult = await upgrades.deployProxy( - Contract, - deployArguments, - DEFAULT_PROXY_SETTINGS - ); - await deployResult.deployed(); - await proxyStore(CONTRACT_NAME, deployResult.address, network); - - console.log('\x1b[32m'); - console.log( - `Contract ${CONTRACT_NAME} deployed at "${deployResult.address}" by account "${deployResult.signer.address}"` - ); - console.log('\x1b[0m'); - } else { - throw e; - } - - try { - await deployStore(network, CONTRACT_NAME, deployResult); - } catch (e) { - console.error('Could not write deploy files', e); - } - } - - return deployResult; -}; diff --git a/contracts/scripts/deploy/deploy-fleek-apps.ts b/contracts/scripts/deploy/deploy-fleek-apps.ts new file mode 100644 index 0000000..acc8087 --- /dev/null +++ b/contracts/scripts/deploy/deploy-fleek-apps.ts @@ -0,0 +1,31 @@ +import { HardhatRuntimeEnvironment } from 'hardhat/types'; +import { deployLibraries } from './deploy-libraries'; +import { deployContractWithProxy } from './deploy-proxy-contract'; +import { getContract } from '../util'; +import { Contract } from 'ethers'; + +type TaskArgs = { + newProxyInstance: boolean; + name: string; + symbol: string; +}; + +export default async ( + { newProxyInstance, name, symbol }: TaskArgs, + hre: HardhatRuntimeEnvironment +): Promise => { + console.log('Deploying FleekApps...'); + const libraries = await deployLibraries(['FleekSVG'], hre); + + const mainContract = await getContract('FleekERC721'); + + return deployContractWithProxy( + { + name: 'FleekApps', + newProxyInstance, + args: [name, symbol, mainContract.address], + libraries, + }, + hre + ); +}; diff --git a/contracts/scripts/deploy/deploy-fleek-erc721.ts b/contracts/scripts/deploy/deploy-fleek-erc721.ts new file mode 100644 index 0000000..14cd80a --- /dev/null +++ b/contracts/scripts/deploy/deploy-fleek-erc721.ts @@ -0,0 +1,29 @@ +import { HardhatRuntimeEnvironment } from 'hardhat/types'; +import { deployLibraries } from './deploy-libraries'; +import { deployContractWithProxy } from './deploy-proxy-contract'; +import { Contract } from 'ethers'; + +type TaskArgs = { + newProxyInstance: boolean; + name: string; + symbol: string; + billing: number[]; +}; + +export default async ( + { newProxyInstance, name, symbol, billing }: TaskArgs, + hre: HardhatRuntimeEnvironment +): Promise => { + console.log('Deploying FleekERC721...'); + const libraries = await deployLibraries(['FleekSVG'], hre); + + return deployContractWithProxy( + { + name: 'FleekERC721', + newProxyInstance, + args: [name, symbol, billing], + libraries, + }, + hre + ); +}; diff --git a/contracts/scripts/deploy/deploy-libraries.ts b/contracts/scripts/deploy/deploy-libraries.ts new file mode 100644 index 0000000..349f77d --- /dev/null +++ b/contracts/scripts/deploy/deploy-libraries.ts @@ -0,0 +1,30 @@ +import { + deployStore, + getCurrentAddressIfSameBytecode, +} from '../utils/deploy-store'; +import { HardhatRuntimeEnvironment } from 'hardhat/types'; + +export const deployLibraries = async ( + librariesToDeploy: string[], + hre: HardhatRuntimeEnvironment +) => { + console.log('Deploying Libraries...'); + const libraries: Record = {}; + + for (const lib of librariesToDeploy) { + const libAddress: string = await getCurrentAddressIfSameBytecode(lib); + if (libAddress) { + console.log(`Library "${lib}" already deployed at ${libAddress}`); + libraries[lib] = libAddress; + continue; + } + const libContract = await hre.ethers.getContractFactory(lib); + const libInstance = await libContract.deploy(); + await libInstance.deployed(); + await deployStore(hre.network.name, lib, libInstance, false); + console.log(`Library "${lib}" deployed at ${libInstance.address}`); + libraries[lib] = libInstance.address; + } + + return libraries; +}; diff --git a/contracts/scripts/deploy/deploy-proxy-contract.ts b/contracts/scripts/deploy/deploy-proxy-contract.ts new file mode 100644 index 0000000..fc806ca --- /dev/null +++ b/contracts/scripts/deploy/deploy-proxy-contract.ts @@ -0,0 +1,88 @@ +import { getProxyAddress, proxyStore } from '../utils/proxy-store'; +import { deployStore } from '../utils/deploy-store'; +import { UpgradeProxyOptions } from '@openzeppelin/hardhat-upgrades/dist/utils'; +import { Contract } from 'ethers'; +import { HardhatRuntimeEnvironment } from 'hardhat/types'; + +const DEFAULT_PROXY_SETTINGS: UpgradeProxyOptions = { + unsafeAllow: ['external-library-linking'], +}; + +type DeployContractArgs = { + name: string; + newProxyInstance: boolean; + args: unknown[]; + libraries?: Record; +}; + +export const deployContractWithProxy = async ( + { name, newProxyInstance, args, libraries }: DeployContractArgs, + hre: HardhatRuntimeEnvironment +): Promise => { + // const { newProxyInstance, name, symbol, billing } = taskArgs; + const network = hre.network.name; + + console.log(`Deploying: ${name}`); + console.log('Arguments:', args); + console.log(); + + const Contract = await hre.ethers.getContractFactory(name, { + libraries, + }); + const proxyAddress = await getProxyAddress(name, network); + + let deployResult; + + try { + if (!proxyAddress || newProxyInstance) + throw new Error('new-proxy-instance'); + console.log(`Trying to upgrade proxy contract at: "${proxyAddress}"`); + deployResult = await hre.upgrades.upgradeProxy( + proxyAddress, + Contract, + DEFAULT_PROXY_SETTINGS + ); + + console.log('\x1b[32m'); + console.log( + `Contract ${name} upgraded at "${ + deployResult.address + }" by account "${await deployResult.signer.getAddress()}"` + ); + console.log('\x1b[0m'); + } catch (e) { + if ( + e instanceof Error && + (e.message === 'new-proxy-instance' || + e.message.includes("doesn't look like an ERC 1967 proxy")) + ) { + console.log(`Failed to upgrade proxy contract: "${e.message?.trim()}"`); + console.log('Creating new proxy contract...'); + deployResult = await hre.upgrades.deployProxy( + Contract, + args, + DEFAULT_PROXY_SETTINGS + ); + await deployResult.deployed(); + await proxyStore(name, deployResult.address, network); + + console.log('\x1b[32m'); + console.log( + `Contract ${name} deployed at "${ + deployResult.address + }" by account "${await deployResult.signer.getAddress()}"` + ); + console.log('\x1b[0m'); + } else { + throw e; + } + + try { + await deployStore(network, name, deployResult); + } catch (e) { + console.error('Could not write deploy files', e); + } + } + + return deployResult; +}; diff --git a/contracts/scripts/generate-image.ts b/contracts/scripts/generate-image.ts new file mode 100644 index 0000000..1a89553 --- /dev/null +++ b/contracts/scripts/generate-image.ts @@ -0,0 +1,18 @@ +// npx hardhat run scripts/generate-image.ts --network local + +import { getContract } from './util'; + +export const generateImage = async ( + name: string, + ens: string, + logo: string, + color: string +) => { + const contract = await getContract('FleekSVG'); + + const svg = await contract.generateBase64(name, ens, logo, color); + + console.log('SVG:', svg); +}; + +generateImage('Fleek', '', '', '#123456'); diff --git a/contracts/scripts/get-app.ts b/contracts/scripts/get-app.ts new file mode 100644 index 0000000..be5298e --- /dev/null +++ b/contracts/scripts/get-app.ts @@ -0,0 +1,15 @@ +// npx hardhat run scripts/get-app.ts --network local + +import { getContract, parseDataURI } from './util'; + +const getApp = async (tokenId: number) => { + const contract = await getContract('FleekApps'); + + const transaction = await contract.tokenURI(tokenId); + + const parsed = parseDataURI(transaction); + + console.log('App:', parsed); +}; + +getApp(0); diff --git a/contracts/scripts/mint-app.ts b/contracts/scripts/mint-app.ts new file mode 100644 index 0000000..0756f18 --- /dev/null +++ b/contracts/scripts/mint-app.ts @@ -0,0 +1,16 @@ +// npx hardhat run scripts/mint-app.ts --network local + +import { getContract } from './util'; + +const mintApp = async (nfaId: number) => { + const contract = await getContract('FleekApps'); + + const transaction = await contract.mint( + '0x7ed735b7095c05d78df169f991f2b7f1a1f1a049', + nfaId + ); + + console.log('Minted app', transaction.hash); +}; + +mintApp(0); diff --git a/contracts/scripts/mint.js b/contracts/scripts/mint.js index de0708b..764b673 100644 --- a/contracts/scripts/mint.js +++ b/contracts/scripts/mint.js @@ -44,8 +44,9 @@ const DEFAULT_MINTS = { 'aave', // name 'Earn interest, borrow assets, and build applications', // description 'https://aave.com/', // external url - 'aave.eth', // ens - '6ea6ad16c46ae85faced7e50555ff7368422f57', // commit hash + '', // ens + '6ea6ad16c46ae85faced7e50555ff7368422f57', // commit hash, + 'bafybeifc5pgon43a2xoeevwq45ftwghzbgtjxc7k4dqlzhqh432wpahigm', // ipfs hash 'https://github.com/org/repo', // repo path.resolve(__dirname, '../assets/aave.svg'), // svg ], @@ -53,9 +54,10 @@ const DEFAULT_MINTS = { 'Uniswap', // name 'Swap, earn, and build on the leading decentralized crypto trading protocol', // description 'https://uniswap.org/', // external url - 'uniswap.eth', // ens + '', // ens '6ea6ad16c46ae85faced7e50555ff7368422f57', // commit hash 'https://github.com/org/repo', // repo + 'bafybeidwf6m2lhkdifuxqucgaq547bwyxk2mljwmazvhmyryjr6yjoe3nu', // ipfs hash path.resolve(__dirname, '../assets/uniswap.svg'), // svg ], yearn: [ @@ -78,7 +80,7 @@ const DEFAULT_MINTS = { ], }; -const params = DEFAULT_MINTS.fleek; +const params = DEFAULT_MINTS.uniswap; const mintTo = '0x7ED735b7095C05d78dF169F991f2b7f1A1F1A049'; const verifier = '0x7ED735b7095C05d78dF169F991f2b7f1A1F1A049'; @@ -90,11 +92,15 @@ const verifier = '0x7ED735b7095C05d78dF169F991f2b7f1A1F1A049'; console.log('SVG Path: ', svgPath); params.push(await getSVGBase64(svgPath)); console.log('SVG length: ', params[params.length - 1].length); - params.push(await getSVGColor(svgPath)); + params.push( + (await getSVGColor(svgPath)) + .reduce((a, b, i) => a | (b << ((2 - i) * 8)), 0) + .toString() + ); params.push(false); params.push(verifier); const transaction = await contract.mint(...params); - console.log('Response: ', transaction); + console.log('Response: ', transaction.hash); })(); diff --git a/contracts/scripts/owner-of.ts b/contracts/scripts/owner-of.ts new file mode 100644 index 0000000..6f6c10c --- /dev/null +++ b/contracts/scripts/owner-of.ts @@ -0,0 +1,13 @@ +// npx hardhat run scripts/owner-of.ts --network local + +import { getContract } from './util'; + +const ownerOf = async (tokenId: number) => { + const contract = await getContract('FleekERC721'); + + const owner = await contract.ownerOf(tokenId); + + console.log('Owner:', owner); +}; + +ownerOf(0); diff --git a/contracts/scripts/tokenURI.js b/contracts/scripts/tokenURI.js index 09bd7f5..a4e9af0 100644 --- a/contracts/scripts/tokenURI.js +++ b/contracts/scripts/tokenURI.js @@ -1,5 +1,5 @@ // npx hardhat run scripts/tokenURI.js --network mumbai/sepolia/goerli -const { getContract } = require('./util'); +const { getContract, parseDataURI } = require('./util'); // TODO: make this arguments const tokenId = 0; @@ -9,9 +9,7 @@ const tokenId = 0; const transaction = await contract.tokenURI(tokenId); - const parsed = JSON.parse( - Buffer.from(transaction.slice(29), 'base64').toString('utf-8') - ); + const parsed = parseDataURI(transaction); console.log('Response: ', parsed); })(); diff --git a/contracts/scripts/util.js b/contracts/scripts/util.js index efe7131..ebff9df 100644 --- a/contracts/scripts/util.js +++ b/contracts/scripts/util.js @@ -1,14 +1,26 @@ module.exports.getContract = async function (contractName) { - const proxyDeployments = - require(`../deployments/${hre.network.name}/proxy.json`)[contractName]; + const deployment = require(`../deployments/${hre.network.name}/${contractName}.json`); - if (!proxyDeployments || !proxyDeployments.length) { + if (!deployment) { throw new Error( - `No proxy deployments found for "${contractName}" under "${hre.network.name}"` + `No deployment found for "${contractName}" under "${hre.network.name}"` ); } - const latestDeployment = proxyDeployments[0]; + console.log(`Using latest deployment for "${deployment.address}":`); - return hre.ethers.getContractAt(contractName, latestDeployment.address); + return hre.ethers.getContractAt(contractName, deployment.address); +}; + +module.exports.parseDataURI = function (dataURI) { + if (!dataURI.startsWith('data:')) throw new Error('Invalid data URI'); + const content = dataURI.replace('data:', ''); + const [type, data] = content.split(';base64,'); + + switch (type) { + case 'application/json': + return JSON.parse(Buffer.from(data, 'base64').toString('utf-8')); + default: + throw new Error(`Unsupported data URI type: ${type}`); + } }; diff --git a/contracts/scripts/utils/deploy-store.js b/contracts/scripts/utils/deploy-store.js index ba3ef52..37e80d5 100644 --- a/contracts/scripts/utils/deploy-store.js +++ b/contracts/scripts/utils/deploy-store.js @@ -81,7 +81,20 @@ const getCurrentAddressIfSameBytecode = async (contractName) => { hre.network.name, contractName )); - return deployData.bytecode === bytecode ? deployData.address : null; + + if (deployData.bytecode === bytecode) { + try { + const contract = await hre.ethers.getContractAt( + contractName, + deployData.address + ); + return contract.address; + } catch { + console.log( + `Contract ${contractName} at ${deployData.address} is not deployed` + ); + } + } } return null; diff --git a/contracts/test/hardhat/scripts/deploy.ts b/contracts/test/hardhat/scripts/deploy.ts index ad6274a..9200d9b 100644 --- a/contracts/test/hardhat/scripts/deploy.ts +++ b/contracts/test/hardhat/scripts/deploy.ts @@ -2,11 +2,11 @@ import { expect } from 'chai'; import * as hre from 'hardhat'; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore -import deploy from '../../../scripts/deploy'; +import deploy from '../../../scripts/deploy/deploy-fleek-erc721'; import { getImplementationAddress } from '@openzeppelin/upgrades-core'; import { Contract } from 'ethers'; import { loadFixture } from '@nomicfoundation/hardhat-network-helpers'; -import { Errors, TestConstants } from '../contracts/FleekERC721/helpers'; +import { TestConstants } from '../contracts/FleekERC721/helpers'; const taskArgs = { newProxyInstance: false, @@ -28,7 +28,7 @@ const getImplementationContract = async ( const deployFixture = async () => { const [owner] = await hre.ethers.getSigners(); - const proxy = (await deploy(taskArgs, hre)) as Contract; + const proxy = await deploy(taskArgs, hre); const implementation = await getImplementationContract(proxy.address);