Skip to content

Commit

Permalink
Clean IPFS clients
Browse files Browse the repository at this point in the history
  • Loading branch information
brickpop committed Jul 3, 2024
1 parent 15d4755 commit 9bda179
Show file tree
Hide file tree
Showing 13 changed files with 118 additions and 88 deletions.
6 changes: 3 additions & 3 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ NEXT_PUBLIC_WEB3_URL_PREFIX=https://eth-sepolia.g.alchemy.com/v2/

NEXT_PUBLIC_ALCHEMY_API_KEY="ALCHEMY KEY"
NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID="YOUR WALLET CONNECT PROJECT ID"
NEXT_PUBLIC_IPFS_ENDPOINT="https://..."
NEXT_PUBLIC_IPFS_ENDPOINTS="https://domain1/api,https://domain2/api/v0"
NEXT_PUBLIC_PINATA_JWT="..."
NEXT_PUBLIC_ETHERSCAN_API_KEY="OPTIONAL: ETHERSCAN API"

Expand All @@ -24,5 +24,5 @@ DEPLOYMENT_WALLET_PRIVATE_KEY="0x..."
DEPLOYMENT_ALCHEMY_API_KEY="..."
DEPLOYMENT_WEB3_ENDPOINT="https://..."

DEPLOYMENT_IPFS_ENDPOINT="https://..."
DEPLOYMENT_IPFS_API_KEY="..."
DEPLOYMENT_APP_NAME="Taiko"
DEPLOYMENT_PINATA_JWT="..."
2 changes: 1 addition & 1 deletion .github/workflows/app-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ jobs:
NEXT_PUBLIC_WEB3_URL_PREFIX: https://rpc/
NEXT_PUBLIC_ALCHEMY_API_KEY: x
NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID: x
NEXT_PUBLIC_IPFS_ENDPOINT: https://ipfs/
NEXT_PUBLIC_IPFS_ENDPOINTS: https://domain1/api,https://domain2/api/v0
NEXT_PUBLIC_PINATA_JWT: x
NEXT_PUBLIC_ETHERSCAN_API_KEY: x
NODE_ENV: production
Binary file modified bun.lockb
Binary file not shown.
2 changes: 1 addition & 1 deletion constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export const PUB_ETHERSCAN_API_KEY = process.env.NEXT_PUBLIC_ETHERSCAN_API_KEY ?

export const PUB_WALLET_CONNECT_PROJECT_ID = process.env.NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID ?? "";

export const PUB_IPFS_ENDPOINT = process.env.NEXT_PUBLIC_IPFS_ENDPOINT ?? "";
export const PUB_IPFS_ENDPOINTS = process.env.NEXT_PUBLIC_IPFS_ENDPOINTS ?? "";
export const PUB_PINATA_JWT = process.env.NEXT_PUBLIC_PINATA_JWT ?? "";

// General
Expand Down
4 changes: 2 additions & 2 deletions hooks/useMetadata.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { fetchJsonFromIpfs } from "@/utils/ipfs";
import { fetchIpfsAsJson } from "@/utils/ipfs";
import { JsonValue } from "@/utils/types";
import { useQuery } from "@tanstack/react-query";

Expand All @@ -8,7 +8,7 @@ export function useMetadata<T = JsonValue>(ipfsUri?: string) {
queryFn: () => {
if (!ipfsUri) return Promise.resolve("");

return fetchJsonFromIpfs(ipfsUri);
return fetchIpfsAsJson(ipfsUri);
},
retry: true,
refetchOnMount: false,
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
"classnames": "^2.5.1",
"dayjs": "^1.11.10",
"dompurify": "^3.0.11",
"ipfs-http-client": "^60.0.1",
"multiformats": "^13.1.3",
"next": "14.1.4",
"react": "^18.2.0",
"react-blockies": "^1.4.1",
Expand Down
19 changes: 5 additions & 14 deletions plugins/dualGovernance/pages/new.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { create } from "ipfs-http-client";
import { Button, IconType, Icon, InputText, TextAreaRichText } from "@aragon/ods";
import React, { useEffect, useState } from "react";
import { uploadToIPFS } from "@/utils/ipfs";
import { uploadToPinata } from "@/utils/ipfs";
import { useWaitForTransactionReceipt, useWriteContract } from "wagmi";
import { toHex } from "viem";
import { OptimisticTokenVotingPluginAbi } from "@/plugins/dualGovernance/artifacts/OptimisticTokenVotingPlugin.sol";
Expand All @@ -13,7 +12,7 @@ import { getPlainText } from "@/utils/html";
import { useRouter } from "next/router";
import { Else, ElseIf, If, Then } from "@/components/if";
import { PleaseWaitSpinner } from "@/components/please-wait";
import { PUB_IPFS_ENDPOINT, PUB_PINATA_JWT, PUB_DUAL_GOVERNANCE_PLUGIN_ADDRESS, PUB_CHAIN } from "@/constants";
import { PUB_CHAIN, PUB_DUAL_GOVERNANCE_PLUGIN_ADDRESS } from "@/constants";
import { ActionCard } from "@/components/actions/action";

enum ActionType {
Expand All @@ -22,11 +21,6 @@ enum ActionType {
Custom,
}

const ipfsClient = create({
url: PUB_IPFS_ENDPOINT,
headers: { "X-API-KEY": PUB_PINATA_JWT, Accept: "application/json" },
});

export default function Create() {
const { push } = useRouter();
const [title, setTitle] = useState<string>("");
Expand Down Expand Up @@ -85,7 +79,7 @@ export default function Create() {
});

const plainSummary = getPlainText(summary).trim();
if (!plainSummary.trim())
if (!plainSummary)
return addAlert("Invalid proposal details", {
description: "Please, enter a summary of what the proposal is about",
type: "error",
Expand Down Expand Up @@ -113,17 +107,14 @@ export default function Create() {
}

const proposalMetadataJsonObject = { title, summary };
const blob = new Blob([JSON.stringify(proposalMetadataJsonObject)], {
type: "application/json",
});
const ipfsUri = await uploadToPinata(JSON.stringify(proposalMetadataJsonObject));

const ipfsPin = await uploadToIPFS(ipfsClient, blob);
createProposalWrite({
chainId: PUB_CHAIN.id,
abi: OptimisticTokenVotingPluginAbi,
address: PUB_DUAL_GOVERNANCE_PLUGIN_ADDRESS,
functionName: "createProposal",
args: [toHex(ipfsPin), actions, BigInt(0), BigInt(0), BigInt(0)],
args: [toHex(ipfsUri), actions, BigInt(0), BigInt(0), BigInt(0)],
});
};

Expand Down
19 changes: 5 additions & 14 deletions plugins/lockToVote/pages/new.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { create } from "ipfs-http-client";
import { Button, IconType, Icon, InputText, TextAreaRichText } from "@aragon/ods";
import React, { useEffect, useState } from "react";
import { uploadToIPFS } from "@/utils/ipfs";
import { uploadToPinata } from "@/utils/ipfs";
import { useWaitForTransactionReceipt, useWriteContract } from "wagmi";
import { toHex } from "viem";
import { OptimisticTokenVotingPluginAbi } from "@/plugins/dualGovernance/artifacts/OptimisticTokenVotingPlugin.sol";
Expand All @@ -13,7 +12,7 @@ import { getPlainText } from "@/utils/html";
import { useRouter } from "next/router";
import { Else, ElseIf, If, Then } from "@/components/if";
import { PleaseWaitSpinner } from "@/components/please-wait";
import { PUB_IPFS_ENDPOINT, PUB_PINATA_JWT, PUB_CHAIN, PUB_LOCK_TO_VOTE_PLUGIN_ADDRESS } from "@/constants";
import { PUB_CHAIN, PUB_LOCK_TO_VOTE_PLUGIN_ADDRESS } from "@/constants";
import { ActionCard } from "@/components/actions/action";

enum ActionType {
Expand All @@ -22,11 +21,6 @@ enum ActionType {
Custom,
}

const ipfsClient = create({
url: PUB_IPFS_ENDPOINT,
headers: { "X-API-KEY": PUB_PINATA_JWT, Accept: "application/json" },
});

export default function Create() {
const { push } = useRouter();
const [title, setTitle] = useState<string>("");
Expand Down Expand Up @@ -85,7 +79,7 @@ export default function Create() {
});

const plainSummary = getPlainText(summary).trim();
if (!plainSummary.trim())
if (!plainSummary)
return addAlert("Invalid proposal details", {
description: "Please, enter a summary of what the proposal is about",
type: "error",
Expand Down Expand Up @@ -113,17 +107,14 @@ export default function Create() {
}

const proposalMetadataJsonObject = { title, summary };
const blob = new Blob([JSON.stringify(proposalMetadataJsonObject)], {
type: "application/json",
});
const ipfsUri = await uploadToPinata(JSON.stringify(proposalMetadataJsonObject));

const ipfsPin = await uploadToIPFS(ipfsClient, blob);
createProposalWrite({
chainId: PUB_CHAIN.id,
abi: OptimisticTokenVotingPluginAbi,
address: PUB_LOCK_TO_VOTE_PLUGIN_ADDRESS,
functionName: "createProposal",
args: [toHex(ipfsPin), actions, BigInt(0), BigInt(0), BigInt(0)],
args: [toHex(ipfsUri), actions, BigInt(0), BigInt(0), BigInt(0)],
});
};

Expand Down
19 changes: 5 additions & 14 deletions plugins/tokenVoting/pages/new.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { create } from "ipfs-http-client";
import { Button, IconType, Icon, InputText, TextAreaRichText } from "@aragon/ods";
import React, { useEffect, useState } from "react";
import { uploadToIPFS } from "@/utils/ipfs";
import { uploadToPinata } from "@/utils/ipfs";
import { useWaitForTransactionReceipt, useWriteContract } from "wagmi";
import { toHex } from "viem";
import { TokenVotingAbi } from "@/plugins/tokenVoting/artifacts/TokenVoting.sol";
Expand All @@ -13,7 +12,7 @@ import { getPlainText } from "@/utils/html";
import { useRouter } from "next/router";
import { Else, ElseIf, If, Then } from "@/components/if";
import { PleaseWaitSpinner } from "@/components/please-wait";
import { PUB_CHAIN, PUB_PINATA_JWT, PUB_IPFS_ENDPOINT, PUB_TOKEN_VOTING_PLUGIN_ADDRESS } from "@/constants";
import { PUB_CHAIN, PUB_TOKEN_VOTING_PLUGIN_ADDRESS } from "@/constants";
import { ActionCard } from "@/components/actions/action";

enum ActionType {
Expand All @@ -22,11 +21,6 @@ enum ActionType {
Custom,
}

const ipfsClient = create({
url: PUB_IPFS_ENDPOINT,
headers: { "X-API-KEY": PUB_PINATA_JWT, Accept: "application/json" },
});

export default function Create() {
const { push } = useRouter();
const [title, setTitle] = useState<string>("");
Expand Down Expand Up @@ -86,7 +80,7 @@ export default function Create() {
});

const plainSummary = getPlainText(summary).trim();
if (!plainSummary.trim())
if (!plainSummary)
return addAlert("Invalid proposal details", {
description: "Please, enter a summary of what the proposal is about",
type: "error",
Expand Down Expand Up @@ -114,17 +108,14 @@ export default function Create() {
}

const proposalMetadataJsonObject = { title, summary };
const blob = new Blob([JSON.stringify(proposalMetadataJsonObject)], {
type: "application/json",
});
const ipfsUri = await uploadToPinata(JSON.stringify(proposalMetadataJsonObject));

const ipfsPin = await uploadToIPFS(ipfsClient, blob);
createProposalWrite({
chainId: PUB_CHAIN.id,
abi: TokenVotingAbi,
address: PUB_TOKEN_VOTING_PLUGIN_ADDRESS,
functionName: "createProposal",
args: [toHex(ipfsPin), actions, BigInt(0), BigInt(0), BigInt(0), 0, false],
args: [toHex(ipfsUri), actions, BigInt(0), BigInt(0), BigInt(0), 0, false],
});
};

Expand Down
2 changes: 1 addition & 1 deletion scripts/deploy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ NEXT_PUBLIC_WEB3_URL_PREFIX=https://eth-${DEPLOYMENT_TARGET_CHAIN_ID}.g.alchemy.
NEXT_PUBLIC_ALCHEMY_API_KEY=<YOUR KEY GOES HERE>
NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID=<YOUR KEY GOES HERE>
NEXT_PUBLIC_IPFS_ENDPOINT=<YOUR IPFS API URL GOES HERE>
NEXT_PUBLIC_IPFS_ENDPOINTS=<YOUR IPFS API URLs GO HERE>
NEXT_PUBLIC_PINATA_JWT=<YOUR IPFS API KEY GOES HERE>
NEXT_PUBLIC_ETHERSCAN_API_KEY=<YOUR API KEY GOES HERE>
`;
Expand Down
8 changes: 2 additions & 6 deletions scripts/deploy/5-dao.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@ import {
import { type Address, type Hex, type Log, decodeEventLog, toHex } from "viem";
import { deploymentPublicClient as publicClient, deploymentWalletClient as walletClient } from "../lib/util/client";
import { deploymentAccount as account } from "../lib/util/account";
import { uploadToIPFS } from "@/utils/ipfs";
import { deploymentIpfsClient as ipfsClient } from "../lib/util/ipfs";
import { uploadToPinata } from "@/utils/ipfs";
import { ABI as DaoFactoryABI } from "../lib/artifacts/dao-factory";
import { ABI as DaoRegistryABI } from "../lib/artifacts/dao-registry";
import { ABI as PluginSetupProcessorABI } from "../lib/artifacts/plugin-setup-processor";
Expand Down Expand Up @@ -73,11 +72,8 @@ function pinDaoMetadata(): Promise<Hex> {
// },
// ],
};
const blob = new Blob([JSON.stringify(daoMetadata)], {
type: "application/json",
});

return uploadToIPFS(ipfsClient, blob)
return uploadToPinata(JSON.stringify(daoMetadata))
.then((res) => toHex(res))
.catch((err) => {
console.warn("Warning: Could not pin the DAO metadata on IPFS");
Expand Down
33 changes: 26 additions & 7 deletions scripts/lib/util/ipfs.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,29 @@
import { create } from "ipfs-http-client";
import { getEnv } from "./env";

const IPFS_ENDPOINT = getEnv("DEPLOYMENT_IPFS_ENDPOINT", true) ?? "";
const IPFS_API_KEY = getEnv("DEPLOYMENT_IPFS_API_KEY", true) || "";
const PINATA_JWT = getEnv("DEPLOYMENT_PINATA_JWT", true) || "";
const APP_NAME = getEnv("DEPLOYMENT_APP_NAME", true) || "";

export const deploymentIpfsClient = create({
url: IPFS_ENDPOINT,
headers: { "X-API-KEY": IPFS_API_KEY, Accept: "application/json" },
});
const UPLOAD_FILE_NAME = APP_NAME.toLowerCase().trim().replaceAll(" ", "-") + ".json";

export async function uploadToPinata(strBody: string) {
const blob = new Blob([strBody], { type: "text/plain" });
const file = new File([blob], UPLOAD_FILE_NAME);
const data = new FormData();
data.append("file", file);
data.append("pinataMetadata", JSON.stringify({ name: UPLOAD_FILE_NAME }));
data.append("pinataOptions", JSON.stringify({ cidVersion: 1 }));

const res = await fetch("https://api.pinata.cloud/pinning/pinFileToIPFS", {
method: "POST",
headers: {
Authorization: `Bearer ${PINATA_JWT}`,
},
body: data,
});

const resData = await res.json();

if (resData.error) throw new Error("Request failed: " + resData.error);
else if (!resData.IpfsHash) throw new Error("Could not pin the metadata");
return "ipfs://" + resData.IpfsHash;
}
Loading

0 comments on commit 9bda179

Please sign in to comment.