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

feat: local deployment steps #413

Merged
merged 4 commits into from
May 11, 2023
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
70 changes: 69 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,76 @@ Also, curating and creating Players earn reputation (REP) for positive gameplay
We are using ZK-Proof technology and [Waku](https://waku.org/) to ensure privacy, with a hat-tip to [Unirep](https://medium.com/privacy-scaling-explorations/unirep-a-private-and-non-repudiable-reputation-system-7fb5c6478549), and [Semaphore](https://semaphore.appliedzkp.org/).

## For Developers
**Would you like to launch and play with Kurate locally?**

0. Install all dependencies
```sh
pnpm i
```

1. Start blockchain and deploy contracts
```sh
cd packages/contracts
```

```sh
pnpm start:blockchain
```

In another terminal window, compile, deploy the contracts
```
pnpm start
```

If successfully, the output should say:
```
GlobalAnonymousFeedContract contract has been deployed
Don't forget to set the variables for both the UI and relayer

PUBLIC_GLOBAL_ANONYMOUS_FEED_ADDRESS=0xA51c1fc2f0D1a1b8494Ed1FE312d7C3a78Ed91C0
PUBLIC_PROVIDER=http://localhost:8545

Relayer only
PRIVATE_KEY=...

UI only
PUBLIC_RELAYER_URL=...
```

2. Start relayer
```sh
cd packages/contracts
```
Set the environment variables according to the contract deployment (for private key you can use any hardhat key). Should be:
```sh
PUBLIC_GLOBAL_ANONYMOUS_FEED_ADDRESS=0xA51c1fc2f0D1a1b8494Ed1FE312d7C3a78Ed91C0
PUBLIC_PROVIDER=http://localhost:8545
PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
```

Build and start the relayer
```
pnpm build
pnpm start
```

3. Start UI
```sh
cd packages/ui
```

Set the environment variables according to the contract deployment and where the relayer lives: Should be:
```sh
PUBLIC_GLOBAL_ANONYMOUS_FEED_ADDRESS=0xA51c1fc2f0D1a1b8494Ed1FE312d7C3a78Ed91C0
PUBLIC_PROVIDER=http://localhost:8545
PUBLIC_RELAYER_URL=http://localhost:3000
```

Start the UI with
```sh
pnpm dev
```

You can now open the app at http://localhost:5173/ . Just make sure you are using either the `zkitter` or the `zkitter-god-node` adapter. You can configure those in `/dev` route (http://localhost:5173/dev)

**Are you interested in contributing to Kurate?**

Expand Down
33 changes: 10 additions & 23 deletions packages/contracts/hardhat.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,35 +14,25 @@ import "./tasks/deploy"
dotenvConfig({ path: resolve(__dirname, "../../.env") })

function getNetworks(): NetworksUserConfig {
if (process.env.ETHEREUM_URL && process.env.ETHEREUM_PRIVATE_KEY) {
const accounts = [`0x${process.env.ETHEREUM_PRIVATE_KEY}`]
const networks: NetworksUserConfig = {
localhost: {
url: 'http://127.0.0.1:8545',
chainId: 31337
}
}

if (process.env.ETHEREUM_URL && process.env.ETHEREUM_PRIVATE_KEY) {
return {
goerli: {
url: process.env.ETHEREUM_URL,
chainId: 5,
accounts
},
...networks,
// arbitrum goerli
agor: {
url: 'https://goerli-rollup.arbitrum.io/rpc',
chainId: 421613,
accounts,
},
sepolia: {
url: process.env.ETHEREUM_URL,
chainId: 11155111,
accounts
accounts: [process.env.ETHEREUM_PRIVATE_KEY],
},
localhost: {
url: 'http://127.0.0.1:7545',
chainId: 1337,
accounts,
}
}
}

return {}
return networks
}

const hardhatConfig: HardhatUserConfig = {
Expand All @@ -54,9 +44,6 @@ const hardhatConfig: HardhatUserConfig = {
artifacts: config.paths.build.contracts
},
networks: {
hardhat: {
chainId: 1337
},
...getNetworks()
},
gasReporter: {
Expand Down
2 changes: 1 addition & 1 deletion packages/contracts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"private": true,
"main": "index.js",
"scripts": {
"start": "pnpm run compile && pnpm run deploy -- --network localhost",
"start": "pnpm run compile && pnpm run deploy --network localhost",
"start:blockchain": "hardhat node",
"compile": "hardhat compile",
"download:snark-artifacts": "hardhat run scripts/download-snark-artifacts.ts",
Expand Down
12 changes: 0 additions & 12 deletions packages/contracts/scripts/deploy-unirep.ts

This file was deleted.

58 changes: 36 additions & 22 deletions packages/contracts/tasks/deploy.ts
Original file line number Diff line number Diff line change
@@ -1,43 +1,57 @@
import { Unirep } from "@unirep/contracts";
import { deployUnirep } from "@unirep/contracts/deploy";
import { task, types } from "hardhat/config"

// 28800 seconds = 8 hours per epoch
const DEFAULT_EPOCH_LENGTH = 28800;

task("deploy", "Deploy a GlobalAnonymousFeed contract")
.addOptionalParam("unirep", "unirep contract address", undefined, types.string)
.addOptionalParam("logs", "Print the logs", true, types.boolean)
.setAction(async ({ logs, unirep: unirepAddress }, { ethers, run }) => {
.addOptionalParam("epoch", `Epoch length (defaults to ${DEFAULT_EPOCH_LENGTH}`, DEFAULT_EPOCH_LENGTH, types.int)
.setAction(async ({ logs, unirep: unirepAddress, epoch: epochLength }, { ethers }) => {
const globalAnonymousFeedFactory = await ethers.getContractFactory("GlobalAnonymousFeed");

const [deployer] = await ethers.getSigners();

console.log(
"Deploying contracts with the account:",
deployer.address
);
logs && console.log(`Deploying contracts with the account: ${deployer.address}`);
logs && console.log("Account balance:", ethers.utils.formatEther(await deployer.getBalance()));

if (!unirepAddress) {
logs && console.log("Unirep contract address not provided, deploying Unirep first\n")
const unirepContract: Unirep = await deployUnirep(deployer)
unirepAddress = unirepContract.address;
}

console.log("Account balance:", (await deployer.getBalance()).toString());
logs && console.log(`\nUnirep contract address: ${unirepAddress}`);

const gasPrice = await globalAnonymousFeedFactory.signer.getGasPrice();
// const estimatedGas = await globalAnonymousFeedFactory.signer.estimateGas(globalAnonymousFeedFactory.getDeployTransaction('0xF309DDf2Cc1b2701fED5171C5150092bAc946f07', 28800));
const estimatedGas = await globalAnonymousFeedFactory.signer.estimateGas(globalAnonymousFeedFactory.getDeployTransaction('0x5e5384c3EA26185BADF41d6980397eB4D36b850e', 60));
console.log(`Estimated gas: ${estimatedGas}`);
console.log(`Gas Price: ${gasPrice}`)
const estimatedGas = await globalAnonymousFeedFactory.signer.estimateGas(globalAnonymousFeedFactory.getDeployTransaction(unirepAddress, epochLength));
logs && console.log(`Estimated gas: ${estimatedGas}`);
logs && console.log(`Gas price: ${gasPrice}`)

const deploymentPrice = gasPrice.mul(estimatedGas);
const deployerBalance = await globalAnonymousFeedFactory.signer.getBalance();
console.log(`Deployer balance: ${ethers.utils.formatEther(deployerBalance)}`);
console.log(`Deployment price: ${ethers.utils.formatEther(deploymentPrice)}`);
// This is [email protected] contract address on Arbitrum Goerli
// https://developer.unirep.io/docs/testnet-deployment
// 28800 seconds = 8 hours per epoch
// const globalAnonymousFeedContract = await globalAnonymousFeedFactory.deploy('0xF309DDf2Cc1b2701fED5171C5150092bAc946f07', 28800);

// This was used for local dev
// 60 seconds = 1 minute per epoch
const globalAnonymousFeedContract = await globalAnonymousFeedFactory.deploy('0x5e5384c3EA26185BADF41d6980397eB4D36b850e', 60);
logs && console.log(`Deployer balance: ${ethers.utils.formatEther(deployerBalance)}`);
logs && console.log(`Deployment price: ${ethers.utils.formatEther(deploymentPrice)}`);

const globalAnonymousFeedContract = await globalAnonymousFeedFactory.deploy(unirepAddress, epochLength);

await globalAnonymousFeedContract.deployed();

if (logs) {
console.info(`GlobalAnonymousFeedContract contract has been deployed to: ${globalAnonymousFeedContract.address}`);
}
logs && console.info("\n-----------------------------------------------------------------");
logs && console.info('GlobalAnonymousFeedContract contract has been deployed');
logs && console.log("Don't forget to set the variables for both the UI and relayer\n");

logs && console.log(`PUBLIC_GLOBAL_ANONYMOUS_FEED_ADDRESS=${globalAnonymousFeedContract.address}`);
logs && console.log(`PUBLIC_PROVIDER=${ethers.provider.connection.url}`);

logs && console.log("\nRelayer only");
logs && console.log(`PRIVATE_KEY=...`);

logs && console.log("\nUI only");
logs && console.log(`PUBLIC_RELAYER_URL=...`);

return globalAnonymousFeedContract;
})
2 changes: 1 addition & 1 deletion packages/contracts/test/GlobalAnonymousFeed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ describe("Global Anonymous Feed Contract", () => {
before(async () => {
provider = new ethers.providers.JsonRpcProvider(process.env.ETHEREUM_URL)
const signer = new ethers.Wallet(process.env.ETHEREUM_PRIVATE_KEY as string, provider)
postContract = new GlobalAnonymousFeed__factory(signer).attach(process.env.GLOBAL_ANONYMOUS_FEED_ADDRESS as string);
postContract = new GlobalAnonymousFeed__factory(signer).attach(process.env.PUBLIC_GLOBAL_ANONYMOUS_FEED_ADDRESS as string);
unirepContract = getUnirepContract('0x5e5384c3EA26185BADF41d6980397eB4D36b850e', signer);
// unirepContract = getUnirepContract('0xF309DDf2Cc1b2701fED5171C5150092bAc946f07', signer);
// signupVerifier = new ethers.Contract(
Expand Down
4 changes: 2 additions & 2 deletions packages/relayer/.env.example
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
RPC_URL=https://goerli-rollup.arbitrum.io/rpc
GLOBAL_ANONYMOUS_FEED_ADDRESS=0x0
PUBLIC_PROVIDER=https://goerli-rollup.arbitrum.io/rpc
PUBLIC_GLOBAL_ANONYMOUS_FEED_ADDRESS=0x0
PRIVATE_KEY=
6 changes: 3 additions & 3 deletions packages/relayer/src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import AutoLoad, { AutoloadPluginOptions } from "@fastify/autoload";
import { FastifyPluginAsync } from "fastify";
import { JsonSchemaToTsProvider } from "@fastify/type-provider-json-schema-to-ts";
import { syncGroup } from "./services/rln";
import { GLOBAL_ANONYMOUS_FEED_ADDRESS, RPC_URL } from "./config";
import { PUBLIC_GLOBAL_ANONYMOUS_FEED_ADDRESS, PUBLIC_PROVIDER } from "./config";
import { getDefaultProvider } from "@ethersproject/providers";
import epochSealer from "./services/epoch";

Expand All @@ -22,8 +22,8 @@ const app: FastifyPluginAsync<AppOptions> = async (
fastify.withTypeProvider<JsonSchemaToTsProvider>();

// Services
const provider = getDefaultProvider(RPC_URL);
syncGroup(provider, GLOBAL_ANONYMOUS_FEED_ADDRESS);
const provider = getDefaultProvider(PUBLIC_PROVIDER);
syncGroup(provider, PUBLIC_GLOBAL_ANONYMOUS_FEED_ADDRESS);

epochSealer.start();

Expand Down
6 changes: 3 additions & 3 deletions packages/relayer/src/config/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ import { config } from "dotenv";
config();

const {
GLOBAL_ANONYMOUS_FEED_ADDRESS = "",
RPC_URL = "",
PUBLIC_GLOBAL_ANONYMOUS_FEED_ADDRESS = "",
PUBLIC_PROVIDER = "",
PRIVATE_KEY = "",
} = process.env;

export { GLOBAL_ANONYMOUS_FEED_ADDRESS, RPC_URL, PRIVATE_KEY };
export { PUBLIC_GLOBAL_ANONYMOUS_FEED_ADDRESS, PUBLIC_PROVIDER, PRIVATE_KEY };
10 changes: 5 additions & 5 deletions packages/relayer/src/routes/root.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { FastifyPluginAsyncJsonSchemaToTs } from "@fastify/type-provider-json-sc
// import { rlnRegistry, verifyProof } from "../services/rln";
import { getDefaultProvider } from "@ethersproject/providers";
import { Wallet } from "@ethersproject/wallet";
import { GLOBAL_ANONYMOUS_FEED_ADDRESS, PRIVATE_KEY, RPC_URL } from "../config";
import { PUBLIC_GLOBAL_ANONYMOUS_FEED_ADDRESS, PRIVATE_KEY, PUBLIC_PROVIDER } from "../config";
import { GlobalAnonymousFeed__factory } from "../abi";
import cors from '@fastify/cors'
const path = require('path')
Expand Down Expand Up @@ -331,11 +331,11 @@ const getBodySchemaWithoutRep = () => {
const root: FastifyPluginAsyncJsonSchemaToTs = async (
fastify
): Promise<void> => {
console.log(RPC_URL)
const provider = getDefaultProvider(RPC_URL);
console.log(PUBLIC_PROVIDER)
const provider = getDefaultProvider(PUBLIC_PROVIDER);
const wallet = new Wallet(PRIVATE_KEY, provider);
const feed = GlobalAnonymousFeed__factory.connect(
GLOBAL_ANONYMOUS_FEED_ADDRESS,
PUBLIC_GLOBAL_ANONYMOUS_FEED_ADDRESS,
wallet
);

Expand All @@ -360,7 +360,7 @@ const root: FastifyPluginAsyncJsonSchemaToTs = async (
return
}
const hostname = new URL(origin as string).hostname
if(hostname === "localhost"){
if(hostname === "localhost" || hostname === "127.0.0.1" || hostname === "kurate.vercel.app"){
// Request from localhost will pass
cb(null, true)
return
Expand Down
6 changes: 3 additions & 3 deletions packages/relayer/src/services/epoch.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {getDefaultProvider} from "@ethersproject/providers";
import {GLOBAL_ANONYMOUS_FEED_ADDRESS, PRIVATE_KEY, RPC_URL} from "../config";
import {PUBLIC_GLOBAL_ANONYMOUS_FEED_ADDRESS, PRIVATE_KEY, PUBLIC_PROVIDER} from "../config";
import {Wallet} from "@ethersproject/wallet";
import {GlobalAnonymousFeed, GlobalAnonymousFeed__factory} from "../abi";
import {BuildOrderedTree, Circuit, CircuitConfig, Prover} from "@unirep/circuits";
Expand All @@ -23,10 +23,10 @@ class EpochSealer {
nextEpochEnd: number = 0;

constructor() {
const provider = getDefaultProvider(RPC_URL);
const provider = getDefaultProvider(PUBLIC_PROVIDER);
this.wallet = new Wallet(PRIVATE_KEY, provider);
this.contract = GlobalAnonymousFeed__factory.connect(
GLOBAL_ANONYMOUS_FEED_ADDRESS,
PUBLIC_GLOBAL_ANONYMOUS_FEED_ADDRESS,
this.wallet
);
}
Expand Down
4 changes: 2 additions & 2 deletions packages/ui/.env
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ PUBLIC_GLOBAL_ANONYMOUS_FEED_ADDRESS=0x0bd11870C1EBA2e4c316fb580253abAbfBF060A0
PUBLIC_RELAYER_URL=https://relayer.kurate.apyos.dev

# development
#PUBLIC_PROVIDER=http://127.0.0.1:7545
#PUBLIC_GLOBAL_ANONYMOUS_FEED_ADDRESS=0x3bDf5135574a26EEF8648e5a51e6a9a9d87eea6E
#PUBLIC_PROVIDER=http://localhost:8545
#PUBLIC_GLOBAL_ANONYMOUS_FEED_ADDRESS=0xA51c1fc2f0D1a1b8494Ed1FE312d7C3a78Ed91C0
#PUBLIC_RELAYER_URL=http://localhost:3000

PUBLIC_ADAPTER=firebase
7 changes: 6 additions & 1 deletion packages/ui/src/lib/adapters/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,12 @@ import { transaction } from '$lib/stores/transaction'
import type { providers } from 'ethers'

type WindowWithEthereum = Window &
typeof globalThis & { ethereum: providers.ExternalProvider | any }
typeof globalThis & {
ethereum: providers.ExternalProvider & {
on: (name: string, handler: () => unknown) => void
removeListener: (name: string, handler: () => unknown) => void
}
}

const windowWithEthereum = browser && (window as WindowWithEthereum)

Expand Down
13 changes: 2 additions & 11 deletions packages/ui/src/lib/adapters/zkitter-god-mode/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { getGlobalAnonymousFeed } from '$lib/services'
import { sleep } from '$lib/utils'
import { GroupAdapter } from '../zkitter/group-adapter'
import type { Signer } from 'ethers'
import { posts } from '$lib/stores/post'
import { RELAYER_URL } from '../../constants'
import { ZkitterAdapter } from '../zkitter'
Expand All @@ -24,16 +23,9 @@ export class ZkitterAdapterGodMode extends ZkitterAdapter {
return super.start()
}

async publishPost(
personaId: string,
text: string,
images: string[],
signer: Signer,
): Promise<string> {
async publishPost(personaId: string, text: string, images: string[]): Promise<string> {
const { Post, MessageType, PostMessageSubType } = await import('zkitter-js')

if (!signer) throw new Error('must connect with wallet first')

const zkitter = await this.getZkitterClient()

// User did not join the persona yet
Expand Down Expand Up @@ -101,8 +93,7 @@ export class ZkitterAdapterGodMode extends ZkitterAdapter {
return hash
}

async publishPersona(draftPersona: DraftPersona, signer: Signer): Promise<string> {
if (!signer) throw new Error('must connect with wallet first')
async publishPersona(draftPersona: DraftPersona): Promise<string> {
if (!this.identity) throw new Error('must sign in first')
if (!this.userState) throw new Error('user state is not initialized')

Expand Down
Loading