From ddcdc7f77955b1b8fcc8c967bee8ff7e3f2d4ed9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wiktor=20Tkaczy=C5=84ski?= Date: Mon, 19 Feb 2024 20:26:26 +0100 Subject: [PATCH] refactor: use clientConfig ethUrl for evmSlotValue and ozVotesStorageProof (#62) Predefined mapping was used initially, but as each networkConfig will have each own ethUrl we can use it as well (Starknet Goerli will be mapped to Ethereum goerli etc.). --- .changeset/slow-stingrays-smash.md | 5 ++++ apps/ui/.env | 1 - apps/ui/src/networks/starknet/actions.ts | 4 +-- apps/ui/src/networks/starknet/index.ts | 12 ++++++-- .../src/strategies/starknet/evmSlotValue.ts | 23 +++++++------- .../starknet/ozVotesStorageProof.ts | 30 +++++++++---------- .../sx.js/src/strategies/starknet/utils.ts | 18 ----------- 7 files changed, 43 insertions(+), 50 deletions(-) create mode 100644 .changeset/slow-stingrays-smash.md diff --git a/.changeset/slow-stingrays-smash.md b/.changeset/slow-stingrays-smash.md new file mode 100644 index 000000000..0a8bf40ef --- /dev/null +++ b/.changeset/slow-stingrays-smash.md @@ -0,0 +1,5 @@ +--- +"@snapshot-labs/sx": patch +--- + +use clientConfig.ethUrl instead of predefined RPC APIs for starknet strategies diff --git a/apps/ui/.env b/apps/ui/.env index 418f88ca2..ff5d59f60 100644 --- a/apps/ui/.env +++ b/apps/ui/.env @@ -1,5 +1,4 @@ VITE_ENABLED_NETWORKS= -VITE_ETH_RPC_URL=https://rpc.snapshotx.xyz VITE_MANA_URL=https://mana.pizza VITE_HIGHLIGHT_URL= VITE_IPFS_GATEWAY=snapshot.4everland.link diff --git a/apps/ui/src/networks/starknet/actions.ts b/apps/ui/src/networks/starknet/actions.ts index ea9ce0dd0..ef0093153 100644 --- a/apps/ui/src/networks/starknet/actions.ts +++ b/apps/ui/src/networks/starknet/actions.ts @@ -46,13 +46,11 @@ export function createActions( networkId: NetworkID, starkProvider: RpcProvider, helpers: NetworkHelpers, - { l1ChainId }: { l1ChainId: number } + { l1ChainId, ethUrl }: { l1ChainId: number; ethUrl: string } ): NetworkActions { const networkConfig = CONFIGS[networkId]; if (!networkConfig) throw new Error(`Unsupported network ${networkId}`); - const ethUrl: string = import.meta.env.VITE_ETH_RPC_URL; - const l1Provider = getProvider(l1ChainId); const clientConfig = { diff --git a/apps/ui/src/networks/starknet/index.ts b/apps/ui/src/networks/starknet/index.ts index 5f27c537c..4251a53b3 100644 --- a/apps/ui/src/networks/starknet/index.ts +++ b/apps/ui/src/networks/starknet/index.ts @@ -18,6 +18,7 @@ type Metadata = { baseChainId: number; baseNetworkId: NetworkID; rpcUrl: string; + ethRpcUrl: string; explorerUrl: string; apiUrl: string; }; @@ -29,6 +30,7 @@ export const METADATA: Partial> = { baseChainId: 1, baseNetworkId: 'eth', rpcUrl: `https://starknet-mainnet.infura.io/v3/${import.meta.env.VITE_INFURA_API_KEY}`, + ethRpcUrl: `https://mainnet.infura.io/v3/${import.meta.env.VITE_INFURA_API_KEY}`, apiUrl: 'https://api-1.snapshotx.xyz', explorerUrl: 'https://starkscan.co' }, @@ -38,6 +40,7 @@ export const METADATA: Partial> = { baseChainId: 5, baseNetworkId: 'gor', rpcUrl: `https://starknet-goerli.infura.io/v3/${import.meta.env.VITE_INFURA_API_KEY}`, + ethRpcUrl: `https://goerli.infura.io/v3/${import.meta.env.VITE_INFURA_API_KEY}`, apiUrl: 'https://testnet-api-1.snapshotx.xyz', explorerUrl: 'https://testnet.starkscan.co' }, @@ -47,6 +50,7 @@ export const METADATA: Partial> = { baseChainId: 11155111, baseNetworkId: 'sep', rpcUrl: `https://starknet-sepolia.infura.io/v3/${import.meta.env.VITE_INFURA_API_KEY}`, + ethRpcUrl: `https://sepolia.infura.io/v3/${import.meta.env.VITE_INFURA_API_KEY}`, apiUrl: 'https://testnet-api-1.snapshotx.xyz', explorerUrl: 'https://sepolia.starkscan.co' } @@ -56,7 +60,8 @@ export function createStarknetNetwork(networkId: NetworkID): Network { const metadata = METADATA[networkId]; if (!metadata) throw new Error(`Unsupported network ${networkId}`); - const { name, chainId, baseChainId, baseNetworkId, rpcUrl, apiUrl, explorerUrl } = metadata; + const { name, chainId, baseChainId, baseNetworkId, rpcUrl, ethRpcUrl, apiUrl, explorerUrl } = + metadata; const provider = createProvider(rpcUrl); const api = createApi(apiUrl, networkId); @@ -138,7 +143,10 @@ export function createStarknetNetwork(networkId: NetworkID): Network { hasReceive: true, supportsSimulation: true, managerConnectors: STARKNET_CONNECTORS, - actions: createActions(networkId, provider, helpers, { l1ChainId: baseChainId }), + actions: createActions(networkId, provider, helpers, { + l1ChainId: baseChainId, + ethUrl: ethRpcUrl + }), api, constants, helpers diff --git a/packages/sx.js/src/strategies/starknet/evmSlotValue.ts b/packages/sx.js/src/strategies/starknet/evmSlotValue.ts index 8d3443346..01133a033 100644 --- a/packages/sx.js/src/strategies/starknet/evmSlotValue.ts +++ b/packages/sx.js/src/strategies/starknet/evmSlotValue.ts @@ -1,10 +1,11 @@ /* eslint-disable @typescript-eslint/no-unused-vars */ import { Contract, CallData } from 'starknet'; +import { StaticJsonRpcProvider } from '@ethersproject/providers'; import EVMSlotValue from './abis/EVMSlotValue.json'; import SpaceAbi from '../../clients/starknet/starknet-tx/abis/Space.json'; import { getUserAddressEnum } from '../../utils/starknet-enums'; -import { getEthProvider, getSlotKey, getBinaryTree } from './utils'; +import { getSlotKey, getBinaryTree } from './utils'; import type { ClientConfig, Envelope, Strategy, Propose, Vote } from '../../types'; export default function createEvmSlotValueStrategy({ @@ -17,9 +18,10 @@ export default function createEvmSlotValueStrategy({ voterAddress: string, slotIndex: number, blockNumber: number, + ethUrl: string, chainId: number ) { - const provider = getEthProvider(chainId); + const provider = new StaticJsonRpcProvider(ethUrl, chainId); const proof = await provider.send('eth_getProof', [ l1TokenAddress, @@ -59,17 +61,15 @@ export default function createEvmSlotValueStrategy({ const voteEnvelope = envelope as Envelope; - const spaceContract = new Contract( - SpaceAbi, - voteEnvelope.data.space, - clientConfig.starkProvider - ); + const { starkProvider, ethUrl, networkConfig } = clientConfig; + + const spaceContract = new Contract(SpaceAbi, voteEnvelope.data.space, starkProvider); const proposalStruct = (await spaceContract.call('proposals', [ voteEnvelope.data.proposal ])) as any; const startTimestamp = proposalStruct.start_timestamp; - const { herodotusAccumulatesChainId: chainId } = clientConfig.networkConfig; + const { herodotusAccumulatesChainId: chainId } = networkConfig; const { contractAddress, slotIndex } = metadata; const tree = await getBinaryTree(deployedOnChain, startTimestamp, chainId); @@ -80,6 +80,7 @@ export default function createEvmSlotValueStrategy({ signerAddress, slotIndex, l1BlockNumber, + ethUrl, chainId ); @@ -100,11 +101,12 @@ export default function createEvmSlotValueStrategy({ const isEthereumAddress = voterAddress.length === 42; if (!isEthereumAddress) return 0n; - const { herodotusAccumulatesChainId: chainId } = clientConfig.networkConfig; + const { ethUrl, networkConfig } = clientConfig; + const { herodotusAccumulatesChainId: chainId } = networkConfig; const { contractAddress, slotIndex } = metadata; if (!timestamp) { - const provider = getEthProvider(chainId); + const provider = new StaticJsonRpcProvider(clientConfig.ethUrl, chainId); const storage = await provider.getStorageAt( contractAddress, getSlotKey(voterAddress, slotIndex) @@ -123,6 +125,7 @@ export default function createEvmSlotValueStrategy({ voterAddress, slotIndex, l1BlockNumber, + ethUrl, chainId ); diff --git a/packages/sx.js/src/strategies/starknet/ozVotesStorageProof.ts b/packages/sx.js/src/strategies/starknet/ozVotesStorageProof.ts index 1b9dac35b..2447168e2 100644 --- a/packages/sx.js/src/strategies/starknet/ozVotesStorageProof.ts +++ b/packages/sx.js/src/strategies/starknet/ozVotesStorageProof.ts @@ -2,12 +2,13 @@ import { Contract, CallData } from 'starknet'; import { Contract as EvmContract } from '@ethersproject/contracts'; +import { StaticJsonRpcProvider } from '@ethersproject/providers'; import { keccak256 } from '@ethersproject/keccak256'; import OzVotesToken from './abis/OzVotesToken.json'; import OZVotesStorageProof from './abis/OZVotesStorageProof.json'; import SpaceAbi from '../../clients/starknet/starknet-tx/abis/Space.json'; import { getUserAddressEnum } from '../../utils/starknet-enums'; -import { getEthProvider, getSlotKey, getBinaryTree } from './utils'; +import { getSlotKey, getBinaryTree } from './utils'; import type { ClientConfig, Envelope, Strategy, Propose, Vote } from '../../types'; export default function createOzVotesStorageProofStrategy({ @@ -21,9 +22,10 @@ export default function createOzVotesStorageProofStrategy({ numCheckpoints: number, slotIndex: number, blockNumber: number, + ethUrl: string, chainId: number ) { - const provider = getEthProvider(chainId); + const provider = new StaticJsonRpcProvider(ethUrl, chainId); const checkpointSlotKey = BigInt(keccak256(getSlotKey(voterAddress, slotIndex))) + BigInt(numCheckpoints) - BigInt(1); @@ -72,21 +74,18 @@ export default function createOzVotesStorageProofStrategy({ if (signerAddress.length !== 42) throw new Error('Not supported for non-Ethereum addresses'); if (!metadata) throw new Error('Invalid metadata'); - const { herodotusAccumulatesChainId: chainId } = clientConfig.networkConfig; + const { starkProvider, ethUrl, networkConfig } = clientConfig; + const { herodotusAccumulatesChainId: chainId } = networkConfig; const { contractAddress, slotIndex } = metadata; - const provider = getEthProvider(chainId); + const provider = new StaticJsonRpcProvider(ethUrl, chainId); const tokenContract = new EvmContract(contractAddress, OzVotesToken, provider); const numCheckpoints: number = await tokenContract.numCheckpoints(signerAddress); if (numCheckpoints === 0) throw new Error('No checkpoints found'); const voteEnvelope = envelope as Envelope; - const spaceContract = new Contract( - SpaceAbi, - voteEnvelope.data.space, - clientConfig.starkProvider - ); + const spaceContract = new Contract(SpaceAbi, voteEnvelope.data.space, starkProvider); const proposalStruct = (await spaceContract.call('proposals', [ voteEnvelope.data.proposal ])) as any; @@ -101,6 +100,7 @@ export default function createOzVotesStorageProofStrategy({ numCheckpoints, slotIndex, l1BlockNumber, + ethUrl, chainId ); @@ -123,9 +123,10 @@ export default function createOzVotesStorageProofStrategy({ const isEthereumAddress = voterAddress.length === 42; if (!isEthereumAddress) return 0n; - const { herodotusAccumulatesChainId: chainId } = clientConfig.networkConfig; + const { starkProvider, ethUrl, networkConfig } = clientConfig; + const { herodotusAccumulatesChainId: chainId } = networkConfig; const { contractAddress, slotIndex } = metadata; - const provider = getEthProvider(chainId); + const provider = new StaticJsonRpcProvider(ethUrl, chainId); const tokenContract = new EvmContract(contractAddress, OzVotesToken, provider); if (!timestamp) return tokenContract.getVotes(voterAddress); @@ -133,11 +134,7 @@ export default function createOzVotesStorageProofStrategy({ const numCheckpoints: number = await tokenContract.numCheckpoints(voterAddress); if (numCheckpoints === 0) return 0n; - const contract = new Contract( - OZVotesStorageProof, - strategyAddress, - clientConfig.starkProvider - ); + const contract = new Contract(OZVotesStorageProof, strategyAddress, starkProvider); const tree = await getBinaryTree(deployedOnChain, timestamp, chainId); const l1BlockNumber = tree.path[1].blockNumber; @@ -148,6 +145,7 @@ export default function createOzVotesStorageProofStrategy({ numCheckpoints, slotIndex, l1BlockNumber, + ethUrl, chainId ); diff --git a/packages/sx.js/src/strategies/starknet/utils.ts b/packages/sx.js/src/strategies/starknet/utils.ts index 23f60fa53..c4810b5b0 100644 --- a/packages/sx.js/src/strategies/starknet/utils.ts +++ b/packages/sx.js/src/strategies/starknet/utils.ts @@ -1,24 +1,6 @@ import { keccak256 } from '@ethersproject/keccak256'; -import { StaticJsonRpcProvider } from '@ethersproject/providers'; import fetch from 'cross-fetch'; -export function getEthRpcUrl(chainId: number) { - const apiKey = '46a5dd9727bf48d4a132672d3f376146'; - - // TODO: ideally we would use rpc.snapshotx.xyz here but those don't support eth_getProof with past lookup - if (chainId === 1) return `https://mainnet.infura.io/v3/${apiKey}`; - if (chainId === 5) return `https://goerli.infura.io/v3/${apiKey}`; - if (chainId === 11155111) return `https://sepolia.infura.io/v3/${apiKey}`; - if (chainId === 137) return `https://polygon-mainnet.infura.io/v3/${apiKey}`; - if (chainId === 42161) return `https://arbitrum-mainnet.infura.io/v3/${apiKey}`; - - throw new Error(`Unsupported chainId ${chainId}`); -} - -export function getEthProvider(chainId: number) { - return new StaticJsonRpcProvider(getEthRpcUrl(chainId), chainId); -} - export function getSlotKey(voterAddress: string, slotIndex: number) { return keccak256( `0x${voterAddress.slice(2).padStart(64, '0')}${slotIndex.toString(16).padStart(64, '0')}`