From c5a1fc9c924a4a9f97a71c5ec57d54a9c0e448bb Mon Sep 17 00:00:00 2001 From: 0xMillz <37815163+0xMillz@users.noreply.github.com> Date: Mon, 4 Nov 2024 01:06:25 -0600 Subject: [PATCH 01/28] change button to create instead of submit --- .../src/modules/dao/components/Activity/Activity.tsx | 10 +++++----- apps/web/src/styles/Proposals.css.ts | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/web/src/modules/dao/components/Activity/Activity.tsx b/apps/web/src/modules/dao/components/Activity/Activity.tsx index e399bb569..c6e241c1c 100644 --- a/apps/web/src/modules/dao/components/Activity/Activity.tsx +++ b/apps/web/src/modules/dao/components/Activity/Activity.tsx @@ -25,7 +25,7 @@ import { useChainStore } from 'src/stores/useChainStore' import { delegateBtn, selectDelegateBtn, - submitProposalBtn, + createProposalBtn, } from 'src/styles/Proposals.css' import { sectionWrapperStyle } from 'src/styles/dao.css' import { AddressType } from 'src/typings' @@ -148,20 +148,20 @@ export const Activity: React.FC = () => { ) : null} {!address ? ( ) : ( )} diff --git a/apps/web/src/styles/Proposals.css.ts b/apps/web/src/styles/Proposals.css.ts index 965abf2ad..cc17f576f 100644 --- a/apps/web/src/styles/Proposals.css.ts +++ b/apps/web/src/styles/Proposals.css.ts @@ -39,7 +39,7 @@ export const delegateBtn = style({ }, }) -export const submitProposalBtn = style({ +export const createProposalBtn = style({ fontSize: '1rem', fontFamily: 'ptRoot!important', borderRadius: '12px', From 98f4ff7c0663da35ac0e120fd86272781d5987b1 Mon Sep 17 00:00:00 2001 From: 0xMillz <37815163+0xMillz@users.noreply.github.com> Date: Tue, 5 Nov 2024 12:56:26 -0600 Subject: [PATCH 02/28] Testing PR deployment preview workflow --- .github/workflows/deploy_preview.yml | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 .github/workflows/deploy_preview.yml diff --git a/.github/workflows/deploy_preview.yml b/.github/workflows/deploy_preview.yml new file mode 100644 index 000000000..e4edfbd41 --- /dev/null +++ b/.github/workflows/deploy_preview.yml @@ -0,0 +1,25 @@ +name: Deploy Preview to Vercel + +on: + pull_request: + types: [opened, synchronize, reopened] + +jobs: + deploy: + runs-on: ubuntu-latest + + steps: + - name: Checkout Repository + uses: actions/checkout@v2 + + - name: Install Vercel CLI + run: npm install --global vercel@latest + + - name: Pull Vercel Environment Information + run: vercel pull --yes --environment=preview --token=${{ secrets.VERCEL_TOKEN }} + + - name: Build Project + run: vercel build --token=${{ secrets.VERCEL_TOKEN }} + + - name: Deploy to Vercel + run: vercel deploy --prebuilt --token=${{ secrets.VERCEL_TOKEN }} \ No newline at end of file From f20dcedaa83d824880be27fa349ea9cd0d408549 Mon Sep 17 00:00:00 2001 From: 0xMillz <37815163+0xMillz@users.noreply.github.com> Date: Tue, 5 Nov 2024 14:46:40 -0600 Subject: [PATCH 03/28] Take 2: Testing PR deployment preview workflow --- .../{deploy_preview.yml => preview.yaml} | 21 ++++++++--------- .../workflows/{main.yml => production.yaml} | 23 +++++++++++++++++++ 2 files changed, 32 insertions(+), 12 deletions(-) rename .github/workflows/{deploy_preview.yml => preview.yaml} (55%) rename .github/workflows/{main.yml => production.yaml} (71%) diff --git a/.github/workflows/deploy_preview.yml b/.github/workflows/preview.yaml similarity index 55% rename from .github/workflows/deploy_preview.yml rename to .github/workflows/preview.yaml index e4edfbd41..a002a9d18 100644 --- a/.github/workflows/deploy_preview.yml +++ b/.github/workflows/preview.yaml @@ -1,25 +1,22 @@ -name: Deploy Preview to Vercel +name: GitHub Actions Vercel Preview Deployment +env: + VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} + VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }} on: pull_request: types: [opened, synchronize, reopened] jobs: - deploy: + Deploy-Preview: runs-on: ubuntu-latest - steps: - - name: Checkout Repository - uses: actions/checkout@v2 - + - uses: actions/checkout@v3 - name: Install Vercel CLI - run: npm install --global vercel@latest - + run: npm install --global vercel@canary - name: Pull Vercel Environment Information run: vercel pull --yes --environment=preview --token=${{ secrets.VERCEL_TOKEN }} - - - name: Build Project + - name: Build Project Artifacts run: vercel build --token=${{ secrets.VERCEL_TOKEN }} - - - name: Deploy to Vercel + - name: Deploy Project Artifacts to Vercel run: vercel deploy --prebuilt --token=${{ secrets.VERCEL_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/main.yml b/.github/workflows/production.yaml similarity index 71% rename from .github/workflows/main.yml rename to .github/workflows/production.yaml index bef426427..2d9bb5121 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/production.yaml @@ -79,3 +79,26 @@ jobs: # Need to shutdown Anvil so cache gets created - name: πŸ’€ Shutdown Anvil run: pkill -2 anvil + +# TODO @0xMillz for production: (https://vercel.com/guides/how-can-i-use-github-actions-with-vercel) +#name: Vercel Production Deployment +#env: +# VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} +# VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }} +#on: +# push: +# branches: +# - main +#jobs: +# Deploy-Production: +# runs-on: ubuntu-latest +# steps: +# - uses: actions/checkout@v2 +# - name: Install Vercel CLI +# run: npm install --global vercel@latest +# - name: Pull Vercel Environment Information +# run: vercel pull --yes --environment=production --token=${{ secrets.VERCEL_TOKEN }} +# - name: Build Project Artifacts +# run: vercel build --prod --token=${{ secrets.VERCEL_TOKEN }} +# - name: Deploy Project Artifacts to Vercel +# run: vercel deploy --prebuilt --prod --token=${{ secrets.VERCEL_TOKEN }} From 5ca1c5cf3f68734f4c71cc0fabe45914f6bf2b07 Mon Sep 17 00:00:00 2001 From: 0xMillz <37815163+0xMillz@users.noreply.github.com> Date: Tue, 5 Nov 2024 14:49:58 -0600 Subject: [PATCH 04/28] Take 3: Comment out legacy workflowe that is interfering --- .github/workflows/production.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/production.yaml b/.github/workflows/production.yaml index 2d9bb5121..a544e01d5 100644 --- a/.github/workflows/production.yaml +++ b/.github/workflows/production.yaml @@ -2,8 +2,8 @@ name: CI on: - pull_request: - types: [opened, reopened, synchronize, ready_for_review] +# pull_request: +# types: [opened, reopened, synchronize, ready_for_review] push: branches: [main] From c059145261ec3e5efb0eb26a308bafc6a0ed18ef Mon Sep 17 00:00:00 2001 From: 0xMillz <37815163+0xMillz@users.noreply.github.com> Date: Thu, 7 Nov 2024 10:36:31 -0600 Subject: [PATCH 05/28] Update prod workflow --- .github/workflows/production.yaml | 23 ++++++----------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/.github/workflows/production.yaml b/.github/workflows/production.yaml index a544e01d5..6802121b3 100644 --- a/.github/workflows/production.yaml +++ b/.github/workflows/production.yaml @@ -1,12 +1,12 @@ # This workflow runs the CI command defined in package.json name: CI - +env: + VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} + VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }} on: -# pull_request: -# types: [opened, reopened, synchronize, ready_for_review] push: - branches: [main] - + branches: + - main jobs: ci: name: CI @@ -81,18 +81,7 @@ jobs: run: pkill -2 anvil # TODO @0xMillz for production: (https://vercel.com/guides/how-can-i-use-github-actions-with-vercel) -#name: Vercel Production Deployment -#env: -# VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} -# VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }} -#on: -# push: -# branches: -# - main -#jobs: -# Deploy-Production: -# runs-on: ubuntu-latest -# steps: + # - uses: actions/checkout@v2 # - name: Install Vercel CLI # run: npm install --global vercel@latest From 96f6a2462d8d08c1a38f3ed23493e3ff82571c67 Mon Sep 17 00:00:00 2001 From: 0xMillz <37815163+0xMillz@users.noreply.github.com> Date: Thu, 7 Nov 2024 11:23:52 -0600 Subject: [PATCH 06/28] Add VERCEL_TOKEN --- .github/workflows/preview.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/preview.yaml b/.github/workflows/preview.yaml index a002a9d18..ac0c15e4d 100644 --- a/.github/workflows/preview.yaml +++ b/.github/workflows/preview.yaml @@ -2,6 +2,7 @@ name: GitHub Actions Vercel Preview Deployment env: VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }} + VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }} on: pull_request: From 7e36675808b53d9dd5ef61d6f6ba29caedc3309f Mon Sep 17 00:00:00 2001 From: 0xMillz <37815163+0xMillz@users.noreply.github.com> Date: Thu, 7 Nov 2024 11:39:37 -0600 Subject: [PATCH 07/28] Add pnpm step to workflow --- .github/workflows/preview.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/preview.yaml b/.github/workflows/preview.yaml index ac0c15e4d..3b72f07dd 100644 --- a/.github/workflows/preview.yaml +++ b/.github/workflows/preview.yaml @@ -13,6 +13,8 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 + - name: Install pnpm + run: npm install -g pnpm - name: Install Vercel CLI run: npm install --global vercel@canary - name: Pull Vercel Environment Information From 84636b69037164e803df8a65e6f857a91ccfe9bf Mon Sep 17 00:00:00 2001 From: 0xMillz <37815163+0xMillz@users.noreply.github.com> Date: Thu, 7 Nov 2024 11:45:36 -0600 Subject: [PATCH 08/28] Add pnpm caching step to workflow --- .github/workflows/preview.yaml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/preview.yaml b/.github/workflows/preview.yaml index 3b72f07dd..32e2ab727 100644 --- a/.github/workflows/preview.yaml +++ b/.github/workflows/preview.yaml @@ -13,6 +13,13 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 + - name: Cache pnpm + uses: actions/cache@v3 + with: + path: ~/.pnpm-store + key: ${{ runner.os }}-pnpm-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm- - name: Install pnpm run: npm install -g pnpm - name: Install Vercel CLI From 6a6e29a122b2e30b5c405d6988fa1497479ca503 Mon Sep 17 00:00:00 2001 From: 0xMillz <37815163+0xMillz@users.noreply.github.com> Date: Thu, 7 Nov 2024 11:57:04 -0600 Subject: [PATCH 09/28] Optimize preview workflow for efficiency and speed --- .github/workflows/preview.yaml | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/.github/workflows/preview.yaml b/.github/workflows/preview.yaml index 32e2ab727..7a43d77e0 100644 --- a/.github/workflows/preview.yaml +++ b/.github/workflows/preview.yaml @@ -13,20 +13,19 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - name: Cache pnpm + - name: Ensure pnpm store directory exists + run: mkdir -p ~/.pnpm-store + - name: Cache Node Modules and pnpm Store uses: actions/cache@v3 with: - path: ~/.pnpm-store + path: | + ~/.pnpm-store + node_modules key: ${{ runner.os }}-pnpm-${{ hashFiles('**/pnpm-lock.yaml') }} restore-keys: | ${{ runner.os }}-pnpm- - - name: Install pnpm - run: npm install -g pnpm - - name: Install Vercel CLI - run: npm install --global vercel@canary - - name: Pull Vercel Environment Information - run: vercel pull --yes --environment=preview --token=${{ secrets.VERCEL_TOKEN }} - - name: Build Project Artifacts - run: vercel build --token=${{ secrets.VERCEL_TOKEN }} + - name: Install pnpm and Vercel CLI + run: | + npm install -g pnpm vercel@canary - name: Deploy Project Artifacts to Vercel run: vercel deploy --prebuilt --token=${{ secrets.VERCEL_TOKEN }} \ No newline at end of file From 5a7967756e3b8524af4e2d3b600bbd4c65a74d25 Mon Sep 17 00:00:00 2001 From: 0xMillz <37815163+0xMillz@users.noreply.github.com> Date: Thu, 7 Nov 2024 12:08:29 -0600 Subject: [PATCH 10/28] Add build step to workflow --- .github/workflows/preview.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/preview.yaml b/.github/workflows/preview.yaml index 7a43d77e0..59d9f181d 100644 --- a/.github/workflows/preview.yaml +++ b/.github/workflows/preview.yaml @@ -27,5 +27,7 @@ jobs: - name: Install pnpm and Vercel CLI run: | npm install -g pnpm vercel@canary + - name: Build Project Artifacts + run: vercel build --token=${{ secrets.VERCEL_TOKEN }} - name: Deploy Project Artifacts to Vercel run: vercel deploy --prebuilt --token=${{ secrets.VERCEL_TOKEN }} \ No newline at end of file From ab24b4a602f8e849d96122a8aefd93deb6ddd88e Mon Sep 17 00:00:00 2001 From: 0xMillz <37815163+0xMillz@users.noreply.github.com> Date: Thu, 7 Nov 2024 12:11:40 -0600 Subject: [PATCH 11/28] Get token before build --- .github/workflows/preview.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/preview.yaml b/.github/workflows/preview.yaml index 59d9f181d..154f2e16a 100644 --- a/.github/workflows/preview.yaml +++ b/.github/workflows/preview.yaml @@ -8,6 +8,7 @@ on: pull_request: types: [opened, synchronize, reopened] +jobs: jobs: Deploy-Preview: runs-on: ubuntu-latest @@ -27,6 +28,8 @@ jobs: - name: Install pnpm and Vercel CLI run: | npm install -g pnpm vercel@canary + - name: Pull Vercel Environment Information + run: vercel pull --yes --token=${{ secrets.VERCEL_TOKEN }} - name: Build Project Artifacts run: vercel build --token=${{ secrets.VERCEL_TOKEN }} - name: Deploy Project Artifacts to Vercel From 676bbe269765ab14e79be95e1893456857494100 Mon Sep 17 00:00:00 2001 From: 0xMillz <37815163+0xMillz@users.noreply.github.com> Date: Thu, 7 Nov 2024 12:23:56 -0600 Subject: [PATCH 12/28] lnaguage: change words Submit to Create --- apps/web/src/modules/dashboard/DaoProposals.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/web/src/modules/dashboard/DaoProposals.tsx b/apps/web/src/modules/dashboard/DaoProposals.tsx index 77da70a3f..114952391 100644 --- a/apps/web/src/modules/dashboard/DaoProposals.tsx +++ b/apps/web/src/modules/dashboard/DaoProposals.tsx @@ -74,7 +74,7 @@ export const DaoProposals = ({ router.push(`/dao/${currentChainSlug}/${tokenAddress}/proposal/create`) } > - Submit Proposal + Create Proposal From 2a6651a053e710dba24ec62e6d4e23cab516f330 Mon Sep 17 00:00:00 2001 From: 0xMillz <37815163+0xMillz@users.noreply.github.com> Date: Thu, 7 Nov 2024 12:35:24 -0600 Subject: [PATCH 13/28] fix typo --- .github/workflows/preview.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/preview.yaml b/.github/workflows/preview.yaml index 154f2e16a..b00a4c6eb 100644 --- a/.github/workflows/preview.yaml +++ b/.github/workflows/preview.yaml @@ -8,7 +8,6 @@ on: pull_request: types: [opened, synchronize, reopened] -jobs: jobs: Deploy-Preview: runs-on: ubuntu-latest From 9ef5f4b552eac8bc2844ffafd037e7d26f91f890 Mon Sep 17 00:00:00 2001 From: Mills <37815163+0xMillz@users.noreply.github.com> Date: Wed, 4 Dec 2024 14:40:45 -0600 Subject: [PATCH 14/28] Update subgraph docs (#4) - Update subgraph documentation and configuration - Add and update scripts in `package.json` for various environments - Upgrade dependencies - Adjust subgraph build command name --------- Signed-off-by: Mills <37815163+0xMillz@users.noreply.github.com> --- README.md | 257 +++++----- apps/subgraph/.env.example | 6 +- apps/subgraph/README.md | 106 +++-- apps/subgraph/config/base-goerli.json | 8 - .../{sepolia.json => ethereum-sepolia.json} | 2 +- .../config/{mainnet.json => ethereum.json} | 2 +- apps/subgraph/config/goerli.json | 8 - apps/subgraph/config/optimism-goerli.json | 8 - apps/subgraph/config/zora-goerli.json | 8 - apps/subgraph/config/zora.json | 2 +- apps/subgraph/package.json | 23 +- apps/web/src/constants/subgraph.ts | 5 +- pnpm-lock.yaml | 442 +++++++----------- 13 files changed, 352 insertions(+), 525 deletions(-) delete mode 100644 apps/subgraph/config/base-goerli.json rename apps/subgraph/config/{sepolia.json => ethereum-sepolia.json} (80%) rename apps/subgraph/config/{mainnet.json => ethereum.json} (84%) delete mode 100644 apps/subgraph/config/goerli.json delete mode 100644 apps/subgraph/config/optimism-goerli.json delete mode 100644 apps/subgraph/config/zora-goerli.json diff --git a/README.md b/README.md index 4ba55c118..9d76d3d0b 100644 --- a/README.md +++ b/README.md @@ -1,152 +1,105 @@ -# Nouns Builder monorepo - -This is Nouns Builder front-end mono-repo. You can find Nouns Builder deployed on: - -- [Mainnet](//nouns.build) -- [Goerli testnet](//testnet.nouns.build) - -For an introduction to Nouns Builder and its concept, you can find further [documentation here](https://docs.zora.co/docs/smart-contracts/nouns-builder/intro). You can also find [Nouns Protocol here](https://github.com/ourzora/nouns-protocol). - -### Apps and packages in this repository include: - -`apps` - -- `web`: Nouns Builder front-end -- `subgraph`: Nouns Builder subgraph - -`packages` - -- `blocklist`: Package to check for sanctioned wallet addresses -- `analytics`: Shareable analytics package -- `zoralabs-zord`: Shareable ui components -- `eslint-config-custom`: `eslint` configurations (includes `eslint-config-next` and `eslint-config-prettier`) -- `tsconfig`: `tsconfig.json`s used throughout the monorepo -- `ipfs-service`: api to for image uploads to ipfs - -## Quickstart - -#### Get up and running - -1. Clone this repo locally -2. [Install pnpm](https://pnpm.io/installation#using-corepack) - -3. Add the required [environment variables](#environment-variables) - -4. Install dependencies across all apps and packages - -``` -pnpm i -``` - -5. Once environment variables are defined, you can run the app in dev mode - -``` -pnpm dev -``` - -#### Linting and formatting - -> Note: linting and prettier formatting are automatically run on pre-push hooks - -To lint: - -``` -pnpm run lint -``` - -To format: - -``` -pnpm run format -``` - -To run type checks: - -``` -pnpm run type-check -``` - -#### To create and run a production build - -``` -> pnpm run build -> pnpm run start -``` - -## Environment variables - -This app has several third party api keys that you need in order to run Builder: - -- [alchemy](https://www.alchemy.com/) as the main rpc node provider in addition to mainnet forks for testing -- [tenderly](https://docs.tenderly.co/simulations-and-forks/simulation-api) in order to simulate transactions -- [etherscan](https://docs.etherscan.io/api-endpoints/contracts) to dyanamically fetch abis - -We ask that you supply your own secrets locally for running in development environment. Non-secret environment variables are already included in the `.env` files in this repo. - -Add the following variables to `.env.local` within this root directory (needed to run tests against a local anvil node): - -``` -#alchemy -PRIVATE_ALCHEMY_ID= -ANVIL_FORK_URL=https://eth-mainnet.alchemyapi.io/v2/$PRIVATE_ALCHEMY_ID -ANVIL_BLOCK_NUMBER=8305745 -``` - -Add the following variables to `apps/web/.env.local`: - -``` -#alchemy -NEXT_PUBLIC_TENDERLY_RPC_KEY= - - -#tenderly -TENDERLY_ACCESS_KEY= -TENDERLY_PROJECT= -TENDERLY_USER= - -#etherscan (optional to run locally, this is for dynamically fetching abis in the custom transaction builder) -ETHERSCAN_API_KEY= - -#optional zora api key -NEXT_PUBLIC_ZORA_API_KEY= -``` - -## Running tests - -> Note: to run tests you need to [install anvil](https://github.com/foundry-rs/foundry/blob/master/README.md#installation). - -Once anvil is installed, you can now locally run anvil (from the root directory in the monorepo) in a separate terminal session to start a local ethereum node: -`pnpm run anvil` - -Now you can run the tests in a separate terminal session: -`pnpm run test` - -You can also run the tests in watchmode, which will react to any source code or test files changing. To do that, run: -`pnpm run test:watch` - -## Deployments - -### Client - -The Nouns Builder client is deployed on [Vercel](https://vercel.com/). Any pull requests will trigger a new preview deployment providing you with an environment to test out and preview changes. - -### Subgraph - -The Nouns Builder subgraph is deployed for the following networks: - -- [Ethereum Mainnet](https://api.thegraph.com/subgraphs/name/neokry/nouns-builder-mainnet) -- [Ethereum Goerli](https://api.thegraph.com/subgraphs/name/neokry/nouns-builder-goerli) -- [Optimism Mainnet](https://api.thegraph.com/subgraphs/name/neokry/noun-builder-optimism-mainnet) -- [Optimism Goerli](https://api.thegraph.com/subgraphs/name/neokry/nouns-builder-optimism-goerli) -- [Zora Mainnet](https://api.goldsky.com/api/public/project_clkk1ucdyf6ak38svcatie9tf/subgraphs/nouns-builder-zora-mainnet/stable/gn) -- [Zora Goerli](https://api.goldsky.com/api/public/project_clkk1ucdyf6ak38svcatie9tf/subgraphs/nouns-builder-zora-testnet/stable/gn) -- [Base Mainnet](https://api.goldsky.com/api/public/project_clkk1ucdyf6ak38svcatie9tf/subgraphs/nouns-builder-base-mainnet/stable/g) -- [Base Goerli](https://api.studio.thegraph.com/query/49279/nouns-builder-base-goerli/version/latest) - -## Contributions - -Please refer to our [contributions guideline](/.github/contributing.md) on how best to contribute. - -## Questions? - -Feel free to reach out to us via [twitter](https://twitter.com/nounsbuilder), [discord](https://discord.gg/JpMKps2W), or via email at +# Nouns Builder Subgraph + +## Index +- [Getting Started](#getting-started) +- [Step 1 - Install Dependencies](#step-1---install-dependencies) +- [Step 2 - Set Up a Personal Goldsky API Key](#step-2---set-up-a-personal-goldsky-api-key) +- [Step 3 - Log in with the API Key](#step-3---log-in-with-the-api-key) +- [Step 4 - Build the Subgraph from Source](#step-4---build-the-subgraph-from-source) +- [Step 5 - Deploy the Subgraph to Production](#step-5---deploy-the-subgraph-to-production) +- [Step 6 - Query the Subgraph](#step-6---query-the-subgraph) +- [Production Endpoints](#production-endpoints) +- [(DEPRECATED) Local Development with Docker Compose (TODO: fix - pnpm create:local step not working)](#local-development-with-docker-compose) + +## Getting Started +πŸ‘‰ [Read the Goldsky docs](https://docs.goldsky.com/subgraphs/deploying-subgraphs) + +The Nouns Builder subgraph supports eight networks: +- `ethereum` +- `ethereum-sepolia` +- `base` +- `base-sepolia` +- `optimism` +- `optimism-sepolia` +- `zora` +- `zora-sepolia` + +### Step 1 - Install Dependencies +Navigate to the subgraph directory and run: +```bash +# FROM: ./apps/subgraph +pnpm install +``` + +### Step 2 - Set Up a Personal Goldsky API Key +1. Request to join the team account at [goldsky.com](https://goldsky.com). +2. Create an API key on your Settings page. +3. Install the Goldsky CLI: + ```bash + curl https://goldsky.com | sh + ``` + +### Step 3 - Log in with the API Key +Use the API key you created: +```bash +# FROM: ./apps/subgraph +goldsky login +``` + +### Step 4 - Build the Subgraph from Source +Run the following commands (these scripts are defined in `package.json`): +```bash +# FROM: ./apps/subgraph +pnpm prepare: +pnpm codegen +pnpm build +``` + +This will generate types, build the subgraph, and create a local `subgraph.yaml` file. + +### Step 5 - Deploy the Subgraph to Production + +#### IMPORTANT: +**To avoid downtime during upgrades, maintain a backup subgraph. If issues arise, you can redirect traffic to the backup rather than waiting for redeployment or rollback, which can take hours.** + +- The subgraph name follows the pattern `nouns-builder-` regardless of version, don't clients do not need to be notified for non-breaking changes. +- Increase the `specVersion` at the top of `subgraph.yaml.mustache` for each new version. +- Use the **--tag** flag to alias `latest` with the current `specVersion`. +- If you are making breaking changes, make sure to notify clients first and provide a migration path. + +**Always remember to tag!** + +```bash +# FROM: ./apps/subgraph +# Example with specVersion 0.0.6 + +goldsky subgraph deploy nouns-builder-/0.0.6 --path . +goldsky subgraph tag create nouns-builder-/0.0.6 --tag latest +# API endpoint format will be: api.goldsky.com/api/public//subgraphs/nouns-builder-ethereum-sepolia/latest/gn +``` + +### Step 6 - Query the Subgraph + +You can now query the subgraph in the Goldsky GraphQL playground to test your changes. **Note: Full indexing may take several hours.** + +## Production Endpoints + +The subgraph is currently deployed to the following networks: + +- [Ethereum](https://api.goldsky.com/api/public/project_cm33ek8kjx6pz010i2c3w8z25/subgraphs/nouns-builder-ethereum/latest/gn) +- [Ethereum Sepolia](https://api.goldsky.com/api/public/project_cm33ek8kjx6pz010i2c3w8z25/subgraphs/nouns-builder-ethereum-sepolia/latest/gn) +- [Optimism](https://api.goldsky.com/api/public/project_cm33ek8kjx6pz010i2c3w8z25/subgraphs/nouns-builder-optimism/latest/gn) +- TODO: [Optimism Sepolia](https://api.goldsky.com/api/public/project_cm33ek8kjx6pz010i2c3w8z25/subgraphs/nouns-builder-optimism-sepolia/latest/gn) +- TODO: [Zora](https://api.goldsky.com/api/public/project_cm33ek8kjx6pz010i2c3w8z25/subgraphs/nouns-builder-zora/latest/gn) +- TODO: [Zora Sepolia](https://api.goldsky.com/api/public/project_cm33ek8kjx6pz010i2c3w8z25/subgraphs/nouns-builder-zora-sepolia/latest/gn) +- TODO: [Base](https://api.goldsky.com/api/public/project_cm33ek8kjx6pz010i2c3w8z25/subgraphs/nouns-builder-base/latest/gn) +- TODO: [Base Sepolia](https://api.goldsky.com/api/public/project_cm33ek8kjx6pz010i2c3w8z25/subgraphs/nouns-builder-base-sepolia/latest/gn) + +## (DEPRECATED) Local Development with Docker Compose (TODO: fix - pnpm create:local step not working) +- Generate the subgraph.yml file with `pnpm prepare:` +- Generate types with `pnpm codegen` +- Build the subgraph with `pnpm build` +- Run the local graph node with `pnpm local:node` +- For Mac users on Apple Silicon, use a local image of `graphprotocol/graph-node` (see [instructions here](https://github.com/graphprotocol/graph-node/tree/master/docker)). +- Create the local subgraph with `pnpm create:local` +- Deploy changes to the local subgraph with `pnpm deploy-local` diff --git a/apps/subgraph/.env.example b/apps/subgraph/.env.example index c3e9f70a5..77411561b 100644 --- a/apps/subgraph/.env.example +++ b/apps/subgraph/.env.example @@ -1,9 +1,7 @@ # Docker config -## For the Goerli testnet use goerli -## For local testing leave empty (docker compose file has defaults) +## Example: for Ethereum Sepolia the value is ethereum-sepolia NETWORK_NAME= -## For Goerli use https://goerli.infura.io/v3/ -## For local testing leave empty +## Example: for Ethereum Sepolia the value is https://sepolia.infura.io/v3/ NETWORK_RPC= \ No newline at end of file diff --git a/apps/subgraph/README.md b/apps/subgraph/README.md index 8470d6c39..e876bdf90 100644 --- a/apps/subgraph/README.md +++ b/apps/subgraph/README.md @@ -1,51 +1,89 @@ # Nouns Builder Subgraph -This `README` is intended to provide app specific context. +## Getting Started +πŸ‘‰ [Read the Goldsky docs](https://docs.goldsky.com/subgraphs/deploying-subgraphs) -### App Dependencies +The Nouns Builder subgraph supports four networks: +- `ethereum` +- `ethereum-sepolia` +- `base` +- `optimism` +- `zora` -The Nouns Builder Subgraph is built on the Graph Protocol and includes the following dependencies: +### Step 1 - Install Dependencies +Navigate to the subgraph directory and run: +```bash +# FROM: ./apps/subgraph +pnpm install +``` + +### Step 2 - Set Up a Personal Goldsky API Key +1. Request to join the team account at [goldsky.com](https://goldsky.com). +2. Create an API key on your Settings page. +3. Install the Goldsky CLI: + ```bash + curl https://goldsky.com | sh + ``` -- [@graphprotocol/graph-cli](https://www.npmjs.com/package/@graphprotocol/graph-cli) - cli for developing and testing subgraphs -- [@graphprotocol/graph-ts](https://www.npmjs.com/package/@graphprotocol/graph-ts) - core typescript library for writing subgraphs +### Step 3 - Log in with the API Key +Use the API key you created: +```bash +# FROM: ./apps/subgraph +goldsky login +``` -### Chain Environment +### Step 4 - Build the Subgraph from Source +Run the following commands (these scripts are defined in `package.json`): +```bash +# FROM: ./apps/subgraph +pnpm prepare: +pnpm codegen +pnpm build:subgraph +``` -Nouns Builder subgraph currently supports two networks: `mainnet` and `goerli`. The environment variables indicated below dictate the network that the app interacts with. +This will generate types, build the subgraph, and create a local `subgraph.yaml` file. -You can swap out the environment variables as defined below to run the subgraph locally against mainnnet or testnet locally. +### Step 5 - Deploy the Subgraph to Production -``` -# the default chain id defined in .env, to run against testnet -NETWORK_RPC= -NETWORK_NAME=goerli +#### IMPORTANT: +**To avoid downtime during upgrades, maintain a backup subgraph. If issues arise, you can redirect traffic to the backup rather than waiting for redeployment or rollback, which can take hours.** + +- The subgraph name follows the pattern `nouns-builder-`, so clients won’t need to update their URI for minor version changes. +- Increase the `specVersion` at the top of `subgraph.yaml.mustache` for each new version. +- Use the **--tag** flag to alias `latest` with the current `specVersion`. + +**Always remember to tag!** + +```bash +# FROM: ./apps/subgraph +# Example with specVersion 0.0.6 -# to run against mainnet locally -NETWORK_RPC= -NETWORK_NAME=mainnet +goldsky subgraph deploy nouns-builder-/0.0.6 --path . +goldsky subgraph tag create nouns-builder-/0.0.6 --tag latest +# API endpoint format: api.goldsky.com/api/public//subgraphs/nouns-builder-ethereum-sepolia/latest/gn ``` -### Development +### Step 6 - Query the Subgraph -- create a `.env` file with the required environment variables -- generate types with `pnpm codegen` -- build the subgraph with `pnpm build` -- run the local graph node with `pnpm local-node` - - for M1 mac users you will need to use a local image of `graphprotocol/graph-node` [instructions here](https://github.com/graphprotocol/graph-node/tree/master/docker) -- create the local subgraph with `pnpm create-local` -- deploy changes to the local subgraph with `pnpm deploy-local` +You can now query the subgraph in the Goldsky GraphQL playground to test your changes. **Note: Full indexing may take several hours.** -### Deployment +## Production Endpoints -The subgraph is currently deployed for the following networks: +The subgraph is currently deployed to the following networks: -- [Ethereum Mainnet](https://api.thegraph.com/subgraphs/name/neokry/nouns-builder-mainnet) -- [Ethereum Goerli](https://api.thegraph.com/subgraphs/name/neokry/nouns-builder-goerli) -- [Optimism Mainnet](https://api.thegraph.com/subgraphs/name/neokry/noun-builder-optimism-mainnet) -- [Optimism Goerli](https://api.thegraph.com/subgraphs/name/neokry/nouns-builder-optimism-goerli) -- [Zora Mainnet](https://api.goldsky.com/api/public/project_clkk1ucdyf6ak38svcatie9tf/subgraphs/nouns-builder-zora-mainnet/stable/gn) -- [Zora Goerli](https://api.goldsky.com/api/public/project_clkk1ucdyf6ak38svcatie9tf/subgraphs/nouns-builder-zora-testnet/stable/gn) -- [Base Mainnet](https://api.goldsky.com/api/public/project_clkk1ucdyf6ak38svcatie9tf/subgraphs/nouns-builder-base-mainnet/stable/g) -- [Base Goerli](https://api.studio.thegraph.com/query/49279/nouns-builder-base-goerli/version/latest) +- [Ethereum](https://api.goldsky.com/api/public//subgraphs/nouns-builder-ethereum/latest/gn) +- [Ethereum Sepolia](https://api.goldsky.com/api/public//subgraphs/nouns-builder-ethereum-sepolia/latest/gn) +- [Optimism](https://api.goldsky.com/api/public//subgraphs/nouns-builder-optimism/latest/gn) +- TODO: [Optimism Sepolia](https://api.goldsky.com/api/public//subgraphs/nouns-builder-optimism-sepolia/latest/gn) +- TODO: [Zora](https://api.goldsky.com/api/public//subgraphs/nouns-builder-zora/latest/gn) +- TODO: [Zora Sepolia](https://api.goldsky.com/api/public//subgraphs/nouns-builder-zora-sepolia/latest/gn) +- TODO: [Base](https://api.goldsky.com/api/public//subgraphs/nouns-builder-base/latest/gn) +- TODO: [Base Sepolia](https://api.goldsky.com/api/public//subgraphs/nouns-builder-base-sepolia/latest/gn) -To deploy your own version edit the `deploy` script in `package.json` with your deployment information +## Local Development with Docker Compose +- Generate types with `pnpm codegen` +- Build the subgraph with `pnpm build:subgraph` +- Run the local graph node with `pnpm local-node` +- For Mac users on Apple Silicon, use a local image of `graphprotocol/graph-node` (see [instructions here](https://github.com/graphprotocol/graph-node/tree/master/docker)). +- Create the local subgraph with `pnpm create-local` +- Deploy changes to the local subgraph with `pnpm deploy-local` diff --git a/apps/subgraph/config/base-goerli.json b/apps/subgraph/config/base-goerli.json deleted file mode 100644 index f15496289..000000000 --- a/apps/subgraph/config/base-goerli.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "network": "base-goerli", - "manager": { - "address": "0x550c326d688fD51ae65AC6A2d48749E631023A03", - "startBlock": 6585050 - }, - "callHandlers": false -} diff --git a/apps/subgraph/config/sepolia.json b/apps/subgraph/config/ethereum-sepolia.json similarity index 80% rename from apps/subgraph/config/sepolia.json rename to apps/subgraph/config/ethereum-sepolia.json index 9ddf6e0ef..b954f0626 100644 --- a/apps/subgraph/config/sepolia.json +++ b/apps/subgraph/config/ethereum-sepolia.json @@ -1,5 +1,5 @@ { - "network": "sepolia", + "network": "ethereum-sepolia", "manager": { "address": "0x0ca90a96ac58f19b1f69f67103245c9263bc4bfc", "startBlock": 5074430 diff --git a/apps/subgraph/config/mainnet.json b/apps/subgraph/config/ethereum.json similarity index 84% rename from apps/subgraph/config/mainnet.json rename to apps/subgraph/config/ethereum.json index 4ffc68bb6..be4e000d1 100644 --- a/apps/subgraph/config/mainnet.json +++ b/apps/subgraph/config/ethereum.json @@ -1,5 +1,5 @@ { - "network": "mainnet", + "network": "ethereum", "manager": { "address": "0xd310a3041dfcf14def5ccbc508668974b5da7174", "startBlock": 15799000 diff --git a/apps/subgraph/config/goerli.json b/apps/subgraph/config/goerli.json deleted file mode 100644 index 19eb9fdb6..000000000 --- a/apps/subgraph/config/goerli.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "network": "goerli", - "manager": { - "address": "0x0E9F3382Cf2508E3bc83248B5b4707FbA86D7Ee0", - "startBlock": 7810600 - }, - "callHandlers": true -} diff --git a/apps/subgraph/config/optimism-goerli.json b/apps/subgraph/config/optimism-goerli.json deleted file mode 100644 index 4344ad16d..000000000 --- a/apps/subgraph/config/optimism-goerli.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "network": "optimism-goerli", - "manager": { - "address": "0x5f9c1e7E31875beAa6ba6B0AB573a4AbEcC95d67", - "startBlock": 11032400 - }, - "callHandlers": false -} diff --git a/apps/subgraph/config/zora-goerli.json b/apps/subgraph/config/zora-goerli.json deleted file mode 100644 index f30fd81b0..000000000 --- a/apps/subgraph/config/zora-goerli.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "network": "zora-testnet", - "manager": { - "address": "0xc521f85613985b7e417fccd5b348f64263d79397", - "startBlock": 597700 - }, - "callHandlers": false -} diff --git a/apps/subgraph/config/zora.json b/apps/subgraph/config/zora.json index 533af9aa1..0670c39d9 100644 --- a/apps/subgraph/config/zora.json +++ b/apps/subgraph/config/zora.json @@ -1,5 +1,5 @@ { - "network": "zora-mainnet", + "network": "zora", "manager": { "address": "0x3ac0E64Fe2931f8e082C6Bb29283540DE9b5371C", "startBlock": 1778012 diff --git a/apps/subgraph/package.json b/apps/subgraph/package.json index 3a435bab6..1645c62fb 100644 --- a/apps/subgraph/package.json +++ b/apps/subgraph/package.json @@ -3,31 +3,24 @@ "license": "UNLICENSED", "scripts": { "clean": "rm -rf ./generated ./build subgraph.yaml", - "local-node": "docker-compose up", + "build:subgraph": "graph build", "codegen": "graph codegen", - "prepare:sepolia": "mustache config/sepolia.json subgraph.yaml.mustache > subgraph.yaml", - "prepare:mainnet": "mustache config/mainnet.json subgraph.yaml.mustache > subgraph.yaml", + "prepare:ethereum-sepolia": "mustache config/ethereum-sepolia.json subgraph.yaml.mustache > subgraph.yaml", + "prepare:ethereum": "mustache config/ethereum.json subgraph.yaml.mustache > subgraph.yaml", "prepare:base": "mustache config/base.json subgraph.yaml.mustache > subgraph.yaml", "prepare:base-sepolia": "mustache config/base-sepolia.json subgraph.yaml.mustache > subgraph.yaml", "prepare:optimism": "mustache config/optimism.json subgraph.yaml.mustache > subgraph.yaml", "prepare:optimism-sepolia": "mustache config/optimism-sepolia.json subgraph.yaml.mustache > subgraph.yaml", "prepare:zora": "mustache config/zora.json subgraph.yaml.mustache > subgraph.yaml", "prepare:zora-sepolia": "mustache config/zora-sepolia.json subgraph.yaml.mustache > subgraph.yaml", - "deploy:sepolia": "pnpm clean && pnpm prepare:sepolia && pnpm codegen && graph build && goldsky subgraph deploy nouns-builder-sepolia-testnet/1.2.0", - "deploy:mainnet": "pnpm clean && pnpm prepare:mainnet && pnpm codegen && graph build && goldsky subgraph deploy nouns-builder-ethereum-mainnet/1.2.0", - "deploy:base": "pnpm clean && pnpm prepare:base && pnpm codegen && graph build && goldsky subgraph deploy nouns-builder-base-mainnet/1.2.0", - "deploy:base-sepolia": "pnpm clean && pnpm prepare:base-sepolia && pnpm codegen && graph build && goldsky subgraph deploy nouns-builder-base-sepolia/1.2.0", - "deploy:optimism": "pnpm clean && pnpm prepare:optimism && pnpm codegen && graph build && goldsky subgraph deploy nouns-builder-optimism-mainnet/1.2.0", - "deploy:optimism-sepolia": "pnpm clean && pnpm prepare:optimism-sepolia && pnpm codegen && graph build && goldsky subgraph deploy nouns-builder-optimism-sepolia/1.2.0", - "deploy:zora": "pnpm clean && pnpm prepare:zora && pnpm codegen && graph build && goldsky subgraph deploy nouns-builder-zora-mainnet/1.2.0", - "deploy:zora-sepolia": "pnpm clean && pnpm prepare:zora-sepolia && pnpm codegen && graph build && goldsky subgraph deploy nouns-builder-zora-sepolia/1.2.0", - "create:local": "graph create --node http://localhost:8020/ nouns-builder", + "create:local": "graph local http://localhost:8020/ nouns-builder", + "local-node": "docker compose up", "remove:local": "graph remove --node http://localhost:8020/ nouns-builder", - "deploy:local": "graph deploy --node http://localhost:8020/ --ipfs http://localhost:5001 --network sepolia nouns-builder" + "deploy:local": "graph deploy --node http://localhost:8020/ --ipfs http://localhost:5001 nouns-builder" }, "dependencies": { - "@graphprotocol/graph-cli": "0.50.1", - "@graphprotocol/graph-ts": "0.30.0", + "@graphprotocol/graph-cli": "^0.87.0", + "@graphprotocol/graph-ts": "^0.35.1", "as-base64": "^0.2.0" }, "devDependencies": { diff --git a/apps/web/src/constants/subgraph.ts b/apps/web/src/constants/subgraph.ts index fd6860dff..ab870138a 100644 --- a/apps/web/src/constants/subgraph.ts +++ b/apps/web/src/constants/subgraph.ts @@ -1,12 +1,13 @@ import { CHAIN_ID } from 'src/typings' +// TODO: update all when all are deployed to the new BuilderDAO Goldsky account export const PUBLIC_SUBGRAPH_URL = { [CHAIN_ID.ETHEREUM]: 'https://api.goldsky.com/api/public/project_clkk1ucdyf6ak38svcatie9tf/subgraphs/nouns-builder-ethereum-mainnet/stable/gn', [CHAIN_ID.OPTIMISM]: - 'https://api.goldsky.com/api/public/project_clkk1ucdyf6ak38svcatie9tf/subgraphs/nouns-builder-optimism-mainnet/stable/gn', + 'https://api.goldsky.com/api/public/project_cm33ek8kjx6pz010i2c3w8z25/subgraphs/nouns-builder-optimism/0.0.5/gn', [CHAIN_ID.SEPOLIA]: - 'https://api.goldsky.com/api/public/project_clkk1ucdyf6ak38svcatie9tf/subgraphs/nouns-builder-sepolia-testnet/stable/gn', + 'https://api.goldsky.com/api/public/project_cm33ek8kjx6pz010i2c3w8z25/subgraphs/nouns-builder-ethereum-sepolia/latest/gn', [CHAIN_ID.OPTIMISM_SEPOLIA]: 'https://api.goldsky.com/api/public/project_clkk1ucdyf6ak38svcatie9tf/subgraphs/nouns-builder-optimism-sepolia/stable/gn', [CHAIN_ID.BASE]: diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a65322543..83d9614e8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -27,11 +27,11 @@ importers: apps/subgraph: dependencies: '@graphprotocol/graph-cli': - specifier: 0.50.1 - version: 0.50.1(@types/node@18.13.0)(bufferutil@4.0.7)(encoding@0.1.13)(node-fetch@2.6.9(encoding@0.1.13))(typescript@5.5.4)(utf-8-validate@5.0.10) + specifier: ^0.87.0 + version: 0.87.0(@types/node@18.13.0)(bufferutil@4.0.7)(encoding@0.1.13)(node-fetch@2.6.9(encoding@0.1.13))(typescript@5.5.4)(utf-8-validate@5.0.10) '@graphprotocol/graph-ts': - specifier: 0.30.0 - version: 0.30.0 + specifier: ^0.35.1 + version: 0.35.1 as-base64: specifier: ^0.2.0 version: 0.2.0 @@ -367,7 +367,7 @@ importers: devDependencies: '@trivago/prettier-plugin-sort-imports': specifier: ^4.1.1 - version: 4.1.1(prettier@2.8.4) + version: 4.1.1(prettier@3.0.3) packages/ipfs-service: dependencies: @@ -404,7 +404,7 @@ importers: version: 4.9.3 vitest: specifier: ^0.23.4 - version: 0.23.4(jsdom@20.0.3)(terser@5.16.3) + version: 0.23.4(jsdom@20.0.3(bufferutil@4.0.7)(utf-8-validate@5.0.10))(terser@5.16.3) packages/tsconfig: {} @@ -476,7 +476,7 @@ importers: version: link:../tsconfig tsup: specifier: ^6.5.0 - version: 6.6.2(postcss@8.4.41)(ts-node@10.9.1(typescript@4.9.3))(typescript@4.9.3) + version: 6.6.2(postcss@8.4.41)(ts-node@10.9.1(@types/node@18.13.0)(typescript@4.9.3))(typescript@4.9.3) typescript: specifier: ^4.9.3 version: 4.9.3 @@ -1695,16 +1695,16 @@ packages: '@fontsource/londrina-solid@4.5.11': resolution: {integrity: sha512-SbM/TMxDH8eXlSyGeQ/bVz6MUHHj6FiQXnZujUr4cyK27smZPpLXoJCjB9uChJaqQ23TsgctQsGRnuHuwml1kw==} - '@graphprotocol/graph-cli@0.50.1': - resolution: {integrity: sha512-tk3e5NYBwXRuRD1y5+UKTRDv+Hwf3a78qmcpGOpIMjMgIpvDnepApRbqMqxt3Ma/RCRkACp0Kmkt3O5Ey4xlkQ==} - engines: {node: '>=14'} + '@graphprotocol/graph-cli@0.87.0': + resolution: {integrity: sha512-SilWVtSSh00pw7k0gc0kLHOErwtBNPEHoKvvCxw14ixlFZeWuiJP6+sEuQA256wBxZJo80rEQnB3rknRsgGBEg==} + engines: {node: '>=18'} hasBin: true '@graphprotocol/graph-ts@0.27.0': resolution: {integrity: sha512-r1SPDIZVQiGMxcY8rhFSM0y7d/xAbQf5vHMWUf59js1KgoyWpM6P3tczZqmQd7JTmeyNsDGIPzd9FeaxllsU4w==} - '@graphprotocol/graph-ts@0.30.0': - resolution: {integrity: sha512-h5tJqlsZXglGYM0PcBsBOqof4PT0Fr4Z3QBTYN/IjMF3VvRX2A8/bdpqaAnva+2N0uAfXXwRcwcOcW5O35yzXw==} + '@graphprotocol/graph-ts@0.35.1': + resolution: {integrity: sha512-74CfuQmf7JI76/XCC34FTkMMKeaf+3Pn0FIV3m9KNeaOJ+OI3CvjMIVRhOZdKcJxsFCBGaCCl0eQjh47xTjxKA==} '@graphql-codegen/cli@2.16.5': resolution: {integrity: sha512-XYPIp+q7fB0xAGSAoRykiTe4oY80VU+z+dw5nuv4mLY0+pv7+pa2C6Nwhdw7a65lXOhFviBApWCCZeqd54SMnA==} @@ -2340,10 +2340,22 @@ packages: resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} engines: {node: '>= 8'} - '@oclif/core@2.8.4': - resolution: {integrity: sha512-VlFDhoAJ1RDwcpDF46wAlciWTIryapMUViACttY9GwX6Ci6Lud1awe/pC3k4jad5472XshnPQV4bHAl4a/yxpA==} + '@oclif/core@2.16.0': + resolution: {integrity: sha512-dL6atBH0zCZl1A1IXCKJgLPrM/wR7K+Wi401E/IvqsK8m2iCHW+0TEOGrans/cuN3oTW+uxIyJFHJ8Im0k4qBw==} + engines: {node: '>=14.0.0'} + + '@oclif/core@2.8.6': + resolution: {integrity: sha512-1QlPaHMhOORySCXkQyzjsIsy2GYTilOw3LkjeHkCgsPJQjAT4IclVytJusWktPbYNys9O+O4V23J44yomQvnBQ==} engines: {node: '>=14.0.0'} + '@oclif/plugin-autocomplete@2.3.10': + resolution: {integrity: sha512-Ow1AR8WtjzlyCtiWWPgzMyT8SbcDJFr47009riLioHa+MHX2BCDtVn2DVnN/E6b9JlPV5ptQpjefoRSNWBesmg==} + engines: {node: '>=12.0.0'} + + '@oclif/plugin-not-found@2.4.3': + resolution: {integrity: sha512-nIyaR4y692frwh7wIHZ3fb+2L6XEecQwRDIb4zbEam0TvaVmBQWZoColQyWA84ljFBPZ8XWiQyTz+ixSwdRkqg==} + engines: {node: '>=12.0.0'} + '@openzeppelin/contracts-upgradeable@4.8.1': resolution: {integrity: sha512-1wTv+20lNiC0R07jyIAbHU7TNHKRwGiTGRfiNnA8jOWjKT98g5OgLpYWOi40Vgpk8SPLA9EvfJAbAeIyVn+7Bw==} @@ -3677,9 +3689,6 @@ packages: asap@2.0.6: resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==} - asn1@0.2.6: - resolution: {integrity: sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==} - asn1js@3.0.5: resolution: {integrity: sha512-FVnvrKJwpt9LP2lAMl8qZswRNm3T4q9CON+bxldk2iwk3FFpuwhx2FfinyitizWHsVYyaY+y5JzDR0rCMV5yTQ==} engines: {node: '>=12.0.0'} @@ -3692,10 +3701,6 @@ packages: resolution: {integrity: sha512-fwOQNZVTMga5KRsfY80g7cpOl4PsFQczMwHzdtgoqLXaYhkhavufKb0sB0l3T1DUxpAufA0KNhlbpuuhZUwxMA==} hasBin: true - assert-plus@1.0.0: - resolution: {integrity: sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==} - engines: {node: '>=0.8'} - assertion-error@1.1.0: resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==} @@ -3731,12 +3736,6 @@ packages: resolution: {integrity: sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==} engines: {node: '>= 0.4'} - aws-sign2@0.7.0: - resolution: {integrity: sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==} - - aws4@1.12.0: - resolution: {integrity: sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==} - axe-core@4.5.2: resolution: {integrity: sha512-u2MVsXfew5HBvjsczCv+xlwdNnB1oQR9HlAcsejZttNjKKSkeDNVwB1vMThIUIFI9GoT57Vtk8iQLwqOfAkboA==} engines: {node: '>=4'} @@ -3807,9 +3806,6 @@ packages: base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - bcrypt-pbkdf@1.0.2: - resolution: {integrity: sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==} - big.js@5.2.2: resolution: {integrity: sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==} @@ -4225,9 +4221,6 @@ packages: core-js-pure@3.26.1: resolution: {integrity: sha512-VVXcDpp/xJ21KdULRq/lXdLzQAtX7+37LzpyfFM973il0tWSsDEoyzG38G14AjTpK9VTfiNM9jnFauq/CpaWGQ==} - core-util-is@1.0.2: - resolution: {integrity: sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==} - core-util-is@1.0.3: resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} @@ -4339,10 +4332,6 @@ packages: damerau-levenshtein@1.0.8: resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==} - dashdash@1.14.1: - resolution: {integrity: sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==} - engines: {node: '>=0.10'} - dashify@2.0.0: resolution: {integrity: sha512-hpA5C/YrPjucXypHPPc0oJ1l9Hf6wWbiOL7Ik42cxnsUOhWiCB/fylKbKqqJalW9FgkNQCw16YO8uW9Hs0Iy1A==} engines: {node: '>=4'} @@ -4590,14 +4579,11 @@ packages: duplexify@4.1.2: resolution: {integrity: sha512-fz3OjcNCHmRP12MJoZMPglx8m4rrFP8rovnk4vT8Fs+aonZoCwGg10dSsQsfP/E62eZcPTMSMP6686fu9Qlqtw==} - ecc-jsbn@0.1.2: - resolution: {integrity: sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==} - ecdsa-sig-formatter@1.0.11: resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==} - ejs@3.1.6: - resolution: {integrity: sha512-9lt9Zse4hPucPkoP7FHDF0LQAlGyF9JVpnClFLFH3aSSbxmyoqINRpp/9wePWJTUl4KOQwRL72Iw3InHPDkoGw==} + ejs@3.1.8: + resolution: {integrity: sha512-/sXZeMlhS0ArkfX2Aw780gJzXSMPnKjtspYZv+f3NiKLlubezAHDU5+9xz6gd3/NhG3txQCo6xlglmTS+oTGEQ==} engines: {node: '>=0.10.0'} hasBin: true @@ -5111,10 +5097,6 @@ packages: resolution: {integrity: sha512-CvdFfHkC95B4bBBk36hcEmvdR2awOdhhVUYH6S/zrVj3477zven/fJMYg7121h4T1xHZC+tetUpubpAhxwI7hQ==} engines: {node: ^10.17.0 || ^12.0.0 || >= 13.7.0} - extsprintf@1.3.0: - resolution: {integrity: sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==} - engines: {'0': node >=0.6.0} - eyes@0.1.8: resolution: {integrity: sha512-GipyPsXO1anza0AOZdy69Im7hGFCNB7Y/NGjDlZGJ3GJJLtwNSb2vrzYrTYJRrRloVx7pl+bhUaTB8yiccPvFQ==} engines: {node: '> 0.1.90'} @@ -5145,6 +5127,9 @@ packages: fast-levenshtein@2.0.6: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + fast-levenshtein@3.0.0: + resolution: {integrity: sha512-hKKNajm46uNmTlhHSyZkmToAc56uZJwYq7yrciZjqOxnlfQwERDQJmHPUp7m1m9wx8vgOe8IaCKZ5Kv2k1DdCQ==} + fast-querystring@1.1.1: resolution: {integrity: sha512-qR2r+e3HvhEFmpdHMv//U8FnFlnYjaC6QKDuaXALDkw2kvHO8WDjxH+f/rHGR4Me4pnk8p9JAkRNTjYHAKRn2Q==} @@ -5161,6 +5146,10 @@ packages: fast-url-parser@1.1.3: resolution: {integrity: sha512-5jOCVXADYNuRkKFzNJ0dCCewsZiYo0dz8QNYljkOpFC6r2U4OBmKtvm/Tsuh4w1YYdDqDb31a8TVhBJ2OJKdqQ==} + fastest-levenshtein@1.0.16: + resolution: {integrity: sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==} + engines: {node: '>= 4.9.1'} + fastq@1.13.0: resolution: {integrity: sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==} @@ -5228,12 +5217,9 @@ packages: for-each@0.3.3: resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} - forever-agent@0.6.1: - resolution: {integrity: sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==} - - forge-std@https://codeload.github.com/foundry-rs/forge-std/tar.gz/bf6606142994b1e47e2882ce0cd477c020d77623: - resolution: {tarball: https://codeload.github.com/foundry-rs/forge-std/tar.gz/bf6606142994b1e47e2882ce0cd477c020d77623} - version: 1.9.2 + forge-std@https://codeload.github.com/foundry-rs/forge-std/tar.gz/da591f56d8884c5824c0c1b3103fbcfd81123c4c: + resolution: {tarball: https://codeload.github.com/foundry-rs/forge-std/tar.gz/da591f56d8884c5824c0c1b3103fbcfd81123c4c} + version: 1.9.4 form-data@2.3.3: resolution: {integrity: sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==} @@ -5368,9 +5354,6 @@ packages: get-tsconfig@4.3.0: resolution: {integrity: sha512-YCcF28IqSay3fqpIu5y3Krg/utCBHBeoflkZyHj/QcqI2nrLPC3ZegS9CmIo+hJb8K7aiGsuUl7PwWVjNG2HQQ==} - getpass@0.1.7: - resolution: {integrity: sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==} - github-from-package@0.0.0: resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==} @@ -5393,6 +5376,7 @@ packages: glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + deprecated: Glob versions prior to v9 are no longer supported glob@8.1.0: resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==} @@ -5428,8 +5412,8 @@ packages: globrex@0.1.2: resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==} - gluegun@5.1.2: - resolution: {integrity: sha512-Cwx/8S8Z4YQg07a6AFsaGnnnmd8mN17414NcPS3OoDtZRwxgsvwRNJNg69niD6fDa8oNwslCG0xH7rEpRNNE/g==} + gluegun@5.1.6: + resolution: {integrity: sha512-9zbi4EQWIVvSOftJWquWzr9gLX2kaDgPkNR5dYWbM53eVvCI3iKuxLlnKoHC0v4uPoq+Kr/+F569tjoFbA4DSA==} hasBin: true gopd@1.0.1: @@ -5499,15 +5483,6 @@ packages: h3@1.12.0: resolution: {integrity: sha512-Zi/CcNeWBXDrFNlV0hUBJQR9F7a96RjMeAZweW/ZWkR9fuXrMcvKnSA63f/zZ9l0GgQOZDVHGvXivNN9PWOwhA==} - har-schema@2.0.0: - resolution: {integrity: sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==} - engines: {node: '>=4'} - - har-validator@5.1.5: - resolution: {integrity: sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==} - engines: {node: '>=6'} - deprecated: this library is no longer supported - has-bigints@1.0.2: resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==} @@ -5630,10 +5605,6 @@ packages: resolution: {integrity: sha512-S9wWkJ/VSY9/k4qcjG318bqJNruzE4HySUhFYknwmu6LBP97KLLfwNf+n4V1BHurvFNkSKLFnK/RsuUnRTf9Vw==} engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} - http-signature@1.2.0: - resolution: {integrity: sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==} - engines: {node: '>=0.8', npm: '>=1.3.7'} - https-proxy-agent@5.0.1: resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} engines: {node: '>= 6'} @@ -6042,9 +6013,6 @@ packages: peerDependencies: ws: '*' - isstream@0.1.2: - resolution: {integrity: sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==} - it-all@1.0.6: resolution: {integrity: sha512-3cmCc6Heqe3uWi3CVM/k51fa/XbMFpQVzFoDsV0IZNHSQDyAXl3c4MjHkFX5kF3922OGj7Myv1nSEUgRtcuM1A==} @@ -6167,9 +6135,6 @@ packages: resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} hasBin: true - jsbn@0.1.1: - resolution: {integrity: sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==} - jsdom@20.0.3: resolution: {integrity: sha512-SYhBvTh89tTfCD/CRdSOm13mOBa42iTaTyfyEWBdKcGdPxPtLFBXuHR8XHb33YNYaP+lLbmSvBTsnoesCNJEsQ==} engines: {node: '>=14'} @@ -6201,9 +6166,6 @@ packages: json-schema-traverse@0.4.1: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} - json-schema@0.4.0: - resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==} - json-stable-stringify-without-jsonify@1.0.1: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} @@ -6243,10 +6205,6 @@ packages: resolution: {integrity: sha512-tuGfYXxkQGDPnLJ7SibiQgVgeDgfbPq2k2ICcbgqW8WxWLBAxKQM/ZCu/IT8SOSwmaYl4dpTFCW5xZv7YbbWUw==} engines: {node: '>=12', npm: '>=6'} - jsprim@1.4.2: - resolution: {integrity: sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==} - engines: {node: '>=0.6.0'} - jsx-ast-utils@3.3.3: resolution: {integrity: sha512-fYQHZTZ8jSfmWZ0iyzfwiU4WDX4HpHbMCZ3gPlWYiCl3BoeOTsqKBqnTVfH2rYT7eP5c3sVbeSPHnnJOaTrWiw==} engines: {node: '>=4.0'} @@ -6984,9 +6942,6 @@ packages: nwsapi@2.2.2: resolution: {integrity: sha512-90yv+6538zuvUMnN+zCr8LuV6bPFdq50304114vJYJ8RDyK8D5O9Phpbd6SZWgI7PwzmmfN1upeOJlvybDSgCw==} - oauth-sign@0.9.0: - resolution: {integrity: sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==} - object-assign@4.1.1: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} @@ -7045,8 +7000,8 @@ packages: resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} engines: {node: '>=12'} - open@8.4.0: - resolution: {integrity: sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q==} + open@8.4.2: + resolution: {integrity: sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==} engines: {node: '>=12'} opener@1.5.2: @@ -7207,9 +7162,6 @@ packages: resolution: {integrity: sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==} engines: {node: '>=0.12'} - performance-now@2.1.0: - resolution: {integrity: sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==} - picocolors@1.0.0: resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} @@ -7306,11 +7258,6 @@ packages: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} - prettier@1.19.1: - resolution: {integrity: sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==} - engines: {node: '>=4'} - hasBin: true - prettier@2.8.0: resolution: {integrity: sha512-9Lmg8hTFZKG0Asr/kW9Bp8tJjRVluO8EJQVfY2T7FMw9T5jy4I/Uvx0Rca/XWf50QQ1/SS48+6IJWnrb+2yemA==} engines: {node: '>=10.13.0'} @@ -7321,6 +7268,11 @@ packages: engines: {node: '>=10.13.0'} hasBin: true + prettier@3.0.3: + resolution: {integrity: sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==} + engines: {node: '>=14'} + hasBin: true + pretty-format@27.5.1: resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} @@ -7403,10 +7355,6 @@ packages: resolution: {integrity: sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==} engines: {node: '>=0.6'} - qs@6.5.3: - resolution: {integrity: sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==} - engines: {node: '>=0.6'} - query-string@6.13.5: resolution: {integrity: sha512-svk3xg9qHR39P3JlHuD7g3nRnyay5mHbrPctEBDUxUkHRifPHXJDhBUycdCC0NBjXoDf44Gb+IsOZL1Uwn8M/Q==} engines: {node: '>=6'} @@ -7638,11 +7586,6 @@ packages: remove-trailing-spaces@1.0.8: resolution: {integrity: sha512-O3vsMYfWighyFbTd8hk8VaSj9UAGENxAtX+//ugIst2RMk5e03h6RoIS+0ylsFxY1gvmPuAY/PO4It+gPEeySA==} - request@2.88.2: - resolution: {integrity: sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==} - engines: {node: '>= 6'} - deprecated: request has been deprecated, see https://github.com/request/request/issues/3142 - require-directory@2.1.1: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} @@ -7692,6 +7635,7 @@ packages: rimraf@2.6.3: resolution: {integrity: sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==} + deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true rimraf@3.0.2: @@ -7960,11 +7904,6 @@ packages: sprintf-js@1.0.3: resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} - sshpk@1.17.0: - resolution: {integrity: sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==} - engines: {node: '>=0.10.0'} - hasBin: true - stable@0.1.8: resolution: {integrity: sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==} deprecated: 'Modern JS already guarantees Array#sort() is a stable sort, so this library is deprecated. See the compatibility table on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#browser_compatibility' @@ -8323,10 +8262,6 @@ packages: resolution: {integrity: sha512-gduQwd1rOdDMGxFG1gEvhV88Oirdo2p+KjoYFU7k2g+i7n6AFFbDQ5kMPUsW0pNbfQsB/cwXvT1i4Bue0s9g5g==} engines: {node: '>=6'} - tough-cookie@2.5.0: - resolution: {integrity: sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==} - engines: {node: '>=0.8'} - tough-cookie@4.1.2: resolution: {integrity: sha512-G9fqXWoYFZgTc2z8Q5zaHy/vJMjm+WV0AkAeHxVCQiEB1b+dGvWzFW6QV07cY5jQ5gRkeid2qIkzkxUnmoQZUQ==} engines: {node: '>=6'} @@ -8445,9 +8380,6 @@ packages: resolution: {integrity: sha512-1q7+9UJABuBAHrcC4Sxp5lOqYS5mvxRrwa33wpIyM18hlOCpRD/fTJNxZ0vhbMcJmz15o9kkVm743mPn7p6jpQ==} hasBin: true - tweetnacl@0.14.5: - resolution: {integrity: sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==} - type-check@0.3.2: resolution: {integrity: sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==} engines: {node: '>= 0.8.0'} @@ -8704,11 +8636,6 @@ packages: util@0.12.5: resolution: {integrity: sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==} - uuid@3.4.0: - resolution: {integrity: sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==} - deprecated: Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details. - hasBin: true - uuid@8.3.2: resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} hasBin: true @@ -8742,10 +8669,6 @@ packages: varint@6.0.0: resolution: {integrity: sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==} - verror@1.10.0: - resolution: {integrity: sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==} - engines: {'0': node >=0.6.0} - vfile-location@5.0.3: resolution: {integrity: sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==} @@ -10548,10 +10471,12 @@ snapshots: '@fontsource/londrina-solid@4.5.11': {} - '@graphprotocol/graph-cli@0.50.1(@types/node@18.13.0)(bufferutil@4.0.7)(encoding@0.1.13)(node-fetch@2.6.9(encoding@0.1.13))(typescript@5.5.4)(utf-8-validate@5.0.10)': + '@graphprotocol/graph-cli@0.87.0(@types/node@18.13.0)(bufferutil@4.0.7)(encoding@0.1.13)(node-fetch@2.6.9(encoding@0.1.13))(typescript@5.5.4)(utf-8-validate@5.0.10)': dependencies: '@float-capital/float-subgraph-uncrashable': 0.0.0-internal-testing.5 - '@oclif/core': 2.8.4(@types/node@18.13.0)(typescript@5.5.4) + '@oclif/core': 2.8.6(@types/node@18.13.0)(typescript@5.5.4) + '@oclif/plugin-autocomplete': 2.3.10(@types/node@18.13.0)(typescript@5.5.4) + '@oclif/plugin-not-found': 2.4.3(@types/node@18.13.0)(typescript@5.5.4) '@whatwg-node/fetch': 0.8.8 assemblyscript: 0.19.23 binary-install-raw: 0.0.13(debug@4.3.4) @@ -10562,14 +10487,14 @@ snapshots: dockerode: 2.5.8 fs-extra: 9.1.0 glob: 9.3.5 - gluegun: 5.1.2(debug@4.3.4) + gluegun: 5.1.6(debug@4.3.4) graphql: 15.5.0 immutable: 4.2.1 ipfs-http-client: 55.0.0(encoding@0.1.13)(node-fetch@2.6.9(encoding@0.1.13)) jayson: 4.0.0(bufferutil@4.0.7)(utf-8-validate@5.0.10) js-yaml: 3.14.1 - prettier: 1.19.1 - request: 2.88.2 + open: 8.4.2 + prettier: 3.0.3 semver: 7.4.0 sync-request: 6.1.0 tmp-promise: 3.0.3 @@ -10591,7 +10516,7 @@ snapshots: dependencies: assemblyscript: 0.19.10 - '@graphprotocol/graph-ts@0.30.0': + '@graphprotocol/graph-ts@0.35.1': dependencies: assemblyscript: 0.19.10 @@ -11213,7 +11138,7 @@ snapshots: dependencies: '@types/debug': 4.1.7 debug: 4.3.4(supports-color@8.1.1) - semver: 7.4.0 + semver: 7.6.3 superstruct: 1.0.3 transitivePeerDependencies: - supports-color @@ -11469,7 +11394,43 @@ snapshots: '@nodelib/fs.scandir': 2.1.5 fastq: 1.13.0 - '@oclif/core@2.8.4(@types/node@18.13.0)(typescript@5.5.4)': + '@oclif/core@2.16.0(@types/node@18.13.0)(typescript@5.5.4)': + dependencies: + '@types/cli-progress': 3.11.0 + ansi-escapes: 4.3.2 + ansi-styles: 4.3.0 + cardinal: 2.1.1 + chalk: 4.1.2 + clean-stack: 3.0.1 + cli-progress: 3.12.0 + debug: 4.3.4(supports-color@8.1.1) + ejs: 3.1.9 + get-package-type: 0.1.0 + globby: 11.1.0 + hyperlinker: 1.0.0 + indent-string: 4.0.0 + is-wsl: 2.2.0 + js-yaml: 3.14.1 + natural-orderby: 2.0.3 + object-treeify: 1.1.33 + password-prompt: 1.1.2 + slice-ansi: 4.0.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + supports-color: 8.1.1 + supports-hyperlinks: 2.3.0 + ts-node: 10.9.1(@types/node@18.13.0)(typescript@5.5.4) + tslib: 2.5.0 + widest-line: 3.1.0 + wordwrap: 1.0.0 + wrap-ansi: 7.0.0 + transitivePeerDependencies: + - '@swc/core' + - '@swc/wasm' + - '@types/node' + - typescript + + '@oclif/core@2.8.6(@types/node@18.13.0)(typescript@5.5.4)': dependencies: '@types/cli-progress': 3.11.0 ansi-escapes: 4.3.2 @@ -11490,7 +11451,7 @@ snapshots: natural-orderby: 2.0.3 object-treeify: 1.1.33 password-prompt: 1.1.2 - semver: 7.4.0 + semver: 7.6.3 string-width: 4.2.3 strip-ansi: 6.0.1 supports-color: 8.1.1 @@ -11506,6 +11467,29 @@ snapshots: - '@types/node' - typescript + '@oclif/plugin-autocomplete@2.3.10(@types/node@18.13.0)(typescript@5.5.4)': + dependencies: + '@oclif/core': 2.16.0(@types/node@18.13.0)(typescript@5.5.4) + chalk: 4.1.2 + debug: 4.3.4(supports-color@8.1.1) + transitivePeerDependencies: + - '@swc/core' + - '@swc/wasm' + - '@types/node' + - supports-color + - typescript + + '@oclif/plugin-not-found@2.4.3(@types/node@18.13.0)(typescript@5.5.4)': + dependencies: + '@oclif/core': 2.16.0(@types/node@18.13.0)(typescript@5.5.4) + chalk: 4.1.2 + fast-levenshtein: 3.0.0 + transitivePeerDependencies: + - '@swc/core' + - '@swc/wasm' + - '@types/node' + - typescript + '@openzeppelin/contracts-upgradeable@4.8.1': {} '@openzeppelin/contracts@4.8.1': {} @@ -11593,7 +11577,7 @@ snapshots: dependencies: cross-spawn: 7.0.3 is-glob: 4.0.3 - open: 8.4.0 + open: 8.4.2 picocolors: 1.0.0 tiny-glob: 0.2.9 tslib: 2.5.0 @@ -12215,7 +12199,7 @@ snapshots: '@tootallnate/once@2.0.0': {} - '@trivago/prettier-plugin-sort-imports@4.1.1(prettier@2.8.4)': + '@trivago/prettier-plugin-sort-imports@4.1.1(prettier@3.0.3)': dependencies: '@babel/generator': 7.17.7 '@babel/parser': 7.20.15 @@ -12223,7 +12207,7 @@ snapshots: '@babel/types': 7.17.0 javascript-natural-sort: 0.7.1 lodash: 4.17.21 - prettier: 2.8.4 + prettier: 3.0.3 transitivePeerDependencies: - supports-color @@ -13231,7 +13215,7 @@ snapshots: '@openzeppelin/contracts-upgradeable': 4.8.1 '@types/node': 18.13.0 ds-test: https://codeload.github.com/dapphub/ds-test/tar.gz/e282159d5170298eb2455a6c05280ab5a73a4ef0 - forge-std: https://codeload.github.com/foundry-rs/forge-std/tar.gz/bf6606142994b1e47e2882ce0cd477c020d77623 + forge-std: https://codeload.github.com/foundry-rs/forge-std/tar.gz/da591f56d8884c5824c0c1b3103fbcfd81123c4c micro-onchain-metadata-utils: 0.1.1 sol-uriencode: 0.2.0 @@ -13425,10 +13409,6 @@ snapshots: asap@2.0.6: {} - asn1@0.2.6: - dependencies: - safer-buffer: 2.1.2 - asn1js@3.0.5: dependencies: pvtsutils: 1.3.2 @@ -13446,8 +13426,6 @@ snapshots: long: 5.2.1 source-map-support: 0.5.21 - assert-plus@1.0.0: {} - assertion-error@1.1.0: {} ast-types-flow@0.0.7: {} @@ -13470,10 +13448,6 @@ snapshots: available-typed-arrays@1.0.5: {} - aws-sign2@0.7.0: {} - - aws4@1.12.0: {} - axe-core@4.5.2: {} axios@0.21.4(debug@4.3.4): @@ -13587,10 +13561,6 @@ snapshots: base64-js@1.5.1: {} - bcrypt-pbkdf@1.0.2: - dependencies: - tweetnacl: 0.14.5 - big.js@5.2.2: {} bigint-buffer@1.1.5: @@ -13879,7 +13849,7 @@ snapshots: normalize-path: 3.0.0 readdirp: 3.6.0 optionalDependencies: - fsevents: 2.3.2 + fsevents: 2.3.3 chokidar@3.6.0: dependencies: @@ -13891,7 +13861,7 @@ snapshots: normalize-path: 3.0.0 readdirp: 3.6.0 optionalDependencies: - fsevents: 2.3.2 + fsevents: 2.3.3 chownr@1.1.4: {} @@ -14047,8 +14017,6 @@ snapshots: core-js-pure@3.26.1: {} - core-util-is@1.0.2: {} - core-util-is@1.0.3: {} cosmiconfig-typescript-loader@4.3.0(@types/node@18.13.0)(cosmiconfig@7.1.0)(ts-node@10.9.1(@types/node@18.13.0)(typescript@5.5.4))(typescript@5.5.4): @@ -14176,10 +14144,6 @@ snapshots: damerau-levenshtein@1.0.8: {} - dashdash@1.14.1: - dependencies: - assert-plus: 1.0.0 - dashify@2.0.0: {} data-uri-to-buffer@2.0.2: {} @@ -14418,16 +14382,11 @@ snapshots: readable-stream: 3.6.0 stream-shift: 1.0.1 - ecc-jsbn@0.1.2: - dependencies: - jsbn: 0.1.1 - safer-buffer: 2.1.2 - ecdsa-sig-formatter@1.0.11: dependencies: safe-buffer: 5.2.1 - ejs@3.1.6: + ejs@3.1.8: dependencies: jake: 10.8.7 @@ -14775,7 +14734,7 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.7.4(@typescript-eslint/parser@5.54.0(eslint@8.34.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.6)(eslint-import-resolver-typescript@3.5.2(eslint-plugin-import@2.26.0)(eslint@8.34.0))(eslint@8.34.0): + eslint-module-utils@2.7.4(@typescript-eslint/parser@5.54.0(eslint@8.34.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.6)(eslint-import-resolver-typescript@3.5.2)(eslint@8.34.0): dependencies: debug: 3.2.7 optionalDependencies: @@ -14794,7 +14753,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.34.0 eslint-import-resolver-node: 0.3.6 - eslint-module-utils: 2.7.4(@typescript-eslint/parser@5.54.0(eslint@8.34.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.6)(eslint-import-resolver-typescript@3.5.2(eslint-plugin-import@2.26.0)(eslint@8.34.0))(eslint@8.34.0) + eslint-module-utils: 2.7.4(@typescript-eslint/parser@5.54.0(eslint@8.34.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.6)(eslint-import-resolver-typescript@3.5.2)(eslint@8.34.0) has: 1.0.3 is-core-module: 2.11.0 is-glob: 4.0.3 @@ -15196,8 +15155,6 @@ snapshots: extract-files@9.0.0: {} - extsprintf@1.3.0: {} - eyes@0.1.8: {} fast-decode-uri-component@1.0.1: {} @@ -15228,6 +15185,10 @@ snapshots: fast-levenshtein@2.0.6: {} + fast-levenshtein@3.0.0: + dependencies: + fastest-levenshtein: 1.0.16 + fast-querystring@1.1.1: dependencies: fast-decode-uri-component: 1.0.1 @@ -15242,6 +15203,8 @@ snapshots: dependencies: punycode: 1.4.1 + fastest-levenshtein@1.0.16: {} + fastq@1.13.0: dependencies: reusify: 1.0.4 @@ -15313,9 +15276,7 @@ snapshots: dependencies: is-callable: 1.2.7 - forever-agent@0.6.1: {} - - forge-std@https://codeload.github.com/foundry-rs/forge-std/tar.gz/bf6606142994b1e47e2882ce0cd477c020d77623: {} + forge-std@https://codeload.github.com/foundry-rs/forge-std/tar.gz/da591f56d8884c5824c0c1b3103fbcfd81123c4c: {} form-data@2.3.3: dependencies: @@ -15403,14 +15364,14 @@ snapshots: fs-extra@11.2.0: dependencies: - graceful-fs: 4.2.10 + graceful-fs: 4.2.11 jsonfile: 6.1.0 universalify: 2.0.0 fs-extra@9.1.0: dependencies: at-least-node: 1.0.0 - graceful-fs: 4.2.10 + graceful-fs: 4.2.11 jsonfile: 6.1.0 universalify: 2.0.0 @@ -15484,10 +15445,6 @@ snapshots: get-tsconfig@4.3.0: {} - getpass@0.1.7: - dependencies: - assert-plus: 1.0.0 - github-from-package@0.0.0: {} glob-parent@5.1.2: @@ -15573,7 +15530,7 @@ snapshots: globrex@0.1.2: {} - gluegun@5.1.2(debug@4.3.4): + gluegun@5.1.6(debug@4.3.4): dependencies: apisauce: 2.1.6(debug@4.3.4) app-module-path: 2.2.0 @@ -15581,7 +15538,7 @@ snapshots: colors: 1.4.0 cosmiconfig: 7.0.1 cross-spawn: 7.0.3 - ejs: 3.1.6 + ejs: 3.1.8 enquirer: 2.3.6 execa: 5.1.1 fs-jetpack: 4.3.1 @@ -15694,13 +15651,6 @@ snapshots: transitivePeerDependencies: - uWebSockets.js - har-schema@2.0.0: {} - - har-validator@5.1.5: - dependencies: - ajv: 6.12.6 - har-schema: 2.0.0 - has-bigints@1.0.2: {} has-flag@3.0.0: {} @@ -15891,12 +15841,6 @@ snapshots: http-shutdown@1.2.2: {} - http-signature@1.2.0: - dependencies: - assert-plus: 1.0.0 - jsprim: 1.4.2 - sshpk: 1.17.0 - https-proxy-agent@5.0.1: dependencies: agent-base: 6.0.2 @@ -15981,7 +15925,7 @@ snapshots: interface-datastore@6.1.1: dependencies: interface-store: 2.0.2 - nanoid: 3.3.6 + nanoid: 3.3.7 uint8arrays: 3.1.0 interface-datastore@7.0.4: @@ -16062,7 +16006,7 @@ snapshots: multiaddr: 10.0.1(node-fetch@2.6.9(encoding@0.1.13)) multiaddr-to-uri: 8.0.0(node-fetch@2.6.9(encoding@0.1.13)) multiformats: 9.9.0 - nanoid: 3.3.6 + nanoid: 3.3.7 parse-duration: 1.0.2 timeout-abort-controller: 2.0.0 uint8arrays: 3.1.0 @@ -16407,8 +16351,6 @@ snapshots: dependencies: ws: 8.17.1(bufferutil@4.0.7)(utf-8-validate@5.0.10) - isstream@0.1.2: {} - it-all@1.0.6: {} it-all@2.0.0: {} @@ -16516,7 +16458,7 @@ snapshots: '@jest/types': 29.4.2 '@types/stack-utils': 2.0.1 chalk: 4.1.2 - graceful-fs: 4.2.10 + graceful-fs: 4.2.11 micromatch: 4.0.5 pretty-format: 29.4.2 slash: 3.0.0 @@ -16528,7 +16470,7 @@ snapshots: '@types/node': 18.13.0 chalk: 4.1.2 ci-info: 3.8.0 - graceful-fs: 4.2.10 + graceful-fs: 4.2.11 picomatch: 2.3.1 jest-worker@27.5.1: @@ -16558,8 +16500,6 @@ snapshots: dependencies: argparse: 2.0.1 - jsbn@0.1.1: {} - jsdom@20.0.3(bufferutil@4.0.7)(utf-8-validate@5.0.10): dependencies: abab: 2.0.6 @@ -16608,8 +16548,6 @@ snapshots: json-schema-traverse@0.4.1: {} - json-schema@0.4.0: {} - json-stable-stringify-without-jsonify@1.0.1: {} json-stable-stringify@1.0.2: @@ -16635,7 +16573,7 @@ snapshots: dependencies: universalify: 2.0.0 optionalDependencies: - graceful-fs: 4.2.10 + graceful-fs: 4.2.11 jsonify@0.0.1: {} @@ -16648,13 +16586,6 @@ snapshots: ms: 2.1.3 semver: 7.4.0 - jsprim@1.4.2: - dependencies: - assert-plus: 1.0.0 - extsprintf: 1.3.0 - json-schema: 0.4.0 - verror: 1.10.0 - jsx-ast-utils@3.3.3: dependencies: array-includes: 3.1.6 @@ -17597,8 +17528,6 @@ snapshots: nwsapi@2.2.2: {} - oauth-sign@0.9.0: {} - object-assign@4.1.1: {} object-inspect@1.12.2: {} @@ -17664,7 +17593,7 @@ snapshots: dependencies: mimic-fn: 4.0.0 - open@8.4.0: + open@8.4.2: dependencies: define-lazy-prop: 2.0.0 is-docker: 2.2.1 @@ -17851,8 +17780,6 @@ snapshots: safe-buffer: 5.2.1 sha.js: 2.4.11 - performance-now@2.1.0: {} - picocolors@1.0.0: {} picocolors@1.0.1: {} @@ -17917,13 +17844,13 @@ snapshots: postcss: 8.4.24 ts-node: 10.9.1(@types/node@18.13.0)(typescript@5.5.4) - postcss-load-config@3.1.4(postcss@8.4.41)(ts-node@10.9.1(typescript@4.9.3)): + postcss-load-config@3.1.4(postcss@8.4.41)(ts-node@10.9.1(@types/node@18.13.0)(typescript@4.9.3)): dependencies: lilconfig: 2.0.6 yaml: 1.10.2 optionalDependencies: postcss: 8.4.41 - ts-node: 10.9.1(typescript@4.9.3) + ts-node: 10.9.1(@types/node@18.13.0)(typescript@4.9.3) postcss-value-parser@4.2.0: {} @@ -17972,12 +17899,12 @@ snapshots: prelude-ls@1.2.1: {} - prettier@1.19.1: {} - prettier@2.8.0: {} prettier@2.8.4: {} + prettier@3.0.3: {} + pretty-format@27.5.1: dependencies: ansi-regex: 5.0.1 @@ -18084,8 +18011,6 @@ snapshots: dependencies: side-channel: 1.0.4 - qs@6.5.3: {} - query-string@6.13.5: dependencies: decode-uri-component: 0.2.2 @@ -18366,29 +18291,6 @@ snapshots: remove-trailing-spaces@1.0.8: {} - request@2.88.2: - dependencies: - aws-sign2: 0.7.0 - aws4: 1.12.0 - caseless: 0.12.0 - combined-stream: 1.0.8 - extend: 3.0.2 - forever-agent: 0.6.1 - form-data: 2.3.3 - har-validator: 5.1.5 - http-signature: 1.2.0 - is-typedarray: 1.0.0 - isstream: 0.1.2 - json-stringify-safe: 5.0.1 - mime-types: 2.1.35 - oauth-sign: 0.9.0 - performance-now: 2.1.0 - qs: 6.5.3 - safe-buffer: 5.2.1 - tough-cookie: 2.5.0 - tunnel-agent: 0.6.0 - uuid: 3.4.0 - require-directory@2.1.1: {} require-like@0.1.2: {} @@ -18490,7 +18392,7 @@ snapshots: '@babel/runtime': 7.20.1 eventemitter3: 4.0.7 uuid: 8.3.2 - ws: 8.12.0(bufferutil@4.0.7)(utf-8-validate@5.0.10) + ws: 8.18.0(bufferutil@4.0.7)(utf-8-validate@5.0.10) optionalDependencies: bufferutil: 4.0.7 utf-8-validate: 5.0.10 @@ -18736,18 +18638,6 @@ snapshots: sprintf-js@1.0.3: {} - sshpk@1.17.0: - dependencies: - asn1: 0.2.6 - assert-plus: 1.0.0 - bcrypt-pbkdf: 1.0.2 - dashdash: 1.14.1 - ecc-jsbn: 0.1.2 - getpass: 0.1.7 - jsbn: 0.1.1 - safer-buffer: 2.1.2 - tweetnacl: 0.14.5 - stable@0.1.8: {} stack-utils@2.0.6: @@ -19143,11 +19033,6 @@ snapshots: totalist@1.1.0: {} - tough-cookie@2.5.0: - dependencies: - psl: 1.9.0 - punycode: 2.1.1 - tough-cookie@4.1.2: dependencies: psl: 1.9.0 @@ -19175,7 +19060,7 @@ snapshots: ts-log@2.2.5: {} - ts-node@10.9.1(@types/node@18.13.0)(typescript@5.5.4): + ts-node@10.9.1(@types/node@18.13.0)(typescript@4.9.3): dependencies: '@cspotcode/source-map-support': 0.8.1 '@tsconfig/node10': 1.0.9 @@ -19189,27 +19074,28 @@ snapshots: create-require: 1.1.1 diff: 4.0.2 make-error: 1.3.6 - typescript: 5.5.4 + typescript: 4.9.3 v8-compile-cache-lib: 3.0.1 yn: 3.1.1 + optional: true - ts-node@10.9.1(typescript@4.9.3): + ts-node@10.9.1(@types/node@18.13.0)(typescript@5.5.4): dependencies: '@cspotcode/source-map-support': 0.8.1 '@tsconfig/node10': 1.0.9 '@tsconfig/node12': 1.0.11 '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.3 + '@types/node': 18.13.0 acorn: 8.8.2 acorn-walk: 8.2.0 arg: 4.1.3 create-require: 1.1.1 diff: 4.0.2 make-error: 1.3.6 - typescript: 4.9.3 + typescript: 5.5.4 v8-compile-cache-lib: 3.0.1 yn: 3.1.1 - optional: true tsconfig-paths@3.14.1: dependencies: @@ -19226,7 +19112,7 @@ snapshots: tslib@2.5.0: {} - tsup@6.6.2(postcss@8.4.41)(ts-node@10.9.1(typescript@4.9.3))(typescript@4.9.3): + tsup@6.6.2(postcss@8.4.41)(ts-node@10.9.1(@types/node@18.13.0)(typescript@4.9.3))(typescript@4.9.3): dependencies: bundle-require: 4.0.1(esbuild@0.17.8) cac: 6.7.14 @@ -19236,7 +19122,7 @@ snapshots: execa: 5.1.1 globby: 11.1.0 joycon: 3.1.1 - postcss-load-config: 3.1.4(postcss@8.4.41)(ts-node@10.9.1(typescript@4.9.3)) + postcss-load-config: 3.1.4(postcss@8.4.41)(ts-node@10.9.1(@types/node@18.13.0)(typescript@4.9.3)) resolve-from: 5.0.0 rollup: 3.15.0 source-map: 0.8.0-beta.0 @@ -19285,8 +19171,6 @@ snapshots: turbo-windows-64: 1.13.4 turbo-windows-arm64: 1.13.4 - tweetnacl@0.14.5: {} - type-check@0.3.2: dependencies: prelude-ls: 1.1.2 @@ -19517,8 +19401,6 @@ snapshots: is-typed-array: 1.1.10 which-typed-array: 1.1.9 - uuid@3.4.0: {} - uuid@8.3.2: {} uuid@9.0.0: {} @@ -19539,12 +19421,6 @@ snapshots: varint@6.0.0: {} - verror@1.10.0: - dependencies: - assert-plus: 1.0.0 - core-util-is: 1.0.2 - extsprintf: 1.3.0 - vfile-location@5.0.3: dependencies: '@types/unist': 3.0.3 @@ -19673,7 +19549,7 @@ snapshots: fsevents: 2.3.3 terser: 5.16.3 - vitest@0.23.4(jsdom@20.0.3)(terser@5.16.3): + vitest@0.23.4(jsdom@20.0.3(bufferutil@4.0.7)(utf-8-validate@5.0.10))(terser@5.16.3): dependencies: '@types/chai': 4.3.4 '@types/chai-subset': 1.3.3 From ad054d569c38309b30924c9fd9314d1affc78c25 Mon Sep 17 00:00:00 2001 From: Mills <37815163+0xMillz@users.noreply.github.com> Date: Thu, 5 Dec 2024 05:29:28 -0600 Subject: [PATCH 15/28] Update subgraph URLs and run format (#6) * Update subgraph README.md * Update subgraph URLs for Base, Optimism, and Ethereum * format project --- README.md | 22 ++++++-- apps/subgraph/README.md | 31 ++++++++---- .../src/components/Artwork/ArtworkPreview.tsx | 9 ++-- .../src/components/Artwork/LayerOrdering.tsx | 10 ++-- apps/web/src/components/Avatar/Avatar.tsx | 11 ++-- .../BridgeModal/NetworkSelector.tsx | 7 ++- apps/web/src/components/DisplayPanel.tsx | 10 ++-- apps/web/src/components/Fields/Date.tsx | 28 ++++++----- .../web/src/components/Fields/FieldSwitch.tsx | 11 ++-- .../web/src/components/Fields/NumberInput.tsx | 20 ++++---- apps/web/src/components/Fields/Radio.tsx | 18 ++++--- apps/web/src/components/Fields/StickySave.tsx | 10 ++-- apps/web/src/components/Fields/TextInput.tsx | 12 ++--- .../Home/accordian/AccordionItem.tsx | 7 ++- apps/web/src/components/Input/Input.tsx | 13 ++--- apps/web/src/components/MarkdownEditor.tsx | 10 ++-- apps/web/src/components/Meta.tsx | 11 ++-- .../src/components/Modal/AnimatedModal.tsx | 10 ++-- .../components/Modal/SuccessModalContent.tsx | 11 ++-- apps/web/src/components/Pagination/index.tsx | 10 ++-- apps/web/src/constants/subgraph.ts | 4 +- apps/web/src/hooks/useDelayedGovernance.ts | 20 ++++---- apps/web/src/hooks/useIsContract.ts | 10 ++-- apps/web/src/hooks/useVotes.ts | 24 +++++---- .../auction/components/AuctionDetail.tsx | 10 ++-- .../modules/auction/components/BidAmount.tsx | 10 ++-- .../CurrentAuction/AuctionCountdown.tsx | 10 ++-- .../CurrentAuction/WarningModal.tsx | 20 ++++---- .../auction/components/ViewSwitcher.tsx | 20 ++++---- .../modules/auction/hooks/useAuctionEvents.ts | 24 +++++---- .../auction/hooks/useMinBidIncrement.ts | 20 ++++---- .../AllocationForm/Contribution.tsx | 20 ++++---- .../AllocationForm/DaoCopyAddress.tsx | 24 +++++---- .../Artwork/Playground/ImageGrid.tsx | 6 +-- .../create-dao/components/FormHandler.tsx | 10 ++-- .../utils/formatFounderAllocation.ts | 8 ++- .../components/CreateProposalHeading.tsx | 8 ++- .../components/Queue/ConfirmRemove.tsx | 7 ++- .../SelectTransactionType.tsx | 7 ++- .../TransactionTypeCard.tsx | 7 ++- .../forms/CustomTransactionForm.tsx | 18 ++++--- .../Droposal/DroposalPreview.tsx | 7 ++- .../components/TwoColumnLayout.tsx | 7 ++- .../components/UpgradeCard.tsx | 20 ++++---- .../hooks/useFetchCurrentDAOConfig.tsx | 34 ++++++------- .../hooks/usePrepareMigration.tsx | 50 +++++++++---------- .../stores/useProposalStore.ts | 14 +++--- .../create-proposal/utils/applyL1ToL2Alias.ts | 20 ++++---- .../dao/components/AuctionChart/Layouts.tsx | 36 +++++++------ .../modules/dao/components/DaoTopSection.tsx | 19 +++---- .../components/MembersList/MemberListCard.tsx | 20 ++++---- .../MembersList/MembersListLayout.tsx | 20 ++++---- .../src/modules/dashboard/AuctionPaused.tsx | 10 ++-- .../src/modules/dashboard/DashboardLayout.tsx | 10 ++-- .../SuccessfulProposalActions.tsx | 6 +-- .../components/ProposalActions/VetoAction.tsx | 7 ++- .../ProposalActions/VoteStatus/VoteStatus.tsx | 12 ++--- .../proposal/components/ProposalStatus.tsx | 12 ++--- .../ProposalVotes/VoterParticipation.tsx | 7 ++- packages/blocklist/README.md | 9 ++-- packages/zoralabs-zord/README.md | 2 - .../zoralabs-zord/src/components/PopUp.tsx | 28 ++++++----- .../zoralabs-zord/src/elements/Select.tsx | 18 ++++--- packages/zoralabs-zord/src/elements/Text.tsx | 44 +++++++--------- .../zoralabs-zord/src/utils/color-theme.ts | 18 ++++--- 65 files changed, 456 insertions(+), 532 deletions(-) diff --git a/README.md b/README.md index 9d76d3d0b..5758c126a 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # Nouns Builder Subgraph ## Index + - [Getting Started](#getting-started) - [Step 1 - Install Dependencies](#step-1---install-dependencies) - [Step 2 - Set Up a Personal Goldsky API Key](#step-2---set-up-a-personal-goldsky-api-key) @@ -12,9 +13,11 @@ - [(DEPRECATED) Local Development with Docker Compose (TODO: fix - pnpm create:local step not working)](#local-development-with-docker-compose) ## Getting Started + πŸ‘‰ [Read the Goldsky docs](https://docs.goldsky.com/subgraphs/deploying-subgraphs) The Nouns Builder subgraph supports eight networks: + - `ethereum` - `ethereum-sepolia` - `base` @@ -25,41 +28,49 @@ The Nouns Builder subgraph supports eight networks: - `zora-sepolia` ### Step 1 - Install Dependencies + Navigate to the subgraph directory and run: + ```bash # FROM: ./apps/subgraph pnpm install ``` ### Step 2 - Set Up a Personal Goldsky API Key + 1. Request to join the team account at [goldsky.com](https://goldsky.com). 2. Create an API key on your Settings page. 3. Install the Goldsky CLI: - ```bash - curl https://goldsky.com | sh - ``` + ```bash + curl https://goldsky.com | sh + ``` ### Step 3 - Log in with the API Key + Use the API key you created: + ```bash # FROM: ./apps/subgraph goldsky login ``` ### Step 4 - Build the Subgraph from Source + Run the following commands (these scripts are defined in `package.json`): + ```bash # FROM: ./apps/subgraph pnpm prepare: pnpm codegen pnpm build -``` +``` This will generate types, build the subgraph, and create a local `subgraph.yaml` file. ### Step 5 - Deploy the Subgraph to Production #### IMPORTANT: + **To avoid downtime during upgrades, maintain a backup subgraph. If issues arise, you can redirect traffic to the backup rather than waiting for redeployment or rollback, which can take hours.** - The subgraph name follows the pattern `nouns-builder-` regardless of version, don't clients do not need to be notified for non-breaking changes. @@ -73,7 +84,7 @@ This will generate types, build the subgraph, and create a local `subgraph.yaml` # FROM: ./apps/subgraph # Example with specVersion 0.0.6 -goldsky subgraph deploy nouns-builder-/0.0.6 --path . +goldsky subgraph deploy nouns-builder-/0.0.6 --path . goldsky subgraph tag create nouns-builder-/0.0.6 --tag latest # API endpoint format will be: api.goldsky.com/api/public//subgraphs/nouns-builder-ethereum-sepolia/latest/gn ``` @@ -96,6 +107,7 @@ The subgraph is currently deployed to the following networks: - TODO: [Base Sepolia](https://api.goldsky.com/api/public/project_cm33ek8kjx6pz010i2c3w8z25/subgraphs/nouns-builder-base-sepolia/latest/gn) ## (DEPRECATED) Local Development with Docker Compose (TODO: fix - pnpm create:local step not working) + - Generate the subgraph.yml file with `pnpm prepare:` - Generate types with `pnpm codegen` - Build the subgraph with `pnpm build` diff --git a/apps/subgraph/README.md b/apps/subgraph/README.md index e876bdf90..72e117a72 100644 --- a/apps/subgraph/README.md +++ b/apps/subgraph/README.md @@ -1,9 +1,11 @@ # Nouns Builder Subgraph ## Getting Started + πŸ‘‰ [Read the Goldsky docs](https://docs.goldsky.com/subgraphs/deploying-subgraphs) The Nouns Builder subgraph supports four networks: + - `ethereum` - `ethereum-sepolia` - `base` @@ -11,41 +13,49 @@ The Nouns Builder subgraph supports four networks: - `zora` ### Step 1 - Install Dependencies + Navigate to the subgraph directory and run: + ```bash # FROM: ./apps/subgraph pnpm install ``` ### Step 2 - Set Up a Personal Goldsky API Key + 1. Request to join the team account at [goldsky.com](https://goldsky.com). 2. Create an API key on your Settings page. 3. Install the Goldsky CLI: - ```bash - curl https://goldsky.com | sh - ``` + ```bash + curl https://goldsky.com | sh + ``` ### Step 3 - Log in with the API Key + Use the API key you created: + ```bash # FROM: ./apps/subgraph goldsky login ``` ### Step 4 - Build the Subgraph from Source + Run the following commands (these scripts are defined in `package.json`): + ```bash # FROM: ./apps/subgraph pnpm prepare: pnpm codegen pnpm build:subgraph -``` +``` This will generate types, build the subgraph, and create a local `subgraph.yaml` file. ### Step 5 - Deploy the Subgraph to Production #### IMPORTANT: + **To avoid downtime during upgrades, maintain a backup subgraph. If issues arise, you can redirect traffic to the backup rather than waiting for redeployment or rollback, which can take hours.** - The subgraph name follows the pattern `nouns-builder-`, so clients won’t need to update their URI for minor version changes. @@ -58,7 +68,7 @@ This will generate types, build the subgraph, and create a local `subgraph.yaml` # FROM: ./apps/subgraph # Example with specVersion 0.0.6 -goldsky subgraph deploy nouns-builder-/0.0.6 --path . +goldsky subgraph deploy nouns-builder-/0.0.6 --path . goldsky subgraph tag create nouns-builder-/0.0.6 --tag latest # API endpoint format: api.goldsky.com/api/public//subgraphs/nouns-builder-ethereum-sepolia/latest/gn ``` @@ -72,15 +82,16 @@ You can now query the subgraph in the Goldsky GraphQL playground to test your ch The subgraph is currently deployed to the following networks: - [Ethereum](https://api.goldsky.com/api/public//subgraphs/nouns-builder-ethereum/latest/gn) -- [Ethereum Sepolia](https://api.goldsky.com/api/public//subgraphs/nouns-builder-ethereum-sepolia/latest/gn) +- [Base](https://api.goldsky.com/api/public//subgraphs/nouns-builder-base/latest/gn) - [Optimism](https://api.goldsky.com/api/public//subgraphs/nouns-builder-optimism/latest/gn) -- TODO: [Optimism Sepolia](https://api.goldsky.com/api/public//subgraphs/nouns-builder-optimism-sepolia/latest/gn) - TODO: [Zora](https://api.goldsky.com/api/public//subgraphs/nouns-builder-zora/latest/gn) -- TODO: [Zora Sepolia](https://api.goldsky.com/api/public//subgraphs/nouns-builder-zora-sepolia/latest/gn) -- TODO: [Base](https://api.goldsky.com/api/public//subgraphs/nouns-builder-base/latest/gn) -- TODO: [Base Sepolia](https://api.goldsky.com/api/public//subgraphs/nouns-builder-base-sepolia/latest/gn) +- TODO?: [Ethereum Sepolia](https://api.goldsky.com/api/public//subgraphs/nouns-builder-ethereum-sepolia/latest/gn) +- TODO?: [Optimism Sepolia](https://api.goldsky.com/api/public//subgraphs/nouns-builder-optimism-sepolia/latest/gn) +- TODO?: [Zora Sepolia](https://api.goldsky.com/api/public//subgraphs/nouns-builder-zora-sepolia/latest/gn) +- TODO?: [Base Sepolia](https://api.goldsky.com/api/public//subgraphs/nouns-builder-base-sepolia/latest/gn) ## Local Development with Docker Compose + - Generate types with `pnpm codegen` - Build the subgraph with `pnpm build:subgraph` - Run the local graph node with `pnpm local-node` diff --git a/apps/web/src/components/Artwork/ArtworkPreview.tsx b/apps/web/src/components/Artwork/ArtworkPreview.tsx index a1b963b25..7ed4cc940 100644 --- a/apps/web/src/components/Artwork/ArtworkPreview.tsx +++ b/apps/web/src/components/Artwork/ArtworkPreview.tsx @@ -17,12 +17,9 @@ export interface ArtworkPreviewProps { images: ImageProps[] | undefined } -export const ArtworkPreview: React.FC = ({ - canvas, - generatedImages, - generateStackedImage, - images, -}) => { +export const ArtworkPreview: React.FC = ( + { canvas, generatedImages, generateStackedImage, images } +) => { return ( diff --git a/apps/web/src/components/Artwork/LayerOrdering.tsx b/apps/web/src/components/Artwork/LayerOrdering.tsx index a6eba43b1..aa06fa94d 100644 --- a/apps/web/src/components/Artwork/LayerOrdering.tsx +++ b/apps/web/src/components/Artwork/LayerOrdering.tsx @@ -19,13 +19,9 @@ interface LayerOrderingProps { setOrderedLayers: (orderedLayers: OrderedTraits) => void } -export const LayerOrdering: React.FC = ({ - title, - images, - artwork, - orderedLayers, - setOrderedLayers, -}) => { +export const LayerOrdering: React.FC = ( + { title, images, artwork, orderedLayers, setOrderedLayers } +) => { /* init layers and drag and drop */ const [dragAndDrop, setDragAndDrop] = React.useState(null) React.useEffect(() => { diff --git a/apps/web/src/components/Avatar/Avatar.tsx b/apps/web/src/components/Avatar/Avatar.tsx index 0f867f9ad..0b7e58658 100644 --- a/apps/web/src/components/Avatar/Avatar.tsx +++ b/apps/web/src/components/Avatar/Avatar.tsx @@ -12,14 +12,9 @@ export interface AvatarProps extends Omit { src?: string | null } -export function Avatar({ - address, - className, - size, - variant, - src, - ...props -}: AvatarProps) { +export function Avatar( + { address, className, size, variant, src, ...props }: AvatarProps +) { const background = useMemo(() => { if (address && !src) { const gradient = gradientForAddress(address) diff --git a/apps/web/src/components/BridgeModal/NetworkSelector.tsx b/apps/web/src/components/BridgeModal/NetworkSelector.tsx index f9de46197..aea666f75 100644 --- a/apps/web/src/components/BridgeModal/NetworkSelector.tsx +++ b/apps/web/src/components/BridgeModal/NetworkSelector.tsx @@ -13,10 +13,9 @@ export interface NetworkSelectorProps { setSelectedChain: (value: Chain) => void } -export const NetworkSelector: React.FC = ({ - selectedChain, - setSelectedChain, -}) => { +export const NetworkSelector: React.FC = ( + { selectedChain, setSelectedChain } +) => { const [isOpenChainMenu, setIsOpenChainMenu] = React.useState(false) const onChainChange = (chainId: number) => { diff --git a/apps/web/src/components/DisplayPanel.tsx b/apps/web/src/components/DisplayPanel.tsx index f6f3f73a2..78575fb4e 100644 --- a/apps/web/src/components/DisplayPanel.tsx +++ b/apps/web/src/components/DisplayPanel.tsx @@ -1,13 +1,9 @@ import { Flex, Text } from '@zoralabs/zord' import React from 'react' -export const DisplayPanel = ({ - title, - description, -}: { - title: string - description: string -}) => { +export const DisplayPanel = ( + { title, description }: { title: string; description: string } +) => { return ( = ({ - inputLabel, - formik, - id, - errorMessage, - autoSubmit, - value, - placeholder, - altFormat, - enableTime = false, - dateFormat = 'Y-m-d', - disabled = false, -}) => { +const Date: React.FC = ( + { + inputLabel, + formik, + id, + errorMessage, + autoSubmit, + value, + placeholder, + altFormat, + enableTime = false, + dateFormat = 'Y-m-d', + disabled = false, + } +) => { const ref = React.useRef(null) React.useEffect(() => { diff --git a/apps/web/src/components/Fields/FieldSwitch.tsx b/apps/web/src/components/Fields/FieldSwitch.tsx index e0d1ff6fc..99cf00ac5 100644 --- a/apps/web/src/components/Fields/FieldSwitch.tsx +++ b/apps/web/src/components/Fields/FieldSwitch.tsx @@ -42,14 +42,9 @@ interface FieldSwitchProps { parentValues?: any } -const FieldSwitch: React.FC = ({ - field, - formik, - autoSubmit, - submitCallback, - options, - parentValues, -}) => { +const FieldSwitch: React.FC = ( + { field, formik, autoSubmit, submitCallback, options, parentValues } +) => { /* handle smartInput onChange diff --git a/apps/web/src/components/Fields/NumberInput.tsx b/apps/web/src/components/Fields/NumberInput.tsx index 9e27f8911..c472145f5 100644 --- a/apps/web/src/components/Fields/NumberInput.tsx +++ b/apps/web/src/components/Fields/NumberInput.tsx @@ -17,15 +17,17 @@ interface NumberInputProps extends InputHTMLAttributes { disableWheelEvent?: boolean } -const NumberInput = ({ - label, - className, - errorMessage, - hasError, - value, - disableWheelEvent = true, - ...rest -}: NumberInputProps) => { +const NumberInput = ( + { + label, + className, + errorMessage, + hasError, + value, + disableWheelEvent = true, + ...rest + }: NumberInputProps +) => { return ( {errorMessage && ( diff --git a/apps/web/src/components/Fields/Radio.tsx b/apps/web/src/components/Fields/Radio.tsx index f3b1782ac..1e48bddd5 100644 --- a/apps/web/src/components/Fields/Radio.tsx +++ b/apps/web/src/components/Fields/Radio.tsx @@ -13,14 +13,16 @@ interface RadioProps { flexDirection?: Atoms['flexDirection'] } -export function Radio({ - formik, - id, - options, - value, - inputLabel, - flexDirection = 'column', -}: React.PropsWithChildren>) { +export function Radio( + { + formik, + id, + options, + value, + inputLabel, + flexDirection = 'column', + }: React.PropsWithChildren> +) { const handleSelection = (val: T) => { formik.setFieldValue(id, val) } diff --git a/apps/web/src/components/Fields/StickySave.tsx b/apps/web/src/components/Fields/StickySave.tsx index 9fc25d6b0..29cf694cc 100644 --- a/apps/web/src/components/Fields/StickySave.tsx +++ b/apps/web/src/components/Fields/StickySave.tsx @@ -33,13 +33,9 @@ const confirmAnimation = { }, } -const StickySave: React.FC = ({ - confirmText, - saveButtonText, - disabled, - isSubmitting, - onSave, -}) => { +const StickySave: React.FC = ( + { confirmText, saveButtonText, disabled, isSubmitting, onSave } +) => { const [hasConfirmed, setHasConfirmed] = React.useState(false) const [showConfirmBanner, setShowConfirmBanner] = React.useState(false) const previousSubmitting = usePrevious(isSubmitting) diff --git a/apps/web/src/components/Fields/TextInput.tsx b/apps/web/src/components/Fields/TextInput.tsx index 0069eb0e1..1a039b514 100644 --- a/apps/web/src/components/Fields/TextInput.tsx +++ b/apps/web/src/components/Fields/TextInput.tsx @@ -21,15 +21,9 @@ interface TextInputProps { disabled?: boolean } -const TextInput: React.FC = ({ - id, - value, - inputLabel, - onChange, - errorMessage, - placeholder, - disabled = false, -}) => { +const TextInput: React.FC = ( + { id, value, inputLabel, onChange, errorMessage, placeholder, disabled = false } +) => { return ( {inputLabel && } diff --git a/apps/web/src/components/Home/accordian/AccordionItem.tsx b/apps/web/src/components/Home/accordian/AccordionItem.tsx index 7a71be2d8..4910af091 100644 --- a/apps/web/src/components/Home/accordian/AccordionItem.tsx +++ b/apps/web/src/components/Home/accordian/AccordionItem.tsx @@ -6,10 +6,9 @@ import { Icon } from 'src/components/Icon' import { accordionItem, accordionName } from '../../../styles/home.css' -const AccordionItem: React.FC<{ title: string; description: ReactElement }> = ({ - title, - description, -}) => { +const AccordionItem: React.FC<{ title: string; description: ReactElement }> = ( + { title, description } +) => { const [isOpen, setIsOpen] = React.useState(false) const variants = { initial: { diff --git a/apps/web/src/components/Input/Input.tsx b/apps/web/src/components/Input/Input.tsx index 621377aa0..c25db16f7 100644 --- a/apps/web/src/components/Input/Input.tsx +++ b/apps/web/src/components/Input/Input.tsx @@ -16,16 +16,9 @@ interface CustomInputProps extends InputComponentProps { error?: string } -const Input: FC = ({ - name, - label, - secondaryLabel, - type, - placeholder, - autoComplete, - error, - ...props -}) => { +const Input: FC = ( + { name, label, secondaryLabel, type, placeholder, autoComplete, error, ...props } +) => { return ( <> diff --git a/apps/web/src/components/MarkdownEditor.tsx b/apps/web/src/components/MarkdownEditor.tsx index 94b1e03d7..5de9d7171 100644 --- a/apps/web/src/components/MarkdownEditor.tsx +++ b/apps/web/src/components/MarkdownEditor.tsx @@ -19,13 +19,9 @@ interface MarkdownEditorProps { disabled?: boolean } -export const MarkdownEditor: React.FC = ({ - onChange, - value, - inputLabel, - errorMessage, - disabled, -}) => { +export const MarkdownEditor: React.FC = ( + { onChange, value, inputLabel, errorMessage, disabled } +) => { const [selectedTab, setSelectedTab] = React.useState<'write' | 'preview'>( disabled ? 'preview' : 'write' ) diff --git a/apps/web/src/components/Meta.tsx b/apps/web/src/components/Meta.tsx index 3aad9486b..987c288e3 100644 --- a/apps/web/src/components/Meta.tsx +++ b/apps/web/src/components/Meta.tsx @@ -18,14 +18,9 @@ interface MetaProps { } } -export const Meta: React.FC = ({ - title, - type, - slug, - image, - description, - farcaster, -}) => { +export const Meta: React.FC = ( + { title, type, slug, image, description, farcaster } +) => { return ( {`Nouns Builder | ${title}`} diff --git a/apps/web/src/components/Modal/AnimatedModal.tsx b/apps/web/src/components/Modal/AnimatedModal.tsx index ed3f0217c..c5d581397 100644 --- a/apps/web/src/components/Modal/AnimatedModal.tsx +++ b/apps/web/src/components/Modal/AnimatedModal.tsx @@ -13,13 +13,9 @@ interface AnimatedModalProps { trigger?: ReactElement } -const AnimatedModal: React.FC = ({ - children, - open, - close, - size = 'small', - trigger, -}) => { +const AnimatedModal: React.FC = ( + { children, open, close, size = 'small', trigger } +) => { const contentVariants = { initial: { y: 50, diff --git a/apps/web/src/components/Modal/SuccessModalContent.tsx b/apps/web/src/components/Modal/SuccessModalContent.tsx index 7b6c1788b..c8cf79244 100644 --- a/apps/web/src/components/Modal/SuccessModalContent.tsx +++ b/apps/web/src/components/Modal/SuccessModalContent.tsx @@ -17,14 +17,9 @@ type SuccessModalContentProps = { pending?: boolean } -const SuccessModalContent: React.FC = ({ - title, - subtitle, - content, - actions, - success, - pending, -}) => { +const SuccessModalContent: React.FC = ( + { title, subtitle, content, actions, success, pending } +) => { return ( {success && ( diff --git a/apps/web/src/components/Pagination/index.tsx b/apps/web/src/components/Pagination/index.tsx index 1ca1a9ec7..14c67c28f 100644 --- a/apps/web/src/components/Pagination/index.tsx +++ b/apps/web/src/components/Pagination/index.tsx @@ -12,13 +12,9 @@ type PaginationProps = { onPrev: () => {} } -const Pagination: React.FC = ({ - onNext, - onPrev, - isFirst, - isLast, - scroll = false, -}) => { +const Pagination: React.FC = ( + { onNext, onPrev, isFirst, isLast, scroll = false } +) => { return ( { +export const useDelayedGovernance = ( + { + tokenAddress, + governorAddress, + chainId, + }: { + tokenAddress?: AddressType + governorAddress?: AddressType + chainId: CHAIN_ID + } +) => { const { data: delayedUntilTimestamp } = useContractRead({ abi: governorAbi, address: governorAddress, diff --git a/apps/web/src/hooks/useIsContract.ts b/apps/web/src/hooks/useIsContract.ts index 3455bf0b9..80f2c5eac 100644 --- a/apps/web/src/hooks/useIsContract.ts +++ b/apps/web/src/hooks/useIsContract.ts @@ -3,13 +3,9 @@ import useSWRImmutable from 'swr/immutable' import { AddressType, CHAIN_ID } from 'src/typings' import { getProvider } from 'src/utils/provider' -export const useIsContract = ({ - address, - chainId = CHAIN_ID.ETHEREUM, -}: { - address?: AddressType - chainId?: CHAIN_ID -}) => { +export const useIsContract = ( + { address, chainId = CHAIN_ID.ETHEREUM }: { address?: AddressType; chainId?: CHAIN_ID } +) => { return useSWRImmutable(address ? [address, chainId] : undefined, async (address) => { const provider = getProvider(chainId) return await provider.getBytecode({ address }).then((x) => x !== '0x') diff --git a/apps/web/src/hooks/useVotes.ts b/apps/web/src/hooks/useVotes.ts index 530450ee3..f04a1d72c 100644 --- a/apps/web/src/hooks/useVotes.ts +++ b/apps/web/src/hooks/useVotes.ts @@ -4,17 +4,19 @@ import { useContractReads } from 'wagmi' import { governorAbi, tokenAbi } from 'src/data/contract/abis' import { AddressType, CHAIN_ID } from 'src/typings' -export const useVotes = ({ - chainId, - collectionAddress, - governorAddress, - signerAddress, -}: { - chainId: CHAIN_ID - collectionAddress?: AddressType - governorAddress?: AddressType - signerAddress?: AddressType -}) => { +export const useVotes = ( + { + chainId, + collectionAddress, + governorAddress, + signerAddress, + }: { + chainId: CHAIN_ID + collectionAddress?: AddressType + governorAddress?: AddressType + signerAddress?: AddressType + } +) => { const { data, isLoading } = useContractReads({ enabled: !!collectionAddress && !!governorAddress && !!signerAddress, allowFailure: false, diff --git a/apps/web/src/modules/auction/components/AuctionDetail.tsx b/apps/web/src/modules/auction/components/AuctionDetail.tsx index 69a3879bb..50708bfb3 100644 --- a/apps/web/src/modules/auction/components/AuctionDetail.tsx +++ b/apps/web/src/modules/auction/components/AuctionDetail.tsx @@ -3,13 +3,9 @@ import { ReactNode } from 'react' import { auctionTextVariants } from './Auction.css' -export const AuctionDetail = ({ - title, - children, -}: { - title: string - children: ReactNode -}) => ( +export const AuctionDetail = ( + { title, children }: { title: string; children: ReactNode } +) => ( {title} ( +export const BidAmount = ( + { isOver, bid }: { isOver: boolean; bid?: number | string } +) => ( {!!bid || (bid === 0 && !isOver) ? `${formatCryptoVal(bid)} ETH` : 'n/a'} diff --git a/apps/web/src/modules/auction/components/CurrentAuction/AuctionCountdown.tsx b/apps/web/src/modules/auction/components/CurrentAuction/AuctionCountdown.tsx index 0d0f1b45c..2f56b57a2 100644 --- a/apps/web/src/modules/auction/components/CurrentAuction/AuctionCountdown.tsx +++ b/apps/web/src/modules/auction/components/CurrentAuction/AuctionCountdown.tsx @@ -2,13 +2,9 @@ import { Countdown } from 'src/components/Countdown' import { AuctionDetail } from '../AuctionDetail' -export const AuctionCountdown = ({ - endTime, - onEnd, -}: { - endTime: number - onEnd: () => void -}) => { +export const AuctionCountdown = ( + { endTime, onEnd }: { endTime: number; onEnd: () => void } +) => { return ( diff --git a/apps/web/src/modules/auction/components/CurrentAuction/WarningModal.tsx b/apps/web/src/modules/auction/components/CurrentAuction/WarningModal.tsx index 6348cf1b6..d82cf11f6 100644 --- a/apps/web/src/modules/auction/components/CurrentAuction/WarningModal.tsx +++ b/apps/web/src/modules/auction/components/CurrentAuction/WarningModal.tsx @@ -12,15 +12,17 @@ export interface WarningModalProps { onCancel: () => void } -export const WarningModal: React.FC = ({ - daoName, - currentBid, - isAverage, - maxReccomendedBid, - isCreatingBid, - onConfirm, - onCancel, -}) => { +export const WarningModal: React.FC = ( + { + daoName, + currentBid, + isAverage, + maxReccomendedBid, + isCreatingBid, + onConfirm, + onCancel, + } +) => { return ( diff --git a/apps/web/src/modules/auction/components/ViewSwitcher.tsx b/apps/web/src/modules/auction/components/ViewSwitcher.tsx index 1d999c3b9..26b36eec2 100644 --- a/apps/web/src/modules/auction/components/ViewSwitcher.tsx +++ b/apps/web/src/modules/auction/components/ViewSwitcher.tsx @@ -6,15 +6,17 @@ import { TopSectionView } from 'src/modules/dao/components/DaoTopSection' import { auctionWrapVariants, switcherBox } from './Auction.css' -export const ViewSwitcher = ({ - topSectionView, - setTopSectionView, - children, -}: { - topSectionView: TopSectionView - setTopSectionView: (view: TopSectionView) => void - children: ReactNode -}) => ( +export const ViewSwitcher = ( + { + topSectionView, + setTopSectionView, + children, + }: { + topSectionView: TopSectionView + setTopSectionView: (view: TopSectionView) => void + children: ReactNode + } +) => ( diff --git a/apps/web/src/modules/auction/hooks/useAuctionEvents.ts b/apps/web/src/modules/auction/hooks/useAuctionEvents.ts index 1c06c2986..86e3d3ed3 100644 --- a/apps/web/src/modules/auction/hooks/useAuctionEvents.ts +++ b/apps/web/src/modules/auction/hooks/useAuctionEvents.ts @@ -9,17 +9,19 @@ import { getBids } from 'src/data/subgraph/requests/getBids' import { useDaoStore } from 'src/modules/dao' import { AddressType, CHAIN_ID } from 'src/typings' -export const useAuctionEvents = ({ - chainId, - collection, - tokenId, - isTokenActiveAuction, -}: { - chainId: CHAIN_ID - collection: string - tokenId: string - isTokenActiveAuction: boolean -}) => { +export const useAuctionEvents = ( + { + chainId, + collection, + tokenId, + isTokenActiveAuction, + }: { + chainId: CHAIN_ID + collection: string + tokenId: string + isTokenActiveAuction: boolean + } +) => { const router = useRouter() const { mutate } = useSWRConfig() const { auction } = useDaoStore((state) => state.addresses) diff --git a/apps/web/src/modules/auction/hooks/useMinBidIncrement.ts b/apps/web/src/modules/auction/hooks/useMinBidIncrement.ts index a2c1c3480..a3b5b7523 100644 --- a/apps/web/src/modules/auction/hooks/useMinBidIncrement.ts +++ b/apps/web/src/modules/auction/hooks/useMinBidIncrement.ts @@ -2,15 +2,17 @@ import { formatEther } from 'viem' const DEFAULT_MIN_BID_AMOUNT = 0.0001 -export const useMinBidIncrement = ({ - highestBid, - reservePrice, - minBidIncrement, -}: { - highestBid?: bigint - reservePrice?: bigint - minBidIncrement?: bigint -}) => { +export const useMinBidIncrement = ( + { + highestBid, + reservePrice, + minBidIncrement, + }: { + highestBid?: bigint + reservePrice?: bigint + minBidIncrement?: bigint + } +) => { if ( reservePrice === undefined || minBidIncrement === undefined || diff --git a/apps/web/src/modules/create-dao/components/AllocationForm/Contribution.tsx b/apps/web/src/modules/create-dao/components/AllocationForm/Contribution.tsx index 244cf0ef7..18834a709 100644 --- a/apps/web/src/modules/create-dao/components/AllocationForm/Contribution.tsx +++ b/apps/web/src/modules/create-dao/components/AllocationForm/Contribution.tsx @@ -3,15 +3,17 @@ import React, { ReactNode } from 'react' import { formatDate } from 'src/utils/helpers' -export const Contribution = ({ - address, - allocation, - endDate, -}: { - address: ReactNode - allocation: string | number - endDate: string -}) => ( +export const Contribution = ( + { + address, + allocation, + endDate, + }: { + address: ReactNode + allocation: string | number + endDate: string + } +) => ( {address} diff --git a/apps/web/src/modules/create-dao/components/AllocationForm/DaoCopyAddress.tsx b/apps/web/src/modules/create-dao/components/AllocationForm/DaoCopyAddress.tsx index eb6b6e934..ee8b113ed 100644 --- a/apps/web/src/modules/create-dao/components/AllocationForm/DaoCopyAddress.tsx +++ b/apps/web/src/modules/create-dao/components/AllocationForm/DaoCopyAddress.tsx @@ -5,17 +5,19 @@ import React from 'react' import CopyButton from 'src/components/CopyButton/CopyButton' import { AddressType } from 'src/typings' -export const DaoCopyAddress = ({ - image, - name, - ens, - address, -}: { - image: string - name?: string - ens: string - address: AddressType -}) => ( +export const DaoCopyAddress = ( + { + image, + name, + ens, + address, + }: { + image: string + name?: string + ens: string + address: AddressType + } +) => ( = ({ - generatedImages, -}) => { +export const ImageGrid: React.FC<{ generatedImages: string[] }> = ( + { generatedImages } +) => { return ( {generatedImages && diff --git a/apps/web/src/modules/create-dao/components/FormHandler.tsx b/apps/web/src/modules/create-dao/components/FormHandler.tsx index 3f370207c..e5b92c06f 100644 --- a/apps/web/src/modules/create-dao/components/FormHandler.tsx +++ b/apps/web/src/modules/create-dao/components/FormHandler.tsx @@ -10,13 +10,9 @@ interface FormHandlerProps extends CreateFormSection { sectionIndex: number } -export const FormHandler = ({ - form, - title, - heading, - subHeading, - sectionIndex, -}: FormHandlerProps) => { +export const FormHandler = ( + { form, title, heading, subHeading, sectionIndex }: FormHandlerProps +) => { return ( diff --git a/apps/web/src/modules/create-dao/utils/formatFounderAllocation.ts b/apps/web/src/modules/create-dao/utils/formatFounderAllocation.ts index 4e70c6a1a..70e338890 100644 --- a/apps/web/src/modules/create-dao/utils/formatFounderAllocation.ts +++ b/apps/web/src/modules/create-dao/utils/formatFounderAllocation.ts @@ -1,9 +1,7 @@ import { TokenAllocation } from '../components/AllocationForm' -export const formatFounderAllocation = ({ - founderAddress, - allocationPercentage, - endDate, -}: TokenAllocation): string => { +export const formatFounderAllocation = ( + { founderAddress, allocationPercentage, endDate }: TokenAllocation +): string => { return `${founderAddress} will receive ${allocationPercentage}% of Tokens, until ${endDate}.` } diff --git a/apps/web/src/modules/create-proposal/components/CreateProposalHeading.tsx b/apps/web/src/modules/create-proposal/components/CreateProposalHeading.tsx index faccd4244..93cbd9175 100644 --- a/apps/web/src/modules/create-proposal/components/CreateProposalHeading.tsx +++ b/apps/web/src/modules/create-proposal/components/CreateProposalHeading.tsx @@ -11,11 +11,9 @@ interface CreateProposalHeadingProps { align?: 'center' | 'left' } -export const CreateProposalHeading: React.FC = ({ - title, - transactionType, - align = 'left', -}) => { +export const CreateProposalHeading: React.FC = ( + { title, transactionType, align = 'left' } +) => { return ( diff --git a/apps/web/src/modules/create-proposal/components/Queue/ConfirmRemove.tsx b/apps/web/src/modules/create-proposal/components/Queue/ConfirmRemove.tsx index 91e646cf7..90dac5788 100644 --- a/apps/web/src/modules/create-proposal/components/Queue/ConfirmRemove.tsx +++ b/apps/web/src/modules/create-proposal/components/Queue/ConfirmRemove.tsx @@ -13,10 +13,9 @@ interface ConfrimRemoveProps { setOpenConfirm: (boolean: boolean) => void } -export const ConfirmRemove: React.FC = ({ - handleRemoveTransaction, - setOpenConfirm, -}) => { +export const ConfirmRemove: React.FC = ( + { handleRemoveTransaction, setOpenConfirm } +) => { return ( Are you sure? diff --git a/apps/web/src/modules/create-proposal/components/SelectTransactionType/SelectTransactionType.tsx b/apps/web/src/modules/create-proposal/components/SelectTransactionType/SelectTransactionType.tsx index fdb7545f3..b34bce9c7 100644 --- a/apps/web/src/modules/create-proposal/components/SelectTransactionType/SelectTransactionType.tsx +++ b/apps/web/src/modules/create-proposal/components/SelectTransactionType/SelectTransactionType.tsx @@ -11,10 +11,9 @@ interface SelectTransactionTypeProps { onSelect: (value: TransactionFormType) => void } -export const SelectTransactionType: React.FC = ({ - transactionTypes, - onSelect, -}) => { +export const SelectTransactionType: React.FC = ( + { transactionTypes, onSelect } +) => { return ( diff --git a/apps/web/src/modules/create-proposal/components/SelectTransactionType/TransactionTypeCard.tsx b/apps/web/src/modules/create-proposal/components/SelectTransactionType/TransactionTypeCard.tsx index cce330f76..41056dac8 100644 --- a/apps/web/src/modules/create-proposal/components/SelectTransactionType/TransactionTypeCard.tsx +++ b/apps/web/src/modules/create-proposal/components/SelectTransactionType/TransactionTypeCard.tsx @@ -9,10 +9,9 @@ interface TransactionTypeCardProps { onClick: () => void } -const TransactionTypeCard: React.FC = ({ - transactionType, - onClick, -}) => { +const TransactionTypeCard: React.FC = ( + { transactionType, onClick } +) => { return ( diff --git a/apps/web/src/modules/create-proposal/components/TransactionForm/CustomTransaction/forms/CustomTransactionForm.tsx b/apps/web/src/modules/create-proposal/components/TransactionForm/CustomTransaction/forms/CustomTransactionForm.tsx index 591f7a449..3bb753cf7 100644 --- a/apps/web/src/modules/create-proposal/components/TransactionForm/CustomTransaction/forms/CustomTransactionForm.tsx +++ b/apps/web/src/modules/create-proposal/components/TransactionForm/CustomTransaction/forms/CustomTransactionForm.tsx @@ -25,14 +25,16 @@ interface CustomTransactionFormProps { validateOnBlur?: boolean } -export function CustomTransactionForm({ - fields, - initialValues, - validationSchema, - submitCallback, - options, - validateOnBlur = false, -}: React.PropsWithChildren>) { +export function CustomTransactionForm( + { + fields, + initialValues, + validationSchema, + submitCallback, + options, + validateOnBlur = false, + }: React.PropsWithChildren> +) { const { active: activeCustomTransactionSection, next: nextCustomTransactionForm, diff --git a/apps/web/src/modules/create-proposal/components/TransactionForm/Droposal/DroposalPreview.tsx b/apps/web/src/modules/create-proposal/components/TransactionForm/Droposal/DroposalPreview.tsx index a8834bba6..cc5d81361 100644 --- a/apps/web/src/modules/create-proposal/components/TransactionForm/Droposal/DroposalPreview.tsx +++ b/apps/web/src/modules/create-proposal/components/TransactionForm/Droposal/DroposalPreview.tsx @@ -12,10 +12,9 @@ interface DroposalPreviewProps { editionType: EditionType } -export const DroposalPreview: React.FC = ({ - formik, - editionType, -}) => { +export const DroposalPreview: React.FC = ( + { formik, editionType } +) => { const { mediaUrl, coverUrl, diff --git a/apps/web/src/modules/create-proposal/components/TwoColumnLayout.tsx b/apps/web/src/modules/create-proposal/components/TwoColumnLayout.tsx index 47edd9d88..f5677c982 100644 --- a/apps/web/src/modules/create-proposal/components/TwoColumnLayout.tsx +++ b/apps/web/src/modules/create-proposal/components/TwoColumnLayout.tsx @@ -8,10 +8,9 @@ interface CustomTransactionLayoutProps { rightColumn?: ReactNode } -export const TwoColumnLayout: FC = ({ - leftColumn, - rightColumn, -}) => { +export const TwoColumnLayout: FC = ( + { leftColumn, rightColumn } +) => { return ( diff --git a/apps/web/src/modules/create-proposal/components/UpgradeCard.tsx b/apps/web/src/modules/create-proposal/components/UpgradeCard.tsx index aaf200e20..a07bc75ed 100644 --- a/apps/web/src/modules/create-proposal/components/UpgradeCard.tsx +++ b/apps/web/src/modules/create-proposal/components/UpgradeCard.tsx @@ -15,15 +15,17 @@ interface UpgradeCardProps { alert?: ReactElement } -export const UpgradeCard = ({ - version, - hasThreshold, - totalContractUpgrades, - date, - description, - onUpgrade, - alert, -}: UpgradeCardProps) => { +export const UpgradeCard = ( + { + version, + hasThreshold, + totalContractUpgrades, + date, + description, + onUpgrade, + alert, + }: UpgradeCardProps +) => { const imgurl = 'https://api.zora.co/renderer/stack-images?contractAddress=0x963ac521c595d3d1be72c1eb057f24d4d42cb70b&tokenId=90&images=ipfs%3a%2f%2fbafybeieah7wjevdirq3clfpno4mkgn6z7vhdnqqniba62pwyfbwzf7mzqi%2fbackgrounds%2f9-5.svg&images=ipfs%3a%2f%2fbafybeieah7wjevdirq3clfpno4mkgn6z7vhdnqqniba62pwyfbwzf7mzqi%2f0%2f0_14_2_b.svg&images=ipfs%3a%2f%2fbafybeieah7wjevdirq3clfpno4mkgn6z7vhdnqqniba62pwyfbwzf7mzqi%2f1%2f1_a_3.svg&images=ipfs%3a%2f%2fbafybeieah7wjevdirq3clfpno4mkgn6z7vhdnqqniba62pwyfbwzf7mzqi%2f2%2f2_07_1_b.svg&images=ipfs%3a%2f%2fbafybeieah7wjevdirq3clfpno4mkgn6z7vhdnqqniba62pwyfbwzf7mzqi%2f3%2f3_21_10_b.svg&images=ipfs%3a%2f%2fbafybeieah7wjevdirq3clfpno4mkgn6z7vhdnqqniba62pwyfbwzf7mzqi%2f4c%2f4c-13.svg&images=ipfs%3a%2f%2fbafybeieah7wjevdirq3clfpno4mkgn6z7vhdnqqniba62pwyfbwzf7mzqi%2f5%2f5_05_6_w.svg&images=ipfs%3a%2f%2fbafybeieah7wjevdirq3clfpno4mkgn6z7vhdnqqniba62pwyfbwzf7mzqi%2f6%2f6_01-5%20b.svg&images=ipfs%3a%2f%2fbafybeieah7wjevdirq3clfpno4mkgn6z7vhdnqqniba62pwyfbwzf7mzqi%2f7%2f7_13_1_b.svg&images=ipfs%3a%2f%2fbafybeieah7wjevdirq3clfpno4mkgn6z7vhdnqqniba62pwyfbwzf7mzqi%2f8%2f8_14_2_w.svg' diff --git a/apps/web/src/modules/create-proposal/hooks/useFetchCurrentDAOConfig.tsx b/apps/web/src/modules/create-proposal/hooks/useFetchCurrentDAOConfig.tsx index 8aaa49164..16870d9bd 100644 --- a/apps/web/src/modules/create-proposal/hooks/useFetchCurrentDAOConfig.tsx +++ b/apps/web/src/modules/create-proposal/hooks/useFetchCurrentDAOConfig.tsx @@ -20,17 +20,19 @@ import { unpackOptionalArray } from 'src/utils/helpers' import { applyL1ToL2Alias } from '../utils/applyL1ToL2Alias' -export const useFetchCurrentDAOConfig = ({ - chainId, - migratingToChainId, - currentAddresses, - enabled, -}: { - enabled?: boolean - chainId: CHAIN_ID - migratingToChainId: CHAIN_ID - currentAddresses: DaoContractAddresses -}) => { +export const useFetchCurrentDAOConfig = ( + { + chainId, + migratingToChainId, + currentAddresses, + enabled, + }: { + enabled?: boolean + chainId: CHAIN_ID + migratingToChainId: CHAIN_ID + currentAddresses: DaoContractAddresses + } +) => { const contracts = setupContracts({ addresses: currentAddresses as Required, chainId, @@ -158,13 +160,9 @@ export const useFetchCurrentDAOConfig = ({ } } -const setupContracts = ({ - addresses, - chainId, -}: { - addresses: Required - chainId: CHAIN_ID -}) => { +const setupContracts = ( + { addresses, chainId }: { addresses: Required; chainId: CHAIN_ID } +) => { const token = { abi: tokenAbi, address: addresses.token, diff --git a/apps/web/src/modules/create-proposal/hooks/usePrepareMigration.tsx b/apps/web/src/modules/create-proposal/hooks/usePrepareMigration.tsx index 1f5a10203..f8fcd0db7 100644 --- a/apps/web/src/modules/create-proposal/hooks/usePrepareMigration.tsx +++ b/apps/web/src/modules/create-proposal/hooks/usePrepareMigration.tsx @@ -22,13 +22,9 @@ import { useFetchCurrentDAOConfig } from './useFetchCurrentDAOConfig' const UINT_64_MAX = 18446744073709551615n -export const usePrepareMigration = ({ - enabled, - migratingToChainId, -}: { - enabled: boolean - migratingToChainId: CHAIN_ID -}): { transactions: Transaction[] | undefined; error: Error | undefined } => { +export const usePrepareMigration = ( + { enabled, migratingToChainId }: { enabled: boolean; migratingToChainId: CHAIN_ID } +): { transactions: Transaction[] | undefined; error: Error | undefined } => { const { id: currentChainId } = useChainStore((x) => x.chain) const { addresses: currentAddresses } = useDaoStore() @@ -115,26 +111,28 @@ export const usePrepareMigration = ({ } } -const prepareTransactions = ({ - l1CrossDomainMessenger, - currentDAOConfig, - attributesMerkleRoot, - encodedMetadata, - minterParams, - migratingToChainId, -}: { - l1CrossDomainMessenger: AddressType - currentDAOConfig: ReturnType - attributesMerkleRoot: BytesType - encodedMetadata: BytesType[] - minterParams: { - mintStart: bigint - mintEnd: bigint - pricePerToken: bigint - merkleRoot: BytesType +const prepareTransactions = ( + { + l1CrossDomainMessenger, + currentDAOConfig, + attributesMerkleRoot, + encodedMetadata, + minterParams, + migratingToChainId, + }: { + l1CrossDomainMessenger: AddressType + currentDAOConfig: ReturnType + attributesMerkleRoot: BytesType + encodedMetadata: BytesType[] + minterParams: { + mintStart: bigint + mintEnd: bigint + pricePerToken: bigint + merkleRoot: BytesType + } + migratingToChainId: CHAIN_ID } - migratingToChainId: CHAIN_ID -}) => { +) => { const { founderParams, tokenParams, auctionParams, govParams } = currentDAOConfig! const ONE_HOUR_IN_SECONDS = 3600n diff --git a/apps/web/src/modules/create-proposal/stores/useProposalStore.ts b/apps/web/src/modules/create-proposal/stores/useProposalStore.ts index a8aa3d2fb..c7cd5b431 100644 --- a/apps/web/src/modules/create-proposal/stores/useProposalStore.ts +++ b/apps/web/src/modules/create-proposal/stores/useProposalStore.ts @@ -29,12 +29,14 @@ interface Actions { addTransactions: (builderTransactions: BuilderTransaction[]) => void removeTransaction: (index: number) => void removeAllTransactions: () => void - createProposal: ({ - title, - summary, - disabled, - transactions, - }: Pick) => void + createProposal: ( + { + title, + summary, + disabled, + transactions, + }: Pick + ) => void clearProposal: () => void } diff --git a/apps/web/src/modules/create-proposal/utils/applyL1ToL2Alias.ts b/apps/web/src/modules/create-proposal/utils/applyL1ToL2Alias.ts index 34de67aba..3f9114ea7 100644 --- a/apps/web/src/modules/create-proposal/utils/applyL1ToL2Alias.ts +++ b/apps/web/src/modules/create-proposal/utils/applyL1ToL2Alias.ts @@ -7,15 +7,17 @@ import { AddressType, CHAIN_ID } from 'src/typings' // We are calling a pure function so we can default to any network with an L2 migration deployer const DEFAULT_L2_CHAIN_ID = CHAIN_ID.BASE -export const applyL1ToL2Alias = async ({ - l1ChainId, - l2ChainId = DEFAULT_L2_CHAIN_ID, - address, -}: { - l1ChainId: CHAIN_ID - l2ChainId?: CHAIN_ID - address: AddressType -}) => { +export const applyL1ToL2Alias = async ( + { + l1ChainId, + l2ChainId = DEFAULT_L2_CHAIN_ID, + address, + }: { + l1ChainId: CHAIN_ID + l2ChainId?: CHAIN_ID + address: AddressType + } +) => { const publicClient = getPublicClient({ chainId: l1ChainId }) const bytecode = await publicClient.getBytecode({ address }) diff --git a/apps/web/src/modules/dao/components/AuctionChart/Layouts.tsx b/apps/web/src/modules/dao/components/AuctionChart/Layouts.tsx index 3b581bb84..456e12549 100644 --- a/apps/web/src/modules/dao/components/AuctionChart/Layouts.tsx +++ b/apps/web/src/modules/dao/components/AuctionChart/Layouts.tsx @@ -13,18 +13,20 @@ import { viewBox, } from './AuctionChart.css' -export const AuctionGraphLayout = ({ - chart, - startTime, - setStartTime, - chartData, -}: { - chart?: ReactNode - viewSwitcher?: ReactNode - startTime: StartTimes - setStartTime: (startTime: StartTimes) => void - chartData?: AuctionHistory[] -}) => { +export const AuctionGraphLayout = ( + { + chart, + startTime, + setStartTime, + chartData, + }: { + chart?: ReactNode + viewSwitcher?: ReactNode + startTime: StartTimes + setStartTime: (startTime: StartTimes) => void + chartData?: AuctionHistory[] + } +) => { const startTimeText = useMemo(() => { if (!chartData || !chartData.length) return '--' @@ -87,13 +89,9 @@ export const AuctionGraphLayout = ({ ) } -export const DisplayPanel = ({ - title, - description, -}: { - title: string - description: string -}) => ( +export const DisplayPanel = ( + { title, description }: { title: string; description: string } +) => ( { +export const DaoTopSection = ( + { chain, auctionAddress, collection, token }: TopSectionProps +) => { const [topSectionView, setTopSectionView] = React.useState( TopSectionView.Auction ) @@ -47,13 +44,9 @@ export const DaoTopSection = ({ ) } -const TabSwitchAnimation = ({ - children, - topSectionView, -}: { - children: ReactElement - topSectionView: string -}) => { +const TabSwitchAnimation = ( + { children, topSectionView }: { children: ReactElement; topSectionView: string } +) => { return ( { +export const MemberCard = ( + { + member, + totalSupply, + isMobile, + }: { + member: DaoMember + totalSupply?: number + isMobile: boolean + } +) => { const { displayName, ensAvatar } = useEnsData(member.address) const timeJoined = useMemo( diff --git a/apps/web/src/modules/dao/components/MembersList/MembersListLayout.tsx b/apps/web/src/modules/dao/components/MembersList/MembersListLayout.tsx index b935f0643..626a4cc45 100644 --- a/apps/web/src/modules/dao/components/MembersList/MembersListLayout.tsx +++ b/apps/web/src/modules/dao/components/MembersList/MembersListLayout.tsx @@ -3,15 +3,17 @@ import React, { ReactNode } from 'react' import { cardSkeleton, firstRowItem, lastRowItem, row, rowItem } from './MembersList.css' -export const MembersPanel = ({ - children, - isMobile, - tableRuler = true, -}: { - children: ReactNode - isMobile: boolean - tableRuler?: boolean -}) => { +export const MembersPanel = ( + { + children, + isMobile, + tableRuler = true, + }: { + children: ReactNode + isMobile: boolean + tableRuler?: boolean + } +) => { return ( <> { +export const AuctionPaused = ( + { currentChainSlug, tokenAddress, chainName, name, chainIcon }: PausedType +) => { const router = useRouter() const Paused = icons.pause diff --git a/apps/web/src/modules/dashboard/DashboardLayout.tsx b/apps/web/src/modules/dashboard/DashboardLayout.tsx index 8d4e2dcda..d193a0e2f 100644 --- a/apps/web/src/modules/dashboard/DashboardLayout.tsx +++ b/apps/web/src/modules/dashboard/DashboardLayout.tsx @@ -3,13 +3,9 @@ import React, { ReactNode } from 'react' import { Meta } from 'src/components/Meta' -export const DashboardLayout = ({ - auctionCards, - daoProposals, -}: { - auctionCards: ReactNode - daoProposals?: ReactNode -}) => { +export const DashboardLayout = ( + { auctionCards, daoProposals }: { auctionCards: ReactNode; daoProposals?: ReactNode } +) => { return ( diff --git a/apps/web/src/modules/proposal/components/ProposalActions/SuccessfulProposalActions.tsx b/apps/web/src/modules/proposal/components/ProposalActions/SuccessfulProposalActions.tsx index 267574ae1..cdec52736 100644 --- a/apps/web/src/modules/proposal/components/ProposalActions/SuccessfulProposalActions.tsx +++ b/apps/web/src/modules/proposal/components/ProposalActions/SuccessfulProposalActions.tsx @@ -56,9 +56,9 @@ const Execute: React.FC<{ ) } -export const SuccessfulProposalActions: React.FC = ({ - proposal, -}) => { +export const SuccessfulProposalActions: React.FC = ( + { proposal } +) => { const { mutate } = useSWRConfig() const chain = useChainStore((x) => x.chain) diff --git a/apps/web/src/modules/proposal/components/ProposalActions/VetoAction.tsx b/apps/web/src/modules/proposal/components/ProposalActions/VetoAction.tsx index ed0323cb4..5b70afd2f 100644 --- a/apps/web/src/modules/proposal/components/ProposalActions/VetoAction.tsx +++ b/apps/web/src/modules/proposal/components/ProposalActions/VetoAction.tsx @@ -78,10 +78,9 @@ const VetoModal: React.FC<{ ) } -export const VetoAction: React.FC = ({ - proposalId, - proposalNumber, -}) => { +export const VetoAction: React.FC = ( + { proposalId, proposalNumber } +) => { const [open, setOpen] = useState(false) const { addresses: { token }, diff --git a/apps/web/src/modules/proposal/components/ProposalActions/VoteStatus/VoteStatus.tsx b/apps/web/src/modules/proposal/components/ProposalActions/VoteStatus/VoteStatus.tsx index 9b3e7a7db..e10dabedc 100644 --- a/apps/web/src/modules/proposal/components/ProposalActions/VoteStatus/VoteStatus.tsx +++ b/apps/web/src/modules/proposal/components/ProposalActions/VoteStatus/VoteStatus.tsx @@ -33,15 +33,9 @@ interface VoteStatusProps { signerVote?: ProposalVote } -export const VoteStatus: React.FC = ({ - signerVote, - votesAvailable, - proposalId, - voteStart, - state, - daoName, - title, -}) => { +export const VoteStatus: React.FC = ( + { signerVote, votesAvailable, proposalId, voteStart, state, daoName, title } +) => { const { address: userAddress } = useAccount() const { governor } = useDaoStore((state) => state.addresses) const [showVoteModal, setShowVoteModal] = useState(false) diff --git a/apps/web/src/modules/proposal/components/ProposalStatus.tsx b/apps/web/src/modules/proposal/components/ProposalStatus.tsx index e790cd7ac..6db7bf1ca 100644 --- a/apps/web/src/modules/proposal/components/ProposalStatus.tsx +++ b/apps/web/src/modules/proposal/components/ProposalStatus.tsx @@ -16,15 +16,9 @@ type StatusProps = { showTime?: Boolean } -export const ProposalStatus: React.FC = ({ - state, - voteEnd, - voteStart, - expiresAt, - className, - flipped, - showTime, -}) => { +export const ProposalStatus: React.FC = ( + { state, voteEnd, voteStart, expiresAt, className, flipped, showTime } +) => { const now = dayjs.unix(Date.now() / 1000) const diffEnd = dayjs.unix(voteEnd).diff(now, 'second') diff --git a/apps/web/src/modules/proposal/components/ProposalVotes/VoterParticipation.tsx b/apps/web/src/modules/proposal/components/ProposalVotes/VoterParticipation.tsx index 03dd18f41..ee1e802b6 100644 --- a/apps/web/src/modules/proposal/components/ProposalVotes/VoterParticipation.tsx +++ b/apps/web/src/modules/proposal/components/ProposalVotes/VoterParticipation.tsx @@ -11,10 +11,9 @@ export interface VoterParticipationProps { const POSITIVE_VOTER_PARTICIPATION_RATE = 20 -export const VoterParticipation: React.FC = ({ - totalVotes, - maxVotes, -}) => { +export const VoterParticipation: React.FC = ( + { totalVotes, maxVotes } +) => { const { isMobile } = useLayoutStore() const participation = (totalVotes / maxVotes) * 100 diff --git a/packages/blocklist/README.md b/packages/blocklist/README.md index 5d0948362..7feb795eb 100644 --- a/packages/blocklist/README.md +++ b/packages/blocklist/README.md @@ -22,14 +22,11 @@ Then you can use the provided React hook to check an address against the block l ```ts import { useBlocklist } from 'blocklist' - const { address } = useAccount() - const isBlocked = useBlocklist(address) - useEffect(() => { if (isBlocked) { - // do something + do something } }, [isBlocked]) ``` @@ -38,8 +35,8 @@ There is also a simple imperative function to perform this check synchronously. ```ts import { isBlocked } from 'blocklist' - if (isBlocked('0x...')) { - // do something + do something +} } ``` diff --git a/packages/zoralabs-zord/README.md b/packages/zoralabs-zord/README.md index 1397a4d2c..360f0e7bf 100644 --- a/packages/zoralabs-zord/README.md +++ b/packages/zoralabs-zord/README.md @@ -17,7 +17,6 @@ import '@fontsource/inter/600.css' import { ThemeProvider, lightTheme } from '@zoralabs/zord' import '@zoralabs/zord/index.css' import type { AppProps } from 'next/app' - export default function MyApp({ Component, pageProps }: AppProps) { return ( @@ -249,7 +248,6 @@ Each theme maps 1-1 with the ThemeContract: ```ts import { border, colorTheme, ease, radii, size, space, typography } from './tokens' - export const lightTheme = createTheme(theme, { fonts: { heading: typography.fonts.body, diff --git a/packages/zoralabs-zord/src/components/PopUp.tsx b/packages/zoralabs-zord/src/components/PopUp.tsx index 78f6c95ca..41708d5e4 100644 --- a/packages/zoralabs-zord/src/components/PopUp.tsx +++ b/packages/zoralabs-zord/src/components/PopUp.tsx @@ -19,19 +19,21 @@ export interface PopUpProps { onOpenChange?: (state: boolean) => void } -export function PopUp({ - trigger, - children, - open = false, - close = false, - placement = 'bottom-start', - padding = 'x4', - offsetX = 0, - offsetY = 8, - triggerClassName, - onOpenChange, - wrapperClassName, -}: PopUpProps) { +export function PopUp( + { + trigger, + children, + open = false, + close = false, + placement = 'bottom-start', + padding = 'x4', + offsetX = 0, + offsetY = 8, + triggerClassName, + onOpenChange, + wrapperClassName, + }: PopUpProps +) { const [triggerElement, setTriggerElement] = useState(null) const [popperElement, setPopperElement] = useState(null) const [openState, setOpenState] = useState(open) diff --git a/packages/zoralabs-zord/src/elements/Select.tsx b/packages/zoralabs-zord/src/elements/Select.tsx index 7ea61be4e..783da1bd6 100644 --- a/packages/zoralabs-zord/src/elements/Select.tsx +++ b/packages/zoralabs-zord/src/elements/Select.tsx @@ -17,14 +17,16 @@ export interface SelectProps extends FlexComponentProps<'select'> { value?: string | number } -export const Select = ({ - className, - containerClassName, - variant = 'sm', - children, - disabled, - ...props -}: SelectProps) => { +export const Select = ( + { + className, + containerClassName, + variant = 'sm', + children, + disabled, + ...props + }: SelectProps +) => { const large = variant === 'lg' return ( diff --git a/packages/zoralabs-zord/src/elements/Text.tsx b/packages/zoralabs-zord/src/elements/Text.tsx index ffa13fa48..844655ff2 100644 --- a/packages/zoralabs-zord/src/elements/Text.tsx +++ b/packages/zoralabs-zord/src/elements/Text.tsx @@ -67,11 +67,9 @@ export interface ParagraphProps extends Omit { export type ParagraphComponentProps = PolymorphicPropsWithRef -export function Paragraph({ - size = 'md', - variant, - ...props -}: ParagraphComponentProps) { +export function Paragraph( + { size = 'md', variant, ...props }: ParagraphComponentProps +) { return } @@ -82,11 +80,9 @@ export interface HeadingProps extends Omit { export type HeadingComponentProps = PolymorphicPropsWithRef -export function Heading({ - size = 'md', - variant, - ...props -}: HeadingComponentProps) { +export function Heading( + { size = 'md', variant, ...props }: HeadingComponentProps +) { return } @@ -97,11 +93,9 @@ export interface DisplayProps extends Omit { export type DisplayComponentProps = PolymorphicPropsWithRef -export function Display({ - size = 'md', - variant, - ...props -}: DisplayComponentProps) { +export function Display( + { size = 'md', variant, ...props }: DisplayComponentProps +) { return } @@ -110,10 +104,9 @@ export interface EyebrowProps extends Omit {} export type EyebrowComponentProps = PolymorphicPropsWithRef -export function Eyebrow({ - variant, - ...props -}: EyebrowComponentProps) { +export function Eyebrow( + { variant, ...props }: EyebrowComponentProps +) { return } @@ -124,10 +117,9 @@ export interface LabelProps extends Omit { export type LabelComponentProps = PolymorphicPropsWithRef -export function Label({ - size = 'md', - ...props -}: LabelComponentProps) { +export function Label( + { size = 'md', ...props }: LabelComponentProps +) { return } @@ -136,8 +128,8 @@ export interface MenuProps extends TextProps {} export type MenuTextComponentProps = PolymorphicPropsWithRef -export function MenuText({ - ...props -}: MenuTextComponentProps) { +export function MenuText( + { ...props }: MenuTextComponentProps +) { return } diff --git a/packages/zoralabs-zord/src/utils/color-theme.ts b/packages/zoralabs-zord/src/utils/color-theme.ts index 6572e6ad9..58361b593 100644 --- a/packages/zoralabs-zord/src/utils/color-theme.ts +++ b/packages/zoralabs-zord/src/utils/color-theme.ts @@ -31,14 +31,16 @@ return ( */ -export function colorThemeVars({ - foreground = '#000000', - background = '#ffffff', - accent = '#000000', - positive = '#1CB687', - negative = '#F03232', - warning = '#F5A623', -}) { +export function colorThemeVars( + { + foreground = '#000000', + background = '#ffffff', + accent = '#000000', + positive = '#1CB687', + negative = '#F03232', + warning = '#F5A623', + } +) { return { background1: background, background2: mix(0.1, background, foreground), From 4f95b86eb5211be1eb5c78e5b24c589616082b3c Mon Sep 17 00:00:00 2001 From: Mills <37815163+0xMillz@users.noreply.github.com> Date: Fri, 6 Dec 2024 00:13:26 -0600 Subject: [PATCH 16/28] Deploy and update final subgraph URLs (#7) * Deploy and update final subgraph URLs * refactor: upgrade to Map for TypeScript happiness --- apps/subgraph/README.md | 10 +++--- .../{ethereum-sepolia.json => sepolia.json} | 2 +- apps/subgraph/package.json | 2 +- apps/web/src/constants/addresses.ts | 3 +- apps/web/src/constants/subgraph.ts | 31 +++++----------- apps/web/src/data/subgraph/client.ts | 36 +++++++++---------- apps/web/src/typings/index.tsx | 2 +- 7 files changed, 36 insertions(+), 50 deletions(-) rename apps/subgraph/config/{ethereum-sepolia.json => sepolia.json} (80%) diff --git a/apps/subgraph/README.md b/apps/subgraph/README.md index 72e117a72..f88fc3526 100644 --- a/apps/subgraph/README.md +++ b/apps/subgraph/README.md @@ -81,11 +81,11 @@ You can now query the subgraph in the Goldsky GraphQL playground to test your ch The subgraph is currently deployed to the following networks: -- [Ethereum](https://api.goldsky.com/api/public//subgraphs/nouns-builder-ethereum/latest/gn) -- [Base](https://api.goldsky.com/api/public//subgraphs/nouns-builder-base/latest/gn) -- [Optimism](https://api.goldsky.com/api/public//subgraphs/nouns-builder-optimism/latest/gn) -- TODO: [Zora](https://api.goldsky.com/api/public//subgraphs/nouns-builder-zora/latest/gn) -- TODO?: [Ethereum Sepolia](https://api.goldsky.com/api/public//subgraphs/nouns-builder-ethereum-sepolia/latest/gn) +- [Ethereum](https://api.goldsky.com/api/public//subgraphs/nouns-builder-ethereum-mainnet/latest/gn) +- [Base](https://api.goldsky.com/api/public//subgraphs/nouns-builder-base-mainnet/latest/gn) +- [Optimism](https://api.goldsky.com/api/public//subgraphs/nouns-builder-optimism-mainnet/latest/gn) +- [Zora](https://api.goldsky.com/api/public//subgraphs/nouns-builder-zora-mainnet/latest/gn) +- [Ethereum Sepolia](https://api.goldsky.com/api/public//subgraphs/nouns-builder-ethereum-sepolia/latest/gn) - TODO?: [Optimism Sepolia](https://api.goldsky.com/api/public//subgraphs/nouns-builder-optimism-sepolia/latest/gn) - TODO?: [Zora Sepolia](https://api.goldsky.com/api/public//subgraphs/nouns-builder-zora-sepolia/latest/gn) - TODO?: [Base Sepolia](https://api.goldsky.com/api/public//subgraphs/nouns-builder-base-sepolia/latest/gn) diff --git a/apps/subgraph/config/ethereum-sepolia.json b/apps/subgraph/config/sepolia.json similarity index 80% rename from apps/subgraph/config/ethereum-sepolia.json rename to apps/subgraph/config/sepolia.json index b954f0626..9ddf6e0ef 100644 --- a/apps/subgraph/config/ethereum-sepolia.json +++ b/apps/subgraph/config/sepolia.json @@ -1,5 +1,5 @@ { - "network": "ethereum-sepolia", + "network": "sepolia", "manager": { "address": "0x0ca90a96ac58f19b1f69f67103245c9263bc4bfc", "startBlock": 5074430 diff --git a/apps/subgraph/package.json b/apps/subgraph/package.json index 1645c62fb..9537b3a80 100644 --- a/apps/subgraph/package.json +++ b/apps/subgraph/package.json @@ -5,7 +5,7 @@ "clean": "rm -rf ./generated ./build subgraph.yaml", "build:subgraph": "graph build", "codegen": "graph codegen", - "prepare:ethereum-sepolia": "mustache config/ethereum-sepolia.json subgraph.yaml.mustache > subgraph.yaml", + "prepare:ethereum-sepolia": "mustache config/sepolia.json subgraph.yaml.mustache > subgraph.yaml", "prepare:ethereum": "mustache config/ethereum.json subgraph.yaml.mustache > subgraph.yaml", "prepare:base": "mustache config/base.json subgraph.yaml.mustache > subgraph.yaml", "prepare:base-sepolia": "mustache config/base-sepolia.json subgraph.yaml.mustache > subgraph.yaml", diff --git a/apps/web/src/constants/addresses.ts b/apps/web/src/constants/addresses.ts index d9a9418cd..27112051d 100644 --- a/apps/web/src/constants/addresses.ts +++ b/apps/web/src/constants/addresses.ts @@ -71,8 +71,7 @@ export const L2_MIGRATION_DEPLOYER = { [CHAIN_ID.ETHEREUM]: '0x0000000000000000000000000000000000000000' as AddressType, [CHAIN_ID.OPTIMISM]: '0x7D8Ea0D056f5B8443cdD8495D4e90FFCf0a8A354' as AddressType, [CHAIN_ID.SEPOLIA]: '0x0000000000000000000000000000000000000000' as AddressType, - [CHAIN_ID.OPTIMISM_SEPOLIA]: - '0xF3a4ca161a88e26115d1C1DBcB8C4874E1786F42' as AddressType, + [CHAIN_ID.OPTIMISM_SEPOLIA]: '0xF3a4ca161a88e26115d1C1DBcB8C4874E1786F42' as AddressType, [CHAIN_ID.BASE]: '0x8ef7b563Ff9F4A1f2d294845000cDf782d9afd7c' as AddressType, [CHAIN_ID.BASE_SEPOLIA]: '0x1e57Cad7C22042BD765011d0F2eb36606Fe12C3F' as AddressType, [CHAIN_ID.ZORA]: '0x7D8Ea0D056f5B8443cdD8495D4e90FFCf0a8A354' as AddressType, diff --git a/apps/web/src/constants/subgraph.ts b/apps/web/src/constants/subgraph.ts index 454ea4dfa..b8a5f8320 100644 --- a/apps/web/src/constants/subgraph.ts +++ b/apps/web/src/constants/subgraph.ts @@ -1,23 +1,10 @@ -import { CHAIN_ID } from 'src/typings' +import {CHAIN_ID} from 'src/typings' -// TODO: update all when all are deployed to the new BuilderDAO Goldsky account -export const PUBLIC_SUBGRAPH_URL = { - [CHAIN_ID.ETHEREUM]: - 'https://api.goldsky.com/api/public/project_clkk1ucdyf6ak38svcatie9tf/subgraphs/nouns-builder-ethereum-mainnet/stable/gn', - [CHAIN_ID.OPTIMISM]: - 'https://api.goldsky.com/api/public/project_cm33ek8kjx6pz010i2c3w8z25/subgraphs/nouns-builder-optimism-mainnet/latest/gn', - [CHAIN_ID.SEPOLIA]: - 'https://api.goldsky.com/api/public/project_cm33ek8kjx6pz010i2c3w8z25/subgraphs/nouns-builder-ethereum-sepolia/latest/gn', - [CHAIN_ID.OPTIMISM_SEPOLIA]: - 'https://api.goldsky.com/api/public/project_clkk1ucdyf6ak38svcatie9tf/subgraphs/nouns-builder-optimism-sepolia/stable/gn', - [CHAIN_ID.BASE]: - 'https://api.goldsky.com/api/public/project_cm33ek8kjx6pz010i2c3w8z25/subgraphs/nouns-builder-base-mainnet/latest/gn', - [CHAIN_ID.BASE_SEPOLIA]: - 'https://api.goldsky.com/api/public/project_clkk1ucdyf6ak38svcatie9tf/subgraphs/nouns-builder-base-sepolia/stable/gn', - [CHAIN_ID.ZORA]: - 'https://api.goldsky.com/api/public/project_clkk1ucdyf6ak38svcatie9tf/subgraphs/nouns-builder-zora-mainnet/stable/gn', - [CHAIN_ID.ZORA_SEPOLIA]: - 'https://api.goldsky.com/api/public/project_clkk1ucdyf6ak38svcatie9tf/subgraphs/nouns-builder-zora-sepolia/stable/gn', - [CHAIN_ID.FOUNDRY]: - 'https://api.thegraph.com/subgraphs/name/neokry/nouns-builder-mainnet', -} +export const PUBLIC_SUBGRAPH_URL: Map = new Map([ + [CHAIN_ID.ETHEREUM, 'https://api.goldsky.com/api/public/project_cm33ek8kjx6pz010i2c3w8z25/subgraphs/nouns-builder-ethereum-mainnet/latest/gn'], + [CHAIN_ID.OPTIMISM, 'https://api.goldsky.com/api/public/project_cm33ek8kjx6pz010i2c3w8z25/subgraphs/nouns-builder-optimism-mainnet/latest/gn'], + [CHAIN_ID.SEPOLIA, 'https://api.goldsky.com/api/public/project_cm33ek8kjx6pz010i2c3w8z25/subgraphs/nouns-builder-ethereum-sepolia/latest/gn'], + [CHAIN_ID.BASE, 'https://api.goldsky.com/api/public/project_cm33ek8kjx6pz010i2c3w8z25/subgraphs/nouns-builder-base-mainnet/latest/gn'], + [CHAIN_ID.ZORA, 'https://api.goldsky.com/api/public/project_cm33ek8kjx6pz010i2c3w8z25/subgraphs/nouns-builder-zora-mainnet/latest/gn'], + [CHAIN_ID.FOUNDRY, 'https://api.thegraph.com/subgraphs/name/neokry/nouns-builder-mainnet'] +]); \ No newline at end of file diff --git a/apps/web/src/data/subgraph/client.ts b/apps/web/src/data/subgraph/client.ts index 2cc0c71bb..70099aaea 100644 --- a/apps/web/src/data/subgraph/client.ts +++ b/apps/web/src/data/subgraph/client.ts @@ -1,29 +1,29 @@ -import { GraphQLClient } from 'graphql-request' +import {GraphQLClient} from 'graphql-request' -import { PUBLIC_SUBGRAPH_URL } from 'src/constants/subgraph' -import { CHAIN_ID } from 'src/typings' +import {CHAIN_ID} from 'src/typings' -import { getSdk } from './sdk.generated' +import {getSdk} from './sdk.generated' +import {PUBLIC_SUBGRAPH_URL} from "src/constants/subgraph"; const globalForClient = global as unknown as { - subgraphClient: Map + subgraphClient: Map } export class SDK { - static connect(chainId: CHAIN_ID) { - if (!globalForClient.subgraphClient) globalForClient.subgraphClient = new Map() + static connect(chainId: CHAIN_ID) { + if (!globalForClient.subgraphClient) globalForClient.subgraphClient = new Map() - const client = globalForClient.subgraphClient.has(chainId) - ? globalForClient.subgraphClient.get(chainId)! - : new GraphQLClient(PUBLIC_SUBGRAPH_URL[chainId], { - headers: { - 'Content-Type': 'application/json', - }, - }) + const client = globalForClient.subgraphClient.has(chainId) + ? globalForClient.subgraphClient.get(chainId)! + : new GraphQLClient(PUBLIC_SUBGRAPH_URL.get(chainId) as string, { + headers: { + 'Content-Type': 'application/json', + }, + }) - if (process.env.NODE_ENV !== 'production') - globalForClient.subgraphClient.set(chainId, client) + if (process.env.NODE_ENV !== 'production') + globalForClient.subgraphClient.set(chainId, client) - return getSdk(client) - } + return getSdk(client) + } } diff --git a/apps/web/src/typings/index.tsx b/apps/web/src/typings/index.tsx index 4e1ecef1c..e4b750440 100644 --- a/apps/web/src/typings/index.tsx +++ b/apps/web/src/typings/index.tsx @@ -7,7 +7,7 @@ export interface Duration { minutes?: number } -export const enum CHAIN_ID { +export enum CHAIN_ID { ETHEREUM = 1, SEPOLIA = 11155111, OPTIMISM = 10, From 64e8816c33e55eb6ae1ed8f71ec6587dd39184f4 Mon Sep 17 00:00:00 2001 From: Mills <37815163+0xMillz@users.noreply.github.com> Date: Sun, 8 Dec 2024 17:20:40 -0600 Subject: [PATCH 17/28] update subgraph README (#10) --- README.md | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 5758c126a..04388b6e2 100644 --- a/README.md +++ b/README.md @@ -16,16 +16,13 @@ πŸ‘‰ [Read the Goldsky docs](https://docs.goldsky.com/subgraphs/deploying-subgraphs) -The Nouns Builder subgraph supports eight networks: +The Nouns Builder subgraph supports five networks: - `ethereum` - `ethereum-sepolia` - `base` -- `base-sepolia` - `optimism` -- `optimism-sepolia` - `zora` -- `zora-sepolia` ### Step 1 - Install Dependencies @@ -97,14 +94,14 @@ You can now query the subgraph in the Goldsky GraphQL playground to test your ch The subgraph is currently deployed to the following networks: -- [Ethereum](https://api.goldsky.com/api/public/project_cm33ek8kjx6pz010i2c3w8z25/subgraphs/nouns-builder-ethereum/latest/gn) +- [Ethereum](https://api.goldsky.com/api/public/project_cm33ek8kjx6pz010i2c3w8z25/subgraphs/nouns-builder-ethereum-mainnet/latest/gn) - [Ethereum Sepolia](https://api.goldsky.com/api/public/project_cm33ek8kjx6pz010i2c3w8z25/subgraphs/nouns-builder-ethereum-sepolia/latest/gn) -- [Optimism](https://api.goldsky.com/api/public/project_cm33ek8kjx6pz010i2c3w8z25/subgraphs/nouns-builder-optimism/latest/gn) -- TODO: [Optimism Sepolia](https://api.goldsky.com/api/public/project_cm33ek8kjx6pz010i2c3w8z25/subgraphs/nouns-builder-optimism-sepolia/latest/gn) -- TODO: [Zora](https://api.goldsky.com/api/public/project_cm33ek8kjx6pz010i2c3w8z25/subgraphs/nouns-builder-zora/latest/gn) -- TODO: [Zora Sepolia](https://api.goldsky.com/api/public/project_cm33ek8kjx6pz010i2c3w8z25/subgraphs/nouns-builder-zora-sepolia/latest/gn) -- TODO: [Base](https://api.goldsky.com/api/public/project_cm33ek8kjx6pz010i2c3w8z25/subgraphs/nouns-builder-base/latest/gn) -- TODO: [Base Sepolia](https://api.goldsky.com/api/public/project_cm33ek8kjx6pz010i2c3w8z25/subgraphs/nouns-builder-base-sepolia/latest/gn) +- [Base](https://api.goldsky.com/api/public/project_cm33ek8kjx6pz010i2c3w8z25/subgraphs/nouns-builder-base-mainnet/latest/gn) +- [Optimism](https://api.goldsky.com/api/public/project_cm33ek8kjx6pz010i2c3w8z25/subgraphs/nouns-builder-optimism-mainnet/latest/gn) +- [Zora](https://api.goldsky.com/api/public/project_cm33ek8kjx6pz010i2c3w8z25/subgraphs/nouns-builder-zora-mainnet/latest/gn) +- TODO?: [Optimism Sepolia](https://api.goldsky.com/api/public/project_cm33ek8kjx6pz010i2c3w8z25/subgraphs/nouns-builder-optimism-sepolia/latest/gn) +- TODO?: [Zora Sepolia](https://api.goldsky.com/api/public/project_cm33ek8kjx6pz010i2c3w8z25/subgraphs/nouns-builder-zora-sepolia/latest/gn) +- TODO?: [Base Sepolia](https://api.goldsky.com/api/public/project_cm33ek8kjx6pz010i2c3w8z25/subgraphs/nouns-builder-base-sepolia/latest/gn) ## (DEPRECATED) Local Development with Docker Compose (TODO: fix - pnpm create:local step not working) From a382cb0aba55c955c74e8a1ff352f6d299a8cb6c Mon Sep 17 00:00:00 2001 From: 0xMillz <37815163+0xMillz@users.noreply.github.com> Date: Wed, 11 Dec 2024 19:57:32 -0600 Subject: [PATCH 18/28] Add .nvmrc --- .nvmrc | 1 + pnpm-lock.yaml | 222 ++++++++++++++++++++++++++++--------------------- 2 files changed, 127 insertions(+), 96 deletions(-) create mode 100644 .nvmrc diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 000000000..25bf17fc5 --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +18 \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 83d9614e8..c20350136 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -404,7 +404,7 @@ importers: version: 4.9.3 vitest: specifier: ^0.23.4 - version: 0.23.4(jsdom@20.0.3(bufferutil@4.0.7)(utf-8-validate@5.0.10))(terser@5.16.3) + version: 0.23.4(jsdom@20.0.3)(terser@5.16.3) packages/tsconfig: {} @@ -476,7 +476,7 @@ importers: version: link:../tsconfig tsup: specifier: ^6.5.0 - version: 6.6.2(postcss@8.4.41)(ts-node@10.9.1(@types/node@18.13.0)(typescript@4.9.3))(typescript@4.9.3) + version: 6.6.2(postcss@8.4.41)(ts-node@10.9.1(typescript@4.9.3))(typescript@4.9.3) typescript: specifier: ^4.9.3 version: 4.9.3 @@ -489,6 +489,9 @@ packages: '@adraffy/ens-normalize@1.10.0': resolution: {integrity: sha512-nA9XHtlAkYfJxY7bce8DcN7eKxWWCWkU+1GR9d+U6MbNpfwQp8TI7vqOsBsMcHoT4mBu2kypKoSKnghEzOOq5Q==} + '@adraffy/ens-normalize@1.11.0': + resolution: {integrity: sha512-/3DDPKHqqIqxUULp8yP4zODUY1i+2xvVWsv8A79xGWdCAG+8sb0hRh0Rk2QyOJUnnbyPUAZYcpBuRe3nS2OIUg==} + '@adraffy/ens-normalize@1.9.0': resolution: {integrity: sha512-iowxq3U30sghZotgl4s/oJRci6WPBfNO5YYgk2cIOMCHr3LeGPcsZjCEr+33Q4N+oV3OABDAtA+pyvWjbvBifQ==} @@ -2295,18 +2298,16 @@ packages: '@noble/curves@1.0.0': resolution: {integrity: sha512-2upgEu0iLiDVDZkNLeFV2+ht0BAVgQnEmCk6JsOch9Rp8xfkMCbvbAZlA2pBHQc73dbl+vFOXfqkf4uemdn0bw==} - '@noble/curves@1.1.0': - resolution: {integrity: sha512-091oBExgENk/kGj3AZmtBDMpxQPDtxQABR2B9lb1JbVTs6ytdzZNwvhxQ4MWasRNEzlbEH8jCWFCwhF/Obj5AA==} - '@noble/curves@1.2.0': resolution: {integrity: sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==} - '@noble/curves@1.4.0': - resolution: {integrity: sha512-p+4cb332SFCrReJkCYe8Xzm0OWi4Jji5jVdIZRL/PmacmDkFNw6MrrV+gGpiPxLHbV+zKFRywUWbaseT+tZRXg==} - '@noble/curves@1.5.0': resolution: {integrity: sha512-J5EKamIHnKPyClwVrzmaf5wSdQXgdHcPZIZLu3bwnbeCx8/7NPK5q2ZBWF+5FvYGByjiQQsJYX6jfgB2wDPn3A==} + '@noble/curves@1.7.0': + resolution: {integrity: sha512-UTMhXK9SeDhFJVrHeUJ5uZlI6ajXg10O6Ddocf9S6GjbSBVZsJo88HzKwXznNfGpMTRDyJkqMjNDPYgf0qFWnw==} + engines: {node: ^14.21.3 || >=16} + '@noble/hashes@1.1.2': resolution: {integrity: sha512-KYRCASVTv6aeUi1tsF8/vpyR7zpfs3FUzy2Jqm+MU+LmUKhQ0y2FpfwqkCcxSg2ua4GALJd8k2R76WxwZGbQpA==} @@ -2325,6 +2326,14 @@ packages: resolution: {integrity: sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==} engines: {node: '>= 16'} + '@noble/hashes@1.6.0': + resolution: {integrity: sha512-YUULf0Uk4/mAA89w+k3+yUYh6NrEvxZa5T6SY3wlMvE2chHkxFUUIDI8/XW1QSC357iA5pSnqt7XEhvFOqmDyQ==} + engines: {node: ^14.21.3 || >=16} + + '@noble/hashes@1.6.1': + resolution: {integrity: sha512-pq5D8h10hHBjyqX+cfBm0i8JUXJ0UhczFc4r74zbuT9XgewFo2E3J1cOaGtdZynILNmQ685YWGzGE1Zv6io50w==} + engines: {node: ^14.21.3 || >=16} + '@noble/secp256k1@1.7.1': resolution: {integrity: sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw==} @@ -2637,14 +2646,17 @@ packages: '@scure/base@1.1.7': resolution: {integrity: sha512-PPNYBslrLNNUQ/Yad37MHYsNQtK67EhWb6WtSvNLLPo7SdVZgkUjD6Dg+5On7zNwmskf8OX7I7Nx5oN+MIWE0g==} + '@scure/base@1.2.1': + resolution: {integrity: sha512-DGmGtC8Tt63J5GfHgfl5CuAXh96VF/LD8K9Hr/Gv0J2lAoRGlPOMpqMpMbCTOoOJMZCk2Xt+DskdDyn6dEFdzQ==} + '@scure/bip32@1.3.0': resolution: {integrity: sha512-bcKpo1oj54hGholplGLpqPHRbIsnbixFtc06nwuNM5/dwSXOq/AAYoIBRsBmnZJSdfeNW5rnff7NTAz3ZCqR9Q==} '@scure/bip32@1.3.2': resolution: {integrity: sha512-N1ZhksgwD3OBlwTv3R6KFEcPojl/W4ElJOeCZdi+vuI5QmTFwLq3OFf2zd2ROpKvxFdgZ6hUpb0dx9bVNEwYCA==} - '@scure/bip32@1.4.0': - resolution: {integrity: sha512-sVUpc0Vq3tXCkDGYVWGIZTRfnvu8LoTDaev7vbwh0omSvVORONr960MQWdKqJDCReIEmTj3PAr73O3aoxz7OPg==} + '@scure/bip32@1.6.0': + resolution: {integrity: sha512-82q1QfklrUUdXJzjuRU7iG7D7XiFx5PHYVS0+oeNKhyDLT7WPqs6pBcM2W5ZdwOwKCwoE1Vy1se+DHjcXwCYnA==} '@scure/bip39@1.2.0': resolution: {integrity: sha512-SX/uKq52cuxm4YFXWFaVByaSHJh2w3BnokVSeUJVCv6K7WulT9u2BuNRBhuFl8vAuYnzx9bEu9WgpcNYTrYieg==} @@ -2652,8 +2664,8 @@ packages: '@scure/bip39@1.2.1': resolution: {integrity: sha512-Z3/Fsz1yr904dduJD0NpiyRHhRYHdcnyh73FZWiV+/qhWi83wNJ3NWolYqCEN+ZWsUz2TWwajJggcRE9r1zUYg==} - '@scure/bip39@1.3.0': - resolution: {integrity: sha512-disdg7gHuTDZtY+ZdkmLpPCk7fxZSu3gBiEGuoC1XYxv9cGx3Z6cpTggCgW6odSOOIXCiDjuGejW+aJKCY/pIQ==} + '@scure/bip39@1.5.0': + resolution: {integrity: sha512-Dop+ASYhnrwm9+HA/HwXg7j2ZqM6yk2fyLWb5znexjctFY3+E+eU8cIWI0Pql0Qx4hPZCijlGq4OL71g+Uz30A==} '@sentry-internal/feedback@7.119.0': resolution: {integrity: sha512-om8TkAU5CQGO8nkmr7qsSBVkP+/vfeS4JgtW3sjoTK0fhj26+DljR6RlfCGWtYQdPSP6XV7atcPTjbSnsmG9FQ==} @@ -3520,8 +3532,8 @@ packages: zod: optional: true - abitype@1.0.5: - resolution: {integrity: sha512-YzDhti7cjlfaBhHutMaboYB21Ha3rXR9QTkNJFzYC4kC8YclaiwPBBBJY8ejFdu2wnJeZCVZSMlQJ7fi8S6hsw==} + abitype@1.0.7: + resolution: {integrity: sha512-ZfYYSktDQUwc2eduYu8C4wOs+RDPmnRYMh7zNfzeMtGGgb0U+6tLGjixUic6mXf5xKKCcgT5Qp6cv39tOARVFw==} peerDependencies: typescript: '>=5.0.4' zod: ^3 >=3.22.0 @@ -3540,6 +3552,7 @@ packages: acorn-import-assertions@1.8.0: resolution: {integrity: sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==} + deprecated: package has been renamed to acorn-import-attributes peerDependencies: acorn: ^8 @@ -5055,6 +5068,9 @@ packages: eventemitter3@4.0.7: resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==} + eventemitter3@5.0.1: + resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==} + events@3.3.0: resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} engines: {node: '>=0.8.x'} @@ -5217,8 +5233,8 @@ packages: for-each@0.3.3: resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} - forge-std@https://codeload.github.com/foundry-rs/forge-std/tar.gz/da591f56d8884c5824c0c1b3103fbcfd81123c4c: - resolution: {tarball: https://codeload.github.com/foundry-rs/forge-std/tar.gz/da591f56d8884c5824c0c1b3103fbcfd81123c4c} + forge-std@https://codeload.github.com/foundry-rs/forge-std/tar.gz/d3db4ef90a72b7d24aa5a2e5c649593eaef7801d: + resolution: {tarball: https://codeload.github.com/foundry-rs/forge-std/tar.gz/d3db4ef90a72b7d24aa5a2e5c649593eaef7801d} version: 1.9.4 form-data@2.3.3: @@ -6008,8 +6024,8 @@ packages: peerDependencies: ws: '*' - isows@1.0.4: - resolution: {integrity: sha512-hEzjY+x9u9hPmBom9IIAqdJCwNLax+xrPb51vEPpERoFlIxgmZcHzsT5jKG06nvInKOBGvReAVz80Umed5CczQ==} + isows@1.0.6: + resolution: {integrity: sha512-lPHCayd40oW98/I0uvgaHKWCSvkzY27LjWLbtzOm64yQ+G3Q5npjjbdppU65iZXkK1Zt+kH9pfegli0AYfwYYw==} peerDependencies: ws: '*' @@ -7031,6 +7047,14 @@ packages: outdent@0.8.0: resolution: {integrity: sha512-KiOAIsdpUTcAXuykya5fnVVT+/5uS0Q1mrkRHcF89tpieSmY33O/tmc54CqwA+bfhbtEfZUNLHaPUiB9X3jt1A==} + ox@0.1.2: + resolution: {integrity: sha512-ak/8K0Rtphg9vnRJlbOdaX9R7cmxD2MiSthjWGaQdMk3D7hrAlDoM+6Lxn7hN52Za3vrXfZ7enfke/5WjolDww==} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + p-defer@3.0.0: resolution: {integrity: sha512-ugZxsxmtTln604yeYd29EGrNhazN2lywetzpKhfmQjW/VJmhpDmWbiX+h0zL8V91R0UXkhb3KtPmyq9PZw3aYw==} engines: {node: '>=8'} @@ -8689,8 +8713,8 @@ packages: typescript: optional: true - viem@2.19.7: - resolution: {integrity: sha512-zoaBWnI6vf7MVRn4lAbuKd25hR31088yrMqONMHU8RjHTY4nqf+O589BPODwJak1LkfpbawyGyCY2tRFwZCWgw==} + viem@2.21.54: + resolution: {integrity: sha512-G9mmtbua3UtnVY9BqAtWdNp+3AO+oWhD0B9KaEsZb6gcrOWgmA4rz02yqEMg+qW9m6KgKGie7q3zcHqJIw6AqA==} peerDependencies: typescript: '>=5.0.4' peerDependenciesMeta: @@ -8875,8 +8899,8 @@ packages: resolution: {integrity: sha512-O8Tl4Ky40Sp6pe89Olk2FsaUkgHyb5QAXuaKo38ms3CxZZ4d3rPGfjP9DNKGm5+IUgAZBNpF1VmlSmNCqfDI1w==} engines: {node: '>=8.0.0'} - webauthn-p256@0.0.5: - resolution: {integrity: sha512-drMGNWKdaixZNobeORVIqq7k5DsRC9FnG201K2QjeOoQLmtSDaSsVZdkg6n5jUALJKcAG++zBPJXmv6hy0nWFg==} + webauthn-p256@0.0.10: + resolution: {integrity: sha512-EeYD+gmIT80YkSIDb2iWq0lq2zbHo1CxHlQTeJ+KkCILWpVy3zASH3ByD4bopzfk0uCwXxLqKGLqp2W4O28VFA==} webcrypto-core@1.7.6: resolution: {integrity: sha512-TBPiewB4Buw+HI3EQW+Bexm19/W4cP/qZG/02QJCXN+iN+T5sl074vZ3rJcle/ZtDBQSgjkbsQO/1eFcxnSBUA==} @@ -9024,18 +9048,6 @@ packages: utf-8-validate: optional: true - ws@8.17.1: - resolution: {integrity: sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==} - engines: {node: '>=10.0.0'} - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: '>=5.0.2' - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - ws@8.18.0: resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==} engines: {node: '>=10.0.0'} @@ -9156,6 +9168,8 @@ snapshots: '@adraffy/ens-normalize@1.10.0': {} + '@adraffy/ens-normalize@1.11.0': {} + '@adraffy/ens-normalize@1.9.0': {} '@ampproject/remapping@2.2.0': @@ -10434,8 +10448,8 @@ snapshots: '@farcaster/core@0.9.0(bufferutil@4.0.7)(typescript@5.5.4)(utf-8-validate@5.0.10)(zod@3.23.8)': dependencies: '@ethersproject/abstract-signer': 5.7.0 - '@noble/curves': 1.1.0 - '@noble/hashes': 1.3.1 + '@noble/curves': 1.5.0 + '@noble/hashes': 1.4.0 ethers: 6.2.3(bufferutil@4.0.7)(utf-8-validate@5.0.10) neverthrow: 6.0.0 viem: 0.3.50(bufferutil@4.0.7)(typescript@5.5.4)(utf-8-validate@5.0.10)(zod@3.23.8) @@ -10910,10 +10924,10 @@ snapshots: '@types/ws': 8.5.4 '@whatwg-node/fetch': 0.8.1(@types/node@18.13.0) graphql: 16.6.0 - isomorphic-ws: 5.0.0(ws@8.12.0(bufferutil@4.0.7)(utf-8-validate@5.0.10)) + isomorphic-ws: 5.0.0(ws@8.18.0(bufferutil@4.0.7)(utf-8-validate@5.0.10)) tslib: 2.5.0 value-or-promise: 1.0.12 - ws: 8.12.0(bufferutil@4.0.7)(utf-8-validate@5.0.10) + ws: 8.18.0(bufferutil@4.0.7)(utf-8-validate@5.0.10) transitivePeerDependencies: - '@types/node' - bufferutil @@ -11354,21 +11368,17 @@ snapshots: dependencies: '@noble/hashes': 1.3.0 - '@noble/curves@1.1.0': - dependencies: - '@noble/hashes': 1.3.1 - '@noble/curves@1.2.0': dependencies: '@noble/hashes': 1.3.2 - '@noble/curves@1.4.0': + '@noble/curves@1.5.0': dependencies: '@noble/hashes': 1.4.0 - '@noble/curves@1.5.0': + '@noble/curves@1.7.0': dependencies: - '@noble/hashes': 1.4.0 + '@noble/hashes': 1.6.0 '@noble/hashes@1.1.2': {} @@ -11380,6 +11390,10 @@ snapshots: '@noble/hashes@1.4.0': {} + '@noble/hashes@1.6.0': {} + + '@noble/hashes@1.6.1': {} + '@noble/secp256k1@1.7.1': {} '@nodelib/fs.scandir@2.1.5': @@ -11727,7 +11741,7 @@ snapshots: '@safe-global/safe-apps-sdk@9.1.0(bufferutil@4.0.7)(encoding@0.1.13)(typescript@5.5.4)(utf-8-validate@5.0.10)(zod@3.23.8)': dependencies: '@safe-global/safe-gateway-typescript-sdk': 3.7.0(encoding@0.1.13) - viem: 2.19.7(bufferutil@4.0.7)(typescript@5.5.4)(utf-8-validate@5.0.10)(zod@3.23.8) + viem: 2.21.54(bufferutil@4.0.7)(typescript@5.5.4)(utf-8-validate@5.0.10)(zod@3.23.8) transitivePeerDependencies: - bufferutil - encoding @@ -11745,11 +11759,13 @@ snapshots: '@scure/base@1.1.7': {} + '@scure/base@1.2.1': {} + '@scure/bip32@1.3.0': dependencies: '@noble/curves': 1.0.0 - '@noble/hashes': 1.3.1 - '@scure/base': 1.1.1 + '@noble/hashes': 1.3.2 + '@scure/base': 1.1.7 '@scure/bip32@1.3.2': dependencies: @@ -11757,26 +11773,26 @@ snapshots: '@noble/hashes': 1.3.2 '@scure/base': 1.1.7 - '@scure/bip32@1.4.0': + '@scure/bip32@1.6.0': dependencies: - '@noble/curves': 1.4.0 - '@noble/hashes': 1.4.0 - '@scure/base': 1.1.7 + '@noble/curves': 1.7.0 + '@noble/hashes': 1.6.1 + '@scure/base': 1.2.1 '@scure/bip39@1.2.0': dependencies: - '@noble/hashes': 1.3.1 - '@scure/base': 1.1.1 + '@noble/hashes': 1.3.2 + '@scure/base': 1.1.7 '@scure/bip39@1.2.1': dependencies: '@noble/hashes': 1.3.2 '@scure/base': 1.1.1 - '@scure/bip39@1.3.0': + '@scure/bip39@1.5.0': dependencies: - '@noble/hashes': 1.4.0 - '@scure/base': 1.1.7 + '@noble/hashes': 1.6.1 + '@scure/base': 1.2.1 '@sentry-internal/feedback@7.119.0': dependencies: @@ -11915,8 +11931,8 @@ snapshots: '@solana/web3.js@1.77.3(bufferutil@4.0.7)(encoding@0.1.13)(utf-8-validate@5.0.10)': dependencies: '@babel/runtime': 7.20.1 - '@noble/curves': 1.1.0 - '@noble/hashes': 1.3.1 + '@noble/curves': 1.5.0 + '@noble/hashes': 1.4.0 '@solana/buffer-layout': 4.0.1 agentkeepalive: 4.3.0 bigint-buffer: 1.1.5 @@ -13215,7 +13231,7 @@ snapshots: '@openzeppelin/contracts-upgradeable': 4.8.1 '@types/node': 18.13.0 ds-test: https://codeload.github.com/dapphub/ds-test/tar.gz/e282159d5170298eb2455a6c05280ab5a73a4ef0 - forge-std: https://codeload.github.com/foundry-rs/forge-std/tar.gz/da591f56d8884c5824c0c1b3103fbcfd81123c4c + forge-std: https://codeload.github.com/foundry-rs/forge-std/tar.gz/d3db4ef90a72b7d24aa5a2e5c649593eaef7801d micro-onchain-metadata-utils: 0.1.1 sol-uriencode: 0.2.0 @@ -13242,7 +13258,7 @@ snapshots: typescript: 5.5.4 zod: 3.23.8 - abitype@1.0.5(typescript@5.5.4)(zod@3.23.8): + abitype@1.0.7(typescript@5.5.4)(zod@3.23.8): optionalDependencies: typescript: 5.5.4 zod: 3.23.8 @@ -14734,7 +14750,7 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.7.4(@typescript-eslint/parser@5.54.0(eslint@8.34.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.6)(eslint-import-resolver-typescript@3.5.2)(eslint@8.34.0): + eslint-module-utils@2.7.4(@typescript-eslint/parser@5.54.0(eslint@8.34.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.6)(eslint-import-resolver-typescript@3.5.2(eslint-plugin-import@2.26.0)(eslint@8.34.0))(eslint@8.34.0): dependencies: debug: 3.2.7 optionalDependencies: @@ -14753,7 +14769,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.34.0 eslint-import-resolver-node: 0.3.6 - eslint-module-utils: 2.7.4(@typescript-eslint/parser@5.54.0(eslint@8.34.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.6)(eslint-import-resolver-typescript@3.5.2)(eslint@8.34.0) + eslint-module-utils: 2.7.4(@typescript-eslint/parser@5.54.0(eslint@8.34.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.6)(eslint-import-resolver-typescript@3.5.2(eslint-plugin-import@2.26.0)(eslint@8.34.0))(eslint@8.34.0) has: 1.0.3 is-core-module: 2.11.0 is-glob: 4.0.3 @@ -15100,6 +15116,8 @@ snapshots: eventemitter3@4.0.7: {} + eventemitter3@5.0.1: {} + events@3.3.0: {} evp_bytestokey@1.0.3: @@ -15276,7 +15294,7 @@ snapshots: dependencies: is-callable: 1.2.7 - forge-std@https://codeload.github.com/foundry-rs/forge-std/tar.gz/da591f56d8884c5824c0c1b3103fbcfd81123c4c: {} + forge-std@https://codeload.github.com/foundry-rs/forge-std/tar.gz/d3db4ef90a72b7d24aa5a2e5c649593eaef7801d: {} form-data@2.3.3: dependencies: @@ -15342,7 +15360,7 @@ snapshots: lz-string: 1.5.0 path-browserify: 1.0.1 qrcode: 1.5.3 - viem: 2.19.7(bufferutil@4.0.7)(typescript@5.5.4)(utf-8-validate@5.0.10)(zod@3.23.8) + viem: 2.21.54(bufferutil@4.0.7)(typescript@5.5.4)(utf-8-validate@5.0.10)(zod@3.23.8) vite: 5.4.1(@types/node@18.13.0)(terser@5.16.3) optionalDependencies: typescript: 5.5.4 @@ -16343,13 +16361,17 @@ snapshots: dependencies: ws: 8.12.0(bufferutil@4.0.7)(utf-8-validate@5.0.10) + isomorphic-ws@5.0.0(ws@8.18.0(bufferutil@4.0.7)(utf-8-validate@5.0.10)): + dependencies: + ws: 8.18.0(bufferutil@4.0.7)(utf-8-validate@5.0.10) + isows@1.0.3(ws@8.13.0(bufferutil@4.0.7)(utf-8-validate@5.0.10)): dependencies: ws: 8.13.0(bufferutil@4.0.7)(utf-8-validate@5.0.10) - isows@1.0.4(ws@8.17.1(bufferutil@4.0.7)(utf-8-validate@5.0.10)): + isows@1.0.6(ws@8.18.0(bufferutil@4.0.7)(utf-8-validate@5.0.10)): dependencies: - ws: 8.17.1(bufferutil@4.0.7)(utf-8-validate@5.0.10) + ws: 8.18.0(bufferutil@4.0.7)(utf-8-validate@5.0.10) it-all@1.0.6: {} @@ -17645,6 +17667,20 @@ snapshots: outdent@0.8.0: {} + ox@0.1.2(typescript@5.5.4)(zod@3.23.8): + dependencies: + '@adraffy/ens-normalize': 1.11.0 + '@noble/curves': 1.7.0 + '@noble/hashes': 1.6.1 + '@scure/bip32': 1.6.0 + '@scure/bip39': 1.5.0 + abitype: 1.0.7(typescript@5.5.4)(zod@3.23.8) + eventemitter3: 5.0.1 + optionalDependencies: + typescript: 5.5.4 + transitivePeerDependencies: + - zod + p-defer@3.0.0: {} p-fifo@1.0.0: @@ -17844,13 +17880,13 @@ snapshots: postcss: 8.4.24 ts-node: 10.9.1(@types/node@18.13.0)(typescript@5.5.4) - postcss-load-config@3.1.4(postcss@8.4.41)(ts-node@10.9.1(@types/node@18.13.0)(typescript@4.9.3)): + postcss-load-config@3.1.4(postcss@8.4.41)(ts-node@10.9.1(typescript@4.9.3)): dependencies: lilconfig: 2.0.6 yaml: 1.10.2 optionalDependencies: postcss: 8.4.41 - ts-node: 10.9.1(@types/node@18.13.0)(typescript@4.9.3) + ts-node: 10.9.1(typescript@4.9.3) postcss-value-parser@4.2.0: {} @@ -19060,7 +19096,7 @@ snapshots: ts-log@2.2.5: {} - ts-node@10.9.1(@types/node@18.13.0)(typescript@4.9.3): + ts-node@10.9.1(@types/node@18.13.0)(typescript@5.5.4): dependencies: '@cspotcode/source-map-support': 0.8.1 '@tsconfig/node10': 1.0.9 @@ -19074,28 +19110,27 @@ snapshots: create-require: 1.1.1 diff: 4.0.2 make-error: 1.3.6 - typescript: 4.9.3 + typescript: 5.5.4 v8-compile-cache-lib: 3.0.1 yn: 3.1.1 - optional: true - ts-node@10.9.1(@types/node@18.13.0)(typescript@5.5.4): + ts-node@10.9.1(typescript@4.9.3): dependencies: '@cspotcode/source-map-support': 0.8.1 '@tsconfig/node10': 1.0.9 '@tsconfig/node12': 1.0.11 '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.3 - '@types/node': 18.13.0 acorn: 8.8.2 acorn-walk: 8.2.0 arg: 4.1.3 create-require: 1.1.1 diff: 4.0.2 make-error: 1.3.6 - typescript: 5.5.4 + typescript: 4.9.3 v8-compile-cache-lib: 3.0.1 yn: 3.1.1 + optional: true tsconfig-paths@3.14.1: dependencies: @@ -19112,7 +19147,7 @@ snapshots: tslib@2.5.0: {} - tsup@6.6.2(postcss@8.4.41)(ts-node@10.9.1(@types/node@18.13.0)(typescript@4.9.3))(typescript@4.9.3): + tsup@6.6.2(postcss@8.4.41)(ts-node@10.9.1(typescript@4.9.3))(typescript@4.9.3): dependencies: bundle-require: 4.0.1(esbuild@0.17.8) cac: 6.7.14 @@ -19122,7 +19157,7 @@ snapshots: execa: 5.1.1 globby: 11.1.0 joycon: 3.1.1 - postcss-load-config: 3.1.4(postcss@8.4.41)(ts-node@10.9.1(@types/node@18.13.0)(typescript@4.9.3)) + postcss-load-config: 3.1.4(postcss@8.4.41)(ts-node@10.9.1(typescript@4.9.3)) resolve-from: 5.0.0 rollup: 3.15.0 source-map: 0.8.0-beta.0 @@ -19471,17 +19506,17 @@ snapshots: - utf-8-validate - zod - viem@2.19.7(bufferutil@4.0.7)(typescript@5.5.4)(utf-8-validate@5.0.10)(zod@3.23.8): + viem@2.21.54(bufferutil@4.0.7)(typescript@5.5.4)(utf-8-validate@5.0.10)(zod@3.23.8): dependencies: - '@adraffy/ens-normalize': 1.10.0 - '@noble/curves': 1.4.0 - '@noble/hashes': 1.4.0 - '@scure/bip32': 1.4.0 - '@scure/bip39': 1.3.0 - abitype: 1.0.5(typescript@5.5.4)(zod@3.23.8) - isows: 1.0.4(ws@8.17.1(bufferutil@4.0.7)(utf-8-validate@5.0.10)) - webauthn-p256: 0.0.5 - ws: 8.17.1(bufferutil@4.0.7)(utf-8-validate@5.0.10) + '@noble/curves': 1.7.0 + '@noble/hashes': 1.6.1 + '@scure/bip32': 1.6.0 + '@scure/bip39': 1.5.0 + abitype: 1.0.7(typescript@5.5.4)(zod@3.23.8) + isows: 1.0.6(ws@8.18.0(bufferutil@4.0.7)(utf-8-validate@5.0.10)) + ox: 0.1.2(typescript@5.5.4)(zod@3.23.8) + webauthn-p256: 0.0.10 + ws: 8.18.0(bufferutil@4.0.7)(utf-8-validate@5.0.10) optionalDependencies: typescript: 5.5.4 transitivePeerDependencies: @@ -19549,7 +19584,7 @@ snapshots: fsevents: 2.3.3 terser: 5.16.3 - vitest@0.23.4(jsdom@20.0.3(bufferutil@4.0.7)(utf-8-validate@5.0.10))(terser@5.16.3): + vitest@0.23.4(jsdom@20.0.3)(terser@5.16.3): dependencies: '@types/chai': 4.3.4 '@types/chai-subset': 1.3.3 @@ -19678,10 +19713,10 @@ snapshots: randombytes: 2.1.0 utf8: 3.0.0 - webauthn-p256@0.0.5: + webauthn-p256@0.0.10: dependencies: - '@noble/curves': 1.5.0 - '@noble/hashes': 1.4.0 + '@noble/curves': 1.7.0 + '@noble/hashes': 1.6.1 webcrypto-core@1.7.6: dependencies: @@ -19860,11 +19895,6 @@ snapshots: bufferutil: 4.0.7 utf-8-validate: 5.0.10 - ws@8.17.1(bufferutil@4.0.7)(utf-8-validate@5.0.10): - optionalDependencies: - bufferutil: 4.0.7 - utf-8-validate: 5.0.10 - ws@8.18.0(bufferutil@4.0.7)(utf-8-validate@5.0.10): optionalDependencies: bufferutil: 4.0.7 From 669cd7e984ea458a50eed679cdefcca2665743d9 Mon Sep 17 00:00:00 2001 From: Mills <37815163+0xMillz@users.noreply.github.com> Date: Sat, 21 Dec 2024 07:31:42 -0600 Subject: [PATCH 19/28] Update READMEs and links to docs (#26) --- README.md | 188 +++++++++++------- apps/subgraph/README.md | 40 ++-- .../web/public/builder-avatar-circle60x60.png | Bin 0 -> 6159 bytes .../src/components/BridgeModal/BridgeForm.tsx | 2 +- apps/web/src/constants/addresses.ts | 3 +- apps/web/src/constants/subgraph.ts | 34 +++- apps/web/src/data/subgraph/client.ts | 36 ++-- apps/web/src/layouts/DefaultLayout/Footer.tsx | 2 +- apps/web/src/layouts/DefaultLayout/Nav.tsx | 2 +- .../web/src/layouts/DefaultLayout/NavMenu.tsx | 2 +- apps/web/src/layouts/HomeLayout/Footer.tsx | 2 +- .../create-dao/components/FormHandler.tsx | 2 +- .../ReviewAndDeploy/ReviewAndDeploy.tsx | 2 +- .../TransactionForm/Droposal/DroposalForm.tsx | 2 +- 14 files changed, 194 insertions(+), 123 deletions(-) create mode 100644 apps/web/public/builder-avatar-circle60x60.png diff --git a/README.md b/README.md index 04388b6e2..76b5e29a5 100644 --- a/README.md +++ b/README.md @@ -1,114 +1,152 @@ -# Nouns Builder Subgraph +# ![Builder Avatar](apps/web/public/builder-avatar-circle60x60.png) Nouns Builder Monorepo -## Index +This is Nouns Builder front-end website and subgraph mono-repo. You can find Nouns Builder deployed on: -- [Getting Started](#getting-started) -- [Step 1 - Install Dependencies](#step-1---install-dependencies) -- [Step 2 - Set Up a Personal Goldsky API Key](#step-2---set-up-a-personal-goldsky-api-key) -- [Step 3 - Log in with the API Key](#step-3---log-in-with-the-api-key) -- [Step 4 - Build the Subgraph from Source](#step-4---build-the-subgraph-from-source) -- [Step 5 - Deploy the Subgraph to Production](#step-5---deploy-the-subgraph-to-production) -- [Step 6 - Query the Subgraph](#step-6---query-the-subgraph) -- [Production Endpoints](#production-endpoints) -- [(DEPRECATED) Local Development with Docker Compose (TODO: fix - pnpm create:local step not working)](#local-development-with-docker-compose) +- [Mainnet](//nouns.build) +- [Sepolia testnet](//testnet.nouns.build) -## Getting Started +For an introduction to Nouns Builder and its concept, you can find further [documentation here](https://nouns-builder-docs.vercel.app/). +You can also find the [Builder Protocol code here](https://github.com/BuilderOSS/builder-protocol). -πŸ‘‰ [Read the Goldsky docs](https://docs.goldsky.com/subgraphs/deploying-subgraphs) +### Apps and packages in this repository include: -The Nouns Builder subgraph supports five networks: +`apps` -- `ethereum` -- `ethereum-sepolia` -- `base` -- `optimism` -- `zora` +- `web`: Nouns Builder front-end +- `subgraph`: Nouns Builder subgraph -### Step 1 - Install Dependencies +`packages` -Navigate to the subgraph directory and run: +- `blocklist`: Package to check for sanctioned wallet addresses +- `analytics`: Shareable analytics package +- `zoralabs-zord`: Shareable ui components +- `eslint-config-custom`: `eslint` configurations (includes `eslint-config-next` and `eslint-config-prettier`) +- `tsconfig`: `tsconfig.json`s used throughout the monorepo +- `ipfs-service`: api to for image uploads to ipfs + +## Quickstart + +#### Get up and running + +1. Clone this repo locally +2. [Install pnpm](https://pnpm.io/installation#using-corepack) + +3. Add the required [environment variables](#environment-variables) + +4. Install dependencies across all apps and packages -```bash -# FROM: ./apps/subgraph -pnpm install ``` +pnpm i +``` + +5. Once environment variables are defined, you can run the app in dev mode -### Step 2 - Set Up a Personal Goldsky API Key +``` +pnpm dev +``` -1. Request to join the team account at [goldsky.com](https://goldsky.com). -2. Create an API key on your Settings page. -3. Install the Goldsky CLI: - ```bash - curl https://goldsky.com | sh - ``` +#### Linting and formatting -### Step 3 - Log in with the API Key +> Note: linting and prettier formatting are automatically run on pre-push hooks -Use the API key you created: +To lint: -```bash -# FROM: ./apps/subgraph -goldsky login +``` +pnpm run lint ``` -### Step 4 - Build the Subgraph from Source +To format: -Run the following commands (these scripts are defined in `package.json`): +``` +pnpm run format +``` -```bash -# FROM: ./apps/subgraph -pnpm prepare: -pnpm codegen -pnpm build +To run type checks: + +``` +pnpm run type-check ``` -This will generate types, build the subgraph, and create a local `subgraph.yaml` file. +#### To create and run a production build -### Step 5 - Deploy the Subgraph to Production +``` +> pnpm run build +> pnpm run start +``` -#### IMPORTANT: +## Environment variables -**To avoid downtime during upgrades, maintain a backup subgraph. If issues arise, you can redirect traffic to the backup rather than waiting for redeployment or rollback, which can take hours.** +This app has several third party api keys that you need in order to run Builder: -- The subgraph name follows the pattern `nouns-builder-` regardless of version, don't clients do not need to be notified for non-breaking changes. -- Increase the `specVersion` at the top of `subgraph.yaml.mustache` for each new version. -- Use the **--tag** flag to alias `latest` with the current `specVersion`. -- If you are making breaking changes, make sure to notify clients first and provide a migration path. +- [Tenderly](https://docs.tenderly.co/simulations-and-forks/simulation-api) as the main rpc node provider and transaction simulator +- [Etherscan](https://docs.etherscan.io/api-endpoints/contracts) to dynamically fetch abis -**Always remember to tag!** +We ask that you supply your own secrets locally for running in development environment. Non-secret environment variables are already included in the `.env` files in this repo. -```bash -# FROM: ./apps/subgraph -# Example with specVersion 0.0.6 +Add the following variables to `.env.local` within this root directory (needed to run tests against a local anvil node): -goldsky subgraph deploy nouns-builder-/0.0.6 --path . -goldsky subgraph tag create nouns-builder-/0.0.6 --tag latest -# API endpoint format will be: api.goldsky.com/api/public//subgraphs/nouns-builder-ethereum-sepolia/latest/gn +``` +ANVIL_FORK_URL=https://eth-mainnet.alchemyapi.io/v2/$TENDERLY_RPC_KEY +ANVIL_BLOCK_NUMBER=8305745 ``` -### Step 6 - Query the Subgraph +Add the following variables to `apps/web/.env.local`: -You can now query the subgraph in the Goldsky GraphQL playground to test your changes. **Note: Full indexing may take several hours.** +``` +# tenderly RPCs +NEXT_PUBLIC_TENDERLY_MAINNET_RPC_KEY +NEXT_PUBLIC_TENDERLY_BASE_RPC_KEY +NEXT_PUBLIC_TENDERLY_OPTIMISM_RPC_KEY +NEXT_PUBLIC_TENDERLY_SEPOLIA_RPC_KEY -## Production Endpoints +# conduit RPC for Zora +NEXT_PUBLIC_ZORA_CONDUIT_RPC_KEY -The subgraph is currently deployed to the following networks: +# tenderly simulator env variables +TENDERLY_ACCESS_KEY= +TENDERLY_PROJECT= +TENDERLY_USER= + +#etherscan (optional to run locally, this is for dynamically fetching abis in the custom transaction builder) +ETHERSCAN_API_KEY= + +# optional zora api key +NEXT_PUBLIC_ZORA_API_KEY= +``` + +## Running tests + +> Note: to run tests you need to [install anvil](https://github.com/foundry-rs/foundry/blob/master/README.md#installation). + +Once anvil is installed, you can now locally run anvil (from the root directory in the monorepo) in a separate terminal session to start a local ethereum node: +`pnpm run anvil` + +Now you can run the tests in a separate terminal session: +`pnpm run test` + +You can also run the tests in watchmode, which will react to any source code or test files changing. To do that, run: +`pnpm run test:watch` + +## Deployments + +### Client + +The Nouns Builder client is deployed on [Vercel](https://vercel.com/). Any pull requests will trigger a new preview deployment providing you with an environment to test out and preview changes. + +### Subgraph + +The Nouns Builder subgraph is deployed for the following networks: - [Ethereum](https://api.goldsky.com/api/public/project_cm33ek8kjx6pz010i2c3w8z25/subgraphs/nouns-builder-ethereum-mainnet/latest/gn) - [Ethereum Sepolia](https://api.goldsky.com/api/public/project_cm33ek8kjx6pz010i2c3w8z25/subgraphs/nouns-builder-ethereum-sepolia/latest/gn) - [Base](https://api.goldsky.com/api/public/project_cm33ek8kjx6pz010i2c3w8z25/subgraphs/nouns-builder-base-mainnet/latest/gn) - [Optimism](https://api.goldsky.com/api/public/project_cm33ek8kjx6pz010i2c3w8z25/subgraphs/nouns-builder-optimism-mainnet/latest/gn) - [Zora](https://api.goldsky.com/api/public/project_cm33ek8kjx6pz010i2c3w8z25/subgraphs/nouns-builder-zora-mainnet/latest/gn) -- TODO?: [Optimism Sepolia](https://api.goldsky.com/api/public/project_cm33ek8kjx6pz010i2c3w8z25/subgraphs/nouns-builder-optimism-sepolia/latest/gn) -- TODO?: [Zora Sepolia](https://api.goldsky.com/api/public/project_cm33ek8kjx6pz010i2c3w8z25/subgraphs/nouns-builder-zora-sepolia/latest/gn) -- TODO?: [Base Sepolia](https://api.goldsky.com/api/public/project_cm33ek8kjx6pz010i2c3w8z25/subgraphs/nouns-builder-base-sepolia/latest/gn) - -## (DEPRECATED) Local Development with Docker Compose (TODO: fix - pnpm create:local step not working) - -- Generate the subgraph.yml file with `pnpm prepare:` -- Generate types with `pnpm codegen` -- Build the subgraph with `pnpm build` -- Run the local graph node with `pnpm local:node` -- For Mac users on Apple Silicon, use a local image of `graphprotocol/graph-node` (see [instructions here](https://github.com/graphprotocol/graph-node/tree/master/docker)). -- Create the local subgraph with `pnpm create:local` -- Deploy changes to the local subgraph with `pnpm deploy-local` + +## Contributions + +Please refer to our [contributions guideline](/.github/contributing.md) on how best to contribute. + +## Questions? + +Feel free to reach out to us via [Discord](https://discord.gg/rSswr2wC) diff --git a/apps/subgraph/README.md b/apps/subgraph/README.md index f88fc3526..41cda8fd0 100644 --- a/apps/subgraph/README.md +++ b/apps/subgraph/README.md @@ -1,10 +1,21 @@ # Nouns Builder Subgraph +## Index + +- [Getting Started](#getting-started) +- [Step 1 - Install Dependencies](#step-1---install-dependencies) +- [Step 2 - Set Up a Personal Goldsky API Key](#step-2---set-up-a-personal-goldsky-api-key) +- [Step 3 - Log in with the API Key](#step-3---log-in-with-the-api-key) +- [Step 4 - Build the Subgraph from Source](#step-4---build-the-subgraph-from-source) +- [Step 5 - Deploy the Subgraph to Production](#step-5---deploy-the-subgraph-to-production) +- [Step 6 - Query the Subgraph](#step-6---query-the-subgraph) +- [Production Endpoints](#production-endpoints) + ## Getting Started πŸ‘‰ [Read the Goldsky docs](https://docs.goldsky.com/subgraphs/deploying-subgraphs) -The Nouns Builder subgraph supports four networks: +The Nouns Builder subgraph supports five networks: - `ethereum` - `ethereum-sepolia` @@ -62,6 +73,8 @@ This will generate types, build the subgraph, and create a local `subgraph.yaml` - Increase the `specVersion` at the top of `subgraph.yaml.mustache` for each new version. - Use the **--tag** flag to alias `latest` with the current `specVersion`. +*If you are making breaking changes, make sure to notify clients first and provide a migration path. + **Always remember to tag!** ```bash @@ -81,20 +94,21 @@ You can now query the subgraph in the Goldsky GraphQL playground to test your ch The subgraph is currently deployed to the following networks: -- [Ethereum](https://api.goldsky.com/api/public//subgraphs/nouns-builder-ethereum-mainnet/latest/gn) -- [Base](https://api.goldsky.com/api/public//subgraphs/nouns-builder-base-mainnet/latest/gn) -- [Optimism](https://api.goldsky.com/api/public//subgraphs/nouns-builder-optimism-mainnet/latest/gn) -- [Zora](https://api.goldsky.com/api/public//subgraphs/nouns-builder-zora-mainnet/latest/gn) -- [Ethereum Sepolia](https://api.goldsky.com/api/public//subgraphs/nouns-builder-ethereum-sepolia/latest/gn) -- TODO?: [Optimism Sepolia](https://api.goldsky.com/api/public//subgraphs/nouns-builder-optimism-sepolia/latest/gn) -- TODO?: [Zora Sepolia](https://api.goldsky.com/api/public//subgraphs/nouns-builder-zora-sepolia/latest/gn) -- TODO?: [Base Sepolia](https://api.goldsky.com/api/public//subgraphs/nouns-builder-base-sepolia/latest/gn) +- [Ethereum](https://api.goldsky.com/api/public/project_cm33ek8kjx6pz010i2c3w8z25/subgraphs/nouns-builder-ethereum-mainnet/latest/gn) +- [Ethereum Sepolia](https://api.goldsky.com/api/public/project_cm33ek8kjx6pz010i2c3w8z25/subgraphs/nouns-builder-ethereum-sepolia/latest/gn) +- [Base](https://api.goldsky.com/api/public/project_cm33ek8kjx6pz010i2c3w8z25/subgraphs/nouns-builder-base-mainnet/latest/gn) +- [Optimism](https://api.goldsky.com/api/public/project_cm33ek8kjx6pz010i2c3w8z25/subgraphs/nouns-builder-optimism-mainnet/latest/gn) +- [Zora](https://api.goldsky.com/api/public/project_cm33ek8kjx6pz010i2c3w8z25/subgraphs/nouns-builder-zora-mainnet/latest/gn) +- TODO?: [Optimism Sepolia](https://api.goldsky.com/api/public/project_cm33ek8kjx6pz010i2c3w8z25/subgraphs/nouns-builder-optimism-sepolia/latest/gn) +- TODO?: [Zora Sepolia](https://api.goldsky.com/api/public/project_cm33ek8kjx6pz010i2c3w8z25/subgraphs/nouns-builder-zora-sepolia/latest/gn) +- TODO?: [Base Sepolia](https://api.goldsky.com/api/public/project_cm33ek8kjx6pz010i2c3w8z25/subgraphs/nouns-builder-base-sepolia/latest/gn) -## Local Development with Docker Compose +## (DEPRECATED) Local Development with Docker Compose (TODO: fix - pnpm create:local step not working) +- Generate the subgraph.yml file with `pnpm prepare:` - Generate types with `pnpm codegen` -- Build the subgraph with `pnpm build:subgraph` -- Run the local graph node with `pnpm local-node` +- Build the subgraph with `pnpm build` +- Run the local graph node with `pnpm local:node` - For Mac users on Apple Silicon, use a local image of `graphprotocol/graph-node` (see [instructions here](https://github.com/graphprotocol/graph-node/tree/master/docker)). -- Create the local subgraph with `pnpm create-local` +- Create the local subgraph with `pnpm create:local` - Deploy changes to the local subgraph with `pnpm deploy-local` diff --git a/apps/web/public/builder-avatar-circle60x60.png b/apps/web/public/builder-avatar-circle60x60.png new file mode 100644 index 0000000000000000000000000000000000000000..697d032283f3c9676640fef8a64316e541f743ae GIT binary patch literal 6159 zcmZ`+1yCH@wjCJU-3jh8xD4(ZEHGGb9o*er!-U`jCwR~hBsc^~&;Y>+3?3}OgMPU8 z{`cOmdjE8t-mA}EYwvxey1L`FG?cJ0C@=s30Je&qt)_owS_v_007GI>H4S!FGfi6jZ*4083hGHQcRz%=NP-~bwRFOu1B|*1^f@9o=2mdz5p$; z5&U=$ZEwIyR5X0vJT$;Vl|Ana2^Nl02mqRot&_xMO--!>GKwyaw^p8qDK9zV=)4cT zc$h2h-5_;CkS?av*dca1rIkbjn0_XX$3&o2^*?2cre}*GwvV?6!vm$l)kSMl;a;Mv z98K{lHZsc?VW}9g4C6@B=NOxN3d`yhMT@u%Z(uBVh=q!=^DH1x0jfL2fY78OQiE>6 z>-$KJ?H>Zuv4Wy+M=dxD5^GqI(JPv)JNzssZkMd02IlLoUdt zL$j2_(nka9X$`-MH6Vp6+(z_>M333Jht%|uF2d++d5LfRUm0xc|J)B}WC^dF49)v& z$8p9x3$M9ijAO$yCPF7*po2uuH_)*p@S zB4G3kw~HzYNP-6Nq74_M-i&mjwLf+|i1ae+fG8|I2G*gAa{ z#>;~$ep=7QSVUT>;4Lfz%ToAl%3> zh+t@hH?0x0BD#cqayvf@BQ2!q02bgQ(b4Hf#q82C$1z!^h%jIcprXt7y*6M(R*~bw zr=yp#r9FMkXU(J&?j+*?3m&%EB=SJmlXhWPQ3jn*{E4!xz^IC*D1z*=riJrO@d!N2 z3$rbLGiB+8&`x9$3n}?Dg>ps|fZiGIQv{ksz%u`mg=3o_YL1l@tzc1UfWkazYw^xN z6p}n^G4@N;tiQcp@_<2O04hT58^$4mq}kJUWgSG)g;dw$3&-~32*Excy!q{l#NG=t z*Zjp;k3JHm-bW;hUi7v;&n?ak<>=kBJ~8^&6>=Y#+xt7SWJj4bSh(q2XulI`5{Sj6 z!~q!zR8p)pPnZ>6is8}54{ig0^}5(!p7|rt zXOHBG6gmLM_hzVl=Uh&`*1I{EkgXP5!p$wwGgU+gPVq zr?cB!+jk_)B={u!oDN(^2B}=+8HO2-ToZ;}EsY;l8;$H|?axPz=5m}(oJ<^pCt@5n z9QhZ@7Ps5ErZOyYtv>Z$Bv3o-IAq%BLwy&XHTyP^&b!thlc|vH@#=^)23VIzCIF|4 zhKs%zEol$&F1zPjm27;~CMnTTdQax4}|~KWs|Aa_Q$dM(xYak<8V(9JyGwfLly`F)sx!*)KI>NEmV& zqTE*_*Vd1Dmo_Sflr)7WWGC+OL;Xelw)_rH0))N?aE2ayY)I)C>kwTv?)Vh6D+!g% z4Q>y59xU25+l6~Kdgm9ibeGTPoV_r*GMag>ac}t`cYkb{Uz1()2EjnuO&Tg4SZHf5 zYp$>sN!wI7TDVwvZ$7uS*UKV@MrT3CAq!qmbmIOLvqJOp8JPcrpgI#LcMbi4MXO1x zNQWq5GFq|$u{-D+pAOjq8FKNwc6ITQlChHJD@g*mr1)2rN&W<4U?0VUHW8!c(pD4q zWBA=h=I0;J>s4Tk9~i5cUTM~-1Qig$KJZm?`0JjGZmO|evqhwp>FPLG{=Aq8cMsqA zp0rPX4DPbN9Yg<4SfD{5~Oe;$xxI+9P1z}7TcpYDGMpo1ABw5()l*Y|n zbX-%1H~%UOfi@x7m4yzQ{{=oV4$=mfB3X-(=@Act-)F$$%c zF|H^`Dx@pWlrd_E^5|Jrxj8Hee1ayHOK{<^-#ddP^TaxBV)l~S_}lIH>|C;=M^y`E z`Idq%A{Hb(BX$nns%7W$UtaoaoI=I}#iXDir-&uUo+RSeOjntU1hWM0Dm$`u(YYk+ ziAafyq$!3SA-`L6O!q$Xl{cO=g49~oxbMN&bKc!J++zldU8BwmgIfbzeOto%SGDtP zI#xEnzbIAHLj-He>bOnre8x%zNxztU5q|%!CcWm+h_tH~+WGlORUa$kttnSJRD+GKwEo~zfGqUwFs*A{{n66fGXF88IjA7tILPIEs@ zKi=)*tiP(wYY;PbTy}KuAwM#LBz{+Q2=q<)5p1K`lV1joZRa`%pW6iXnvSgQ+t4axrfnwh!8z!4PXM0W^D~H=65GY6khWl9$X-}7=4}D1C z64MavTDw|{hZ6!>6j*LFZ1MwU_$s%K_BN;IjIE58CZh60Lxpw^_B=;DS;hkkqylba5|cBRxdlJ8eWbo#Ilq)UbUDP%TmcE2{BHfW%=>ZUO7BN?c`fowvB13GyKl+E zl+?n6E~`JOek^z=`tC0rE-%#`5v}|Q@*S7x>-=`}^YSYVnPkO%|3%6*cT26+3c`vr z?#8p#;DO*XxO?vgNCGoos~}BE(BJ5E^v}Z7YT+u!#E`_XKV87@wz^HtWT|S?#SZbS z%pYdXcO!Qabpv%MW+4BPOWPsi%oZ--6cBfHtMlfz>nw6LHjjp!W+GVi`t0m94O9x+ z?^+CTz9+djTs2=^D~w~<9u7g~F_=oi0+=2H!g3G+*!dHz8=E^)hBBLW5OTx^^sf_f zjc^oc>f6wiy~t4EJix&UN{X45nX@=xN*4f^0Dx^r-KfFUBjf4cWTSS%#-_}sPrvnc zvz_qo;JQC7BUV;nUbWqkrqu+wbT#kyJpNJm*%+wUK7S5if5d12WCQ{L@DU+AUH}9N z0PVGU^A>zLn;)TF}<0q;x7uMmU zL3dL&^aKDf37Xi3#|eU-JRn|f9?*Z2 z+4w>KAK8=VZ`oh-`a7NYQ!ucm2h`@V;HR=AdBy)q@PEesU7q+;6tEW5&&J6>9_no4 z;`x_`M?f6(Up@a-Y54yt|HJc-QXKTOPXDoPe{afPqmR2Hi6IX9*A7c!gm)q-Jf2Os zioA@jJ@TPZ=PN1&yxRPgPv`DrNw`aBbcjgdTLa=idO-XREekyoy=;C|R1_H+Hg1>= zViczZ`5&i(i54mT{!2aI^Rv-|gNwJ$y$dcY8oqN6`m@vgft};Q#&ai#&2Z$tDlId_ zkW~&z6U<4bnVkciV-OTMw@|&8#b2blU(#IRvq9uc@! zn~FVbCa8@>c<^~6Y`P7#t)W4yy6ZQ1K~-583nB;NXNMn0ax`|85V-L)J4Fcexd0zv z)MSQ7UChlKM6Jx0^nAcj4-d}7MPSAJ`ioZNdRZS21n`?y>0!@VorE_G1r=2=+1?LR zZi>dUNRRKt(ki_B1MyS^;5Df^wr_UW9yPJ?YUW;w*~r<^F`pFTRZ2GuzNnN!xiWOF-ksuY4nn%->c9MKKkPZV` z&=lru$>TYgz&Nrwj}kw5>3z}cM%cw9!fEU`9~l9Tw$>+=HNxQIbvi$84KvMoAE?q1 zQ}!{?Erz5y0F|zH%(GLVC>qMX*lb{S5MPQwPJYjYwYTQ-A*Ie;Ffh!5MfD7IkRySR zk)S$8jS4Kvh3i(YtIyAt=-a?3Qy5vFmW`z(kQCKhVw@)inzh36;bs70X18bSo_^9X z0f%8@k_QRxLWnm-S0AL8f140>Gsr!oaILmHNvPRw(cbed6gf>2Xv%NAXvcT^%5v)& z{oJjtfyIWf_V*={GKWrA24F04lLqRFo7$>xK15@W9Hr2^1j4CP|E zna$O!`025hAB}q>clQvqiK^t(e-4j2A7ob?kSu>z=hJdVp&tz%PhQAMxyBx;_TBD( zu{a~KkZ2B!=f&b^7AXPTh+B0UZT>or4F@;|t^ULw%iF1JaUs~7ix~0DK+Os%K1AXf zril1aRidu9md{OF{+`mBRw~_v%AkD|NOeemwHe~vNQrEoDotl6^1i&~LFOw^oQRcU z378g9PH&^U|1CC2(m3FrJC86nVh87tG(umLY2K9H6LFsV)SB4Tu0YH#QSzCaakotk zKYEL1Y&$duRm3(>?N{0~?xxqL?Vv;rQ2TDpkUvF~cux|!`;}IXK6Cjw#d?DnT)-&2|u$pR;dtDT-LiWz{I6aH)>Wihfguz;20 z(D@1+8PAs(cKy}B6osD^6%MD3_l;4aM;6xd=vRbvI;!)&K86~DXLS*2`_`cjyqYmvbiQ;X9!oVh5gok+b z(Vs`1=Q6KZk+!nb^Kum~E>yfyEoRj0<@#>}$sn^l58ZDB%wBq2{gxqcI}NZ5XHngc z@d^AeVEm@SrkK&K!<0Rt1!aRhiD@&{W?<*NFG}4&HFnw=Z#q7<-WcbNJ-fm3Or<}& z^;J=xc9>v=K%wBCH=r6}2*5L)iq%g$#AHL6VLhz!;ja+1|1E*27yFTg$lK z>MMK@xgi4&=4uV3z+w?9kiNAc4?9)N{-ad&4@)M-9{$c5_en@?Cv`&+$A6uIlb=)1aEX~7nSC>zUG^Z zNcg-jBPW!j6ASzjUZbjQ(d4woJms1>w}uApaEfNBE#7=s8Efu>{Yt|gv&J&``58Vd z=hCe^laa~mIJwF5XW*1=cR>DKjBt`LH#AY^D@rU5%dvNOiPS6TOh~a737^7CH72+? z)z{X1*;nOJ)B3+F7Nh%~jla??YylAt*JXvnkjJo7Ol3TdsP5fQ+P7xJidW2YWfk0U zb{dAonw+w2@zqiKi$3DJ>5u%D4*HY1#;9;sNN_xRk4Ee|k&}labGQ5YnUk77%Yb{u z-DUx*$SwDoo=zsIE=(ybbax`1W<~cVNy=b)b#OrUYmwB5*&X_19OH9k;ob2dqP51w z*Vk*{gX6?ykUL2y%L{qPx>+OU{Tk2;#SF3IQ-Ddr=UlWHEY1T8me5$j<0q?^P)11E|C9hrH?@LyC?22(VBevA&J z?|e9@K7gLdqIkg8S9*wHh-I8F0X$9+5rfQZk^2hdq?bJl#E|;4)=P?-KvYj~6(D-b zVsy=~-RyhCT7F%zExOamc_fbA4+ptJSdzbl%-{tm2hAyrcP2@x;A|qw(y1_ZMtK6I zMiJ3L(uf$1+G2?JA&t%+H+2dYF}OPTmgO~DHrNTxG<$*w*7`Vk-4kX zv%@@{MfL`{^53 NML|QpR@OY?e*hS%DvkgE literal 0 HcmV?d00001 diff --git a/apps/web/src/components/BridgeModal/BridgeForm.tsx b/apps/web/src/components/BridgeModal/BridgeForm.tsx index 8e98f871c..a4f79a63e 100644 --- a/apps/web/src/components/BridgeModal/BridgeForm.tsx +++ b/apps/web/src/components/BridgeModal/BridgeForm.tsx @@ -221,7 +221,7 @@ export const BridgeForm = () => { rel="noopener noreferrer" target="_blank" style={{ textDecoration: 'underline' }} - href="https://docs.zora.co/docs/guides/builder-bridging" + href="https://nouns-builder-docs.vercel.app/guides/builder-bridging/" > bridging diff --git a/apps/web/src/constants/addresses.ts b/apps/web/src/constants/addresses.ts index 27112051d..d9a9418cd 100644 --- a/apps/web/src/constants/addresses.ts +++ b/apps/web/src/constants/addresses.ts @@ -71,7 +71,8 @@ export const L2_MIGRATION_DEPLOYER = { [CHAIN_ID.ETHEREUM]: '0x0000000000000000000000000000000000000000' as AddressType, [CHAIN_ID.OPTIMISM]: '0x7D8Ea0D056f5B8443cdD8495D4e90FFCf0a8A354' as AddressType, [CHAIN_ID.SEPOLIA]: '0x0000000000000000000000000000000000000000' as AddressType, - [CHAIN_ID.OPTIMISM_SEPOLIA]: '0xF3a4ca161a88e26115d1C1DBcB8C4874E1786F42' as AddressType, + [CHAIN_ID.OPTIMISM_SEPOLIA]: + '0xF3a4ca161a88e26115d1C1DBcB8C4874E1786F42' as AddressType, [CHAIN_ID.BASE]: '0x8ef7b563Ff9F4A1f2d294845000cDf782d9afd7c' as AddressType, [CHAIN_ID.BASE_SEPOLIA]: '0x1e57Cad7C22042BD765011d0F2eb36606Fe12C3F' as AddressType, [CHAIN_ID.ZORA]: '0x7D8Ea0D056f5B8443cdD8495D4e90FFCf0a8A354' as AddressType, diff --git a/apps/web/src/constants/subgraph.ts b/apps/web/src/constants/subgraph.ts index b8a5f8320..ab238f599 100644 --- a/apps/web/src/constants/subgraph.ts +++ b/apps/web/src/constants/subgraph.ts @@ -1,10 +1,28 @@ -import {CHAIN_ID} from 'src/typings' +import { CHAIN_ID } from 'src/typings' export const PUBLIC_SUBGRAPH_URL: Map = new Map([ - [CHAIN_ID.ETHEREUM, 'https://api.goldsky.com/api/public/project_cm33ek8kjx6pz010i2c3w8z25/subgraphs/nouns-builder-ethereum-mainnet/latest/gn'], - [CHAIN_ID.OPTIMISM, 'https://api.goldsky.com/api/public/project_cm33ek8kjx6pz010i2c3w8z25/subgraphs/nouns-builder-optimism-mainnet/latest/gn'], - [CHAIN_ID.SEPOLIA, 'https://api.goldsky.com/api/public/project_cm33ek8kjx6pz010i2c3w8z25/subgraphs/nouns-builder-ethereum-sepolia/latest/gn'], - [CHAIN_ID.BASE, 'https://api.goldsky.com/api/public/project_cm33ek8kjx6pz010i2c3w8z25/subgraphs/nouns-builder-base-mainnet/latest/gn'], - [CHAIN_ID.ZORA, 'https://api.goldsky.com/api/public/project_cm33ek8kjx6pz010i2c3w8z25/subgraphs/nouns-builder-zora-mainnet/latest/gn'], - [CHAIN_ID.FOUNDRY, 'https://api.thegraph.com/subgraphs/name/neokry/nouns-builder-mainnet'] -]); \ No newline at end of file + [ + CHAIN_ID.ETHEREUM, + 'https://api.goldsky.com/api/public/project_cm33ek8kjx6pz010i2c3w8z25/subgraphs/nouns-builder-ethereum-mainnet/latest/gn', + ], + [ + CHAIN_ID.OPTIMISM, + 'https://api.goldsky.com/api/public/project_cm33ek8kjx6pz010i2c3w8z25/subgraphs/nouns-builder-optimism-mainnet/latest/gn', + ], + [ + CHAIN_ID.SEPOLIA, + 'https://api.goldsky.com/api/public/project_cm33ek8kjx6pz010i2c3w8z25/subgraphs/nouns-builder-ethereum-sepolia/latest/gn', + ], + [ + CHAIN_ID.BASE, + 'https://api.goldsky.com/api/public/project_cm33ek8kjx6pz010i2c3w8z25/subgraphs/nouns-builder-base-mainnet/latest/gn', + ], + [ + CHAIN_ID.ZORA, + 'https://api.goldsky.com/api/public/project_cm33ek8kjx6pz010i2c3w8z25/subgraphs/nouns-builder-zora-mainnet/latest/gn', + ], + [ + CHAIN_ID.FOUNDRY, + 'https://api.thegraph.com/subgraphs/name/neokry/nouns-builder-mainnet', + ], +]) diff --git a/apps/web/src/data/subgraph/client.ts b/apps/web/src/data/subgraph/client.ts index 70099aaea..2825ff877 100644 --- a/apps/web/src/data/subgraph/client.ts +++ b/apps/web/src/data/subgraph/client.ts @@ -1,29 +1,29 @@ -import {GraphQLClient} from 'graphql-request' +import { GraphQLClient } from 'graphql-request' -import {CHAIN_ID} from 'src/typings' +import { PUBLIC_SUBGRAPH_URL } from 'src/constants/subgraph' +import { CHAIN_ID } from 'src/typings' -import {getSdk} from './sdk.generated' -import {PUBLIC_SUBGRAPH_URL} from "src/constants/subgraph"; +import { getSdk } from './sdk.generated' const globalForClient = global as unknown as { - subgraphClient: Map + subgraphClient: Map } export class SDK { - static connect(chainId: CHAIN_ID) { - if (!globalForClient.subgraphClient) globalForClient.subgraphClient = new Map() + static connect(chainId: CHAIN_ID) { + if (!globalForClient.subgraphClient) globalForClient.subgraphClient = new Map() - const client = globalForClient.subgraphClient.has(chainId) - ? globalForClient.subgraphClient.get(chainId)! - : new GraphQLClient(PUBLIC_SUBGRAPH_URL.get(chainId) as string, { - headers: { - 'Content-Type': 'application/json', - }, - }) + const client = globalForClient.subgraphClient.has(chainId) + ? globalForClient.subgraphClient.get(chainId)! + : new GraphQLClient(PUBLIC_SUBGRAPH_URL.get(chainId) as string, { + headers: { + 'Content-Type': 'application/json', + }, + }) - if (process.env.NODE_ENV !== 'production') - globalForClient.subgraphClient.set(chainId, client) + if (process.env.NODE_ENV !== 'production') + globalForClient.subgraphClient.set(chainId, client) - return getSdk(client) - } + return getSdk(client) + } } diff --git a/apps/web/src/layouts/DefaultLayout/Footer.tsx b/apps/web/src/layouts/DefaultLayout/Footer.tsx index 8f71129a7..6e23b2994 100644 --- a/apps/web/src/layouts/DefaultLayout/Footer.tsx +++ b/apps/web/src/layouts/DefaultLayout/Footer.tsx @@ -27,7 +27,7 @@ export const Footer = () => { variant="paragraph-sm" color="tertiary" as="a" - href="https://builder-docs.vercel.app/reference/intro" + href="https://nouns-builder-docs.vercel.app/reference/intro" rel="noopener noreferrer" target="_blank" mr={{ '@initial': 'x0', '@768': 'x4', '@1024': 'x6' }} diff --git a/apps/web/src/layouts/DefaultLayout/Nav.tsx b/apps/web/src/layouts/DefaultLayout/Nav.tsx index 1355ccba9..495538a95 100644 --- a/apps/web/src/layouts/DefaultLayout/Nav.tsx +++ b/apps/web/src/layouts/DefaultLayout/Nav.tsx @@ -60,7 +60,7 @@ export const Nav = () => { diff --git a/apps/web/src/layouts/DefaultLayout/NavMenu.tsx b/apps/web/src/layouts/DefaultLayout/NavMenu.tsx index 4307b68f0..550e211fa 100644 --- a/apps/web/src/layouts/DefaultLayout/NavMenu.tsx +++ b/apps/web/src/layouts/DefaultLayout/NavMenu.tsx @@ -391,7 +391,7 @@ export const NavMenu = () => { diff --git a/apps/web/src/layouts/HomeLayout/Footer.tsx b/apps/web/src/layouts/HomeLayout/Footer.tsx index 42eb029f8..440b10322 100644 --- a/apps/web/src/layouts/HomeLayout/Footer.tsx +++ b/apps/web/src/layouts/HomeLayout/Footer.tsx @@ -49,7 +49,7 @@ export const Footer = () => { diff --git a/apps/web/src/modules/create-dao/components/FormHandler.tsx b/apps/web/src/modules/create-dao/components/FormHandler.tsx index e5b92c06f..331719486 100644 --- a/apps/web/src/modules/create-dao/components/FormHandler.tsx +++ b/apps/web/src/modules/create-dao/components/FormHandler.tsx @@ -19,7 +19,7 @@ export const FormHandler = ( Create A dao {sectionIndex === 0 ? ( diff --git a/apps/web/src/modules/create-dao/components/ReviewAndDeploy/ReviewAndDeploy.tsx b/apps/web/src/modules/create-dao/components/ReviewAndDeploy/ReviewAndDeploy.tsx index 8d2bb0a17..56a47dba9 100644 --- a/apps/web/src/modules/create-dao/components/ReviewAndDeploy/ReviewAndDeploy.tsx +++ b/apps/web/src/modules/create-dao/components/ReviewAndDeploy/ReviewAndDeploy.tsx @@ -382,7 +382,7 @@ export const ReviewAndDeploy: React.FC = ({ title }) => { I have read the{' '} = ({ onSubmit, disabled }) Lean more From 216ab3168aac3abce10595aae314e50b7305a662 Mon Sep 17 00:00:00 2001 From: Mills <37815163+0xMillz@users.noreply.github.com> Date: Sat, 21 Dec 2024 12:03:42 -0600 Subject: [PATCH 20/28] Update env vars (#28) --- .nvmrc | 2 +- apps/web/.env.local.example | 18 +++++++++++++++++- apps/web/.env.testing | 2 +- apps/web/README.md | 2 -- apps/web/src/constants/rpc.ts | 15 ++++++--------- turbo.json | 6 +++++- 6 files changed, 30 insertions(+), 15 deletions(-) diff --git a/.nvmrc b/.nvmrc index 25bf17fc5..2edeafb09 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -18 \ No newline at end of file +20 \ No newline at end of file diff --git a/apps/web/.env.local.example b/apps/web/.env.local.example index 038d77247..1de888ccc 100644 --- a/apps/web/.env.local.example +++ b/apps/web/.env.local.example @@ -6,4 +6,20 @@ ETHERSCAN_API_KEY= NEXT_PUBLIC_ALCHEMY_ID= PRIVATE_REDIS_CONNECTION_URI= NEXT_PUBLIC_ZORA_API_KEY= -NEXT_PUBLIC_TENDERLY_RPC_KEY= +NEXT_PUBLIC_NETWORK_TYPE= + +# go to each node rpc in Tenderly => settings to access these keys +NEXT_PUBLIC_TENDERLY_MAINNET_RPC_KEY= +NEXT_PUBLIC_TENDERLY_BASE_RPC_KEY= +NEXT_PUBLIC_TENDERLY_OPTIMISM_RPC_KEY= +NEXT_PUBLIC_TENDERLY_SEPOLIA_RPC_KEY= + +# Zora is not available on Tenderly (use conduit.xyz) +NEXT_PUBLIC_ZORA_CONDUIT_RPC_KEY= + +# "Access token" in Tenderly Builder Protocol => Nouns Builder => Access Tokens +TENDERLY_ACCESS_KEY= +# "Account slug" in Tenderly (TODO: make env var names consistent with Tenderly's names) +TENDERLY_USER= + +PINATA_API_KEY= diff --git a/apps/web/.env.testing b/apps/web/.env.testing index 058883550..77c129951 100644 --- a/apps/web/.env.testing +++ b/apps/web/.env.testing @@ -3,4 +3,4 @@ # We use mainnet fork for anvil instance so needs to point to mainnet NEXT_PUBLIC_CHAIN_ID=1 NEXT_PUBLIC_NETWORK_TYPE=mainnet -TENDERLY_PROJECT=nouns-builder-public \ No newline at end of file +TENDERLY_PROJECT=nouns-builder \ No newline at end of file diff --git a/apps/web/README.md b/apps/web/README.md index 33e33c5ba..7deb7ea29 100644 --- a/apps/web/README.md +++ b/apps/web/README.md @@ -49,11 +49,9 @@ You can swap out the environment variables as defined below to run against mainn ``` # the default network type is defined in .env, to run against testnet -NEXT_PUBLIC_TENDERLY_RPC_KEY= NEXT_PUBLIC_NETWORK_TYPE="testnet" # to run against mainnet locally -NEXT_PUBLIC_TENDERLY_RPC_KEY= NEXT_PUBLIC_NETWORK_TYPE="mainnet" ``` diff --git a/apps/web/src/constants/rpc.ts b/apps/web/src/constants/rpc.ts index 1463513d0..d7158b7fe 100644 --- a/apps/web/src/constants/rpc.ts +++ b/apps/web/src/constants/rpc.ts @@ -2,14 +2,11 @@ import { foundry } from 'wagmi/chains' import { CHAIN_ID } from 'src/typings' -export const RPC_URL = { - [CHAIN_ID.ETHEREUM]: `https://mainnet.gateway.tenderly.co/${process.env.NEXT_PUBLIC_TENDERLY_RPC_KEY}`, - [CHAIN_ID.OPTIMISM]: `https://optimism.gateway.tenderly.co/${process.env.NEXT_PUBLIC_TENDERLY_RPC_KEY}`, - [CHAIN_ID.SEPOLIA]: `https://sepolia.gateway.tenderly.co/${process.env.NEXT_PUBLIC_TENDERLY_RPC_KEY}`, - [CHAIN_ID.OPTIMISM_SEPOLIA]: `https://optimism-sepolia.gateway.tenderly.co/${process.env.NEXT_PUBLIC_TENDERLY_RPC_KEY}`, - [CHAIN_ID.BASE]: `https://base.gateway.tenderly.co/${process.env.NEXT_PUBLIC_TENDERLY_RPC_KEY}`, - [CHAIN_ID.BASE_SEPOLIA]: `https://base-sepolia.gateway.tenderly.co/${process.env.NEXT_PUBLIC_TENDERLY_RPC_KEY}`, - [CHAIN_ID.ZORA]: 'https://rpc.zora.energy', - [CHAIN_ID.ZORA_SEPOLIA]: 'https://sepolia.rpc.zora.energy', +export const RPC_URL: Record = { + [CHAIN_ID.ETHEREUM]: `https://mainnet.gateway.tenderly.co/${process.env.NEXT_PUBLIC_TENDERLY_MAINNET_RPC_KEY}`, + [CHAIN_ID.OPTIMISM]: `https://optimism.gateway.tenderly.co/${process.env.NEXT_PUBLIC_TENDERLY_OPTIMISM_RPC_KEY}`, + [CHAIN_ID.SEPOLIA]: `https://sepolia.gateway.tenderly.co/${process.env.NEXT_PUBLIC_TENDERLY_SEPOLIA_RPC_KEY}`, + [CHAIN_ID.BASE]: `https://base.gateway.tenderly.co/${process.env.NEXT_PUBLIC_TENDERLY_BASE_RPC_KEY}`, + [CHAIN_ID.ZORA]: `https://rpc-zora-mainnet-0.t.conduit.xyz/${process.env.NEXT_PUBLIC_ZORA_CONDUIT_RPC_KEY}`, [CHAIN_ID.FOUNDRY]: foundry.rpcUrls.default.http[0], } diff --git a/turbo.json b/turbo.json index c5b1d32af..e043f4525 100644 --- a/turbo.json +++ b/turbo.json @@ -33,13 +33,17 @@ "ETHERSCAN_API_KEY", "NEXT_PUBLIC_UPLOAD_API", "NEXT_PUBLIC_IPFS_UPLOAD_API", - "NEXT_PUBLIC_TENDERLY_RPC_KEY", "NEXT_PUBLIC_QUICKNODE_ID", "NEXT_PUBLIC_IPFS_GATEWAY", "NEXT_PUBLIC_SENTRY_DSN", "NEXT_PUBLIC_ZORA_API_KEY", "NEXT_PUBLIC_NETWORK_TYPE", "NEXT_PUBLIC_VERCEL_ENV", + "NEXT_PUBLIC_TENDERLY_MAINNET_RPC_KEY", + "NEXT_PUBLIC_TENDERLY_BASE_RPC_KEY", + "NEXT_PUBLIC_TENDERLY_OPTIMISM_RPC_KEY", + "NEXT_PUBLIC_ZORA_CONDUIT_RPC_KEY", + "NEXT_PUBLIC_TENDERLY_SEPOLIA_RPC_KEY", "SENTRY_DSN", "SENTRY_ORG", "SENTRY_PROJECT", From c8dcadd73e95d927023b02ca86508d31e79bd92e Mon Sep 17 00:00:00 2001 From: Dan OneTree Date: Tue, 10 Dec 2024 20:09:50 +0530 Subject: [PATCH 21/28] added execution tx hash to proposal entity --- apps/subgraph/schema.graphql | 1 + apps/subgraph/src/governor.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/apps/subgraph/schema.graphql b/apps/subgraph/schema.graphql index acd34c1d2..af6a02437 100644 --- a/apps/subgraph/schema.graphql +++ b/apps/subgraph/schema.graphql @@ -69,6 +69,7 @@ type Proposal @entity { quorumVotes: BigInt! queued: Boolean! executed: Boolean! + executionTransactionHash: Bytes canceled: Boolean! vetoed: Boolean! voteCount: Int! diff --git a/apps/subgraph/src/governor.ts b/apps/subgraph/src/governor.ts index e87771f9e..6c414b81c 100644 --- a/apps/subgraph/src/governor.ts +++ b/apps/subgraph/src/governor.ts @@ -82,6 +82,7 @@ export function handleProposalQueued(event: ProposalQueuedEvent): void { export function handleProposalExecuted(event: ProposalExecutedEvent): void { let proposal = new Proposal(event.params.proposalId.toHexString()) proposal.executed = true + proposal.executionTransactionHash = event.transaction.hash proposal.queued = false proposal.save() } From 439d52c69981645c14baf6155ba4762c36c1ff21 Mon Sep 17 00:00:00 2001 From: dan13ram Date: Wed, 8 Jan 2025 15:16:13 +0530 Subject: [PATCH 22/28] added types for executionTxHash --- apps/web/src/data/subgraph/fragments/Proposal.graphql | 1 + apps/web/src/data/subgraph/requests/proposalQuery.ts | 10 ++++++++-- apps/web/src/data/subgraph/sdk.generated.ts | 5 +++++ 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/apps/web/src/data/subgraph/fragments/Proposal.graphql b/apps/web/src/data/subgraph/fragments/Proposal.graphql index 0f1adcfb9..7a47f2448 100644 --- a/apps/web/src/data/subgraph/fragments/Proposal.graphql +++ b/apps/web/src/data/subgraph/fragments/Proposal.graphql @@ -20,6 +20,7 @@ fragment Proposal on Proposal { voteStart snapshotBlockNumber transactionHash + executionTransactionHash dao { governorAddress tokenAddress diff --git a/apps/web/src/data/subgraph/requests/proposalQuery.ts b/apps/web/src/data/subgraph/requests/proposalQuery.ts index d0c5401cc..e1f9d0bb3 100644 --- a/apps/web/src/data/subgraph/requests/proposalQuery.ts +++ b/apps/web/src/data/subgraph/requests/proposalQuery.ts @@ -12,16 +12,21 @@ import { import { CHAIN_ID } from 'src/typings' export interface Proposal - extends Omit { + extends Omit< + ProposalFragment, + 'executableFrom' | 'expiresAt' | 'calldatas' | 'executionTransactionHash' + > { calldatas: string[] state: ProposalState + executionTransactionHash?: string executableFrom?: number expiresAt?: number votes?: ProposalVote[] } export const formatAndFetchState = async (chainId: CHAIN_ID, data: ProposalFragment) => { - const { executableFrom, expiresAt, calldatas, ...proposal } = data + const { executableFrom, expiresAt, calldatas, executionTransactionHash, ...proposal } = + data const baseProposal = { ...proposal, @@ -39,6 +44,7 @@ export const formatAndFetchState = async (chainId: CHAIN_ID, data: ProposalFragm ...baseProposal, executableFrom, expiresAt, + executionTransactionHash, } } return baseProposal diff --git a/apps/web/src/data/subgraph/sdk.generated.ts b/apps/web/src/data/subgraph/sdk.generated.ts index 8b9197c47..b4c3e2fea 100644 --- a/apps/web/src/data/subgraph/sdk.generated.ts +++ b/apps/web/src/data/subgraph/sdk.generated.ts @@ -1099,6 +1099,7 @@ export type Proposal = { description?: Maybe descriptionHash: Scalars['Bytes'] executableFrom?: Maybe + executionTransactionHash?: Maybe executed: Scalars['Boolean'] expiresAt?: Maybe forVotes: Scalars['Int'] @@ -2239,6 +2240,7 @@ export type ProposalFragment = { description?: string | null descriptionHash: any executableFrom?: any | null + executionTransactionHash?: any | null expiresAt?: any | null forVotes: number proposalId: any @@ -2552,6 +2554,7 @@ export type ProposalQuery = { description?: string | null descriptionHash: any executableFrom?: any | null + executionTransactionHash?: any | null expiresAt?: any | null forVotes: number proposalId: any @@ -2644,6 +2647,7 @@ export type ProposalsQuery = { description?: string | null descriptionHash: any executableFrom?: any | null + executionTransactionHash?: any | null expiresAt?: any | null forVotes: number proposalId: any @@ -2800,6 +2804,7 @@ export const ProposalFragmentDoc = gql` description descriptionHash executableFrom + executionTransactionHash expiresAt forVotes proposalId From 6181fa2f6034d55ce5559bd8f24fede86a3a920e Mon Sep 17 00:00:00 2001 From: dan13ram Date: Thu, 23 Jan 2025 15:53:00 +0530 Subject: [PATCH 23/28] use etherscan v2 api --- apps/web/src/services/abiService.ts | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/apps/web/src/services/abiService.ts b/apps/web/src/services/abiService.ts index d07aa29e3..e27f1870d 100644 --- a/apps/web/src/services/abiService.ts +++ b/apps/web/src/services/abiService.ts @@ -19,17 +19,6 @@ export type ContractABIResult = { source: 'fetched' | 'cache' } -const CHAIN_API_LOOKUP: Record = { - [CHAIN_ID.ETHEREUM]: 'api.etherscan.io', - [CHAIN_ID.OPTIMISM]: 'api-optimistic.etherscan.io', - [CHAIN_ID.SEPOLIA]: 'api-sepolia.etherscan.io', - [CHAIN_ID.OPTIMISM_SEPOLIA]: 'api-sepolia-optimistic.etherscan.io', - [CHAIN_ID.BASE]: 'api.basescan.org', - [CHAIN_ID.BASE_SEPOLIA]: 'api-sepolia.basescan.org', - [CHAIN_ID.ZORA]: 'explorer.zora.energy', - [CHAIN_ID.ZORA_SEPOLIA]: 'sepolia.explorer.zora.energy', - [CHAIN_ID.FOUNDRY]: '', -} const ZERO_BYTES32 = '0x0000000000000000000000000000000000000000000000000000000000000000' @@ -80,15 +69,19 @@ export const getContractABIByAddress = async ( source: 'cache', } } else { + const etherscan = await axios.get( - `https://${CHAIN_API_LOOKUP[chainId]}/api?module=contract&action=getabi&address=${fetchedAddress}&apikey=${process.env.ETHERSCAN_API_KEY}` + `https://api.etherscan.io/v2/api?chainid=${chainId}&module=contract&action=getabi&address=${fetchedAddress}&tag=latest&apikey=${process.env.ETHERSCAN_API_KEY}` ) + if (etherscan.status !== 200) { throw new BackendFailedError('Remote request failed') } const abi = etherscan.data + + if (abi.status === '1') { redisConnection?.set(getRedisKey(chainIdStr, fetchedAddress), JSON.stringify(abi)) return { From f82bcce366fa19a67d4c767e5089a492d2c5a378 Mon Sep 17 00:00:00 2001 From: dan13ram Date: Thu, 23 Jan 2025 16:57:13 +0530 Subject: [PATCH 24/28] added support for gnosis safe connector --- apps/web/src/data/contract/config.ts | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/apps/web/src/data/contract/config.ts b/apps/web/src/data/contract/config.ts index 435c80e96..2f99a7b2f 100644 --- a/apps/web/src/data/contract/config.ts +++ b/apps/web/src/data/contract/config.ts @@ -1,18 +1,26 @@ -import { getDefaultWallets } from '@rainbow-me/rainbowkit' +import { connectorsForWallets, getDefaultWallets } from '@rainbow-me/rainbowkit' +import { safeWallet } from '@rainbow-me/rainbowkit/wallets' import { createConfig } from 'wagmi' import { PUBLIC_WALLLET_CONNECT_PROJECT_ID } from 'src/constants/walletconnect' import { chains, publicClient } from './chains' -const { connectors } = getDefaultWallets({ +const { connectors: defaultConnectors } = getDefaultWallets({ appName: 'Nouns builder', chains, projectId: PUBLIC_WALLLET_CONNECT_PROJECT_ID, }) +const safeConnector = connectorsForWallets([ + { + groupName: 'Safe Wallet', + wallets: [safeWallet({ chains })], + }, +]) + export const config = createConfig({ autoConnect: true, - connectors, + connectors: [...defaultConnectors(), ...safeConnector()], publicClient, }) From 6f144ab9c82083307fab95e78267fa1d06ec2ed5 Mon Sep 17 00:00:00 2001 From: dan13ram Date: Thu, 23 Jan 2025 17:10:01 +0530 Subject: [PATCH 25/28] add support for escrow proposal type --- apps/web/package.json | 2 + apps/web/src/components/Fields/Date.tsx | 20 +- .../Home/accordian/AccordionItem.tsx | 7 +- .../src/components/Home/accordian/index.tsx | 6 +- .../web/src/components/Icon/assets/escrow.svg | 3 + apps/web/src/components/Icon/icons.ts | 2 + apps/web/src/constants/swrKeys.ts | 1 + .../ReviewProposalForm/ReviewProposalForm.tsx | 3 + .../TransactionForm/Escrow/Escrow.tsx | 163 ++++++++++ .../Escrow/EscrowDetailsDisplay.tsx | 60 ++++ .../Escrow/EscrowForm.schema.ts | 136 ++++++++ .../TransactionForm/Escrow/EscrowForm.tsx | 294 ++++++++++++++++++ .../TransactionForm/Escrow/EscrowUtils.ts | 193 ++++++++++++ .../TransactionForm/Escrow/index.ts | 1 + .../TransactionForm/TransactionForm.tsx | 3 + .../constants/transactionType.tsx | 7 + pnpm-lock.yaml | 166 ++++++++-- 17 files changed, 1037 insertions(+), 30 deletions(-) create mode 100644 apps/web/src/components/Icon/assets/escrow.svg create mode 100644 apps/web/src/modules/create-proposal/components/TransactionForm/Escrow/Escrow.tsx create mode 100644 apps/web/src/modules/create-proposal/components/TransactionForm/Escrow/EscrowDetailsDisplay.tsx create mode 100644 apps/web/src/modules/create-proposal/components/TransactionForm/Escrow/EscrowForm.schema.ts create mode 100644 apps/web/src/modules/create-proposal/components/TransactionForm/Escrow/EscrowForm.tsx create mode 100644 apps/web/src/modules/create-proposal/components/TransactionForm/Escrow/EscrowUtils.ts create mode 100644 apps/web/src/modules/create-proposal/components/TransactionForm/Escrow/index.ts diff --git a/apps/web/package.json b/apps/web/package.json index 4c1959e21..837e61eb2 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -20,6 +20,7 @@ "@fontsource/londrina-solid": "^4.5.9", "@rainbow-me/rainbowkit": "^1.3.1", "@sentry/nextjs": "^7.105.0", + "@smartinvoicexyz/constants": "^0.1.17", "@types/lodash": "^4.14.186", "@types/react-portal": "^4.0.4", "@types/tinycolor2": "^1.4.3", @@ -32,6 +33,7 @@ "axios": "^0.27.2", "bignumber.js": "^9.1.0", "blocklist": "workspace:*", + "bs58": "^5.0.0", "dayjs": "^1.11.3", "flatpickr": "^4.6.13", "formik": "^2.2.9", diff --git a/apps/web/src/components/Fields/Date.tsx b/apps/web/src/components/Fields/Date.tsx index be5b460d1..3c1b425b8 100644 --- a/apps/web/src/components/Fields/Date.tsx +++ b/apps/web/src/components/Fields/Date.tsx @@ -5,6 +5,7 @@ import React, { ReactElement } from 'react' import { defaultFieldsetStyle, + defaultHelperTextStyle, defaultInputErrorMessageStyle, defaultInputErrorStyle, defaultInputLabelStyle, @@ -18,6 +19,7 @@ interface DateProps { formik: FormikProps id: string errorMessage: string | FormikErrors | string[] | undefined | FormikErrors[] + helperText?: string value: any altFormat?: string dateFormat?: string @@ -34,6 +36,7 @@ const Date: React.FC = ( formik, id, errorMessage, + helperText, autoSubmit, value, placeholder, @@ -70,10 +73,10 @@ const Date: React.FC = ( {inputLabel && } {errorMessage && ( {errorMessage as string} @@ -89,6 +92,17 @@ const Date: React.FC = ( readOnly={true} disabled={disabled} /> + {helperText && ( + + {helperText} + + )} ) } diff --git a/apps/web/src/components/Home/accordian/AccordionItem.tsx b/apps/web/src/components/Home/accordian/AccordionItem.tsx index 4910af091..ce77e17b6 100644 --- a/apps/web/src/components/Home/accordian/AccordionItem.tsx +++ b/apps/web/src/components/Home/accordian/AccordionItem.tsx @@ -6,9 +6,10 @@ import { Icon } from 'src/components/Icon' import { accordionItem, accordionName } from '../../../styles/home.css' -const AccordionItem: React.FC<{ title: string; description: ReactElement }> = ( - { title, description } -) => { +const AccordionItem: React.FC<{ + title: string | ReactElement + description: ReactElement +}> = ({ title, description }) => { const [isOpen, setIsOpen] = React.useState(false) const variants = { initial: { diff --git a/apps/web/src/components/Home/accordian/index.tsx b/apps/web/src/components/Home/accordian/index.tsx index d5f82cb14..697084323 100644 --- a/apps/web/src/components/Home/accordian/index.tsx +++ b/apps/web/src/components/Home/accordian/index.tsx @@ -3,9 +3,9 @@ import React, { ReactElement } from 'react' import AccordionItem from './AccordionItem' -const Accordion: React.FC<{ items: { title: string; description: ReactElement }[] }> = ({ - items, -}) => { +const Accordion: React.FC<{ + items: { title: string | ReactElement; description: ReactElement }[] +}> = ({ items }) => { return ( {items?.map((item, key) => ( diff --git a/apps/web/src/components/Icon/assets/escrow.svg b/apps/web/src/components/Icon/assets/escrow.svg new file mode 100644 index 000000000..d50483e4f --- /dev/null +++ b/apps/web/src/components/Icon/assets/escrow.svg @@ -0,0 +1,3 @@ + + + diff --git a/apps/web/src/components/Icon/icons.ts b/apps/web/src/components/Icon/icons.ts index 61620c58b..2db84171e 100644 --- a/apps/web/src/components/Icon/icons.ts +++ b/apps/web/src/components/Icon/icons.ts @@ -19,6 +19,7 @@ import Dash from './assets/dash.svg' import Discord from './assets/discord.svg' import Dots from './assets/dots.svg' import Download from './assets/download.svg' +import Escrow from './assets/escrow.svg' import Eth from './assets/eth.svg' import External from './assets/external-16.svg' import Github from './assets/github.svg' @@ -84,6 +85,7 @@ export const icons = { share: Share, warning: Warning, 'warning-16': Warning16, + escrow: Escrow, } export type IconType = keyof typeof icons diff --git a/apps/web/src/constants/swrKeys.ts b/apps/web/src/constants/swrKeys.ts index 31994f87e..0dc6e447a 100644 --- a/apps/web/src/constants/swrKeys.ts +++ b/apps/web/src/constants/swrKeys.ts @@ -26,6 +26,7 @@ const SWR_KEYS = { ENCODED_DAO_METADATA: 'encoded-dao-metadata', DAO_MIGRATED: 'dao-migrated', DAO_NEXT_AND_PREVIOUS_TOKENS: 'dao-next-and-previous-tokens', + IPFS: 'ipfs', DYNAMIC: { MY_DAOS(str: string) { return `my-daos-${str}` diff --git a/apps/web/src/modules/create-proposal/components/ReviewProposalForm/ReviewProposalForm.tsx b/apps/web/src/modules/create-proposal/components/ReviewProposalForm/ReviewProposalForm.tsx index 47b6ef245..dff7434b3 100644 --- a/apps/web/src/modules/create-proposal/components/ReviewProposalForm/ReviewProposalForm.tsx +++ b/apps/web/src/modules/create-proposal/components/ReviewProposalForm/ReviewProposalForm.tsx @@ -23,6 +23,7 @@ import { AddressType, CHAIN_ID } from 'src/typings' import { BuilderTransaction, useProposalStore } from '../../stores' import { prepareProposalTransactions } from '../../utils/prepareTransactions' +import { useEscrowFormStore } from '../TransactionForm/Escrow/EscrowUtils' import { Transactions } from './Transactions' import { ERROR_CODE, FormValues, validationSchema } from './fields' @@ -69,6 +70,7 @@ export const ReviewProposalForm = ({ const [simulating, setSimulating] = useState(false) const [simulations, setSimulations] = useState>([]) const [proposing, setProposing] = useState(false) + const { clear: clearEscrowForm } = useEscrowFormStore() const { data: votes, isLoading } = useContractRead({ address: addresses?.token as AddressType, @@ -178,6 +180,7 @@ export const ReviewProposalForm = ({ .then(() => { setProposing(false) clearProposal() + clearEscrowForm() }) } catch (err: any) { setProposing(false) diff --git a/apps/web/src/modules/create-proposal/components/TransactionForm/Escrow/Escrow.tsx b/apps/web/src/modules/create-proposal/components/TransactionForm/Escrow/Escrow.tsx new file mode 100644 index 000000000..761ec745c --- /dev/null +++ b/apps/web/src/modules/create-proposal/components/TransactionForm/Escrow/Escrow.tsx @@ -0,0 +1,163 @@ +import { Stack } from '@zoralabs/zord' +import { useCallback } from 'hono/jsx' +import { uploadFile } from 'ipfs-service' +import { useRouter } from 'next/router' +import { useState } from 'react' +import useSWR from 'swr' +import { encodeFunctionData, formatEther } from 'viem' + +import SWR_KEYS from 'src/constants/swrKeys' +import { ProposalsResponse } from 'src/data/subgraph/requests/proposalsQuery' +import { getProposals } from 'src/data/subgraph/requests/proposalsQuery' +import { TransactionType } from 'src/modules/create-proposal/constants' +import { useProposalStore } from 'src/modules/create-proposal/stores' +import { getChainFromLocalStorage } from 'src/utils/getChainFromLocalStorage' + +import EscrowForm from './EscrowForm' +import { EscrowFormValues } from './EscrowForm.schema' +import { useEscrowFormStore } from './EscrowUtils' +import { + KLEROS_ARBITRATION_PROVIDER, + createEscrowData, + deployEscrowAbi, + getEscrowBundler, +} from './EscrowUtils' + +export const Escrow: React.FC = () => { + const [isSubmitting, setIsSubmitting] = useState(false) + const [ipfsUploadError, setIpfsUploadError] = useState(null) + + const { query, isReady } = useRouter() + + const { id: chainId } = getChainFromLocalStorage() + + const addTransaction = useProposalStore((state) => state.addTransaction) + + const { data } = useSWR( + isReady ? [SWR_KEYS.PROPOSALS, chainId, query.token, '0'] : null, + (_, chainId, token, page) => getProposals(chainId, token, 1, Number(0)) + ) + + const lastProposalId = data?.proposals?.[0]?.proposalNumber ?? 0 + + const { formValues } = useEscrowFormStore() + + const handleEscrowTransaction = useCallback( + async (values: EscrowFormValues) => { + const ipfsDataToUpload = { + title: 'Proposal #' + (lastProposalId + 1), + description: window?.location.href.replace( + '/proposal/create', + '/vote/' + lastProposalId + 1 + ), + endDate: new Date( + values.milestones[values.milestones.length - 1].endDate + ).getTime(), + milestones: values.milestones.map((x, index) => ({ + id: 'milestone-00' + index, + title: x.title, + description: x.description, + endDate: new Date(x.endDate).getTime() / 1000, // in seconds + createdAt: Date.now() / 1000, // in seconds + startDate: Date.now() + 7 * 86400, // set start date 7 days from submission in seconds + resolverType: 'kleros', + totalAmount: values.milestones.reduce((acc, x) => acc + x.amount, 0), + klerosCourt: 1, + arbitrationProvider: KLEROS_ARBITRATION_PROVIDER, + ...(x.mediaType && x.mediaUrl + ? { + documents: [ + { + id: 'doc-001', + type: 'ipfs', + src: x.mediaUrl, + mimeType: x.mediaType, + createdAt: new Date().getTime() / 1000, + }, + ], + } + : {}), + })), + } + + const jsonDataToUpload = JSON.stringify(ipfsDataToUpload, null, 2) + const fileToUpload = new File([jsonDataToUpload], 'escrow-data.json', { + type: 'application/json', + }) + + let cid: string, uri: string; + + try { + console.log('Uploading to IPFS...') + setIsSubmitting(true) + const response = await uploadFile(fileToUpload, { + cache: true, + onProgress: (progress) => { + console.log(`Upload progress: ${progress}%`) + }, + }) + cid = response.cid + uri = response.uri + setIsSubmitting(false) + setIpfsUploadError(null) + console.log('IPFS upload successful. CID:', cid, 'URI:', uri) + } catch (err: any) { + console.log('IPFS upload error:', err) + setIsSubmitting(false) + setIpfsUploadError( + new Error( + `Sorry, there was an error with our file uploading service. ${err?.message}` + ) + ) + return + } + + // create bundler transaction data + const escrowData = createEscrowData(values, cid, chainId) + const milestoneAmounts = values.milestones.map((x) => x.amount * 10 ** 18) + const fundAmount = milestoneAmounts.reduce((acc, x) => acc + x, 0) + + console.log(milestoneAmounts, fundAmount) + + const escrow = { + target: getEscrowBundler(chainId), + functionSignature: 'deployEscrow()', + calldata: encodeFunctionData({ + abi: deployEscrowAbi, + functionName: 'deployEscrow', + args: [milestoneAmounts, escrowData, fundAmount], + }), + value: formatEther(BigInt(fundAmount)), + } + + try { + // add 2.5s delay here before adding to queue + setTimeout( + () => + addTransaction({ + type: TransactionType.ESCROW, + summary: `Create and fund new Escrow with ${formatEther( + BigInt(fundAmount) + )} ETH`, + transactions: [escrow], + }), + 2500 + ) + } catch (err) { + console.log('Error', err) + } + setIsSubmitting(false) + }, + [formValues] + ) + + return ( + + + {ipfsUploadError?.message &&
Error: {ipfsUploadError.message}
} +
+ ) +} diff --git a/apps/web/src/modules/create-proposal/components/TransactionForm/Escrow/EscrowDetailsDisplay.tsx b/apps/web/src/modules/create-proposal/components/TransactionForm/Escrow/EscrowDetailsDisplay.tsx new file mode 100644 index 000000000..47bb65ac9 --- /dev/null +++ b/apps/web/src/modules/create-proposal/components/TransactionForm/Escrow/EscrowDetailsDisplay.tsx @@ -0,0 +1,60 @@ +import { Box, Stack, Text } from '@zoralabs/zord' +import { useFormikContext } from 'formik' +import { useBalance } from 'wagmi' + +import { useDaoStore } from 'src/modules/dao' +import { useLayoutStore } from 'src/stores' +import { useChainStore } from 'src/stores/useChainStore' + +import { EscrowFormValues } from './EscrowForm.schema' + +export default function EscrowDetailsDisplay() { + const { values } = useFormikContext() + const isMobile = useLayoutStore((x) => x.isMobile) + + const { treasury } = useDaoStore((state) => state.addresses) + const chain = useChainStore((x) => x.chain) + const { data: treasuryBalance } = useBalance({ + address: treasury, + chainId: chain.id, + }) + + const totalEscrowAmount = values?.milestones + .map((x) => x.amount) + .reduce((acc, x) => acc + x, 0) + return ( + + + {Number(totalEscrowAmount) > Number(treasuryBalance?.formatted) && ( + + Escrow amount exceeding treasury balance + + )} + + + Total Escrow Amount + + + {totalEscrowAmount ?? '0.00'} ETH + + + + + Escrow Service by + + + SmartInvoice + + + + + ) +} diff --git a/apps/web/src/modules/create-proposal/components/TransactionForm/Escrow/EscrowForm.schema.ts b/apps/web/src/modules/create-proposal/components/TransactionForm/Escrow/EscrowForm.schema.ts new file mode 100644 index 000000000..61d2aef9a --- /dev/null +++ b/apps/web/src/modules/create-proposal/components/TransactionForm/Escrow/EscrowForm.schema.ts @@ -0,0 +1,136 @@ +import { FormikHelpers } from 'formik' +import * as yup from 'yup' + +import { AddressType } from 'src/typings' +import { addressValidationSchema } from 'src/utils/yup' + +export interface Milestone { + amount: number + title: string + endDate: number & string & Date + mediaUrl: string | undefined + mediaType: string | undefined + mediaFileName: string + description: string +} + +export interface EscrowFormValues { + clientAddress: string | AddressType + recipientAddress: string | AddressType + safetyValveDate: Date | number | string + milestones: Array +} + +export interface EscrowFormState { + formValues: EscrowFormValues + setFormValues: (values: EscrowFormValues) => void + resetForm: () => void + clear: () => void +} + +export interface EscrowFormProps { + onSubmit: (values: EscrowFormValues, actions: FormikHelpers) => void + isSubmitting: boolean +} + +export const MilestoneSchema = yup.object({ + amount: yup + .number() + .moreThan(0, 'Amount must be greater than 0') + .required('Amount is required'), + title: yup.string().required('Title is required'), + endDate: yup.date().required('End date is required'), + mediaUrl: yup.string(), + mediaType: yup + .string() + .oneOf([ + 'image/jpeg', + 'image/png', + 'image/svg+xml', + 'image/webp', + 'image/gif', + 'video/mp4', + 'video/quicktime', + 'audio/mpeg', + 'audio/wav', + undefined, + ]), + mediaFileName: yup.string(), + description: yup.string(), +}) + +export const EscrowFormSchema = yup + .object({ + clientAddress: addressValidationSchema, + recipientAddress: addressValidationSchema.test( + 'not-same-as-client', + 'Recipient address must be different from client address', + function(value) { + return value?.toLowerCase() !== this?.parent.clientAddress.toLowerCase() + } + ), + safetyValveDate: yup + .date() + .required('Safety valve date is required.') + .min( + new Date(Date.now() + 30 * 24 * 60 * 60 * 1000), + 'Safety valve date must be at least 30 days from today or the last milestone whichever is later.' + ) + .test( + 'after-last-milestone', + 'Safety valve date must be at least 30 days after the last milestone date.', + function(value) { + const milestones = (this.parent.milestones || []) as Milestone[] + if (milestones.length === 0) return true + + // Get the last milestone's end date + const lastMilestoneDate = new Date( + Math.max(...milestones.map((m) => new Date(m.endDate).getTime())) + ) + + // Add 30 days to last milestone date + const minSafetyValveDate = + lastMilestoneDate.getTime() + 30 * 24 * 60 * 60 * 1000 + + const safetyValveDate = new Date(value as any).getTime() + + return safetyValveDate >= minSafetyValveDate + } + ), + milestones: yup + .array() + .of(MilestoneSchema) + .min(1, 'At least one milestone is required'), + }) + .test( + 'addresses-not-same', + 'Client address and recipient address must be different', + function(values) { + return values.clientAddress !== values.recipientAddress + } + ) + +// IPFS Interface Interface + +export type Document = Partial<{ + id: string + src: string + type: string + mimeType: string // image/png, application/pdf, etc. + createdAt: number +}> + +export type BasicMetadata = Partial<{ + version: string + id: string + title: string + description: string + image: Document + documents: Document[] + createdAt: number +}> + +export type IpfsMilestone = Omit & + Partial<{ + endDate: number + }> diff --git a/apps/web/src/modules/create-proposal/components/TransactionForm/Escrow/EscrowForm.tsx b/apps/web/src/modules/create-proposal/components/TransactionForm/Escrow/EscrowForm.tsx new file mode 100644 index 000000000..0289ac486 --- /dev/null +++ b/apps/web/src/modules/create-proposal/components/TransactionForm/Escrow/EscrowForm.tsx @@ -0,0 +1,294 @@ +import { Box, Button, Flex, Stack } from '@zoralabs/zord' +import { FieldArray, Form, Formik } from 'formik' +import type { FormikHelpers } from 'formik' +import { useFormikContext } from 'formik' +import { truncate } from 'lodash' +import React, { useCallback, useState } from 'react' + +import DatePicker from 'src/components/Fields/Date' +import SmartInput from 'src/components/Fields/SmartInput' +import { NUMBER, TEXT, TEXTAREA } from 'src/components/Fields/types' +import Accordion from 'src/components/Home/accordian' +import { Icon } from 'src/components/Icon' +import SingleMediaUpload from 'src/components/SingleMediaUpload/SingleMediaUpload' +import { useDaoStore } from 'src/modules/dao' + +import EscrowDetailsDisplay from './EscrowDetailsDisplay' +import { + EscrowFormProps, + EscrowFormSchema, + EscrowFormValues, + Milestone, +} from './EscrowForm.schema' +import { useEscrowFormStore } from './EscrowUtils' + +const MilestoneForm: React.FC<{ + index: number + setIsMediaUploading: React.Dispatch> + removeMilestone: () => void +}> = ({ index, removeMilestone, setIsMediaUploading }) => { + const formik = useFormikContext() + + const handleRemoveMilestone = () => { + removeMilestone() + } + + const handleMediaUploadStart = useCallback( + (media: File) => { + formik.setFieldValue(`milestones.${index}.mediaType`, media.type) + formik.setFieldValue(`milestones.${index}.mediaFileName`, media.name) + setIsMediaUploading(true) + }, + [formik, index, setIsMediaUploading] + ) + + return ( + + + + + + + + + setIsMediaUploading(false)} + /> + + + {formik.values.milestones.length > 1 && ( + + )} + + + ) +} + +const EscrowForm: React.FC = ({ + onSubmit, + isSubmitting, +}) => { + const [isMediaUploading, setIsMediaUploading] = useState(false) + + const { formValues, setFormValues } = useEscrowFormStore() + const { + addresses: { treasury }, + } = useDaoStore() + + const handleSubmit = useCallback( + (values: EscrowFormValues, actions: FormikHelpers) => { + setFormValues(values) + onSubmit?.(values, actions) + }, + [onSubmit, setFormValues] + ) + + const handleAddMilestone = useCallback( + ( + push: (obj: Milestone) => void, + previousMilestone: Milestone, + newMilestoneIndex: number + ) => { + push({ + amount: 0.5, + title: 'Milestone ' + newMilestoneIndex, + endDate: new Date(Date.parse(previousMilestone?.endDate) + 864000000) + .toISOString() + .slice(0, 10) as never, // adds 10 days to previous milestone + mediaUrl: '', + mediaType: undefined, + mediaFileName: '', + description: '', + }) + }, + [] + ) + + return ( + + + {(formik) => ( + +
+ + + + + + + + + {({ push, remove }) => ( + <> + ({ + title: truncate(formik.values.milestones[index].title, { + length: 32, + separator: '...', + }), + description: ( + + formik.values.milestones.length != 1 && remove(index) + } + /> + ), + }))} + /> + + + + + )} + + + + +
+
+ )} +
+
+ ) +} + +export default EscrowForm diff --git a/apps/web/src/modules/create-proposal/components/TransactionForm/Escrow/EscrowUtils.ts b/apps/web/src/modules/create-proposal/components/TransactionForm/Escrow/EscrowUtils.ts new file mode 100644 index 000000000..4bf1e0ad4 --- /dev/null +++ b/apps/web/src/modules/create-proposal/components/TransactionForm/Escrow/EscrowUtils.ts @@ -0,0 +1,193 @@ +import { decode, encode } from 'bs58' +import { Address, Hex, encodeAbiParameters, toBytes, toHex } from 'viem' +import { create } from 'zustand' +import { createJSONStorage, persist } from 'zustand/middleware' + +import { CHAIN_ID } from 'src/typings' + +import { EscrowFormState, EscrowFormValues } from './EscrowForm.schema' + +const KLEROS_ARBITRATION_PROVIDER = + '0x18542245cA523DFF96AF766047fE9423E0BED3C0' as Address +const ESCROW_RESOLVER_TYPE = 0 +const ESCROW_REQUIRE_VERIFICATION = true +const ESCROW_TYPE = toHex(toBytes('updatable', { size: 32 })) + +export function convertIpfsCidV0ToByte32(cid: string) { + return `0x${Buffer.from(decode(cid).slice(2)).toString('hex')}` +} + +export function convertByte32ToIpfsCidV0(str: Hex) { + let newStr: string = str + if (str.indexOf('0x') === 0) { + newStr = str.slice(2) + } + return encode(Buffer.from(`1220${newStr}`, 'hex')) +} + +function getWrappedTokenAddress(chainId: number | string): Address { + chainId = Number(chainId) + switch (chainId) { + case CHAIN_ID.ETHEREUM: + return '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2' as Address + case CHAIN_ID.OPTIMISM: + return '0x4200000000000000000000000000000000000006' as Address + case CHAIN_ID.BASE: + return '0x4200000000000000000000000000000000000006' as Address + case CHAIN_ID.ZORA: + return '0x4200000000000000000000000000000000000006' as Address + case CHAIN_ID.SEPOLIA: + return '0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14' as Address + case CHAIN_ID.OPTIMISM_SEPOLIA: + return '0x4200000000000000000000000000000000000006' as Address + case CHAIN_ID.BASE_SEPOLIA: + return '0x4200000000000000000000000000000000000006' as Address + case CHAIN_ID.ZORA_SEPOLIA: + return '0x4200000000000000000000000000000000000006' as Address + default: + throw new Error(`Unsupported chain ID: ${chainId}`) + } +} + +function getEscrowBundler(chainId: number | string): Address { + chainId = Number(chainId) + switch (chainId) { + case CHAIN_ID.ETHEREUM: + return '0xb4cdef4aa610c046864467592fae456a58d3443a' as Address + case CHAIN_ID.OPTIMISM: + return '0xdafeb89f713e25a02e4ec21a18e3757d7a76d19e' as Address + case CHAIN_ID.BASE: + return '0xf4640751e7363a0572d4ba93a9b049b956b33c17' as Address + case CHAIN_ID.ZORA: + return '0x0325e1b676c4cf59e0b690a05e0181be862193d4' as Address + case CHAIN_ID.SEPOLIA: + return '0x9c1E057B37605B7f6ed6f4c8E2826C3d84ddC08D' as Address + case CHAIN_ID.OPTIMISM_SEPOLIA: + return '0xe0986c3bdab537fbeb7c94d0c5ef961d6d8bf63a' as Address + case CHAIN_ID.BASE_SEPOLIA: + return '0x3add1d027116a5406ced10411945cf2d4d9ed68e' as Address + case CHAIN_ID.ZORA_SEPOLIA: + return '0x851e59a39571e599954702f0e4996bf838d9c863' as Address + default: + throw new Error(`Unsupported chain ID: ${chainId}`) + } +} + +function createEscrowData( + values: EscrowFormValues, + ipfsCID: string, + chainId: string | number +) { + const warappedTokenAddress = getWrappedTokenAddress(chainId) + const terminationTime = new Date(values.safetyValveDate).getTime() / 1000 + const ipfsBytesCid = convertIpfsCidV0ToByte32(ipfsCID) + + // encode abi parameters to create escrowData + const encodedParams = encodeAbiParameters( + [ + 'address', + 'address', + 'uint8', + 'address', + 'uint256', + 'bytes32', + 'address', + 'address', + 'bool', + 'bytes32', + ].map((type) => ({ type })), + [ + values.clientAddress, + KLEROS_ARBITRATION_PROVIDER, + ESCROW_RESOLVER_TYPE, + warappedTokenAddress, + terminationTime, + ipfsBytesCid, + values.recipientAddress, + values.recipientAddress, + ESCROW_REQUIRE_VERIFICATION, + ESCROW_TYPE, + ] + ) + + return encodedParams +} + +const deployEscrowAbi = [ + { + name: 'deployEscrow', + type: 'function', + inputs: [ + { + name: '_milestoneAmounts', + type: 'uint256[]', + internalType: 'uint256[]', + }, + { + name: '_escrowData', + type: 'bytes', + internalType: 'bytes', + }, + { + name: '_fundAmount', + type: 'uint256', + internalType: 'uint256', + }, + ], + outputs: [ + { + name: 'escrow', + type: 'address', + internalType: 'address', + }, + ], + stateMutability: 'nonpayable', + }, +] + +const initialState: EscrowFormValues = { + clientAddress: '', + recipientAddress: '', + milestones: [ + { + amount: 0.5, + title: 'Milestone 1', + endDate: new Date(Date.now() + 1000 * 60 * 60 * 24 * 10) + .toISOString() + .split('T')[0] as never, + mediaUrl: '', + mediaType: undefined, + mediaFileName: '', + description: 'About Milestone 1', + }, + ], + safetyValveDate: new Date(Date.now() + 1000 * 60 * 60 * 24 * 30) + .toISOString() + .split('T')[0], +} + +const useEscrowFormStore = create( + persist( + (set) => ({ + formValues: initialState, + setFormValues: (values) => set({ formValues: values }), + resetForm: () => set({ formValues: initialState }), + clear: () => { + set({ formValues: initialState }) + localStorage.removeItem('escrow-form-storage') + }, + }), + { + name: 'escrow-form-storage', + storage: createJSONStorage(() => localStorage), + } + ) +) + +export { + createEscrowData, + getEscrowBundler, + KLEROS_ARBITRATION_PROVIDER, + deployEscrowAbi, + useEscrowFormStore, +} diff --git a/apps/web/src/modules/create-proposal/components/TransactionForm/Escrow/index.ts b/apps/web/src/modules/create-proposal/components/TransactionForm/Escrow/index.ts new file mode 100644 index 000000000..a3aa85eb8 --- /dev/null +++ b/apps/web/src/modules/create-proposal/components/TransactionForm/Escrow/index.ts @@ -0,0 +1 @@ +export * from './Escrow' diff --git a/apps/web/src/modules/create-proposal/components/TransactionForm/TransactionForm.tsx b/apps/web/src/modules/create-proposal/components/TransactionForm/TransactionForm.tsx index 9f9306ff9..2f003fa62 100644 --- a/apps/web/src/modules/create-proposal/components/TransactionForm/TransactionForm.tsx +++ b/apps/web/src/modules/create-proposal/components/TransactionForm/TransactionForm.tsx @@ -5,6 +5,7 @@ import { TransactionType } from 'src/modules/create-proposal/constants' import { Airdrop } from './Airdrop' import { CustomTransaction } from './CustomTransaction' import { Droposal } from './Droposal' +import { Escrow } from './Escrow' import { Migration } from './Migration' import { PauseAuctions } from './PauseAuctions' import { ReplaceArtwork } from './ReplaceArtwork' @@ -20,6 +21,7 @@ export type TransactionFormType = typeof TRANSACTION_FORM_OPTIONS[number] export const TRANSACTION_FORM_OPTIONS = [ TransactionType.SEND_ETH, TransactionType.AIRDROP, + TransactionType.ESCROW, TransactionType.PAUSE_AUCTIONS, TransactionType.RESUME_AUCTIONS, TransactionType.REPLACE_ARTWORK, @@ -32,6 +34,7 @@ export const TransactionForm = ({ type }: TransactionFormProps) => { const FORMS: { [key in TransactionFormType]: ReactNode } = { [TransactionType.CUSTOM]: , [TransactionType.AIRDROP]: , + [TransactionType.ESCROW]: , [TransactionType.DROPOSAL]: , [TransactionType.SEND_ETH]: , [TransactionType.PAUSE_AUCTIONS]: , diff --git a/apps/web/src/modules/create-proposal/constants/transactionType.tsx b/apps/web/src/modules/create-proposal/constants/transactionType.tsx index d9118e263..23daeab2a 100644 --- a/apps/web/src/modules/create-proposal/constants/transactionType.tsx +++ b/apps/web/src/modules/create-proposal/constants/transactionType.tsx @@ -8,6 +8,7 @@ export enum TransactionType { DROPOSAL = 'droposal', CUSTOM = 'custom', UPGRADE = 'upgrade', + ESCROW = 'escrow', PAUSE_AUCTIONS = 'pause-auctions', RESUME_AUCTIONS = 'resume-auctions', UPDATE_MINTER = 'update-minter', @@ -40,6 +41,12 @@ export const TRANSACTION_TYPES = { icon: 'airdrop', iconBackdrop: 'rgba(28, 182, 135, 0.1)', }, + [TransactionType.ESCROW]: { + title: 'Escrow Milestones', + subTitle: 'Create a proposal and escrow milestones ', + icon: 'escrow', + iconBackdrop: 'rgba(255, 155, 155, 0.102)', + }, [TransactionType.DROPOSAL]: { title: 'Droposal: Single edition', subTitle: 'Create a droposal for a Single-edition ERC721 collection', diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c20350136..5df42f79e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -60,6 +60,9 @@ importers: '@sentry/nextjs': specifier: ^7.105.0 version: 7.119.0(encoding@0.1.13)(next@14.2.5(@babel/core@7.20.12)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react@18.2.0)(webpack@5.75.0) + '@smartinvoicexyz/constants': + specifier: ^0.1.17 + version: 0.1.18(bufferutil@4.0.7)(typescript@5.5.4)(utf-8-validate@5.0.10)(zod@3.23.8) '@types/lodash': specifier: ^4.14.186 version: 4.14.191 @@ -96,6 +99,9 @@ importers: blocklist: specifier: workspace:* version: link:../../packages/blocklist + bs58: + specifier: ^5.0.0 + version: 5.0.0 dayjs: specifier: ^1.11.3 version: 1.11.7 @@ -404,7 +410,7 @@ importers: version: 4.9.3 vitest: specifier: ^0.23.4 - version: 0.23.4(jsdom@20.0.3)(terser@5.16.3) + version: 0.23.4(jsdom@20.0.3(bufferutil@4.0.7)(utf-8-validate@5.0.10))(terser@5.16.3) packages/tsconfig: {} @@ -476,7 +482,7 @@ importers: version: link:../tsconfig tsup: specifier: ^6.5.0 - version: 6.6.2(postcss@8.4.41)(ts-node@10.9.1(typescript@4.9.3))(typescript@4.9.3) + version: 6.6.2(postcss@8.4.41)(ts-node@10.9.1(@types/node@18.13.0)(typescript@4.9.3))(typescript@4.9.3) typescript: specifier: ^4.9.3 version: 4.9.3 @@ -2301,6 +2307,9 @@ packages: '@noble/curves@1.2.0': resolution: {integrity: sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==} + '@noble/curves@1.4.0': + resolution: {integrity: sha512-p+4cb332SFCrReJkCYe8Xzm0OWi4Jji5jVdIZRL/PmacmDkFNw6MrrV+gGpiPxLHbV+zKFRywUWbaseT+tZRXg==} + '@noble/curves@1.5.0': resolution: {integrity: sha512-J5EKamIHnKPyClwVrzmaf5wSdQXgdHcPZIZLu3bwnbeCx8/7NPK5q2ZBWF+5FvYGByjiQQsJYX6jfgB2wDPn3A==} @@ -2655,6 +2664,9 @@ packages: '@scure/bip32@1.3.2': resolution: {integrity: sha512-N1ZhksgwD3OBlwTv3R6KFEcPojl/W4ElJOeCZdi+vuI5QmTFwLq3OFf2zd2ROpKvxFdgZ6hUpb0dx9bVNEwYCA==} + '@scure/bip32@1.4.0': + resolution: {integrity: sha512-sVUpc0Vq3tXCkDGYVWGIZTRfnvu8LoTDaev7vbwh0omSvVORONr960MQWdKqJDCReIEmTj3PAr73O3aoxz7OPg==} + '@scure/bip32@1.6.0': resolution: {integrity: sha512-82q1QfklrUUdXJzjuRU7iG7D7XiFx5PHYVS0+oeNKhyDLT7WPqs6pBcM2W5ZdwOwKCwoE1Vy1se+DHjcXwCYnA==} @@ -2664,6 +2676,9 @@ packages: '@scure/bip39@1.2.1': resolution: {integrity: sha512-Z3/Fsz1yr904dduJD0NpiyRHhRYHdcnyh73FZWiV+/qhWi83wNJ3NWolYqCEN+ZWsUz2TWwajJggcRE9r1zUYg==} + '@scure/bip39@1.3.0': + resolution: {integrity: sha512-disdg7gHuTDZtY+ZdkmLpPCk7fxZSu3gBiEGuoC1XYxv9cGx3Z6cpTggCgW6odSOOIXCiDjuGejW+aJKCY/pIQ==} + '@scure/bip39@1.5.0': resolution: {integrity: sha512-Dop+ASYhnrwm9+HA/HwXg7j2ZqM6yk2fyLWb5znexjctFY3+E+eU8cIWI0Pql0Qx4hPZCijlGq4OL71g+Uz30A==} @@ -2745,6 +2760,10 @@ packages: '@sinclair/typebox@0.25.21': resolution: {integrity: sha512-gFukHN4t8K4+wVC+ECqeqwzBDeFeTzBXroBTqE6vcWrQGbEUpHO7LYdG0f4xnvYq4VOEwITSlHlp0JBAIFMS/g==} + '@smartinvoicexyz/constants@0.1.18': + resolution: {integrity: sha512-m0XQz9/CPOMiIeKJX11UNuSdoR1kHLUfuqqWUJaRe6iYmEwbDPbpyZyFqUWMcCqFvDaKeB5zb0zAvjip3pIvxA==} + engines: {node: '>=18'} + '@solana/buffer-layout@4.0.1': resolution: {integrity: sha512-E1ImOIAD1tBZFRdjeM4/pzTiTApC0AOBGwyAMS4fwIodCWArzJ3DWdoh8cKxeFM2fElkxBh2Aqts1BPC373rHA==} engines: {node: '>=5.10'} @@ -3532,6 +3551,17 @@ packages: zod: optional: true + abitype@1.0.5: + resolution: {integrity: sha512-YzDhti7cjlfaBhHutMaboYB21Ha3rXR9QTkNJFzYC4kC8YclaiwPBBBJY8ejFdu2wnJeZCVZSMlQJ7fi8S6hsw==} + peerDependencies: + typescript: '>=5.0.4' + zod: ^3 >=3.22.0 + peerDependenciesMeta: + typescript: + optional: true + zod: + optional: true + abitype@1.0.7: resolution: {integrity: sha512-ZfYYSktDQUwc2eduYu8C4wOs+RDPmnRYMh7zNfzeMtGGgb0U+6tLGjixUic6mXf5xKKCcgT5Qp6cv39tOARVFw==} peerDependencies: @@ -3812,6 +3842,9 @@ packages: base-x@3.0.9: resolution: {integrity: sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==} + base-x@4.0.0: + resolution: {integrity: sha512-FuwxlW4H5kh37X/oW59pwTzzTKRzfrrQwhmyspRM7swOEZcHtDZSCt45U6oKgtuFE+WYPblePMVIPR4RZrh/hw==} + base64-js@0.0.8: resolution: {integrity: sha512-3XSA2cR/h/73EzlXXdU6YNycmYI7+kicTxks4eJg2g39biHR84slg2+des+p7iHYhbRg/udIS4TD53WabcOUkw==} engines: {node: '>= 0.4'} @@ -3913,6 +3946,9 @@ packages: bs58@4.0.1: resolution: {integrity: sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==} + bs58@5.0.0: + resolution: {integrity: sha512-r+ihvQJvahgYT50JD05dyJNKlmmSlMoOGwn1lCcEzanPglg7TxYjioQUYehQ9mAR/+hOSd2jRc/Z2y5UxBymvQ==} + bs58check@2.1.2: resolution: {integrity: sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==} @@ -5233,9 +5269,9 @@ packages: for-each@0.3.3: resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} - forge-std@https://codeload.github.com/foundry-rs/forge-std/tar.gz/d3db4ef90a72b7d24aa5a2e5c649593eaef7801d: - resolution: {tarball: https://codeload.github.com/foundry-rs/forge-std/tar.gz/d3db4ef90a72b7d24aa5a2e5c649593eaef7801d} - version: 1.9.4 + forge-std@https://codeload.github.com/foundry-rs/forge-std/tar.gz/726a6ee5fc8427a0013d6f624e486c9130c0e336: + resolution: {tarball: https://codeload.github.com/foundry-rs/forge-std/tar.gz/726a6ee5fc8427a0013d6f624e486c9130c0e336} + version: 1.9.5 form-data@2.3.3: resolution: {integrity: sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==} @@ -6024,6 +6060,11 @@ packages: peerDependencies: ws: '*' + isows@1.0.4: + resolution: {integrity: sha512-hEzjY+x9u9hPmBom9IIAqdJCwNLax+xrPb51vEPpERoFlIxgmZcHzsT5jKG06nvInKOBGvReAVz80Umed5CczQ==} + peerDependencies: + ws: '*' + isows@1.0.6: resolution: {integrity: sha512-lPHCayd40oW98/I0uvgaHKWCSvkzY27LjWLbtzOm64yQ+G3Q5npjjbdppU65iZXkK1Zt+kH9pfegli0AYfwYYw==} peerDependencies: @@ -8713,6 +8754,14 @@ packages: typescript: optional: true + viem@2.17.0: + resolution: {integrity: sha512-+gaVlsfDsHL1oYdjpatdRxW1WK/slLYVvpOws3fEdLfQFUToezKI6YLC9l1g2uKm4Hg3OdGX1KQy/G7/58tTKQ==} + peerDependencies: + typescript: '>=5.0.4' + peerDependenciesMeta: + typescript: + optional: true + viem@2.21.54: resolution: {integrity: sha512-G9mmtbua3UtnVY9BqAtWdNp+3AO+oWhD0B9KaEsZb6gcrOWgmA4rz02yqEMg+qW9m6KgKGie7q3zcHqJIw6AqA==} peerDependencies: @@ -9048,6 +9097,18 @@ packages: utf-8-validate: optional: true + ws@8.17.1: + resolution: {integrity: sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + ws@8.18.0: resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==} engines: {node: '>=10.0.0'} @@ -11372,6 +11433,10 @@ snapshots: dependencies: '@noble/hashes': 1.3.2 + '@noble/curves@1.4.0': + dependencies: + '@noble/hashes': 1.4.0 + '@noble/curves@1.5.0': dependencies: '@noble/hashes': 1.4.0 @@ -11773,6 +11838,12 @@ snapshots: '@noble/hashes': 1.3.2 '@scure/base': 1.1.7 + '@scure/bip32@1.4.0': + dependencies: + '@noble/curves': 1.4.0 + '@noble/hashes': 1.4.0 + '@scure/base': 1.1.7 + '@scure/bip32@1.6.0': dependencies: '@noble/curves': 1.7.0 @@ -11789,6 +11860,11 @@ snapshots: '@noble/hashes': 1.3.2 '@scure/base': 1.1.1 + '@scure/bip39@1.3.0': + dependencies: + '@noble/hashes': 1.4.0 + '@scure/base': 1.1.7 + '@scure/bip39@1.5.0': dependencies: '@noble/hashes': 1.6.1 @@ -11924,6 +12000,16 @@ snapshots: '@sinclair/typebox@0.25.21': {} + '@smartinvoicexyz/constants@0.1.18(bufferutil@4.0.7)(typescript@5.5.4)(utf-8-validate@5.0.10)(zod@3.23.8)': + dependencies: + lodash: 4.17.21 + viem: 2.17.0(bufferutil@4.0.7)(typescript@5.5.4)(utf-8-validate@5.0.10)(zod@3.23.8) + transitivePeerDependencies: + - bufferutil + - typescript + - utf-8-validate + - zod + '@solana/buffer-layout@4.0.1': dependencies: buffer: 6.0.3 @@ -11931,8 +12017,8 @@ snapshots: '@solana/web3.js@1.77.3(bufferutil@4.0.7)(encoding@0.1.13)(utf-8-validate@5.0.10)': dependencies: '@babel/runtime': 7.20.1 - '@noble/curves': 1.5.0 - '@noble/hashes': 1.4.0 + '@noble/curves': 1.7.0 + '@noble/hashes': 1.6.1 '@solana/buffer-layout': 4.0.1 agentkeepalive: 4.3.0 bigint-buffer: 1.1.5 @@ -13231,7 +13317,7 @@ snapshots: '@openzeppelin/contracts-upgradeable': 4.8.1 '@types/node': 18.13.0 ds-test: https://codeload.github.com/dapphub/ds-test/tar.gz/e282159d5170298eb2455a6c05280ab5a73a4ef0 - forge-std: https://codeload.github.com/foundry-rs/forge-std/tar.gz/d3db4ef90a72b7d24aa5a2e5c649593eaef7801d + forge-std: https://codeload.github.com/foundry-rs/forge-std/tar.gz/726a6ee5fc8427a0013d6f624e486c9130c0e336 micro-onchain-metadata-utils: 0.1.1 sol-uriencode: 0.2.0 @@ -13258,6 +13344,11 @@ snapshots: typescript: 5.5.4 zod: 3.23.8 + abitype@1.0.5(typescript@5.5.4)(zod@3.23.8): + optionalDependencies: + typescript: 5.5.4 + zod: 3.23.8 + abitype@1.0.7(typescript@5.5.4)(zod@3.23.8): optionalDependencies: typescript: 5.5.4 @@ -13573,6 +13664,8 @@ snapshots: dependencies: safe-buffer: 5.2.1 + base-x@4.0.0: {} + base64-js@0.0.8: {} base64-js@1.5.1: {} @@ -13679,6 +13772,10 @@ snapshots: dependencies: base-x: 3.0.9 + bs58@5.0.0: + dependencies: + base-x: 4.0.0 + bs58check@2.1.2: dependencies: bs58: 4.0.1 @@ -14750,7 +14847,7 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.7.4(@typescript-eslint/parser@5.54.0(eslint@8.34.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.6)(eslint-import-resolver-typescript@3.5.2(eslint-plugin-import@2.26.0)(eslint@8.34.0))(eslint@8.34.0): + eslint-module-utils@2.7.4(@typescript-eslint/parser@5.54.0(eslint@8.34.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.6)(eslint-import-resolver-typescript@3.5.2)(eslint@8.34.0): dependencies: debug: 3.2.7 optionalDependencies: @@ -14769,7 +14866,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.34.0 eslint-import-resolver-node: 0.3.6 - eslint-module-utils: 2.7.4(@typescript-eslint/parser@5.54.0(eslint@8.34.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.6)(eslint-import-resolver-typescript@3.5.2(eslint-plugin-import@2.26.0)(eslint@8.34.0))(eslint@8.34.0) + eslint-module-utils: 2.7.4(@typescript-eslint/parser@5.54.0(eslint@8.34.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.6)(eslint-import-resolver-typescript@3.5.2)(eslint@8.34.0) has: 1.0.3 is-core-module: 2.11.0 is-glob: 4.0.3 @@ -15294,7 +15391,7 @@ snapshots: dependencies: is-callable: 1.2.7 - forge-std@https://codeload.github.com/foundry-rs/forge-std/tar.gz/d3db4ef90a72b7d24aa5a2e5c649593eaef7801d: {} + forge-std@https://codeload.github.com/foundry-rs/forge-std/tar.gz/726a6ee5fc8427a0013d6f624e486c9130c0e336: {} form-data@2.3.3: dependencies: @@ -16369,6 +16466,10 @@ snapshots: dependencies: ws: 8.13.0(bufferutil@4.0.7)(utf-8-validate@5.0.10) + isows@1.0.4(ws@8.17.1(bufferutil@4.0.7)(utf-8-validate@5.0.10)): + dependencies: + ws: 8.17.1(bufferutil@4.0.7)(utf-8-validate@5.0.10) + isows@1.0.6(ws@8.18.0(bufferutil@4.0.7)(utf-8-validate@5.0.10)): dependencies: ws: 8.18.0(bufferutil@4.0.7)(utf-8-validate@5.0.10) @@ -17880,13 +17981,13 @@ snapshots: postcss: 8.4.24 ts-node: 10.9.1(@types/node@18.13.0)(typescript@5.5.4) - postcss-load-config@3.1.4(postcss@8.4.41)(ts-node@10.9.1(typescript@4.9.3)): + postcss-load-config@3.1.4(postcss@8.4.41)(ts-node@10.9.1(@types/node@18.13.0)(typescript@4.9.3)): dependencies: lilconfig: 2.0.6 yaml: 1.10.2 optionalDependencies: postcss: 8.4.41 - ts-node: 10.9.1(typescript@4.9.3) + ts-node: 10.9.1(@types/node@18.13.0)(typescript@4.9.3) postcss-value-parser@4.2.0: {} @@ -19096,7 +19197,7 @@ snapshots: ts-log@2.2.5: {} - ts-node@10.9.1(@types/node@18.13.0)(typescript@5.5.4): + ts-node@10.9.1(@types/node@18.13.0)(typescript@4.9.3): dependencies: '@cspotcode/source-map-support': 0.8.1 '@tsconfig/node10': 1.0.9 @@ -19110,27 +19211,28 @@ snapshots: create-require: 1.1.1 diff: 4.0.2 make-error: 1.3.6 - typescript: 5.5.4 + typescript: 4.9.3 v8-compile-cache-lib: 3.0.1 yn: 3.1.1 + optional: true - ts-node@10.9.1(typescript@4.9.3): + ts-node@10.9.1(@types/node@18.13.0)(typescript@5.5.4): dependencies: '@cspotcode/source-map-support': 0.8.1 '@tsconfig/node10': 1.0.9 '@tsconfig/node12': 1.0.11 '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.3 + '@types/node': 18.13.0 acorn: 8.8.2 acorn-walk: 8.2.0 arg: 4.1.3 create-require: 1.1.1 diff: 4.0.2 make-error: 1.3.6 - typescript: 4.9.3 + typescript: 5.5.4 v8-compile-cache-lib: 3.0.1 yn: 3.1.1 - optional: true tsconfig-paths@3.14.1: dependencies: @@ -19147,7 +19249,7 @@ snapshots: tslib@2.5.0: {} - tsup@6.6.2(postcss@8.4.41)(ts-node@10.9.1(typescript@4.9.3))(typescript@4.9.3): + tsup@6.6.2(postcss@8.4.41)(ts-node@10.9.1(@types/node@18.13.0)(typescript@4.9.3))(typescript@4.9.3): dependencies: bundle-require: 4.0.1(esbuild@0.17.8) cac: 6.7.14 @@ -19157,7 +19259,7 @@ snapshots: execa: 5.1.1 globby: 11.1.0 joycon: 3.1.1 - postcss-load-config: 3.1.4(postcss@8.4.41)(ts-node@10.9.1(typescript@4.9.3)) + postcss-load-config: 3.1.4(postcss@8.4.41)(ts-node@10.9.1(@types/node@18.13.0)(typescript@4.9.3)) resolve-from: 5.0.0 rollup: 3.15.0 source-map: 0.8.0-beta.0 @@ -19506,6 +19608,23 @@ snapshots: - utf-8-validate - zod + viem@2.17.0(bufferutil@4.0.7)(typescript@5.5.4)(utf-8-validate@5.0.10)(zod@3.23.8): + dependencies: + '@adraffy/ens-normalize': 1.10.0 + '@noble/curves': 1.4.0 + '@noble/hashes': 1.4.0 + '@scure/bip32': 1.4.0 + '@scure/bip39': 1.3.0 + abitype: 1.0.5(typescript@5.5.4)(zod@3.23.8) + isows: 1.0.4(ws@8.17.1(bufferutil@4.0.7)(utf-8-validate@5.0.10)) + ws: 8.17.1(bufferutil@4.0.7)(utf-8-validate@5.0.10) + optionalDependencies: + typescript: 5.5.4 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + - zod + viem@2.21.54(bufferutil@4.0.7)(typescript@5.5.4)(utf-8-validate@5.0.10)(zod@3.23.8): dependencies: '@noble/curves': 1.7.0 @@ -19584,7 +19703,7 @@ snapshots: fsevents: 2.3.3 terser: 5.16.3 - vitest@0.23.4(jsdom@20.0.3)(terser@5.16.3): + vitest@0.23.4(jsdom@20.0.3(bufferutil@4.0.7)(utf-8-validate@5.0.10))(terser@5.16.3): dependencies: '@types/chai': 4.3.4 '@types/chai-subset': 1.3.3 @@ -19895,6 +20014,11 @@ snapshots: bufferutil: 4.0.7 utf-8-validate: 5.0.10 + ws@8.17.1(bufferutil@4.0.7)(utf-8-validate@5.0.10): + optionalDependencies: + bufferutil: 4.0.7 + utf-8-validate: 5.0.10 + ws@8.18.0(bufferutil@4.0.7)(utf-8-validate@5.0.10): optionalDependencies: bufferutil: 4.0.7 From 2ed8d31db36f289f36f14bcda993bf636909ea33 Mon Sep 17 00:00:00 2001 From: dan13ram Date: Thu, 23 Jan 2025 18:43:50 +0530 Subject: [PATCH 26/28] added escrow milestones view for proposal --- .../DecodedTransactions.tsx | 239 ++++++-------- .../ProposalDescription/MilestoneDetails.tsx | 307 ++++++++++++++++++ .../ProposalDescription.tsx | 42 ++- .../useDecodedTransactions.tsx | 106 ++++++ apps/web/src/pages/api/decode.ts | 6 +- 5 files changed, 562 insertions(+), 138 deletions(-) create mode 100644 apps/web/src/modules/proposal/components/ProposalDescription/MilestoneDetails.tsx create mode 100644 apps/web/src/modules/proposal/components/ProposalDescription/useDecodedTransactions.tsx diff --git a/apps/web/src/modules/proposal/components/ProposalDescription/DecodedTransactions.tsx b/apps/web/src/modules/proposal/components/ProposalDescription/DecodedTransactions.tsx index 5c0c0779d..dbd50e8c9 100644 --- a/apps/web/src/modules/proposal/components/ProposalDescription/DecodedTransactions.tsx +++ b/apps/web/src/modules/proposal/components/ProposalDescription/DecodedTransactions.tsx @@ -1,162 +1,133 @@ import { Box, Flex, Stack, Text, atoms } from '@zoralabs/zord' -import axios from 'axios' +import { toLower } from 'lodash' +import { get } from 'lodash' import React, { Fragment } from 'react' -import useSWR from 'swr' -import { formatEther } from 'viem' +import { decodeAbiParameters, formatEther, parseAbiParameters } from 'viem' import { ETHERSCAN_BASE_URL } from 'src/constants/etherscan' -import SWR_KEYS from 'src/constants/swrKeys' +import { getEscrowBundler } from 'src/modules/create-proposal/components/TransactionForm/Escrow/EscrowUtils' import { useChainStore } from 'src/stores/useChainStore' -import { CHAIN_ID } from 'src/typings' import { walletSnippet } from 'src/utils/helpers' +import { DecodedTransaction } from './useDecodedTransactions' interface DecodedTransactionProps { - targets: string[] - calldatas: string[] - values: string[] + decodedTransactions: DecodedTransaction[] | undefined } + export const DecodedTransactions: React.FC = ({ - targets, - calldatas, - values, + decodedTransactions, }) => { const chain = useChainStore((x) => x.chain) - /* - - format in shape defined in ethers actor - - */ - const formatSendEth = (value: string) => { - const amount = formatEther(BigInt(value)) - return { - functionName: 'Transfer', - name: 'Transfer', - args: { - ['Transfer']: { name: `value`, value: `${amount} ETH` }, - }, - } - } - - const decodeTransaction = async ( - chainId: CHAIN_ID, - target: string, - calldata: string, - value: string - ) => { - /* if calldata is '0x' */ - const isTransfer = calldata === '0x' + const renderArgument = (arg: any) => { + if (arg?.name === '_escrowData') { + // Decode escrow data + const decodedAbiData = decodeAbiParameters( + parseAbiParameters([ + 'address client', + 'address resolver', + 'uint8 resolverType', + 'address token', + 'uint256 terminationTime', + 'bytes32 details', + 'address provider', + 'address providerReceiver', + 'bool requireVerification', + 'bytes32 escrowType', + ]), + arg.value + ) - if (isTransfer) { - return formatSendEth(value) + return ( + + client/signer: {get(decodedAbiData, '[0]', '')} + resolver: {get(decodedAbiData, '[1]', '')} + + Safety Valve Date:{' '} + {new Date(Number(get(decodedAbiData, '[4]', 0)) * 1000).toLocaleString()} + + Service Provider: {get(decodedAbiData, '[6]', '')} + + ) } - try { - const decoded = await axios.post('/api/decode', { - calldata: calldata, - contract: target, - chain: chainId, - }) - - if (decoded?.data?.statusCode) throw new Error('Decode failed') - - return decoded.data - } catch (err) { - console.log('err', err) - - // if this tx has value display it as a send eth tx - if (value.length && parseInt(value)) return formatSendEth(value) - - // if no value return original calldata - return calldata - } + return ( + + {arg?.name}:{' '} + {arg?.name === '_milestoneAmounts' + ? arg.value + .split(',') + .map((amt: string) => `${formatEther(BigInt(amt))} ETH`) + .join(', ') + : arg?.name === '_fundAmount' + ? formatEther(BigInt(arg?.value)) + ' ETH' + : arg?.value} + + ) } - const { data: decodedTransactions } = useSWR( - targets && calldatas && values - ? [SWR_KEYS.PROPOSALS_TRANSACTIONS, targets, calldatas, values] - : null, - async (_, targets, calldatas, values) => { - return await Promise.all( - targets.map(async (target, i) => { - const transaction = await decodeTransaction( - chain.id, - target, - calldatas[i], - values[i] - ) - - return { - target, - transaction, - isNotDecoded: transaction === calldatas[i], - } - }) - ) - }, - { revalidateOnFocus: false } - ) - return (
    - {decodedTransactions?.map((decoded, i) => ( - - {decoded.isNotDecoded ? ( -
  1. {decoded.transaction}
  2. - ) : ( -
  3. - - - - { + const isEscrow = toLower(decoded.target).includes(toLower(getEscrowBundler(chain.id))) + + return ( + + {decoded.isNotDecoded ? ( +
  4. {decoded.transaction.toString()}
  5. + ) : ( +
  6. + + + - - {walletSnippet(decoded?.target)} - - - {decoded?.target} - - - - - {`.${decoded?.transaction?.functionName}(`} - {!decoded?.transaction?.args && - !decoded.transaction.decoded.length && + + + {walletSnippet(decoded?.target)} + + + {decoded?.target} + + + + + {`.${!isEscrow ? decoded?.transaction?.functionName : 'deployEscrow' + }(`} + {!decoded?.transaction?.args && + !decoded.transaction?.decoded?.length && + `)`} + + + + {(decoded?.transaction?.args && + Object?.values(decoded?.transaction?.args).map((arg: any) => + renderArgument(arg) + )) || + (decoded?.transaction?.decoded && + decoded?.transaction?.decoded?.map((arg: any) => ( + {arg} + )))} + + + {(!!decoded?.transaction?.args || + !!decoded?.transaction?.decoded?.length) && `)`} - - - {(decoded?.transaction?.args && - Object?.values(decoded?.transaction?.args).map((arg: any) => ( - // if verified contract and arguments object {name, value} - - {arg?.name}: {arg?.value} - - ))) || - // if unverified contract and arguments array [value] - (decoded?.transaction?.decoded && - decoded?.transaction?.decoded?.map((arg: any) => ( - {arg} - )))} - {(!!decoded?.transaction?.args || - !!decoded?.transaction.decoded.length) && - `)`} - -
  7. - )} -
    - ))} + + )} + + ); + })}
) diff --git a/apps/web/src/modules/proposal/components/ProposalDescription/MilestoneDetails.tsx b/apps/web/src/modules/proposal/components/ProposalDescription/MilestoneDetails.tsx new file mode 100644 index 000000000..e771940ec --- /dev/null +++ b/apps/web/src/modules/proposal/components/ProposalDescription/MilestoneDetails.tsx @@ -0,0 +1,307 @@ +import { Button, Stack, Text } from '@zoralabs/zord' +import axios from 'axios' +import { IPFS_GATEWAY } from 'ipfs-service/src/gateway' +import _ from 'lodash' +import { useRouter } from 'next/router' +import { useCallback, useEffect, useMemo, useState } from 'react' +import useSWR from 'swr' +import { + Hex, + decodeAbiParameters, + encodeFunctionData, + formatEther, + isAddressEqual, + parseAbiParameters, +} from 'viem' +import { useContractRead } from 'wagmi' + +import Accordion from 'src/components/Home/accordian' +import { Icon } from 'src/components/Icon' +import { OptionalLink } from 'src/components/OptionalLink' +import SWR_KEYS from 'src/constants/swrKeys' +import { TransactionType } from 'src/modules/create-proposal' +import { IpfsMilestone } from 'src/modules/create-proposal/components/TransactionForm/Escrow/EscrowForm.schema' +import { convertByte32ToIpfsCidV0 } from 'src/modules/create-proposal/components/TransactionForm/Escrow/EscrowUtils' +import { useProposalStore } from 'src/modules/create-proposal/stores' +import { useDaoStore } from 'src/modules/dao' +import { useChainStore } from 'src/stores/useChainStore' +import { AddressType } from 'src/typings' + +import { DecodedTransactionData } from './useDecodedTransactions' + +type DecodedTransactionArgs = DecodedTransactionData['args'] + +const RELEASE_FUNCTION_ABI = [ + { + inputs: [{ internalType: 'uint256', name: '_milestone', type: 'uint256' }], + name: 'release', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, +] + +const SAFE_APP_URL = + 'https://app.safe.global/share/safe-app?appUrl=https://app.smartinvoice.xyz/invoices' + +const INVOICE_QUERY = ` + query GetInvoice($txHash: String!) { + invoices(where: { + creationTxHash: $txHash + }) { + address + id + createdAt + network + creationTxHash + } + } +` + +interface MilestoneDetailsProps { + decodedTxnArgs: DecodedTransactionArgs + executionTransactionHash?: string +} + +interface Document { + type: string + src: string +} + +const useNetworkConfig = () => { + const [networkConfig, setNetworkConfig] = useState(null) + const [isLoading, setIsLoading] = useState(true) + const [error, setError] = useState(null) + + useEffect(() => { + const loadNetworkConfig = async () => { + try { + const { NETWORK_CONFIG } = await import('@smartinvoicexyz/constants') + setNetworkConfig(NETWORK_CONFIG) + } catch (err) { + setError(err as Error) + } finally { + setIsLoading(false) + } + } + loadNetworkConfig() + }, []) + + return { networkConfig, isLoading, error } +} + +export const MilestoneDetails = ({ + decodedTxnArgs, + executionTransactionHash, +}: MilestoneDetailsProps) => { + const router = useRouter() + const { chain: invoiceChain } = useChainStore() + const { addresses } = useDaoStore() + const { addTransaction } = useProposalStore() + const { networkConfig, isLoading, error: networkConfigError } = useNetworkConfig() + + const subgraphURL = useMemo(() => { + return networkConfig?.[invoiceChain.id]?.SUBGRAPH + }, [networkConfig, invoiceChain.id]) + + const { data: INVOICE_ADDRESS } = useSWR( + [subgraphURL, executionTransactionHash], + async () => { + const response = await axios.post(subgraphURL, { + query: INVOICE_QUERY, + variables: { + txHash: executionTransactionHash, + }, + }) + + return _.get(response, 'data.data.invoices[0].address') + } + ) + + const { invoiceCid, clientAddress, milestoneAmount } = useMemo(() => { + const decodedAbiData = decodeAbiParameters( + parseAbiParameters([ + 'address client', + 'address resolver', + 'uint8 resolverType', + 'address token', + 'uint256 terminationTime', + 'bytes32 details', + 'address provider', + 'address providerReceiver', + 'bool requireVerification', + 'bytes32 escrowType', + ]), + decodedTxnArgs?._escrowData?.value as Hex + ) + + return { + invoiceCid: convertByte32ToIpfsCidV0((decodedAbiData as never)?.[5]), + clientAddress: (decodedAbiData as never)?.[0], + milestoneAmount: decodedTxnArgs['_milestoneAmounts']['value'] + .split(',') + .map((x: string) => formatEther(BigInt(x))), + } + }, [decodedTxnArgs]) + + const { data: invoiceData } = useSWR( + invoiceCid ? [SWR_KEYS.IPFS, invoiceCid] : null, + async () => { + try { + const response = await axios.get(`https://ipfs.io/ipfs/${invoiceCid}`) + return response.data + } catch (error) { + console.error('Failed to fetch invoice data:', error) + return null + } + } + ) + + const { data: numOfMilestonesReleased } = useContractRead({ + address: INVOICE_ADDRESS, + abi: [ + { + inputs: [], + name: 'released', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'view', + type: 'function', + }, + ], + functionName: 'released', + chainId: invoiceChain.id, + }) + + const handleReleaseMilestone = useCallback( + async (index: number) => { + const isClientGoverner = isAddressEqual( + clientAddress as AddressType, + addresses.governor as AddressType + ) + const isClientTreasury = isAddressEqual( + clientAddress as AddressType, + addresses.treasury as AddressType + ) + + if (!isClientGoverner && !isClientTreasury) { + router.replace(SAFE_APP_URL) + return + } + + const releaseMilestone = { + target: INVOICE_ADDRESS as AddressType, + functionSignature: 'release(_milestone)', + calldata: encodeFunctionData({ + abi: RELEASE_FUNCTION_ABI, + functionName: 'release', + args: [index], + }), + value: '', + } + + const releaseEscrowTxnData = { + type: TransactionType.RELEASE_ESCROW_MILESTONE, + summary: `Release Milestone #${index + 1} for ${invoiceData?.title}`, + transactions: [releaseMilestone], + } + + setTimeout(() => addTransaction(releaseEscrowTxnData), 3000) + + router.push({ + pathname: `/dao/[network]/[token]/proposal/review`, + query: { + network: router.query?.network, + token: router.query?.token, + }, + }) + }, + [router, clientAddress, addresses, addTransaction, invoiceData?.title] + ) + + const renderMilestoneButton = useCallback( + (index: number, isReleased: boolean, isNext: boolean) => { + if (isReleased) { + return ( + + ) + } + + return ( + + ) + }, + [handleReleaseMilestone] + ) + + const renderDocumentLink = useCallback((doc: Partial) => { + if (!doc.src) return null + + const href = + doc.type === 'ipfs' ? doc.src.replace('ipfs://', `${IPFS_GATEWAY}/ipfs/`) : doc.src + + return ( + + {href} + + ) + }, []) + + const milestonesDetails = useMemo(() => { + return invoiceData?.milestones?.map((milestone: IpfsMilestone, index: number) => { + const releasedCount = Number(numOfMilestonesReleased?.toString() || 0) + const isReleased = releasedCount - 1 >= index + const isNext = releasedCount === index + + return { + title: {`${index + 1}. ${milestone.title}`}, + description: ( + + + + {`Amount: ${milestoneAmount[index]} ETH`} + + + {`Due by: ${new Date( + (milestone?.endDate as number) * 1000 + ).toLocaleDateString()}`} + + + + {milestone.description || 'No Description'} + + {milestone.documents?.map((doc, i) => renderDocumentLink(doc))} + + {!!executionTransactionHash && + renderMilestoneButton(index, isReleased, isNext)} + + ), + } + }) + }, [ + invoiceData?.milestones, + numOfMilestonesReleased, + milestoneAmount, + executionTransactionHash, + renderMilestoneButton, + renderDocumentLink, + ]) + + if (isLoading) { + return
Loading network configuration...
+ } + + if (networkConfigError) { + return
Error loading network configuration
+ } + + return +} diff --git a/apps/web/src/modules/proposal/components/ProposalDescription/ProposalDescription.tsx b/apps/web/src/modules/proposal/components/ProposalDescription/ProposalDescription.tsx index 9e24d4504..fc3a727f9 100644 --- a/apps/web/src/modules/proposal/components/ProposalDescription/ProposalDescription.tsx +++ b/apps/web/src/modules/proposal/components/ProposalDescription/ProposalDescription.tsx @@ -1,5 +1,7 @@ -import { Box, Flex, Paragraph, atoms } from '@zoralabs/zord' +import { Box, Flex, Paragraph, Text, atoms } from '@zoralabs/zord' +import { toLower } from 'lodash' import Image from 'next/image' +import { Suspense } from 'react' import React, { ReactNode } from 'react' import ReactMarkdown from 'react-markdown' import rehypeRaw from 'rehype-raw' @@ -12,11 +14,14 @@ import { SDK } from 'src/data/subgraph/client' import { Proposal } from 'src/data/subgraph/requests/proposalQuery' import { OrderDirection, Token_OrderBy } from 'src/data/subgraph/sdk.generated' import { useEnsData } from 'src/hooks/useEnsData' +import { getEscrowBundler } from 'src/modules/create-proposal/components/TransactionForm/Escrow/EscrowUtils' import { useChainStore } from 'src/stores/useChainStore' import { propPageWrapper } from 'src/styles/Proposals.css' import { DecodedTransactions } from './DecodedTransactions' +import { MilestoneDetails } from './MilestoneDetails' import { proposalDescription } from './ProposalDescription.css' +import { useDecodedTransactions } from './useDecodedTransactions'; const Section = ({ children, title }: { children: ReactNode; title: string }) => ( @@ -36,10 +41,22 @@ export const ProposalDescription: React.FC = ({ proposal, collection, }) => { - const { description, proposer, calldatas, values, targets } = proposal + const { description, proposer, calldatas, values, targets, executionTransactionHash } = + proposal + const { displayName } = useEnsData(proposer) const chain = useChainStore((x) => x.chain) + const decodedTransactions = useDecodedTransactions( + targets, + calldatas, + values); + + const escrowIndex = targets.findIndex(t => t === toLower(getEscrowBundler(chain.id))) + const decodedEscrowTransaction = escrowIndex !== -1 && decodedTransactions ? decodedTransactions[escrowIndex] : undefined + const decodedEscrowData = !!decodedEscrowTransaction && !decodedEscrowTransaction.isNotDecoded ? decodedEscrowTransaction.transaction : undefined + const decodedTxnArgs = !!decodedEscrowData ? decodedEscrowData.args : undefined + const { data: tokenImage, error } = useSWR( !!collection && !!proposer ? [SWR_KEYS.TOKEN_IMAGE, chain.id, collection, proposer] @@ -59,6 +76,23 @@ export const ProposalDescription: React.FC = ({ return ( + {!!decodedEscrowData && ( +
+ Loading escrow milestones...}> + {decodedTxnArgs?._escrowData?.value ? ( + + ) : ( + + Error Decoding Escrow Milestones + + )} + +
+ )} +
{description && ( @@ -100,7 +134,9 @@ export const ProposalDescription: React.FC = ({
- +
diff --git a/apps/web/src/modules/proposal/components/ProposalDescription/useDecodedTransactions.tsx b/apps/web/src/modules/proposal/components/ProposalDescription/useDecodedTransactions.tsx new file mode 100644 index 000000000..88816cfa0 --- /dev/null +++ b/apps/web/src/modules/proposal/components/ProposalDescription/useDecodedTransactions.tsx @@ -0,0 +1,106 @@ +import axios from 'axios' +import useSWR from 'swr' +import { formatEther } from 'viem' + +import SWR_KEYS from 'src/constants/swrKeys' +import { useChainStore } from 'src/stores/useChainStore' +import { CHAIN_ID } from 'src/typings' + +type Argument = { name: string; value: string, type: string } + +export type DecodedTransactionData = { + functionName: string + args: { [key: string]: Argument } + decoded?: string[] | undefined +} + +type DecodedTransactionSuccess = { + target: string + transaction: DecodedTransactionData + isNotDecoded: false +} + +type DecodedTransactionFailure = { + target: string + transaction: string + isNotDecoded: true +} + +export type DecodedTransaction = DecodedTransactionSuccess | DecodedTransactionFailure + +export const useDecodedTransactions = ( + targets: string[], + calldatas: string[], + values: string[] +): DecodedTransaction[] | undefined => { + const chain = useChainStore((x) => x.chain) + + /* format in shape defined in ethers actor */ + const formatSendEth = (value: string) => { + const amount = formatEther(BigInt(value)) + return { + functionName: 'Transfer', + args: { + ['Transfer']: { name: `value`, value: `${amount} ETH`, type: `uint256` }, + }, + } + } + + const decodeTransaction = async ( + chainId: CHAIN_ID, + target: string, + calldata: string, + value: string + ): Promise => { + /* if calldata is '0x' */ + const isTransfer = calldata === '0x' + + if (isTransfer) { + return formatSendEth(value) + } + + try { + const decoded = await axios.post('/api/decode', { + calldata: calldata, + contract: target, + chain: chainId, + }) + + if (decoded?.data?.statusCode) throw new Error('Decode failed') + + return decoded.data + } catch (err) { + console.log('err', err) + + // if this tx has value display it as a send eth tx + if (value.length && parseInt(value)) return formatSendEth(value) + + // if no value return original calldata + return calldata + } + } + + const { data: decodedTransactions } = useSWR( + targets && calldatas && values + ? [SWR_KEYS.PROPOSALS_TRANSACTIONS, targets, calldatas, values] + : null, + async (_, targets, calldatas, values) => { + return await Promise.all( + targets.map(async (target, i) => { + const transaction = await decodeTransaction( + chain.id, + target, + calldatas[i], + values[i] + ) + + if (typeof transaction === 'string') return { target, transaction, isNotDecoded: true } as DecodedTransactionFailure + return { target, transaction, isNotDecoded: false } as DecodedTransactionSuccess + }) + ) + }, + { revalidateOnFocus: false } + ) + + return decodedTransactions +} diff --git a/apps/web/src/pages/api/decode.ts b/apps/web/src/pages/api/decode.ts index d580067fd..d69c23ee7 100644 --- a/apps/web/src/pages/api/decode.ts +++ b/apps/web/src/pages/api/decode.ts @@ -21,9 +21,13 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) const decodeResult = decodeFunctionData({ abi: JSON.parse(abi), data: calldata }) const functionInfo = getAbiItem({ abi: JSON.parse(abi), - name: decodeResult.functionName, + name: + decodeResult.functionName !== 'release' + ? decodeResult.functionName + : '0x37bdc99b', // manually set function signature for release(_milestone) instead of release() }) + const argMapping = functionInfo.inputs.reduce( (last: any, input: any, index: number) => { last[input.name] = { From a558a2446e54b0016cd6eeafc35b375773caca42 Mon Sep 17 00:00:00 2001 From: Sayo <82053242+wtfsayo@users.noreply.github.com> Date: Wed, 25 Sep 2024 13:05:59 +0530 Subject: [PATCH 27/28] added support for escrow delegate --- .../data/contract/requests/getDAOAddresses.ts | 4 + .../contract/requests/getEscrowDelegate.ts | 123 ++++++++++++++++++ .../TransactionForm/Escrow/EscrowForm.tsx | 40 +++--- .../constants/transactionType.tsx | 1 + .../modules/dao/components/SmartContracts.tsx | 3 + .../web/src/modules/dao/stores/useDaoStore.ts | 2 + .../pages/dao/[network]/[token]/[tokenId].tsx | 7 + .../pages/dao/[network]/[token]/vote/[id].tsx | 7 + 8 files changed, 168 insertions(+), 19 deletions(-) create mode 100644 apps/web/src/data/contract/requests/getEscrowDelegate.ts diff --git a/apps/web/src/data/contract/requests/getDAOAddresses.ts b/apps/web/src/data/contract/requests/getDAOAddresses.ts index c0a850cfd..af1c98f0a 100644 --- a/apps/web/src/data/contract/requests/getDAOAddresses.ts +++ b/apps/web/src/data/contract/requests/getDAOAddresses.ts @@ -5,6 +5,7 @@ import { AddressType, CHAIN_ID } from 'src/typings' import { unpackOptionalArray } from 'src/utils/helpers' import { managerAbi } from '../abis' +import { getEscrowDelegate } from './getEscrowDelegate' const getDAOAddresses = async (chainId: CHAIN_ID, tokenAddress: AddressType) => { const addresses = await readContract({ @@ -17,6 +18,8 @@ const getDAOAddresses = async (chainId: CHAIN_ID, tokenAddress: AddressType) => const [metadata, auction, treasury, governor] = unpackOptionalArray(addresses, 4) + const escrowDelegate = await getEscrowDelegate(treasury as AddressType, chainId) + const hasMissingAddresses = Object.values(addresses).includes(NULL_ADDRESS) if (hasMissingAddresses) return null @@ -26,6 +29,7 @@ const getDAOAddresses = async (chainId: CHAIN_ID, tokenAddress: AddressType) => governor, metadata, treasury, + escrowDelegate, } } diff --git a/apps/web/src/data/contract/requests/getEscrowDelegate.ts b/apps/web/src/data/contract/requests/getEscrowDelegate.ts new file mode 100644 index 000000000..73d695e6c --- /dev/null +++ b/apps/web/src/data/contract/requests/getEscrowDelegate.ts @@ -0,0 +1,123 @@ +import axios from 'axios' +import { checksumAddress, isAddress } from 'viem' + +import { CHAIN_ID } from 'src/typings' + +interface AttestationResponse { + data: { + attestations: Array<{ + attester: string + recipient: string + decodedDataJson: string + }> + } +} + +interface DecodedData { + name: string + type: string + value: { + type: string + value: string + } +} + +const ATTESTATION_SCHEMA_UID = `0x1289c5f988998891af7416d83820c40ba1c6f5ba31467f2e611172334dc53a0e` +const SMART_INVOICE_MULTISIG = `0x503a5161D1c5D9d82BF35a4c80DA0C3Ad72d9244` // TODO: replace with actual multisig address +const BUILDER_DAO_TREASURY = `0xcf325a4c78912216249b818521b0798a0f904c10` +const BUILDER_DAO_OPS_MULTISIG = `0x58eAEfBEd9EEFbC564E302D0AfAE0B113E42eAb3` + +const ATTESTATION_URL: Record = { + [CHAIN_ID.ETHEREUM]: 'https://easscan.org/graphql', + [CHAIN_ID.OPTIMISM]: 'https://optimism.easscan.org/graphql', + [CHAIN_ID.SEPOLIA]: 'https://sepolia.easscan.org/graphql', + [CHAIN_ID.OPTIMISM_SEPOLIA]: 'https://optimism-sepolia.easscan.org/graphql', + [CHAIN_ID.BASE]: 'https://base.easscan.org/graphql', + [CHAIN_ID.BASE_SEPOLIA]: 'https://base-sepolia.easscan.org/graphql', + [CHAIN_ID.ZORA]: '', + [CHAIN_ID.ZORA_SEPOLIA]: '', + [CHAIN_ID.FOUNDRY]: '', +} + +export async function getEscrowDelegate( + daoTreasuryAddress: string, + chainId: CHAIN_ID +): Promise { + // Input validation + if (!daoTreasuryAddress || !isAddress(daoTreasuryAddress)) { + return null + } + + const attestationUrl = ATTESTATION_URL[chainId] + if (!attestationUrl) { + return null + } + + const attestationIssuerPriorityOrder = [ + checksumAddress(daoTreasuryAddress), + checksumAddress(BUILDER_DAO_TREASURY), + checksumAddress(BUILDER_DAO_OPS_MULTISIG), + checksumAddress(SMART_INVOICE_MULTISIG), + ] + + const query = ` + query Attestations { + attestations( + where: { + schemaId: { equals: "${ATTESTATION_SCHEMA_UID}" } + attester: { in: ["${attestationIssuerPriorityOrder.join('","')}"] } + recipient: { equals: "${checksumAddress(daoTreasuryAddress)}" } + } + ) { + attester + recipient + decodedDataJson + } + } +` + + try { + const response = await axios.post( + attestationUrl, + { query }, + { + headers: { + 'Content-Type': 'application/json', + }, + } + ) + + const attestations = response?.data?.data?.attestations + + // Sort attestations based on priority order + const sortedAttestations = attestations.sort((a, b) => { + const indexA = attestationIssuerPriorityOrder.indexOf(a.attester as `0x${string}`) + const indexB = attestationIssuerPriorityOrder.indexOf(b.attester as `0x${string}`) + return indexA - indexB + }) + + if (!attestations?.length) { + return null + } + + try { + // Get the first attestation from priority + const decodedData = JSON.parse( + sortedAttestations[0].decodedDataJson + ) as DecodedData[] + + const escrowDelegateAddress = decodedData[0]?.value?.value + if (!escrowDelegateAddress || !isAddress(escrowDelegateAddress)) { + return null + } + + return escrowDelegateAddress + } catch (parseError) { + console.error('Error parsing attestation data:', parseError) + return null + } + } catch (error) { + console.error('Error fetching attestations:', error) + return null + } +} diff --git a/apps/web/src/modules/create-proposal/components/TransactionForm/Escrow/EscrowForm.tsx b/apps/web/src/modules/create-proposal/components/TransactionForm/Escrow/EscrowForm.tsx index 0289ac486..b19678752 100644 --- a/apps/web/src/modules/create-proposal/components/TransactionForm/Escrow/EscrowForm.tsx +++ b/apps/web/src/modules/create-proposal/components/TransactionForm/Escrow/EscrowForm.tsx @@ -119,7 +119,7 @@ const EscrowForm: React.FC = ({ const { formValues, setFormValues } = useEscrowFormStore() const { - addresses: { treasury }, + addresses: { escrowDelegate, treasury }, } = useDaoStore() const handleSubmit = useCallback( @@ -156,7 +156,7 @@ const EscrowForm: React.FC = ({ = ({ 'The wallet address to which funds will be released on milestone completions.' } /> - + {!escrowDelegate && ( + + )} { + {addresses?.escrowDelegate && ( + + )}
diff --git a/apps/web/src/modules/dao/stores/useDaoStore.ts b/apps/web/src/modules/dao/stores/useDaoStore.ts index 5d7b32428..dd82b9d7a 100644 --- a/apps/web/src/modules/dao/stores/useDaoStore.ts +++ b/apps/web/src/modules/dao/stores/useDaoStore.ts @@ -16,6 +16,7 @@ export interface DaoContractAddresses { auction?: AddressType treasury?: AddressType governor?: AddressType + escrowDelegate?: AddressType } export interface DaoContracts { @@ -38,6 +39,7 @@ export const useDaoStore = create((set) => ({ auction: undefined, treasury: undefined, governor: undefined, + escrowDelegate: undefined, }, setAddresses: (addresses: DaoContractAddresses) => set({ addresses }), })) diff --git a/apps/web/src/pages/dao/[network]/[token]/[tokenId].tsx b/apps/web/src/pages/dao/[network]/[token]/[tokenId].tsx index 1c761ebbb..5e03f19f6 100644 --- a/apps/web/src/pages/dao/[network]/[token]/[tokenId].tsx +++ b/apps/web/src/pages/dao/[network]/[token]/[tokenId].tsx @@ -11,6 +11,7 @@ import { CACHE_TIMES } from 'src/constants/cacheTimes' import { PUBLIC_ALL_CHAINS, PUBLIC_DEFAULT_CHAINS } from 'src/constants/defaultChains' import { CAST_ENABLED } from 'src/constants/farcasterEnabled' import { SUCCESS_MESSAGES } from 'src/constants/messages' +import { getEscrowDelegate } from 'src/data/contract/requests/getEscrowDelegate' import { SDK } from 'src/data/subgraph/client' import { TokenWithDaoQuery } from 'src/data/subgraph/sdk.generated' import { useVotes } from 'src/hooks' @@ -212,12 +213,18 @@ export const getServerSideProps: GetServerSideProps = async ({ auctionAddress, } = token.dao + const escrowDelegateAddress = (await getEscrowDelegate( + treasuryAddress, + chain.id + )) as AddressType + const addresses: DaoContractAddresses = { token: collection, metadata: metadataAddress, treasury: treasuryAddress, governor: governorAddress, auction: auctionAddress, + escrowDelegate: escrowDelegateAddress, } const daoOgMetadata: DaoOgMetadata = { diff --git a/apps/web/src/pages/dao/[network]/[token]/vote/[id].tsx b/apps/web/src/pages/dao/[network]/[token]/vote/[id].tsx index a5c0176a6..2049c42e8 100644 --- a/apps/web/src/pages/dao/[network]/[token]/vote/[id].tsx +++ b/apps/web/src/pages/dao/[network]/[token]/vote/[id].tsx @@ -11,6 +11,7 @@ import { Meta } from 'src/components/Meta' import { CACHE_TIMES } from 'src/constants/cacheTimes' import { PUBLIC_DEFAULT_CHAINS } from 'src/constants/defaultChains' import SWR_KEYS from 'src/constants/swrKeys' +import { getEscrowDelegate } from 'src/data/contract/requests/getEscrowDelegate' import { SDK } from 'src/data/subgraph/client' import { formatAndFetchState, @@ -211,6 +212,11 @@ export const getServerSideProps: GetServerSideProps = async ({ params, req, res auctionAddress, } = data.dao + const escrowDelegateAddress = (await getEscrowDelegate( + treasuryAddress, + chain.id + )) as AddressType + const ogMetadata: ProposalOgMetadata = { proposal: { proposalNumber: proposal.proposalNumber, @@ -230,6 +236,7 @@ export const getServerSideProps: GetServerSideProps = async ({ params, req, res governor: governorAddress, treasury: treasuryAddress, auction: auctionAddress, + escrowDelegate: escrowDelegateAddress, } const ogImageURL = `${protocol}://${ From 8a554955790997058705508bec62e8fe248192d5 Mon Sep 17 00:00:00 2001 From: dan13ram Date: Thu, 23 Jan 2025 19:27:44 +0530 Subject: [PATCH 28/28] reset rpc for old envs --- apps/web/src/constants/rpc.ts | 17 +++++++++++------ turbo.json | 1 + 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/apps/web/src/constants/rpc.ts b/apps/web/src/constants/rpc.ts index d7158b7fe..1231b5935 100644 --- a/apps/web/src/constants/rpc.ts +++ b/apps/web/src/constants/rpc.ts @@ -2,11 +2,16 @@ import { foundry } from 'wagmi/chains' import { CHAIN_ID } from 'src/typings' -export const RPC_URL: Record = { - [CHAIN_ID.ETHEREUM]: `https://mainnet.gateway.tenderly.co/${process.env.NEXT_PUBLIC_TENDERLY_MAINNET_RPC_KEY}`, - [CHAIN_ID.OPTIMISM]: `https://optimism.gateway.tenderly.co/${process.env.NEXT_PUBLIC_TENDERLY_OPTIMISM_RPC_KEY}`, - [CHAIN_ID.SEPOLIA]: `https://sepolia.gateway.tenderly.co/${process.env.NEXT_PUBLIC_TENDERLY_SEPOLIA_RPC_KEY}`, - [CHAIN_ID.BASE]: `https://base.gateway.tenderly.co/${process.env.NEXT_PUBLIC_TENDERLY_BASE_RPC_KEY}`, - [CHAIN_ID.ZORA]: `https://rpc-zora-mainnet-0.t.conduit.xyz/${process.env.NEXT_PUBLIC_ZORA_CONDUIT_RPC_KEY}`, +const TENDERLY_RPC_KEY = process.env.NEXT_PUBLIC_TENDERLY_RPC_KEY ?? '' + +export const RPC_URL = { + [CHAIN_ID.ETHEREUM]: `https://mainnet.gateway.tenderly.co/${TENDERLY_RPC_KEY}`, + [CHAIN_ID.OPTIMISM]: `https://optimism.gateway.tenderly.co/${TENDERLY_RPC_KEY}`, + [CHAIN_ID.SEPOLIA]: `https://sepolia.gateway.tenderly.co/${TENDERLY_RPC_KEY}`, + [CHAIN_ID.OPTIMISM_SEPOLIA]: `https://optimism-sepolia.gateway.tenderly.co/${TENDERLY_RPC_KEY}`, + [CHAIN_ID.BASE]: `https://base.gateway.tenderly.co/${TENDERLY_RPC_KEY}`, + [CHAIN_ID.BASE_SEPOLIA]: `https://base-sepolia.gateway.tenderly.co/${TENDERLY_RPC_KEY}`, + [CHAIN_ID.ZORA]: 'https://rpc.zora.energy', + [CHAIN_ID.ZORA_SEPOLIA]: 'https://sepolia.rpc.zora.energy', [CHAIN_ID.FOUNDRY]: foundry.rpcUrls.default.http[0], } diff --git a/turbo.json b/turbo.json index e043f4525..5d39625ba 100644 --- a/turbo.json +++ b/turbo.json @@ -39,6 +39,7 @@ "NEXT_PUBLIC_ZORA_API_KEY", "NEXT_PUBLIC_NETWORK_TYPE", "NEXT_PUBLIC_VERCEL_ENV", + "NEXT_PUBLIC_TENDERLY_RPC_KEY", "NEXT_PUBLIC_TENDERLY_MAINNET_RPC_KEY", "NEXT_PUBLIC_TENDERLY_BASE_RPC_KEY", "NEXT_PUBLIC_TENDERLY_OPTIMISM_RPC_KEY",