diff --git a/.env b/.env index 2c8419708b..89ec911893 100644 --- a/.env +++ b/.env @@ -12,6 +12,8 @@ VITE_APP_ALCHEMY_MAINNET_API_KEY="" VITE_APP_ALCHEMY_POLYGON_API_KEY="" # Alchemy provider API key, used on Sepolia VITE_APP_ALCHEMY_SEPOLIA_API_KEY="" +# Alchemy provider API key, used on Base Sepolia +VITE_APP_ALCHEMY_BASE_SEPOLIA_API_KEY="" # Alchemy automated testing workflows VITE_APP_ALCHEMY_TESTING_API_KEY="" @@ -21,6 +23,8 @@ VITE_APP_ETHERSCAN_MAINNET_API_KEY="" VITE_APP_ETHERSCAN_POLYGON_API_KEY="" # ABI selector, used on Sepolia VITE_APP_ETHERSCAN_SEPOLIA_API_KEY="" +# ABI selector, used on Base Sepolia +VITE_APP_ETHERSCAN_BASE_SEPOLIA_API_KEY="" # IPFS pinning VITE_APP_INFURA_IPFS_API_KEY="" diff --git a/package-lock.json b/package-lock.json index c44819cfc6..8b83859c6d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,12 +16,12 @@ "@ethersproject/providers": "^5.7.2", "@fontsource/ibm-plex-mono": "^4.5.12", "@fontsource/ibm-plex-sans": "^4.5.13", - "@fractal-framework/fractal-contracts": "^0.4.0", + "@fractal-framework/fractal-contracts": "^0.5.0", "@graphprotocol/client-apollo": "^1.0.16", "@lido-sdk/contracts": "^3.0.2", "@netlify/blobs": "^6.5.0", "@netlify/functions": "^2.6.0", - "@safe-global/safe-deployments": "^1.23.0", + "@safe-global/safe-deployments": "^1.34.0", "@safe-global/safe-ethers-lib": "^1.9.2", "@safe-global/safe-service-client": "^1.5.2", "@sentry/react": "^7.104.0", @@ -4917,9 +4917,9 @@ "integrity": "sha512-7oDAqvuIArnMJck/JBqCnQZwqL4za+5xG+1Gu4enYbGcGqmUPktiuOy1i0N3XrzrNO70ZvsSt1Rdkxr2oemE6Q==" }, "node_modules/@fractal-framework/fractal-contracts": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@fractal-framework/fractal-contracts/-/fractal-contracts-0.4.0.tgz", - "integrity": "sha512-kFtpv/pPPZ4neimnRu4ILWUyrJJlaNTP+jc2/uyfq183UxmcN35AU7eZmDfE+5pFwXaQeKioHsnNVy9wcQZNMQ==", + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@fractal-framework/fractal-contracts/-/fractal-contracts-0.5.0.tgz", + "integrity": "sha512-oQRJWVbshJu+4VCsJJkLtR1JaMbX7aCMKUTeIo1qnFu7gk94AA4eBahNDgRPYOnaYafNaUN73YaMxmUNtUqNVw==", "dependencies": { "solidity-docgen": "^0.6.0-beta.35" } @@ -10295,9 +10295,9 @@ } }, "node_modules/@safe-global/safe-deployments": { - "version": "1.23.0", - "resolved": "https://registry.npmjs.org/@safe-global/safe-deployments/-/safe-deployments-1.23.0.tgz", - "integrity": "sha512-8kyARY3DHZrAnig3LaM6AKoQtSvkhnKpyZ3jsxNCdnNb38DVuMXWcKA63UdZMWSnKJfkieVXGhof2Kt5cUHTEw==", + "version": "1.34.0", + "resolved": "https://registry.npmjs.org/@safe-global/safe-deployments/-/safe-deployments-1.34.0.tgz", + "integrity": "sha512-J55iHhB1tiNoPeVQ5s943zrfeKRYPqBtnz/EM7d878WzUmmDlTGKHN98qPYKBxkRKP1UjEWuQDrZxy80lx1rJw==", "dependencies": { "semver": "^7.3.7" } diff --git a/package.json b/package.json index 73740da9c2..3ea4ebe413 100644 --- a/package.json +++ b/package.json @@ -11,12 +11,12 @@ "@ethersproject/providers": "^5.7.2", "@fontsource/ibm-plex-mono": "^4.5.12", "@fontsource/ibm-plex-sans": "^4.5.13", - "@fractal-framework/fractal-contracts": "^0.4.0", + "@fractal-framework/fractal-contracts": "^0.5.0", "@graphprotocol/client-apollo": "^1.0.16", "@lido-sdk/contracts": "^3.0.2", "@netlify/blobs": "^6.5.0", "@netlify/functions": "^2.6.0", - "@safe-global/safe-deployments": "^1.23.0", + "@safe-global/safe-deployments": "^1.34.0", "@safe-global/safe-ethers-lib": "^1.9.2", "@safe-global/safe-service-client": "^1.5.2", "@sentry/react": "^7.104.0", diff --git a/src/providers/NetworkConfig/NetworkConfigProvider.tsx b/src/providers/NetworkConfig/NetworkConfigProvider.tsx index 910fffca8c..f66ffe1a80 100644 --- a/src/providers/NetworkConfig/NetworkConfigProvider.tsx +++ b/src/providers/NetworkConfig/NetworkConfigProvider.tsx @@ -1,15 +1,19 @@ import { Context, createContext, ReactNode, useContext, useEffect, useState } from 'react'; import { useChainId } from 'wagmi'; import { NetworkConfig } from '../../types/network'; -import { sepoliaConfig, mainnetConfig } from './networks'; -import { polygonConfig } from './networks/polygon'; +import { sepoliaConfig, mainnetConfig, polygonConfig, baseSepoliaConfig } from './networks'; export const NetworkConfigContext = createContext({} as NetworkConfig); export const useNetworkConfig = (): NetworkConfig => useContext(NetworkConfigContext as Context); -export const supportedChains: NetworkConfig[] = [mainnetConfig, sepoliaConfig, polygonConfig]; +export const supportedChains: NetworkConfig[] = [ + mainnetConfig, + sepoliaConfig, + polygonConfig, + baseSepoliaConfig, +]; const getNetworkConfig = (chainId: number) => { const foundChain = supportedChains.find(chain => chain.chainId === chainId); diff --git a/src/providers/NetworkConfig/networks/baseSepolia.ts b/src/providers/NetworkConfig/networks/baseSepolia.ts new file mode 100644 index 0000000000..8783e4f64b --- /dev/null +++ b/src/providers/NetworkConfig/networks/baseSepolia.ts @@ -0,0 +1,78 @@ +import Azorius from '@fractal-framework/fractal-contracts/deployments/baseSepolia/Azorius.json'; +import AzoriusFreezeGuard from '@fractal-framework/fractal-contracts/deployments/baseSepolia/AzoriusFreezeGuard.json'; +import ERC20Claim from '@fractal-framework/fractal-contracts/deployments/baseSepolia/ERC20Claim.json'; +import ERC20FreezeVoting from '@fractal-framework/fractal-contracts/deployments/baseSepolia/ERC20FreezeVoting.json'; +import ERC721FreezeVoting from '@fractal-framework/fractal-contracts/deployments/baseSepolia/ERC721FreezeVoting.json'; +import FractalModule from '@fractal-framework/fractal-contracts/deployments/baseSepolia/FractalModule.json'; +import FractalRegistry from '@fractal-framework/fractal-contracts/deployments/baseSepolia/FractalRegistry.json'; +import KeyValuePairs from '@fractal-framework/fractal-contracts/deployments/baseSepolia/KeyValuePairs.json'; +import LinearERC20Voting from '@fractal-framework/fractal-contracts/deployments/baseSepolia/LinearERC20Voting.json'; +import LinearVotingERC721 from '@fractal-framework/fractal-contracts/deployments/baseSepolia/LinearERC721Voting.json'; +import ModuleProxyFactory from '@fractal-framework/fractal-contracts/deployments/baseSepolia/ModuleProxyFactory.json'; +import MultisigFreezeGuard from '@fractal-framework/fractal-contracts/deployments/baseSepolia/MultisigFreezeGuard.json'; +import MultisigFreezeVoting from '@fractal-framework/fractal-contracts/deployments/baseSepolia/MultisigFreezeVoting.json'; +import VotesERC20 from '@fractal-framework/fractal-contracts/deployments/baseSepolia/VotesERC20.json'; +import VotesERC20Wrapper from '@fractal-framework/fractal-contracts/deployments/baseSepolia/VotesERC20Wrapper.json'; +import { + getProxyFactoryDeployment, + getMultiSendCallOnlyDeployment, + getSafeL2SingletonDeployment, + getCompatibilityFallbackHandlerDeployment, +} from '@safe-global/safe-deployments'; +import { baseSepolia } from 'wagmi/chains'; +import { GovernanceType } from '../../../types'; +import { NetworkConfig } from '../../../types/network'; + +const CHAIN_ID = 84532; +const SAFE_VERSION = '1.3.0'; + +export const baseSepoliaConfig: NetworkConfig = { + safeBaseURL: 'https://safe-transaction-base-sepolia.safe.global', + etherscanBaseURL: 'https://basescan.org/', + etherscanAPIUrl: `https://api.basescan.com/api?apikey=${import.meta.env.VITE_APP_ETHERSCAN_BASE_SEPOLIA_API_KEY}`, + chainId: CHAIN_ID, + name: baseSepolia.name, + addressPrefix: 'basesep', + color: 'gold.300', + nativeTokenSymbol: baseSepolia.nativeCurrency.symbol, + nativeTokenIcon: '/images/coin-icon-eth.svg', + wagmiChain: baseSepolia, + subgraphChainName: 'base-sepolia', + contracts: { + fractalAzoriusMasterCopy: Azorius.address, + fractalModuleMasterCopy: FractalModule.address, + fractalRegistry: FractalRegistry.address, + votesERC20MasterCopy: VotesERC20.address, + linearVotingERC721MasterCopy: LinearVotingERC721.address, + claimingMasterCopy: ERC20Claim.address, + azoriusFreezeGuardMasterCopy: AzoriusFreezeGuard.address, + multisigFreezeVotingMasterCopy: MultisigFreezeVoting.address, + erc20FreezeVotingMasterCopy: ERC20FreezeVoting.address, + erc721FreezeVotingMasterCopy: ERC721FreezeVoting.address, + multisigFreezeGuardMasterCopy: MultisigFreezeGuard.address, + fallbackHandler: getCompatibilityFallbackHandlerDeployment({ + version: SAFE_VERSION, + network: CHAIN_ID.toString(), + })?.networkAddresses[CHAIN_ID.toString()]!, + safe: getSafeL2SingletonDeployment({ version: SAFE_VERSION, network: CHAIN_ID.toString() }) + ?.networkAddresses[CHAIN_ID.toString()]!, + safeFactory: getProxyFactoryDeployment({ + version: SAFE_VERSION, + network: CHAIN_ID.toString(), + })?.networkAddresses[CHAIN_ID.toString()]!, + zodiacModuleProxyFactory: ModuleProxyFactory.address, + linearVotingMasterCopy: LinearERC20Voting.address, + multisend: getMultiSendCallOnlyDeployment({ + version: SAFE_VERSION, + network: CHAIN_ID.toString(), + })?.networkAddresses[CHAIN_ID.toString()]!, + votesERC20WrapperMasterCopy: VotesERC20Wrapper.address, + keyValuePairs: KeyValuePairs.address, + }, + staking: {}, + createOptions: [ + GovernanceType.MULTISIG, + GovernanceType.AZORIUS_ERC20, + GovernanceType.AZORIUS_ERC721, + ], +}; diff --git a/src/providers/NetworkConfig/networks/index.ts b/src/providers/NetworkConfig/networks/index.ts index e176e2f86c..6cbbfe96d3 100644 --- a/src/providers/NetworkConfig/networks/index.ts +++ b/src/providers/NetworkConfig/networks/index.ts @@ -1,2 +1,4 @@ export * from './sepolia'; export * from './mainnet'; +export * from './polygon'; +export * from './baseSepolia'; diff --git a/src/providers/NetworkConfig/web3-modal.config.ts b/src/providers/NetworkConfig/web3-modal.config.ts index 855397160f..6af6f19cb3 100644 --- a/src/providers/NetworkConfig/web3-modal.config.ts +++ b/src/providers/NetworkConfig/web3-modal.config.ts @@ -2,7 +2,7 @@ import { QueryClient } from '@tanstack/react-query'; import { createWeb3Modal } from '@web3modal/wagmi/react'; import { defaultWagmiConfig } from '@web3modal/wagmi/react/config'; import { http } from 'wagmi'; -import { hardhat, sepolia, mainnet, Chain, polygon } from 'wagmi/chains'; +import { hardhat, sepolia, mainnet, Chain, polygon, baseSepolia } from 'wagmi/chains'; import { supportedChains } from './NetworkConfigProvider'; const supportedWagmiChains = supportedChains.map(config => config.wagmiChain); @@ -40,6 +40,9 @@ export const wagmiConfig = defaultWagmiConfig({ [polygon.id]: http( `https://polygon-mainnet.g.alchemy.com/v2/${import.meta.env.VITE_APP_ALCHEMY_POLYGON_API_KEY}`, ), + [baseSepolia.id]: http( + `https://base-sepolia.g.alchemy.com/v2/${import.meta.env.VITE_APP_ALCHEMY_BASE_SEPOLIA_API_KEY}`, + ), }, }); diff --git a/src/vite-env.d.ts b/src/vite-env.d.ts index 08f5410bf0..cece37166b 100644 --- a/src/vite-env.d.ts +++ b/src/vite-env.d.ts @@ -8,10 +8,12 @@ interface ImportMetaEnv { readonly VITE_APP_ALCHEMY_MAINNET_API_KEY: string; readonly VITE_APP_ALCHEMY_POLYGON_API_KEY: string; readonly VITE_APP_ALCHEMY_SEPOLIA_API_KEY: string; + readonly VITE_APP_ALCHEMY_BASE_SEPOLIA_API_KEY: string; readonly VITE_APP_ETHERSCAN_MAINNET_API_KEY: string; readonly VITE_APP_ETHERSCAN_POLYGON_API_KEY: string; readonly VITE_APP_ETHERSCAN_SEPOLIA_API_KEY: string; + readonly VITE_APP_ETHERSCAN_BASE_SEPOLIA_API_KEY: string; readonly VITE_APP_INFURA_IPFS_API_KEY: string; readonly VITE_APP_INFURA_IPFS_API_SECRET: string;