Skip to content

Commit

Permalink
feat(app): refactoring to use JSON files for onchain env vars, switch…
Browse files Browse the repository at this point in the history
…ed to simplified resolver contract (passportxyz#1538)
  • Loading branch information
lucianHymer authored Aug 2, 2023
1 parent 50eb700 commit 6b7d724
Show file tree
Hide file tree
Showing 25 changed files with 238 additions and 1,239 deletions.
7 changes: 1 addition & 6 deletions app/.env-example.env
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,7 @@ NEXT_PUBLIC_ALLO_SCORER_ID=ALLO_SCORER_ID
NEXT_PUBLIC_ALLO_SCORER_API_KEY=SCORER_API_KEY
NEXT_PUBLIC_SCORER_ENDPOINT=http://localhost:8002/ceramic-cache

NEXT_PUBLIC_GITCOIN_VERIFIER_CONTRACT_ADDRESS=0x0Bfa7c7AF28F43295A0645077E5b13D41907F249
NEXT_PUBLIC_GITCOIN_RESOLVER_CONTRACT_ADDRESS=0xBC778313E52b1184A15D163b5d3a72AEF8d510A2
NEXT_PUBLIC_PASSPORT_BASE_GOERLI_RPC_URL=https://goerli.base.org
NEXT_PUBLIC_EAS_ADDRESS=0xAcfE09Fd03f7812F022FBf636700AdEA18Fd2A7A
NEXT_PUBLIC_FF_CHAIN_SYNC=on
NEXT_PUBLIC_EAS_EXPLORER=https://sepolia.easscan.org

NEXT_PUBLIC_ENABLE_TESTNET=on

Expand All @@ -77,4 +72,4 @@ NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID=YOUR_WALLET_CONNECT_PROJECT_ID
NEXT_PUBLIC_WEB3_ONBOARD_EXPLORE_URL=http://localhost:3000/

NEXT_PUBLIC_ACTIVE_ON_CHAIN_PASSPORT_CHAINIDS=["0x14a33"]
NEXT_PUBLIC_POSSIBLE_ON_CHAIN_PASSPORT_CHAINIDS=["0x1a8", "0x14a33"]
NEXT_PUBLIC_POSSIBLE_ON_CHAIN_PASSPORT_CHAINIDS=["0x1a8", "0x14a33"]
10 changes: 4 additions & 6 deletions app/__tests__/components/SyncToChainButton.test.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { render, screen, fireEvent, waitFor } from "@testing-library/react";
import { EthersError } from "ethers";
import axios from "axios";
import { getButtonMsg, ErrorDetails, SyncToChainButton } from "../../components/SyncToChainButton";
import { getButtonMsg, SyncToChainButton } from "../../components/SyncToChainButton";
import { OnChainStatus } from "../../components/NetworkCard";
import { UserContextState } from "../../context/userContext";
import {
Expand All @@ -10,13 +9,12 @@ import {
renderWithContext,
} from "../../__test-fixtures__/contextTestHelpers";
import { CeramicContextState } from "../../context/ceramicContext";
import { VerifiableCredential } from "@gitcoin/passport-types";

jest.mock("../../utils/onboard.ts");
const mockSetChain = jest.fn();
const mockConnectedChain = {
chains: [],
connectedChain: { id: "test1", namespace: "mock_namespace", name: "mock_name" },
connectedChain: { id: "0x14a33", namespace: "mock_namespace", name: "mock_name" },
settingChain: false,
};
jest.mock("@web3-onboard/react", () => ({
Expand Down Expand Up @@ -103,7 +101,7 @@ describe("SyncToChainButton component", () => {
renderWithContext(
mockUserContext,
{ ...mockCeramicContext },
<SyncToChainButton onChainStatus={OnChainStatus.NOT_MOVED} isActive={true} chain={{ ...chain, id: "test1" }} />
<SyncToChainButton onChainStatus={OnChainStatus.NOT_MOVED} isActive={true} chain={{ ...chain, id: "0x14a33" }} />
);
const btn = screen.getByTestId("sync-to-chain-button");
fireEvent.click(btn);
Expand All @@ -120,7 +118,7 @@ describe("SyncToChainButton component", () => {
...mockCeramicContext,
passport: { ...mockCeramicContext.passport, stamps: [{ id: "test" } as any] },
},
<SyncToChainButton onChainStatus={OnChainStatus.NOT_MOVED} isActive={true} chain={{ ...chain, id: "test1" }} />
<SyncToChainButton onChainStatus={OnChainStatus.NOT_MOVED} isActive={true} chain={{ ...chain, id: "0x14a33" }} />
);
const btn = screen.getByTestId("sync-to-chain-button");
fireEvent.click(btn);
Expand Down
5 changes: 4 additions & 1 deletion app/__tests__/utils/onChainStamps.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ jest.mock("@ethereum-attestation-service/eas-sdk", () => ({
Attestation: jest.fn(),
}));

jest.mock("../../utils/onboard");
// Prevents issue with module import in jest
jest.mock("../../utils/onboard", () => ({
chains: [{ id: "0x14a33", rpcUrl: "mockRpcUrl" }],
}));

describe("decodeProviderInformation", () => {
beforeEach(() => {
Expand Down
9 changes: 1 addition & 8 deletions app/components/NetworkCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,7 @@ import { CeramicContext, AllProvidersState, ProviderState } from "../context/cer
import { OnChainContext, OnChainProviderType } from "../context/onChainContext";
import { ScorerContext, ScoreStateType } from "../context/scorerContext";
import { SyncToChainButton } from "./SyncToChainButton";

export type Chain = {
id: string;
token: string;
label: string;
rpcUrl: string;
icon: string;
};
import { Chain } from "../utils/onboard";

export enum OnChainStatus {
NOT_MOVED,
Expand Down
54 changes: 36 additions & 18 deletions app/components/SyncToChainButton.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import { Spinner, useToast } from "@chakra-ui/react";
import { EasPayload, Passport, VerifiableCredential } from "@gitcoin/passport-types";
import { EasPayload, VerifiableCredential } from "@gitcoin/passport-types";
import { ethers, EthersError, isError } from "ethers";
import { useCallback, useContext, useState } from "react";
import { CeramicContext } from "../context/ceramicContext";
import { OnChainContext } from "../context/onChainContext";
import { UserContext } from "../context/userContext";
import GitcoinVerifier from "../contracts/GitcoinVerifier.json";
import onchainInfo from "../../deployments/onchainInfo.json";
import GitcoinVerifierAbi from "../../deployments/abi/GitcoinVerifier.json";
import { DoneToastContent } from "./DoneToastContent";
import { Chain, OnChainStatus } from "./NetworkCard";
import { OnChainStatus } from "./NetworkCard";
import { Chain } from "../utils/onboard";
import axios from "axios";
import { useSetChain } from "@web3-onboard/react";
import Tooltip from "../components/Tooltip";
Expand Down Expand Up @@ -85,6 +87,22 @@ export function SyncToChainButton({ onChainStatus, isActive, chain }: SyncToChai
const [syncingToChain, setSyncingToChain] = useState(false);
const toast = useToast();

const loadVerifierContract = useCallback(
async (wallet) => {
const ethersProvider = new ethers.BrowserProvider(wallet.provider, "any");

if (!Object.keys(onchainInfo).includes(chain.id)) {
throw new Error(`No onchainInfo found for chainId ${chain.id}`);
}
const onchainInfoChainId = chain.id as keyof typeof onchainInfo;
const verifierAddress = onchainInfo[onchainInfoChainId].GitcoinVerifier.address;
const verifierAbi = GitcoinVerifierAbi[onchainInfoChainId];

return new ethers.Contract(verifierAddress, verifierAbi, await ethersProvider.getSigner());
},
[chain]
);

const onInitiateSyncToChain = useCallback(async (wallet, passport) => {
if (connectedChain && connectedChain?.id !== chain.id) {
const setChainResponse = await setChain({ chainId: chain.id });
Expand All @@ -99,15 +117,10 @@ export function SyncToChainButton({ onChainStatus, isActive, chain }: SyncToChai
try {
setSyncingToChain(true);
const credentials = passport.stamps.map(({ credential }: { credential: VerifiableCredential }) => credential);
const ethersProvider = new ethers.BrowserProvider(wallet.provider, "any");
const gitcoinAttesterContract = new ethers.Contract(
process.env.NEXT_PUBLIC_GITCOIN_VERIFIER_CONTRACT_ADDRESS as string,
GitcoinVerifier.abi,
await ethersProvider.getSigner()
);
const gitcoinVerifierContract = await loadVerifierContract(wallet);

if (credentials.length === 0) {
// Nothing to be broough on-chain
// Nothing to be brought on-chain
toast({
duration: 9000,
isClosable: true,
Expand All @@ -123,7 +136,7 @@ export function SyncToChainButton({ onChainStatus, isActive, chain }: SyncToChai
return;
}

const nonce = await gitcoinAttesterContract.recipientNonces(address);
const nonce = await gitcoinVerifierContract.recipientNonces(address);

const payload = {
credentials,
Expand All @@ -138,7 +151,7 @@ export function SyncToChainButton({ onChainStatus, isActive, chain }: SyncToChai
"Content-Type": "application/json",
},
transformRequest: [
(data: any) => JSON.stringify(data, (k, v) => (typeof v === "bigint" ? v.toString() : v)),
(data: any) => JSON.stringify(data, (_k, v) => (typeof v === "bigint" ? v.toString() : v)),
],
}
);
Expand All @@ -161,7 +174,7 @@ export function SyncToChainButton({ onChainStatus, isActive, chain }: SyncToChai
if (data.passport) {
const { v, r, s } = data.signature;

const transaction = await gitcoinAttesterContract.verifyAndAttest(data.passport, v, r, s, {
const transaction = await gitcoinVerifierContract.verifyAndAttest(data.passport, v, r, s, {
value: data.passport.fee,
});
toast({
Expand All @@ -177,7 +190,12 @@ export function SyncToChainButton({ onChainStatus, isActive, chain }: SyncToChai
),
});
await transaction.wait();
const easScanURL = `${process.env.NEXT_PUBLIC_EAS_EXPLORER}/address/${address}`;

const easScanBaseUrl = chain.easScanUrl;
if (!easScanBaseUrl) {
throw new Error(`No EAS scan URL found for chain ${chain.id}`);
}
const easScanURL = `${easScanBaseUrl}/address/${address}`;
await readOnChainData();
const successSubmit = (
<p>
Expand All @@ -199,7 +217,7 @@ export function SyncToChainButton({ onChainStatus, isActive, chain }: SyncToChai
} catch (e: any) {
console.error("error syncing credentials to chain: ", e);
let toastDescription: string | JSX.Element =
"An unexpected error occured while trying to bring the data on-chain.";
"An unexpected error occurred while trying to bring the data on-chain.";
if (isError(e, "ACTION_REJECTED")) {
toastDescription = "Transaction rejected by user";
} else if (isError(e, "INSUFFICIENT_FUNDS") || e?.info?.error?.data?.message.includes("insufficient funds")) {
Expand All @@ -216,7 +234,7 @@ export function SyncToChainButton({ onChainStatus, isActive, chain }: SyncToChai
) {
toastDescription = (
<ErrorDetails
msg={"A Blockchain error occured while executing this transaction. Please try again in a few minutes."}
msg={"A Blockchain error occurred while executing this transaction. Please try again in a few minutes."}
ethersError={e}
/>
);
Expand Down Expand Up @@ -246,14 +264,14 @@ export function SyncToChainButton({ onChainStatus, isActive, chain }: SyncToChai
) {
toastDescription = (
<ErrorDetails
msg={"An unexpected error occured while calling the smart contract function. Please contact support."}
msg={"An unexpected error occurred while calling the smart contract function. Please contact support."}
ethersError={e}
/>
);
} else if (isError(e, "BUFFER_OVERRUN") || isError(e, "NUMERIC_FAULT")) {
toastDescription = (
<ErrorDetails
msg={"An operationl error occured while calling the smart contract. Please contact support."}
msg={"An operational error occurred while calling the smart contract. Please contact support."}
ethersError={e}
/>
);
Expand Down
Loading

0 comments on commit 6b7d724

Please sign in to comment.