Skip to content

Commit

Permalink
Merge pull request #32 from dwhiffing/manual-abi-upload
Browse files Browse the repository at this point in the history
Allows custom abi upload
  • Loading branch information
dwhiffing authored Aug 29, 2024
2 parents db0eef1 + d6851ec commit 672f2a5
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 10 deletions.
11 changes: 8 additions & 3 deletions app/api/contracts/route.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { FEATURED_CONTRACTS } from "@/constants";
import { contractCollection } from "@/utils/collections";
import { setAbi } from "@/utils/etherscan";
import { NextRequest, NextResponse } from "next/server";

export const runtime = "nodejs";
Expand All @@ -18,7 +18,6 @@ export async function GET() {
export async function POST(req: NextRequest) {
try {
const body = await req.json();

const existingContracts = await contractCollection.get();

if (
Expand All @@ -33,13 +32,19 @@ export async function POST(req: NextRequest) {
throw new Error("Contract address is not valid");
}

// TODO: fetch abi and throw if not found
if (body.abi) {
const isValidABI = await setAbi(body.address, body.chainId, body.abi);
if (!isValidABI) {
throw new Error("Contract ABI is not valid");
}
}

await contractCollection.add({
address: body.address,
name: body.name,
chainId: body.chainId,
});

const contracts = await contractCollection.get();

return NextResponse.json({ contracts }, { status: 200 });
Expand Down
25 changes: 18 additions & 7 deletions components/UploadContractModal.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useEffect, useState } from "react";
import { useCallback, useEffect, useState } from "react";
import { Input } from "./ui/input";
import { Button } from "./ui/button";
import { LoadingIcon } from "./LoadingIcon";
Expand All @@ -23,6 +23,7 @@ import { NETWORKS } from "@/constants";
import { IContract, ChainIdEnum } from "@/types";
import { useContracts } from "../utils/useContracts";
import { shortenAddress } from "../utils/shortenAddress";
import { Textarea } from "./ui/textarea";

export function UploadContractModal({
isOpen,
Expand All @@ -34,18 +35,20 @@ export function UploadContractModal({
const { onUpload, setErrorMessage, errorMessage, isLoading } = useContracts();
const [address, setAddress] = useState("");
const [name, setName] = useState("");
const [abi, setABI] = useState("");
const [chainId, setChainId] = useState<ChainIdEnum | -1>(-1);

const onResetForm = () => {
const onResetForm = useCallback(() => {
setAddress("");
setChainId(-1);
setName("");
setABI("");
setErrorMessage("");
};
}, [setErrorMessage]);

useEffect(() => {
onResetForm();
}, [isOpen]);
}, [isOpen, onResetForm]);

return (
<Dialog open={isOpen} onOpenChange={onClose}>
Expand All @@ -58,7 +61,7 @@ export function UploadContractModal({
className="flex w-full flex-col gap-4 mt-4"
onSubmit={(e) => {
e.preventDefault();
onUpload({ address, name, chainId }).then((contracts) => {
onUpload({ address, name, chainId, abi }).then((contracts) => {
if (contracts) onClose();
});
}}
Expand All @@ -71,7 +74,6 @@ export function UploadContractModal({
placeholder="Enter a name"
value={name}
onChange={(e) => setName(e.target.value)}
className="col-span-3"
/>
</div>

Expand All @@ -82,11 +84,20 @@ export function UploadContractModal({
value={address}
placeholder="Enter a contract address"
onChange={(e) => setAddress(e.target.value)}
className="col-span-3"
/>
</div>

<NetworkSelect chainId={chainId} setChainId={setChainId} />

<div className="flex flex-col gap-2">
<Label htmlFor="abi">ABI</Label>
<Textarea
id="abi"
value={abi}
placeholder="Enter ABI"
onChange={(e) => setABI(e.target.value)}
/>
</div>
</div>

<DialogFooter>
Expand Down
17 changes: 17 additions & 0 deletions utils/etherscan.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,20 @@ export const getAbi = async function (

return abi;
};

export const setAbi = async function (
contractAddress: string,
chainId: ChainIdEnum,
abi: string,
): Promise<boolean> {
const key = `${contractAddress}-${chainId}`;
let parsed = false;
try {
JSON.parse(abi);
parsed = true;
await cache.set(key, abi);
} catch (e) {
console.error("Failed to parse ABI for contract", contractAddress);
}
return parsed;
};
1 change: 1 addition & 0 deletions utils/useContracts.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export const useContracts = () => {
address: string;
name: string;
chainId: number;
abi?: string;
}) => {
setErrorMessage("");

Expand Down

0 comments on commit 672f2a5

Please sign in to comment.