From 14e607a1e8fb544c59d8c997b7b01c0367231f27 Mon Sep 17 00:00:00 2001 From: bitbeckers Date: Mon, 19 Aug 2024 14:53:14 +0200 Subject: [PATCH] chore(deploy): op mainnet and updated fee recipient b-sep --- contracts/hardhat.config.cts | 6 +- contracts/package.json | 2 +- .../deployment-marketplace-base-sepolia.json | 8 +- ...ployment-marketplace-optimism-mainnet.json | 55 +++++ contracts/src/deployments/index.ts | 10 +- contracts/src/index.ts | 1 + contracts/tasks/config.ts | 2 +- contracts/tasks/deploy-fee-recipient.ts | 190 ++++++++++++++++++ contracts/tasks/index.ts | 1 + 9 files changed, 263 insertions(+), 12 deletions(-) create mode 100644 contracts/src/deployments/deployment-marketplace-optimism-mainnet.json create mode 100644 contracts/tasks/deploy-fee-recipient.ts diff --git a/contracts/hardhat.config.cts b/contracts/hardhat.config.cts index 97eb6fd8..12f16ae9 100644 --- a/contracts/hardhat.config.cts +++ b/contracts/hardhat.config.cts @@ -83,8 +83,7 @@ function getChainConfig(chain: keyof typeof chainIds) { if (chain === "optimism-mainnet") { config = { ...config, - url: "https://virtual.optimism.rpc.tenderly.co/41aca07e-03d1-4a5c-807a-e43c1777100a" - // url: `https://opt-mainnet.g.alchemy.com/v2/${ALCHEMY_API_KEY}`, + url: `https://opt-mainnet.g.alchemy.com/v2/${ALCHEMY_API_KEY}`, }; } @@ -207,9 +206,6 @@ const config: HardhatUserConfig = { path: "m/44'/60'/0'/0", }, chainId: chainIds.hardhat, - forking: { - url: `https://base-sepolia.g.alchemy.com/v2/${ALCHEMY_API_KEY}`, - }, }, localhost: { accounts: { diff --git a/contracts/package.json b/contracts/package.json index 4997625c..647817e0 100644 --- a/contracts/package.json +++ b/contracts/package.json @@ -1,7 +1,7 @@ { "name": "@hypercerts-org/contracts", "description": "EVM compatible protocol for managing impact claims", - "version": "2.0.0-alpha.4", + "version": "2.0.0-alpha.5", "author": { "name": "Hypercerts Foundation", "url": "https://github.com/hypercerts-org/hypercerts" diff --git a/contracts/src/deployments/deployment-marketplace-base-sepolia.json b/contracts/src/deployments/deployment-marketplace-base-sepolia.json index 16baac1f..d237adf4 100644 --- a/contracts/src/deployments/deployment-marketplace-base-sepolia.json +++ b/contracts/src/deployments/deployment-marketplace-base-sepolia.json @@ -7,11 +7,11 @@ "tx": "0x61ffc042c14063f0c04297350fb9b314559a2d661bc1a38e663639a87b33a5aa" }, "ProtocolFeeRecipient": { - "address": "0x5858053C0A20Ff1cBb00bbb58FAc7A575883F628", + "address": "0x25C7f07cd5461E95E48aFf54ea7D160Ed8d1E621", "fullNamespace": "ProtocolFeeRecipient", - "args": ["0xe518aED97D9d45174a06bB8EF663B4fB51330725", "0x7b79995e5f793A07Bc00c21412e50Ecae098E7f9"], - "encodedArgs": "0xe518aed97d9d45174a06bb8ef663b4fb513307257b79995e5f793a07bc00c21412e50ecae098e7f9", - "tx": "0xdccdf1b9feefdd3cb884b285f02a56bd3df8396f73891c8e6cff8792bb628a6c" + "args": ["0xe518aED97D9d45174a06bB8EF663B4fB51330725", "0x4200000000000000000000000000000000000006"], + "encodedArgs": "0xe518aed97d9d45174a06bb8ef663b4fb513307254200000000000000000000000000000000000006", + "tx": "0x74428db26a26f68aabcfd2397ca83d56a5a2f9aa8c6a56f34128e4a88ff88663" }, "HypercertExchange": { "address": "0x5DD43eff9FCC6F70564794e997A47722fE315847", diff --git a/contracts/src/deployments/deployment-marketplace-optimism-mainnet.json b/contracts/src/deployments/deployment-marketplace-optimism-mainnet.json new file mode 100644 index 00000000..5738f382 --- /dev/null +++ b/contracts/src/deployments/deployment-marketplace-optimism-mainnet.json @@ -0,0 +1,55 @@ +{ + "TransferManager": { + "address": "0x658c1695DCb298E57e6144F6dA3e83DdCF5e2BaB", + "fullNamespace": "TransferManager", + "args": ["0xdc6d6f9ab5fcc398b92b017e8482749ae5afbf35"], + "encodedArgs": "0xdc6d6f9ab5fcc398b92b017e8482749ae5afbf35", + "tx": "0x2f991683f500fafe1bbae84dd790d247195f13bf40847dca5db266ad886b607e" + }, + "ProtocolFeeRecipient": { + "address": "0x4d99FE0b683874A6FC78A9FA4Fb677AdFc460Bd0", + "fullNamespace": "ProtocolFeeRecipient", + "args": ["0xE7C4531ad8828794904D332a12702beC8ff1A498", "0x4200000000000000000000000000000000000006"], + "encodedArgs": "0xe7c4531ad8828794904d332a12702bec8ff1a4984200000000000000000000000000000000000006", + "tx": "0xbad35b553a07496fb8a9f4b5703957febc5fa6fb3f16849ca42975c5c10cfe7d" + }, + "HypercertExchange": { + "address": "0x2F7Ab1844594112E00708e18835ba2e731880Db1", + "fullNamespace": "LooksRareProtocol", + "args": [ + "0xdc6d6f9ab5fcc398b92b017e8482749ae5afbf35", + "0x4d99FE0b683874A6FC78A9FA4Fb677AdFc460Bd0", + "0x658c1695DCb298E57e6144F6dA3e83DdCF5e2BaB", + "0x4200000000000000000000000000000000000006" + ], + "encodedArgs": "0xdc6d6f9ab5fcc398b92b017e8482749ae5afbf354d99fe0b683874a6fc78a9fa4fb677adfc460bd0658c1695dcb298e57e6144f6da3e83ddcf5e2bab4200000000000000000000000000000000000006", + "tx": "0xe9f7016b0ca1d9c3c2087ecc42ee8945f120ea5aa9befb0079e023d23d8a15ec" + }, + "RoyaltyFeeRegistry": { + "address": "0xd97b92B740EAf655DFf4f93B0D6D38232cfE84C6", + "fullNamespace": "RoyaltyFeeRegistry", + "args": ["1000"], + "encodedArgs": "0x00000000000000000000000000000000000000000000000000000000000003e8", + "tx": "0x184e33f1ed0dc803a64d1be39758414382393a3797f1a18fe8eb2df1ba249034" + }, + "OrderValidator": { + "address": "0x3B51f8c645b6d1894431A11109787c8814D22C32", + "fullNamespace": "OrderValidatorV2A", + "args": ["0x2F7Ab1844594112E00708e18835ba2e731880Db1"], + "encodedArgs": "0x2f7ab1844594112e00708e18835ba2e731880db1" + }, + "CreatorFeeManager": { + "address": "0x2585159c52180f81a7a5b26acea70d398e3a72f5", + "fullNamespace": "CreatorFeeManagerWithRoyalties", + "args": ["0xd97b92B740EAf655DFf4f93B0D6D38232cfE84C6"], + "encodedArgs": "0xd97b92b740eaf655dff4f93b0d6d38232cfe84c6", + "tx": "0xe72d790b946409a94241eac77bbf6c98be2b7e0bed493842d172ab00b31e2320" + }, + "StrategyHypercertFractionOffer": { + "address": "0x9325027afcc9e86285070db2111d48005006026d", + "fullNamespace": "StrategyHypercertFractionOffer", + "args": [], + "encodedArgs": "0x", + "tx": "0x96ffab4e6d2d5e068ebeafcaf616586f545346bac25ae7c39a942f0e594ff8c0" + } +} diff --git a/contracts/src/deployments/index.ts b/contracts/src/deployments/index.ts index 440cbc63..64c7f776 100644 --- a/contracts/src/deployments/index.ts +++ b/contracts/src/deployments/index.ts @@ -1,8 +1,16 @@ -import deployments_marketplace_base_sepolia from "./deployment-marketplace-base-sepolia.json" +import deployments_marketplace_base_sepolia from "./deployment-marketplace-base-sepolia.json"; +import deployments_marketplace_optimism_mainnet from "./deployment-marketplace-optimism-mainnet.json"; import deployments_marketplace_sepolia from "./deployment-marketplace-sepolia.json"; import deployments_protocol from "./deployments-protocol.json"; const deployments_marketplace = { + "10": { + TransferManager: deployments_marketplace_optimism_mainnet.TransferManager.address, + HypercertExchange: deployments_marketplace_optimism_mainnet.HypercertExchange.address, + OrderValidatorV2A: deployments_marketplace_optimism_mainnet.OrderValidator.address, + RoyaltyFeeRegistry: deployments_marketplace_optimism_mainnet.RoyaltyFeeRegistry.address, + StrategyHypercertFractionOffer: deployments_marketplace_optimism_mainnet.StrategyHypercertFractionOffer.address, + }, "84532": { TransferManager: deployments_marketplace_base_sepolia.TransferManager.address, HypercertExchange: deployments_marketplace_base_sepolia.HypercertExchange.address, diff --git a/contracts/src/index.ts b/contracts/src/index.ts index cb583a5c..e25bc80c 100644 --- a/contracts/src/index.ts +++ b/contracts/src/index.ts @@ -61,6 +61,7 @@ export type DeployedChains = keyof typeof DEPLOYMENTS.protocol; const deployments = { 10: { ...DEPLOYMENTS.protocol["10"], + ...DEPLOYMENTS.marketplace["10"], }, 42220: { ...DEPLOYMENTS.protocol[42220], diff --git a/contracts/tasks/config.ts b/contracts/tasks/config.ts index 4c3f7d7a..c7de1c04 100644 --- a/contracts/tasks/config.ts +++ b/contracts/tasks/config.ts @@ -5,7 +5,7 @@ const WETH: TokenAddressType = { hardhat: "0x7b79995e5f793A07Bc00c21412e50Ecae098E7f9", //dummy sepolia: "0x7b79995e5f793A07Bc00c21412e50Ecae098E7f9", "optimism-mainnet": "0x4200000000000000000000000000000000000006", - "base-sepolia": "0x7b79995e5f793A07Bc00c21412e50Ecae098E7f9", + "base-sepolia": "0x4200000000000000000000000000000000000006", }; // LINK faucet for Sepolia: https://faucets.chain.link/ diff --git a/contracts/tasks/deploy-fee-recipient.ts b/contracts/tasks/deploy-fee-recipient.ts new file mode 100644 index 00000000..75bff887 --- /dev/null +++ b/contracts/tasks/deploy-fee-recipient.ts @@ -0,0 +1,190 @@ +import { task } from "hardhat/config"; +import { solidityPacked } from "ethers"; +import { + getContractAddress, + slice, + encodeDeployData, + getContract, + WalletClient, + encodePacked, + PublicClient, +} from "viem"; +import { writeFile } from "node:fs/promises"; +import { getAdminAccount, getFeeRecipient, getTokenAddresses } from "./config"; + +function sleep(ms) { + return new Promise((resolve) => setTimeout(resolve, ms)); +} + +const getCreate2Address = async ( + deployer: WalletClient, + factory: `0x${string}`, + bytecode: `0x${string}`, + salt: `0x${string}`, +) => { + if (!deployer.account?.address) { + throw new Error("Deployer account is undefined"); + } + + const address = getContractAddress({ + from: factory, + salt, + opcode: "CREATE2", + bytecode, + }); + return { address, salt, deployData: bytecode }; +}; + +const runCreate2Deployment = async ( + publicClient: PublicClient, + create2Instance: ReturnType, + contractName: string, + create2: { + address: `0x${string}`; + salt: `0x${string}`; + deployData: `0x${string}`; + }, + args: string[], +) => { + console.log(`deploying ${contractName} with args: ${args}`); + const { request } = await publicClient.simulateContract({ + address: create2Instance.address, + abi: create2Instance.abi, + functionName: "safeCreate2", + args: [create2.salt, create2.deployData], + account: "0xdc6d6f9ab5fcc398b92b017e8482749ae5afbf35", + }); + + const hash = await create2Instance.write.safeCreate2([create2.salt, create2.deployData]); + const deployTx = await publicClient.waitForTransactionReceipt({ + hash, + }); + + console.log( + deployTx.status === "success" ? `Deployed ${contractName} successfully` : `Failed to deploy ${contractName}`, + ); + + return hash; +}; + +interface ContractDeployment { + address: string; + fullNamespace: string; + args: string[]; + encodedArgs: string; + tx: `0x${string}`; +} + +type ContractDeployments = { + [name: string]: ContractDeployment; +}; + +task("deploy-fee-recipient", "Deploy marketplace fee recipient and verify") + .addOptionalParam("output", "write the details of the deployment to this file if this is set") + .setAction(async ({ output }, hre) => { + //TODO multichain support + const { ethers, network, run, viem } = hre; + const create2Address = "0x0000000000ffe8b47b3e2130213b802212439497"; + const { wethAddress, usdceAddress, daiAddress } = getTokenAddresses(network.name); + + const publicClient = await viem.getPublicClient(); + const [deployer] = await viem.getWalletClients(); + const create2Instance = await viem.getContractAt("IImmutableCreate2Factory", create2Address, { + walletClient: deployer, + }); + + console.log("Deployer: ", deployer.account.address); + + const releaseVersion = "v1.0.2"; + + const salt = slice( + encodePacked(["address", "string", "address"], [deployer.account?.address, releaseVersion, create2Address]), + 0, + 32, + ); + console.log("Calculated salt: ", salt); + + const contracts: ContractDeployments = {}; + + const protocolFeeRecipientContract = await hre.artifacts.readArtifact("ProtocolFeeRecipient"); + + // Create2 ProtocolFeeRecipient + const protocolFeeRecipientArgs = [getFeeRecipient(network.name), wethAddress]; + console.log("ProtocolFeeRecipient args: ", protocolFeeRecipientArgs); + const protocolFeeRecipientCreate2 = await getCreate2Address( + deployer, + create2Address, + encodeDeployData({ + abi: protocolFeeRecipientContract.abi, + bytecode: protocolFeeRecipientContract.bytecode as `0x${string}`, + args: protocolFeeRecipientArgs, + }), + salt, + ); + + // Deploy ProtocolFeeRecipient + const protocolFeeRecipientTx = await runCreate2Deployment( + publicClient, + create2Instance, + "ProtocolFeeRecipient", + protocolFeeRecipientCreate2, + protocolFeeRecipientArgs, + ); + + // Add to deployed contracts object + contracts.ProtocolFeeRecipient = { + address: protocolFeeRecipientCreate2.address, + fullNamespace: "ProtocolFeeRecipient", + args: protocolFeeRecipientArgs, + encodedArgs: solidityPacked(["address", "address"], protocolFeeRecipientArgs), + tx: protocolFeeRecipientTx, + }; + + await sleep(2000); + + console.log("🚀 Done!"); + + // Validate + if (network.name !== "hardhat" && network.name !== "localhost") { + // Write deployment details to file + console.log("Writing deployment details to file. Make sure to update the marketplace deployment file"); + await writeFile( + `src/deployments/deployment-fee-recipeint-${network.name}.json`, + JSON.stringify(contracts), + "utf-8", + ); + + // Verify contracts + console.log("Verifying contracts..."); + for (const [name, { address, tx, args }] of Object.entries(contracts)) { + try { + console.log(`Verifying ${name}...`); + + const code = await publicClient.getBytecode({ address: address as `0x${string}` }); + if (code === "0x") { + console.log(`${name} contract deployment has not completed. waiting to verify...`); + const receipt = await publicClient.waitForTransactionReceipt({ + hash: tx, + }); + + await run("verify:verify", { + address: receipt.contractAddress, + constructorArguments: args, + }); + } else { + await run("verify:verify", { + address, + constructorArguments: args, + }); + } + } catch (error) { + const errorMessage = (error as Error).message; + + if (errorMessage.includes("Reason: Already Verified")) { + console.log("Reason: Already Verified"); + } + console.error(errorMessage); + } + } + } + }); diff --git a/contracts/tasks/index.ts b/contracts/tasks/index.ts index 85d692e5..5a260774 100644 --- a/contracts/tasks/index.ts +++ b/contracts/tasks/index.ts @@ -11,3 +11,4 @@ export * from "./unpause.js"; export * from "./validate-upgrade.js"; export * from "./deploy-marketplace.js"; export * from "./propose-owner.js"; +export * from "./deploy-fee-recipient.js";