Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
f72ed1c
:arrow_up: update pnpm-lock.yaml
knaoe Apr 14, 2023
2f89473
Merge pull request #1 from y-shijo:contracts/main
y-shijo Apr 14, 2023
d87531f
:sparkles: WIP add top page.
knaoe Apr 14, 2023
f2bb27f
Merge remote-tracking branch 'refs/remotes/origin/main'
knaoe Apr 14, 2023
049eaed
Initialize Backend package
y-shijo Apr 14, 2023
dd34ac6
:bug: fix build failed coz Lock skeleton contract was missing.
knaoe Apr 14, 2023
503a49b
:bug: fix build failed due to invalid JSON format.
knaoe Apr 14, 2023
6080c3f
Add configuration for Backend
y-shijo Apr 14, 2023
d733936
Implement EmailJS
y-shijo Apr 14, 2023
88d59f9
Add Instruction
y-shijo Apr 14, 2023
64e8ea5
:sparkles: add /resolve page
knaoe Apr 14, 2023
1143728
:sparkles: /resolve page now load data from deployed contract.
knaoe Apr 14, 2023
97a8f18
:memo: refine Readme
knaoe Apr 14, 2023
cde22e5
:memo: add Protocol spec into Readme.
knaoe Apr 14, 2023
2f67929
:sparkles: implement Send email to resolve component.
knaoe Apr 15, 2023
9f63ba3
:sparkles: activate input form on top page.
knaoe Apr 15, 2023
0b658f3
:lipstick: show loading animation while waiting the transaction.
knaoe Apr 15, 2023
e8f8c86
:memo: add nonce to JWT
knaoe Apr 15, 2023
a7a70bc
:sparkles: impl /resolve?k={jwt} case.
knaoe Apr 15, 2023
a51b9ea
Improve test code
y-shijo Apr 15, 2023
7e76332
Implement Event Subscriber and Email Sending
y-shijo Apr 15, 2023
a0b5846
Merge pull request #2 from y-shijo:backend/main
y-shijo Apr 15, 2023
1992003
Mumbai deployment configuration
y-shijo Apr 15, 2023
1dffadc
resolvedAddressからのRequesterに対してのデータの削除の実装
164zheng Apr 15, 2023
fafb50c
resolvedAdress+requester指定時の削除の正常系テスト
164zheng Apr 15, 2023
57d9727
Enable network switch
y-shijo Apr 15, 2023
8c43a8a
Merge pull request #3 from y-shijo:backend/main
y-shijo Apr 15, 2023
ab11ecb
Merge remote-tracking branch 'origin'
164zheng Apr 15, 2023
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
7 changes: 6 additions & 1 deletion .vscode/ethathon.code-workspace
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@
"name": "Frontend",
"path": "../packages/frontend"
},
{
"name": "Backend",
"path": "../packages/backend"
},
{
"name": "Contracts",
"path": "../packages/contracts"
Expand All @@ -30,6 +34,7 @@
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.addMissingImports": true,
"source.organizeImports": true,
"source.fixAll.eslint": true
},
Expand All @@ -46,4 +51,4 @@
"statusBarItem.remoteForeground": "#15202b"
}
}
}
}
172 changes: 53 additions & 119 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,33 +1,23 @@
# ETHathon – EVM-based Smart Contract & DApp Boilerplate

![Typescript](https://img.shields.io/badge/Typescript-blue)
![Hardhat](https://img.shields.io/badge/Hardhat-yellow)
![Next.js](https://img.shields.io/badge/Next.js-gray)
![Tailwind](https://img.shields.io/badge/Tailwind-pink)
# HiKyaku Protocol – Email 🤝 web3 address

<img src="packages/frontend/public/images/mix-cover.jpg" width="800" height="223" alt="Cover Image" />

---

This is an opinionated boilerplate/starterkit/scaffold to get up and running with smart contract & dApp development in the EVM-ecosystem.

It also comes in handy for hackathons. 👀
Resolve any email address to web3 address.

By [Dennis Zoma](https://twitter.com/dennis_zoma) 🧙‍♂️ & [Scio Labs](https://scio.xyz) 💫.
By [ken](https://twitter.com/kenichiNaoe), [Yoshi](https://twitter.com/yoshijo04), Tei

---

**Table of Contents:**

1. [The Stack](#the-stack)
2. [Projects using it](#projects-using-it)
3. [Getting Started](#getting-started)
2. [Protocol Spec](#protocol-spec)
3. [Live demo](#live-demo)
4. [Development](#development)
1. [Quickstart](#quickstart)
2. [VSCode Setup](#vscode-setup)
3. [Customization](#customization)
5. [Deployment](#deployment)
6. [FAQs & Troubleshooting](#faqs--troubleshooting)

---

Expand All @@ -44,15 +34,49 @@ By [Dennis Zoma](https://twitter.com/dennis_zoma) 🧙‍♂️ & [Scio Labs](ht
- Misc:
- Linting & Formatting: `eslint`, `prettier`, `husky`, `lint-staged`

## Projects using it
## Protocol Spec

### 1. Register email address

When a user try to resolve an email address, the user's email address is encrypted by LitProtocol and stored in the contract. At this time, the user can select the notifier provider from the list of providers registered in the contract.(Currently, only our first-party provider is available.)

### 2. Send email

The notifier provider sends an email to the user's email address. The email contains a url to the web3 address resolution page.

The url SHOULD be in the following format.

https://hikyaku-protocol.vercel.app/resolve?k={signed_jwt_token}

The JWT token is signed by the notifier provider's private key and the format is following:

```json
{
"iss": "https://hikyaku-protocol-notifier.vercel.app",
"sub": "ken@example.com",
"type": "email",
"nonce": 9999,
"exp": 1620000000
}
```

The issuer SHOULD publish the public key of the private key used to sign the JWT token. The path of the public key SHOULD be in the following format `/.well-known/hikyaku-configuration`.

### 3. Resolve web3 address

When the user opens the url in the email, the user can register his/her web3 address. The user's web3 address is encrypted by LitProtocol and stored in the contract.

Below you find a few live projects that use ETHathon, a variation of it, or have a similar setup setup that inspired it:
### 4. Get web3 address

- [Yieldgate](https://github.com/yieldgate/yieldgate) – Hackathon project that built a patreon-like platform to support projects with yield.
- [Debate3](http://debate3.xyz/) – Hackathon project that built discourse-like forums for DAOs.
- [Stablecoins.wtf](https://stablecoins.wtf/) (frontend only) – Crypto Stablecoin Dashboard & Resources
Once the user's web3 address is registered, the email address can be resolved to the web3 address by calling the `getResolvedAddress` function of the contract.

## Getting Started
## Live demo

https://hikyaku-protocol.vercel.app/

## Development

### Quickstart

```bash
# Install pnpm
Expand All @@ -67,10 +91,6 @@ cp packages/frontend/.env.local.example packages/frontend/.env.local
cp packages/contracts/.env.example packages/contracts/.env
```

## Development

### Quickstart

```bash
# Generate contract-types, start local hardhat node, and start frontend with turborepo
pnpm dev
Expand All @@ -80,105 +100,19 @@ pnpm dev
pnpm frontend:dev
```

### VSCode Setup

#### Workspace

I strongly reommend developing in VSCode by opening the workspace file located at `.vscode/ethathon.code-workspace` instead of just the directory. This has multiple advantages and assures a more predictable monorepo configuration. The first plugin listed below will help with getting used to it.

#### Plugins

I strongly recommend installing all plugins listed inside `.vscode/extensions.json`. They should be suggested automatically by VSCode.

<details>
<summary><strong>Plugin Details</strong></summary>

1. [`zoma.vscode-auto-open-workspace`](https://marketplace.visualstudio.com/items?itemName=zoma.vscode-auto-open-workspace) – Automatically suggests opening the according `.code-workspace` file.
2. [`dbaeumer.vscode-eslint`](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint) – Adds ESLint editor support.
3. [`esbenp.prettier-vscode`](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode) – Adds Prettier editor support.
4. [`NomicFoundation.hardhat-solidity`](https://marketplace.visualstudio.com/items?itemName=NomicFoundation.hardhat-solidity) – Adds Solidity language & Hardhat editor support.
5. [`bradlc.vscode-tailwindcss`](https://marketplace.visualstudio.com/items?itemName=bradlc.vscode-tailwindcss) & [`lightyen.tailwindcss-intellisense-twin`](https://marketplace.visualstudio.com/items?itemName=lightyen.tailwindcss-intellisense-twin) – Adds tailwindcss & twin.macro editor support.
6. Optional: [`gruntfuggly.todo-tree`](https://marketplace.visualstudio.com/items?itemName=gruntfuggly.todo-tree) & [`wayou.vscode-todo-highlight`](https://marketplace.visualstudio.com/items?itemName=wayou.vscode-todo-highlight) – Lists all `TODO` comments in your workspace.
7. Optional: [`mikestead.dotenv`](https://marketplace.visualstudio.com/items?itemName=mikestead.dotenv) – Adds syntax highlighting for `.env` files.

</details>

#### Snippets

The file [`packages/frontend/.vscode/frontend.code-snippets`](https://github.com/scio-labs/ethathon/blob/main/packages/frontend/.vscode/frontend.code-snippets) contains useful snippets for quickly creating components & pages with Next.js, React, Typescript, and twin.macro. Example: Enter "Function Component with Props" in an empty `.tsx` file to get a `FC` component boilerplate with an empty TypeScript interface declaration and already imported 'twin.macro'. Check out the snippet-file itself to get a full overview.

### Customization

There are multiple places where you need to insert your actual project name/identifier. I've highlighted most of these occurences with a `/* TODO */` comment in the code. When installing the `todo-tree` plugin [listed above](#vscode-setup) you can easily replace them one by one.

Additionally, there are the following un-highlighted occurences:

- The name of the `.vscode/*.code-workspace` file
- The package names within `package.json`, `packages/frontend/package.json`, and `packages/contracts/package.json`
- The workspace dependency defined in `packages/frontend/package.json`

## Deployment

Setting up a deployment via Vercel is pretty straightforward as build settings are preconfigured in `vercel.json`. To get started, press the **Deploy** button and enter the default environment variables listed below.

[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fethathon%2Fethathon&env=NEXT_PUBLIC_PRODUCTION_MODE,NEXT_PUBLIC_URL,NEXT_PUBLIC_DEFAULT_CHAIN,NEXT_PUBLIC_SUPPORTED_CHAINS,NEXT_PUBLIC_RPC_1,NEXT_PUBLIC_RPC_5&envDescription=See%20Environment%20Variables%20Examples%20%26%20Documentation&envLink=https%3A%2F%2Fgithub.com%2Fethathon%2Fethathon%2Fblob%2Fmain%2Fpackages%2Ffrontend%2F.env.local.example&redirect-url=https%3A%2F%2Fgithub.com%2Fethathon%2Fethathon)

| Environment Variable | Value |
| ----------------------------- | --------------------------------- |
| `NEXT_PUBLIC_PRODUCTION_MODE` | `true` |
| `NEXT_PUBLIC_URL` | `https://your-repo.vercel.app` |
| `NEXT_PUBLIC_DEFAULT_CHAIN` | `5` |
| `NEXT_PUBLIC_DEFAULT_CHAIN` | `[5]` |
| `NEXT_PUBLIC_RPC_1` | `https://rpc.ankr.com/eth` |
| `NEXT_PUBLIC_RPC_5` | `https://rpc.ankr.com/eth_goerli` |
| Environment Variable | Value |
| ------------------------------ | --------------------------------- |
| `NEXT_PUBLIC_PRODUCTION_MODE` | `true` |
| `NEXT_PUBLIC_URL` | `https://your-repo.vercel.app` |
| `NEXT_PUBLIC_DEFAULT_CHAIN` | `5` |
| `NEXT_PUBLIC_SUPPORTED_CHAINS` | `[5]` |
| `NEXT_PUBLIC_RPC_1` | `https://rpc.ankr.com/eth` |
| `NEXT_PUBLIC_RPC_5` | `https://rpc.ankr.com/eth_goerli` |

You can find mode documentation on those environment variables in [`packages/frontend/.env.local.example`](https://github.com/scio-labs/ethathon/blob/main/packages/frontend/.env.local.example). Always make sure to include respective RPCs for supported chains and define them within [`packages/frontend/src/shared/environment.ts`](https://github.com/scio-labs/ethathon/blob/main/packages/frontend/src/shared/environment.ts). Valid hardhat deployments under [`packages/contracts/deployments`](https://github.com/scio-labs/ethathon/blob/main/packages/contracts/deployments) are mandatory for each supported chain.

## FAQs & Troubleshooting

<details>
<summary><strong>What is pnpm and do I really need it?</strong></summary>

[Pnpm](https://pnpm.io/) works in my experience way faster and more reliable within monorepos than npm or yarn. When using it though, it's strongly recommended everyone in the team uses it. No installs should perform be performed nor any other lockfiles should be commited.

</details>

<details>
<summary><strong>What is Turborepo and do I really need it?</strong></summary>

[Turborepo](https://turbo.build/repo) can drastically speed up your incremental builds in monorepos. But you don't have to use it. This is an example on how to rewrite the `build` task in the root `package.json` w/o Turborepo: `turbo run build` → `pnpm --filter contracts build && pnpm --filter frontend build`.

</details>

<details>
<summary><strong>How to approach styling?</strong></summary>

This boilerplate currently offers styling via the following options.

- [Chakra UI](https://chakra-ui.com/) – Component library for quick prototyping e.g. during hackathons)
- [twin.macro](https://github.com/ben-rogerson/twin.macro) – [Tailwindcss](https://tailwindcss.com/) within Styled Components via [Emotion](https://emotion.sh/docs/styled) (see [snippets](#snippets))
- Standard (S)CSS styles via `className` and `*.module.(s)css` files.

Important, in production it's recommended to use at most one of 1. and 2. to reduce bundle size.

</details>

<details>
<summary><strong>Can I just use plain TailwindCSS?</strong></summary>

The packages above can be easily switched out with plain TailwindCSS, a detailed guide on that is coming very soon. In the meantime, open an issue to get guidance.

</details>

<details>
<summary><strong>Resources to learn more about EVM, Solidity, Hardhat, and wagmi.sh</strong></summary>

- [Ethereum Developer Resources](https://ethereum.org/en/developers/)
- [Solidity Language Documentation](https://docs.soliditylang.org/en/v0.8.17/)
- [Solidity by Example](https://solidity-by-example.org/)
- [Hardhat Documentation](https://hardhat.org/docs)
- [OpenZeppelin Documentation](https://docs.openzeppelin.com/)
- [wagmi.sh Documentation](https://wagmi.sh/)
- [RainbowKit Documentation](https://www.rainbowkit.com/docs)

</details>
8 changes: 8 additions & 0 deletions packages/backend/.prettierrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module.exports = {
"semi": false,
"singleQuote": true,
"trailingComma": "all",
"printWidth": 100,
"tabWidth": 4,
"useTabs": false
}
19 changes: 19 additions & 0 deletions packages/backend/.vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "debug main.ts",
"skipFiles": [
"<node_internals>/**"
],
"cwd": "${workspaceFolder}",
"preLaunchTask": "build-ts",
"program": "${file}",
"outFiles": [
"${workspaceFolder}/dist/**/*.js"
]
}
]
}
15 changes: 15 additions & 0 deletions packages/backend/.vscode/tasks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"label": "build-ts",
"type": "typescript",
"tsconfig": "tsconfig.build.json",
"problemMatcher": [
"$tsc"
],
}
]
}
34 changes: 34 additions & 0 deletions packages/backend/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"name": "@ethathon/backend",
"license": "MIT",
"version": "0.1.0",
"description": "Template for TypeScript project using Node.js v16",
"scripts": {
"build": "tsc --project tsconfig.build.json",
"clean": "rimraf dist",
"lint": "eslint '**/*.{js,ts}'",
"prebuild": "npm run clean",
"start": "ts-node src/main.ts",
"test": "jest --passWithNoTests"
},
"devDependencies": {
"@eslint-recommended/eslint-config-typescript": "3.0.0",
"@tsconfig/node18": "1.0.1",
"@types/node": "18.15.11",
"eslint": "8.31.0",
"eslint-plugin-jest": "27.2.1",
"jest": "29.3.1",
"rimraf": "3.0.2",
"ts-jest": "29.0.3",
"ts-node": "10.9.1",
"typescript": "4.9.4"
},
"dependencies": {
"@types/jsonwebtoken": "^9.0.1",
"axios": "^1.2.2",
"dotenv": "^16.0.3",
"email-validator": "^2.0.4",
"ethers": "^5.7.2",
"jsonwebtoken": "^9.0.0"
}
}
62 changes: 62 additions & 0 deletions packages/backend/sample/EventSubscriber.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { ethers } from 'ethers'

require('dotenv').config()

const GREETING_ABI = require('./abi/Greeting.json')

type TnamedAddress = {
address: string
ensName?: string
}

async function main() {
let provider
let greetingContractAddress

const mode: string = process.env.MODE as string
// 環境に応じた設定
if (mode == 'local') {
provider = new ethers.providers.JsonRpcProvider(process.env.LOCAL_RPC_ENDPOINT)
greetingContractAddress = process.env.LOCAL_GREETING_CONTRACT as string
} else if (mode == 'test') {
provider = new ethers.providers.InfuraProvider(
process.env.TESTNET_NETWORK_NAME,
process.env.INFURA_API_KEY,
)
// TODO: Contract Address should be fetched via ENS (facade.thegreeting.eth)
greetingContractAddress = process.env.TESTNET_GREETING_CONTRACT as string
} else {
throw new Error('Unknown Mode')
}

// コントラクトのインスタンス化
const greetingContract = new ethers.Contract(greetingContractAddress, GREETING_ABI, provider)
console.log(`Contract created:: [address] ${greetingContract.address}`)

const campaignList = await greetingContract.getCampaignList()
console.log(`[campaign list] ${campaignList}`)

// Listen対象のイベント
const eventQuery = greetingContract.filters.SendMessage()
// const events = await greetingContract.queryFilter(eventQuery);
// const eventArgs = events[0].args;
// console.log(eventArgs?.from)
// console.log(eventArgs?.to)
// console.log(eventArgs?.campaign)

// Listen Event...
// TODO: When fetched via ENS and address is updated, unsubscribe current subscrption, and subscribe to new contract.
greetingContract.on(eventQuery, (from, to, campaign, event) => {
console.log(`[New log found] from ${from} to ${to} via ${campaign}`)

const fromNamedAddress: TnamedAddress = { address: from }
const toNamedAddress: TnamedAddress = { address: to }
const campaignNamedAddress: TnamedAddress = { address: campaign }
const txHash = event.transactionHash
})
}

main().catch((error) => {
console.error(error)
process.exitCode = 1
})
Loading