Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: use clientConfig ethUrl for evmSlotValue and ozVotesStorageProof #62

Merged
merged 1 commit into from
Feb 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/slow-stingrays-smash.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@snapshot-labs/sx": patch
---

use clientConfig.ethUrl instead of predefined RPC APIs for starknet strategies
1 change: 0 additions & 1 deletion apps/ui/.env
Original file line number Diff line number Diff line change
@@ -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
Expand Down
4 changes: 1 addition & 3 deletions apps/ui/src/networks/starknet/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down
12 changes: 10 additions & 2 deletions apps/ui/src/networks/starknet/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ type Metadata = {
baseChainId: number;
baseNetworkId: NetworkID;
rpcUrl: string;
ethRpcUrl: string;
explorerUrl: string;
apiUrl: string;
};
Expand All @@ -29,6 +30,7 @@ export const METADATA: Partial<Record<NetworkID, Metadata>> = {
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'
},
Expand All @@ -38,6 +40,7 @@ export const METADATA: Partial<Record<NetworkID, Metadata>> = {
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'
},
Expand All @@ -47,6 +50,7 @@ export const METADATA: Partial<Record<NetworkID, Metadata>> = {
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'
}
Expand All @@ -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);
Expand Down Expand Up @@ -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
Expand Down
23 changes: 13 additions & 10 deletions packages/sx.js/src/strategies/starknet/evmSlotValue.ts
Original file line number Diff line number Diff line change
@@ -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({
Expand All @@ -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,
Expand Down Expand Up @@ -59,17 +61,15 @@ export default function createEvmSlotValueStrategy({

const voteEnvelope = envelope as Envelope<Vote>;

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);
Expand All @@ -80,6 +80,7 @@ export default function createEvmSlotValueStrategy({
signerAddress,
slotIndex,
l1BlockNumber,
ethUrl,
chainId
);

Expand All @@ -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)
Expand All @@ -123,6 +125,7 @@ export default function createEvmSlotValueStrategy({
voterAddress,
slotIndex,
l1BlockNumber,
ethUrl,
chainId
);

Expand Down
30 changes: 14 additions & 16 deletions packages/sx.js/src/strategies/starknet/ozVotesStorageProof.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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({
Expand All @@ -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);
Expand Down Expand Up @@ -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<Vote>;

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;
Expand All @@ -101,6 +100,7 @@ export default function createOzVotesStorageProofStrategy({
numCheckpoints,
slotIndex,
l1BlockNumber,
ethUrl,
chainId
);

Expand All @@ -123,21 +123,18 @@ 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);

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;
Expand All @@ -148,6 +145,7 @@ export default function createOzVotesStorageProofStrategy({
numCheckpoints,
slotIndex,
l1BlockNumber,
ethUrl,
chainId
);

Expand Down
18 changes: 0 additions & 18 deletions packages/sx.js/src/strategies/starknet/utils.ts
Original file line number Diff line number Diff line change
@@ -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')}`
Expand Down
Loading