From d91cf721baae43171a98abe17ba70ca32827f00e Mon Sep 17 00:00:00 2001
From: Matthew Bunday
Date: Wed, 30 Oct 2024 12:48:30 -0400
Subject: [PATCH 1/8] Upgrade next (#1179)
---
apps/web/package.json | 2 +-
yarn.lock | 132 +++++++++++++++++++++++++++++++++++++++++-
2 files changed, 131 insertions(+), 3 deletions(-)
diff --git a/apps/web/package.json b/apps/web/package.json
index 7f567ff333c..d94f6f6d682 100644
--- a/apps/web/package.json
+++ b/apps/web/package.json
@@ -55,7 +55,7 @@
"jsdom": "^25.0.0",
"jsonwebtoken": "^9.0.2",
"kysely": "^0.27.3",
- "next": "^14.2.5",
+ "next": "^14.2.16",
"node-fetch": "^3.3.0",
"permissionless": "^0.1.41",
"pg": "^8.12.0",
diff --git a/yarn.lock b/yarn.lock
index 8b4d622b26d..1ed09680cfa 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -414,7 +414,7 @@ __metadata:
jsdom: ^25.0.0
jsonwebtoken: ^9.0.2
kysely: ^0.27.3
- next: ^14.2.5
+ next: ^14.2.16
node-fetch: ^3.3.0
permissionless: ^0.1.41
pg: ^8.12.0
@@ -5311,6 +5311,13 @@ __metadata:
languageName: node
linkType: hard
+"@next/env@npm:14.2.16":
+ version: 14.2.16
+ resolution: "@next/env@npm:14.2.16"
+ checksum: a81d98802fc0268ab1a042c9dba1db114db6bfff8d0054d3fa3d45322c19ff77713c3e46226e0c9231c706e760ba4ede483a3261e8a0e30f3806817349324f01
+ languageName: node
+ linkType: hard
+
"@next/env@npm:14.2.5":
version: 14.2.5
resolution: "@next/env@npm:14.2.5"
@@ -5364,6 +5371,13 @@ __metadata:
languageName: node
linkType: hard
+"@next/swc-darwin-arm64@npm:14.2.16":
+ version: 14.2.16
+ resolution: "@next/swc-darwin-arm64@npm:14.2.16"
+ conditions: os=darwin & cpu=arm64
+ languageName: node
+ linkType: hard
+
"@next/swc-darwin-arm64@npm:14.2.5":
version: 14.2.5
resolution: "@next/swc-darwin-arm64@npm:14.2.5"
@@ -5385,6 +5399,13 @@ __metadata:
languageName: node
linkType: hard
+"@next/swc-darwin-x64@npm:14.2.16":
+ version: 14.2.16
+ resolution: "@next/swc-darwin-x64@npm:14.2.16"
+ conditions: os=darwin & cpu=x64
+ languageName: node
+ linkType: hard
+
"@next/swc-darwin-x64@npm:14.2.5":
version: 14.2.5
resolution: "@next/swc-darwin-x64@npm:14.2.5"
@@ -5420,6 +5441,13 @@ __metadata:
languageName: node
linkType: hard
+"@next/swc-linux-arm64-gnu@npm:14.2.16":
+ version: 14.2.16
+ resolution: "@next/swc-linux-arm64-gnu@npm:14.2.16"
+ conditions: os=linux & cpu=arm64 & libc=glibc
+ languageName: node
+ linkType: hard
+
"@next/swc-linux-arm64-gnu@npm:14.2.5":
version: 14.2.5
resolution: "@next/swc-linux-arm64-gnu@npm:14.2.5"
@@ -5441,6 +5469,13 @@ __metadata:
languageName: node
linkType: hard
+"@next/swc-linux-arm64-musl@npm:14.2.16":
+ version: 14.2.16
+ resolution: "@next/swc-linux-arm64-musl@npm:14.2.16"
+ conditions: os=linux & cpu=arm64 & libc=musl
+ languageName: node
+ linkType: hard
+
"@next/swc-linux-arm64-musl@npm:14.2.5":
version: 14.2.5
resolution: "@next/swc-linux-arm64-musl@npm:14.2.5"
@@ -5462,6 +5497,13 @@ __metadata:
languageName: node
linkType: hard
+"@next/swc-linux-x64-gnu@npm:14.2.16":
+ version: 14.2.16
+ resolution: "@next/swc-linux-x64-gnu@npm:14.2.16"
+ conditions: os=linux & cpu=x64 & libc=glibc
+ languageName: node
+ linkType: hard
+
"@next/swc-linux-x64-gnu@npm:14.2.5":
version: 14.2.5
resolution: "@next/swc-linux-x64-gnu@npm:14.2.5"
@@ -5483,6 +5525,13 @@ __metadata:
languageName: node
linkType: hard
+"@next/swc-linux-x64-musl@npm:14.2.16":
+ version: 14.2.16
+ resolution: "@next/swc-linux-x64-musl@npm:14.2.16"
+ conditions: os=linux & cpu=x64 & libc=musl
+ languageName: node
+ linkType: hard
+
"@next/swc-linux-x64-musl@npm:14.2.5":
version: 14.2.5
resolution: "@next/swc-linux-x64-musl@npm:14.2.5"
@@ -5504,6 +5553,13 @@ __metadata:
languageName: node
linkType: hard
+"@next/swc-win32-arm64-msvc@npm:14.2.16":
+ version: 14.2.16
+ resolution: "@next/swc-win32-arm64-msvc@npm:14.2.16"
+ conditions: os=win32 & cpu=arm64
+ languageName: node
+ linkType: hard
+
"@next/swc-win32-arm64-msvc@npm:14.2.5":
version: 14.2.5
resolution: "@next/swc-win32-arm64-msvc@npm:14.2.5"
@@ -5525,6 +5581,13 @@ __metadata:
languageName: node
linkType: hard
+"@next/swc-win32-ia32-msvc@npm:14.2.16":
+ version: 14.2.16
+ resolution: "@next/swc-win32-ia32-msvc@npm:14.2.16"
+ conditions: os=win32 & cpu=ia32
+ languageName: node
+ linkType: hard
+
"@next/swc-win32-ia32-msvc@npm:14.2.5":
version: 14.2.5
resolution: "@next/swc-win32-ia32-msvc@npm:14.2.5"
@@ -5546,6 +5609,13 @@ __metadata:
languageName: node
linkType: hard
+"@next/swc-win32-x64-msvc@npm:14.2.16":
+ version: 14.2.16
+ resolution: "@next/swc-win32-x64-msvc@npm:14.2.16"
+ conditions: os=win32 & cpu=x64
+ languageName: node
+ linkType: hard
+
"@next/swc-win32-x64-msvc@npm:14.2.5":
version: 14.2.5
resolution: "@next/swc-win32-x64-msvc@npm:14.2.5"
@@ -20252,7 +20322,7 @@ __metadata:
languageName: node
linkType: hard
-"next@npm:*, next@npm:^14.2.5":
+"next@npm:*":
version: 14.2.5
resolution: "next@npm:14.2.5"
dependencies:
@@ -20434,6 +20504,64 @@ __metadata:
languageName: node
linkType: hard
+"next@npm:^14.2.16":
+ version: 14.2.16
+ resolution: "next@npm:14.2.16"
+ dependencies:
+ "@next/env": 14.2.16
+ "@next/swc-darwin-arm64": 14.2.16
+ "@next/swc-darwin-x64": 14.2.16
+ "@next/swc-linux-arm64-gnu": 14.2.16
+ "@next/swc-linux-arm64-musl": 14.2.16
+ "@next/swc-linux-x64-gnu": 14.2.16
+ "@next/swc-linux-x64-musl": 14.2.16
+ "@next/swc-win32-arm64-msvc": 14.2.16
+ "@next/swc-win32-ia32-msvc": 14.2.16
+ "@next/swc-win32-x64-msvc": 14.2.16
+ "@swc/helpers": 0.5.5
+ busboy: 1.6.0
+ caniuse-lite: ^1.0.30001579
+ graceful-fs: ^4.2.11
+ postcss: 8.4.31
+ styled-jsx: 5.1.1
+ peerDependencies:
+ "@opentelemetry/api": ^1.1.0
+ "@playwright/test": ^1.41.2
+ react: ^18.2.0
+ react-dom: ^18.2.0
+ sass: ^1.3.0
+ dependenciesMeta:
+ "@next/swc-darwin-arm64":
+ optional: true
+ "@next/swc-darwin-x64":
+ optional: true
+ "@next/swc-linux-arm64-gnu":
+ optional: true
+ "@next/swc-linux-arm64-musl":
+ optional: true
+ "@next/swc-linux-x64-gnu":
+ optional: true
+ "@next/swc-linux-x64-musl":
+ optional: true
+ "@next/swc-win32-arm64-msvc":
+ optional: true
+ "@next/swc-win32-ia32-msvc":
+ optional: true
+ "@next/swc-win32-x64-msvc":
+ optional: true
+ peerDependenciesMeta:
+ "@opentelemetry/api":
+ optional: true
+ "@playwright/test":
+ optional: true
+ sass:
+ optional: true
+ bin:
+ next: dist/bin/next
+ checksum: 907cf5e34884ae28f922586c072738af26a7fcbf39a9b64ecddf0ed29cce1e07b0f4caea9dd77c716d5435a22f8a0942836d4888843cc8ca33650f0bab358bf1
+ languageName: node
+ linkType: hard
+
"no-case@npm:^3.0.4":
version: 3.0.4
resolution: "no-case@npm:3.0.4"
From 59785fb74a9ac5d928c679da299b7cdabe675038 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Thu, 31 Oct 2024 14:05:34 -0400
Subject: [PATCH 2/8] chore(deps): bump next from 12.2.3 to 14.2.10 (#1180)
Bumps [next](https://github.com/vercel/next.js) from 12.2.3 to 14.2.10.
- [Release notes](https://github.com/vercel/next.js/releases)
- [Changelog](https://github.com/vercel/next.js/blob/canary/release.js)
- [Commits](https://github.com/vercel/next.js/compare/v12.2.3...v14.2.10)
---
updated-dependencies:
- dependency-name: next
dependency-type: direct:production
...
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
package.json | 2 +-
yarn.lock | 255 ++++++++++++++++++---------------------------------
2 files changed, 92 insertions(+), 165 deletions(-)
diff --git a/package.json b/package.json
index cd40e72866a..35276b310f1 100644
--- a/package.json
+++ b/package.json
@@ -87,7 +87,7 @@
"classnames": "^2.3.2",
"clsx": "^1.2.1",
"moment": "^2.29.4",
- "next": "12.2.3",
+ "next": "14.2.10",
"tslib": "^2.3.0"
},
"lint-staged": {
diff --git a/yarn.lock b/yarn.lock
index 1ed09680cfa..e9bb29d77ac 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2090,7 +2090,7 @@ __metadata:
jest-environment-jsdom: ^29.4.1
lint-staged: ">=10"
moment: ^2.29.4
- next: 12.2.3
+ next: 14.2.10
pinst: ">=2"
prettier: ^2.7.1
react: ^18.2.0
@@ -5297,13 +5297,6 @@ __metadata:
languageName: node
linkType: hard
-"@next/env@npm:12.2.3":
- version: 12.2.3
- resolution: "@next/env@npm:12.2.3"
- checksum: e96dcbea3fbb3d6b6a0799fe2e41c4929ded383659709f5bd00b6479b0711b89891b72fb28753b428933871d5fd91792fa54bc64a74a038c704b5862d40821ec
- languageName: node
- linkType: hard
-
"@next/env@npm:13.5.6":
version: 13.5.6
resolution: "@next/env@npm:13.5.6"
@@ -5311,6 +5304,13 @@ __metadata:
languageName: node
linkType: hard
+"@next/env@npm:14.2.10":
+ version: 14.2.10
+ resolution: "@next/env@npm:14.2.10"
+ checksum: edff4b124b11f9fcea4df239b6feb11c16ef49c97d018e098a2fcfc16f4aba27092569fb7bdec148d8b1113ac9b2d2a6b460940287ef5636ad801ac779ffc08c
+ languageName: node
+ linkType: hard
+
"@next/env@npm:14.2.16":
version: 14.2.16
resolution: "@next/env@npm:14.2.16"
@@ -5343,30 +5343,16 @@ __metadata:
languageName: node
linkType: hard
-"@next/swc-android-arm-eabi@npm:12.2.3":
- version: 12.2.3
- resolution: "@next/swc-android-arm-eabi@npm:12.2.3"
- conditions: os=android & cpu=arm
- languageName: node
- linkType: hard
-
-"@next/swc-android-arm64@npm:12.2.3":
- version: 12.2.3
- resolution: "@next/swc-android-arm64@npm:12.2.3"
- conditions: os=android & cpu=arm64
- languageName: node
- linkType: hard
-
-"@next/swc-darwin-arm64@npm:12.2.3":
- version: 12.2.3
- resolution: "@next/swc-darwin-arm64@npm:12.2.3"
+"@next/swc-darwin-arm64@npm:13.5.6":
+ version: 13.5.6
+ resolution: "@next/swc-darwin-arm64@npm:13.5.6"
conditions: os=darwin & cpu=arm64
languageName: node
linkType: hard
-"@next/swc-darwin-arm64@npm:13.5.6":
- version: 13.5.6
- resolution: "@next/swc-darwin-arm64@npm:13.5.6"
+"@next/swc-darwin-arm64@npm:14.2.10":
+ version: 14.2.10
+ resolution: "@next/swc-darwin-arm64@npm:14.2.10"
conditions: os=darwin & cpu=arm64
languageName: node
linkType: hard
@@ -5385,16 +5371,16 @@ __metadata:
languageName: node
linkType: hard
-"@next/swc-darwin-x64@npm:12.2.3":
- version: 12.2.3
- resolution: "@next/swc-darwin-x64@npm:12.2.3"
+"@next/swc-darwin-x64@npm:13.5.6":
+ version: 13.5.6
+ resolution: "@next/swc-darwin-x64@npm:13.5.6"
conditions: os=darwin & cpu=x64
languageName: node
linkType: hard
-"@next/swc-darwin-x64@npm:13.5.6":
- version: 13.5.6
- resolution: "@next/swc-darwin-x64@npm:13.5.6"
+"@next/swc-darwin-x64@npm:14.2.10":
+ version: 14.2.10
+ resolution: "@next/swc-darwin-x64@npm:14.2.10"
conditions: os=darwin & cpu=x64
languageName: node
linkType: hard
@@ -5413,30 +5399,16 @@ __metadata:
languageName: node
linkType: hard
-"@next/swc-freebsd-x64@npm:12.2.3":
- version: 12.2.3
- resolution: "@next/swc-freebsd-x64@npm:12.2.3"
- conditions: os=freebsd & cpu=x64
- languageName: node
- linkType: hard
-
-"@next/swc-linux-arm-gnueabihf@npm:12.2.3":
- version: 12.2.3
- resolution: "@next/swc-linux-arm-gnueabihf@npm:12.2.3"
- conditions: os=linux & cpu=arm
- languageName: node
- linkType: hard
-
-"@next/swc-linux-arm64-gnu@npm:12.2.3":
- version: 12.2.3
- resolution: "@next/swc-linux-arm64-gnu@npm:12.2.3"
+"@next/swc-linux-arm64-gnu@npm:13.5.6":
+ version: 13.5.6
+ resolution: "@next/swc-linux-arm64-gnu@npm:13.5.6"
conditions: os=linux & cpu=arm64 & libc=glibc
languageName: node
linkType: hard
-"@next/swc-linux-arm64-gnu@npm:13.5.6":
- version: 13.5.6
- resolution: "@next/swc-linux-arm64-gnu@npm:13.5.6"
+"@next/swc-linux-arm64-gnu@npm:14.2.10":
+ version: 14.2.10
+ resolution: "@next/swc-linux-arm64-gnu@npm:14.2.10"
conditions: os=linux & cpu=arm64 & libc=glibc
languageName: node
linkType: hard
@@ -5455,16 +5427,16 @@ __metadata:
languageName: node
linkType: hard
-"@next/swc-linux-arm64-musl@npm:12.2.3":
- version: 12.2.3
- resolution: "@next/swc-linux-arm64-musl@npm:12.2.3"
+"@next/swc-linux-arm64-musl@npm:13.5.6":
+ version: 13.5.6
+ resolution: "@next/swc-linux-arm64-musl@npm:13.5.6"
conditions: os=linux & cpu=arm64 & libc=musl
languageName: node
linkType: hard
-"@next/swc-linux-arm64-musl@npm:13.5.6":
- version: 13.5.6
- resolution: "@next/swc-linux-arm64-musl@npm:13.5.6"
+"@next/swc-linux-arm64-musl@npm:14.2.10":
+ version: 14.2.10
+ resolution: "@next/swc-linux-arm64-musl@npm:14.2.10"
conditions: os=linux & cpu=arm64 & libc=musl
languageName: node
linkType: hard
@@ -5483,16 +5455,16 @@ __metadata:
languageName: node
linkType: hard
-"@next/swc-linux-x64-gnu@npm:12.2.3":
- version: 12.2.3
- resolution: "@next/swc-linux-x64-gnu@npm:12.2.3"
+"@next/swc-linux-x64-gnu@npm:13.5.6":
+ version: 13.5.6
+ resolution: "@next/swc-linux-x64-gnu@npm:13.5.6"
conditions: os=linux & cpu=x64 & libc=glibc
languageName: node
linkType: hard
-"@next/swc-linux-x64-gnu@npm:13.5.6":
- version: 13.5.6
- resolution: "@next/swc-linux-x64-gnu@npm:13.5.6"
+"@next/swc-linux-x64-gnu@npm:14.2.10":
+ version: 14.2.10
+ resolution: "@next/swc-linux-x64-gnu@npm:14.2.10"
conditions: os=linux & cpu=x64 & libc=glibc
languageName: node
linkType: hard
@@ -5511,16 +5483,16 @@ __metadata:
languageName: node
linkType: hard
-"@next/swc-linux-x64-musl@npm:12.2.3":
- version: 12.2.3
- resolution: "@next/swc-linux-x64-musl@npm:12.2.3"
+"@next/swc-linux-x64-musl@npm:13.5.6":
+ version: 13.5.6
+ resolution: "@next/swc-linux-x64-musl@npm:13.5.6"
conditions: os=linux & cpu=x64 & libc=musl
languageName: node
linkType: hard
-"@next/swc-linux-x64-musl@npm:13.5.6":
- version: 13.5.6
- resolution: "@next/swc-linux-x64-musl@npm:13.5.6"
+"@next/swc-linux-x64-musl@npm:14.2.10":
+ version: 14.2.10
+ resolution: "@next/swc-linux-x64-musl@npm:14.2.10"
conditions: os=linux & cpu=x64 & libc=musl
languageName: node
linkType: hard
@@ -5539,16 +5511,16 @@ __metadata:
languageName: node
linkType: hard
-"@next/swc-win32-arm64-msvc@npm:12.2.3":
- version: 12.2.3
- resolution: "@next/swc-win32-arm64-msvc@npm:12.2.3"
+"@next/swc-win32-arm64-msvc@npm:13.5.6":
+ version: 13.5.6
+ resolution: "@next/swc-win32-arm64-msvc@npm:13.5.6"
conditions: os=win32 & cpu=arm64
languageName: node
linkType: hard
-"@next/swc-win32-arm64-msvc@npm:13.5.6":
- version: 13.5.6
- resolution: "@next/swc-win32-arm64-msvc@npm:13.5.6"
+"@next/swc-win32-arm64-msvc@npm:14.2.10":
+ version: 14.2.10
+ resolution: "@next/swc-win32-arm64-msvc@npm:14.2.10"
conditions: os=win32 & cpu=arm64
languageName: node
linkType: hard
@@ -5567,16 +5539,16 @@ __metadata:
languageName: node
linkType: hard
-"@next/swc-win32-ia32-msvc@npm:12.2.3":
- version: 12.2.3
- resolution: "@next/swc-win32-ia32-msvc@npm:12.2.3"
+"@next/swc-win32-ia32-msvc@npm:13.5.6":
+ version: 13.5.6
+ resolution: "@next/swc-win32-ia32-msvc@npm:13.5.6"
conditions: os=win32 & cpu=ia32
languageName: node
linkType: hard
-"@next/swc-win32-ia32-msvc@npm:13.5.6":
- version: 13.5.6
- resolution: "@next/swc-win32-ia32-msvc@npm:13.5.6"
+"@next/swc-win32-ia32-msvc@npm:14.2.10":
+ version: 14.2.10
+ resolution: "@next/swc-win32-ia32-msvc@npm:14.2.10"
conditions: os=win32 & cpu=ia32
languageName: node
linkType: hard
@@ -5595,16 +5567,16 @@ __metadata:
languageName: node
linkType: hard
-"@next/swc-win32-x64-msvc@npm:12.2.3":
- version: 12.2.3
- resolution: "@next/swc-win32-x64-msvc@npm:12.2.3"
+"@next/swc-win32-x64-msvc@npm:13.5.6":
+ version: 13.5.6
+ resolution: "@next/swc-win32-x64-msvc@npm:13.5.6"
conditions: os=win32 & cpu=x64
languageName: node
linkType: hard
-"@next/swc-win32-x64-msvc@npm:13.5.6":
- version: 13.5.6
- resolution: "@next/swc-win32-x64-msvc@npm:13.5.6"
+"@next/swc-win32-x64-msvc@npm:14.2.10":
+ version: 14.2.10
+ resolution: "@next/swc-win32-x64-msvc@npm:14.2.10"
conditions: os=win32 & cpu=x64
languageName: node
linkType: hard
@@ -7868,15 +7840,6 @@ __metadata:
languageName: node
linkType: hard
-"@swc/helpers@npm:0.4.3":
- version: 0.4.3
- resolution: "@swc/helpers@npm:0.4.3"
- dependencies:
- tslib: ^2.4.0
- checksum: 5c2f173e950dd3929d84ae48b3586a274d5a874e7cf2013b3d8081e4f8c723fa3a4d4e63b263e84bb7f06431f87b640e91a12655410463c81a3dc2bbc15eceda
- languageName: node
- linkType: hard
-
"@swc/helpers@npm:0.5.2":
version: 0.5.2
resolution: "@swc/helpers@npm:0.5.2"
@@ -11855,7 +11818,7 @@ __metadata:
languageName: node
linkType: hard
-"caniuse-lite@npm:^1.0.0, caniuse-lite@npm:^1.0.30001332, caniuse-lite@npm:^1.0.30001406, caniuse-lite@npm:^1.0.30001524, caniuse-lite@npm:^1.0.30001579, caniuse-lite@npm:^1.0.30001599, caniuse-lite@npm:^1.0.30001640":
+"caniuse-lite@npm:^1.0.0, caniuse-lite@npm:^1.0.30001406, caniuse-lite@npm:^1.0.30001524, caniuse-lite@npm:^1.0.30001579, caniuse-lite@npm:^1.0.30001599, caniuse-lite@npm:^1.0.30001640":
version: 1.0.30001643
resolution: "caniuse-lite@npm:1.0.30001643"
checksum: e39991c13a0fd8f5c2aa99c9128188e4c4e9d6a203c3da6270c36285460ef152c5e9410ee4db560aa723904668946afe50541dce9636ab5e61434ba71dc22955
@@ -20278,7 +20241,7 @@ __metadata:
languageName: node
linkType: hard
-"nanoid@npm:^3.3.4, nanoid@npm:^3.3.6, nanoid@npm:^3.3.7":
+"nanoid@npm:^3.3.6, nanoid@npm:^3.3.7":
version: 3.3.7
resolution: "nanoid@npm:3.3.7"
bin:
@@ -20380,48 +20343,37 @@ __metadata:
languageName: node
linkType: hard
-"next@npm:12.2.3":
- version: 12.2.3
- resolution: "next@npm:12.2.3"
- dependencies:
- "@next/env": 12.2.3
- "@next/swc-android-arm-eabi": 12.2.3
- "@next/swc-android-arm64": 12.2.3
- "@next/swc-darwin-arm64": 12.2.3
- "@next/swc-darwin-x64": 12.2.3
- "@next/swc-freebsd-x64": 12.2.3
- "@next/swc-linux-arm-gnueabihf": 12.2.3
- "@next/swc-linux-arm64-gnu": 12.2.3
- "@next/swc-linux-arm64-musl": 12.2.3
- "@next/swc-linux-x64-gnu": 12.2.3
- "@next/swc-linux-x64-musl": 12.2.3
- "@next/swc-win32-arm64-msvc": 12.2.3
- "@next/swc-win32-ia32-msvc": 12.2.3
- "@next/swc-win32-x64-msvc": 12.2.3
- "@swc/helpers": 0.4.3
- caniuse-lite: ^1.0.30001332
- postcss: 8.4.14
- styled-jsx: 5.0.2
- use-sync-external-store: 1.2.0
+"next@npm:14.2.10":
+ version: 14.2.10
+ resolution: "next@npm:14.2.10"
+ dependencies:
+ "@next/env": 14.2.10
+ "@next/swc-darwin-arm64": 14.2.10
+ "@next/swc-darwin-x64": 14.2.10
+ "@next/swc-linux-arm64-gnu": 14.2.10
+ "@next/swc-linux-arm64-musl": 14.2.10
+ "@next/swc-linux-x64-gnu": 14.2.10
+ "@next/swc-linux-x64-musl": 14.2.10
+ "@next/swc-win32-arm64-msvc": 14.2.10
+ "@next/swc-win32-ia32-msvc": 14.2.10
+ "@next/swc-win32-x64-msvc": 14.2.10
+ "@swc/helpers": 0.5.5
+ busboy: 1.6.0
+ caniuse-lite: ^1.0.30001579
+ graceful-fs: ^4.2.11
+ postcss: 8.4.31
+ styled-jsx: 5.1.1
peerDependencies:
- fibers: ">= 3.1.0"
- node-sass: ^6.0.0 || ^7.0.0
- react: ^17.0.2 || ^18.0.0-0
- react-dom: ^17.0.2 || ^18.0.0-0
+ "@opentelemetry/api": ^1.1.0
+ "@playwright/test": ^1.41.2
+ react: ^18.2.0
+ react-dom: ^18.2.0
sass: ^1.3.0
dependenciesMeta:
- "@next/swc-android-arm-eabi":
- optional: true
- "@next/swc-android-arm64":
- optional: true
"@next/swc-darwin-arm64":
optional: true
"@next/swc-darwin-x64":
optional: true
- "@next/swc-freebsd-x64":
- optional: true
- "@next/swc-linux-arm-gnueabihf":
- optional: true
"@next/swc-linux-arm64-gnu":
optional: true
"@next/swc-linux-arm64-musl":
@@ -20437,15 +20389,15 @@ __metadata:
"@next/swc-win32-x64-msvc":
optional: true
peerDependenciesMeta:
- fibers:
+ "@opentelemetry/api":
optional: true
- node-sass:
+ "@playwright/test":
optional: true
sass:
optional: true
bin:
next: dist/bin/next
- checksum: b13b42fbb327adca51abeef68aca4b31c82297f07eb3a12d31a3bf2c1aa9ca34cf1ab41bc2b9f4d3162623e70a1ddf230da39fd3ce241b1eea113a4a010a11fd
+ checksum: 2d69507cccddc0297ff2e6727d7c0e96653a049c4a0236f6c0cae3e1eb622dabcb576b4f3976046526f31b8252f665f5b98cbb0f66d6e756f4d22b0ccfbd290d
languageName: node
linkType: hard
@@ -22298,17 +22250,6 @@ __metadata:
languageName: node
linkType: hard
-"postcss@npm:8.4.14":
- version: 8.4.14
- resolution: "postcss@npm:8.4.14"
- dependencies:
- nanoid: ^3.3.4
- picocolors: ^1.0.0
- source-map-js: ^1.0.2
- checksum: fe58766ff32e4becf65a7d57678995cfd239df6deed2fe0557f038b47c94e4132e7e5f68b5aa820c13adfec32e523b693efaeb65798efb995ce49ccd83953816
- languageName: node
- linkType: hard
-
"postcss@npm:8.4.31":
version: 8.4.31
resolution: "postcss@npm:8.4.31"
@@ -25397,20 +25338,6 @@ __metadata:
languageName: node
linkType: hard
-"styled-jsx@npm:5.0.2":
- version: 5.0.2
- resolution: "styled-jsx@npm:5.0.2"
- peerDependencies:
- react: ">= 16.8.0 || 17.x.x || ^18.0.0-0"
- peerDependenciesMeta:
- "@babel/core":
- optional: true
- babel-plugin-macros:
- optional: true
- checksum: 86d55819ebeabd283a574d2f44f7d3f8fa6b8c28fa41687ece161bf1e910e04965611618921d8f5cd33dc6dae1033b926a70421ae5ea045440a9861edc3e0d87
- languageName: node
- linkType: hard
-
"styled-jsx@npm:5.1.1":
version: 5.1.1
resolution: "styled-jsx@npm:5.1.1"
From 8364e534e6bdc4e22501ac14ec24b11c0d6a5977 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?L=C3=A9o=20Galley?=
Date: Thu, 31 Oct 2024 14:07:18 -0400
Subject: [PATCH 3/8] BAPP-670: Bump OCK version w dropdown fix (#1182)
* bump ock version w dropdown fix
* reset
* BaseName -> Basename
* rename imports
* reset
* fix
---
.../name/[username]/ProfileProviders.tsx | 4 +-
.../name/[username]/configure-frames/page.tsx | 6 +--
.../app/(basenames)/name/[username]/page.tsx | 6 +--
apps/web/package.json | 2 +-
.../pages/api/basenames/metadata/[tokenId].ts | 4 +-
.../src/components/BasenameIdentity/index.tsx | 4 +-
.../Basenames/BasenameAvatar/index.tsx | 5 +--
.../Basenames/RegistrationContext.tsx | 4 +-
.../Basenames/UsernamePill/types.ts | 4 +-
.../UsernameProfileContext/index.tsx | 8 ++--
.../ConnectWalletButton.tsx | 4 +-
apps/web/src/hooks/useBaseEnsAvatar.ts | 4 +-
apps/web/src/hooks/useBaseEnsName.ts | 6 +--
apps/web/src/hooks/useBasenameChain.ts | 4 +-
apps/web/src/hooks/useSetPrimaryBasename.ts | 4 +-
apps/web/src/utils/redirectIfNotNameOwner.ts | 4 +-
apps/web/src/utils/usernames.ts | 42 +++++++++----------
yarn.lock | 10 ++---
18 files changed, 62 insertions(+), 63 deletions(-)
diff --git a/apps/web/app/(basenames)/name/[username]/ProfileProviders.tsx b/apps/web/app/(basenames)/name/[username]/ProfileProviders.tsx
index d63dfe2dbc5..2339e9d17f8 100644
--- a/apps/web/app/(basenames)/name/[username]/ProfileProviders.tsx
+++ b/apps/web/app/(basenames)/name/[username]/ProfileProviders.tsx
@@ -1,6 +1,6 @@
'use client';
-import { BaseName } from '@coinbase/onchainkit/identity';
+import { Basename } from '@coinbase/onchainkit/identity';
import AnalyticsProvider from 'apps/web/contexts/Analytics';
import UsernameProfileProvider from 'apps/web/src/components/Basenames/UsernameProfileContext';
@@ -9,7 +9,7 @@ const usernameProfileAnalyticContext = 'username_profile';
type ProfileProvidersProps = {
children: React.ReactNode;
- username: BaseName;
+ username: Basename;
};
export default function ProfileProviders({ children, username }: ProfileProvidersProps) {
diff --git a/apps/web/app/(basenames)/name/[username]/configure-frames/page.tsx b/apps/web/app/(basenames)/name/[username]/configure-frames/page.tsx
index 9c3affb6a35..3e2131ea339 100644
--- a/apps/web/app/(basenames)/name/[username]/configure-frames/page.tsx
+++ b/apps/web/app/(basenames)/name/[username]/configure-frames/page.tsx
@@ -1,4 +1,4 @@
-import { BaseName } from '@coinbase/onchainkit/identity';
+import { Basename } from '@coinbase/onchainkit/identity';
import ProfileProviders from 'apps/web/app/(basenames)/name/[username]/ProfileProviders';
import ErrorsProvider from 'apps/web/contexts/Errors';
import FrameBuilder from 'apps/web/src/components/Basenames/ConfigureFramesPageContent/FrameBuilder';
@@ -7,11 +7,11 @@ import { redirectIfNotNameOwner } from 'apps/web/src/utils/redirectIfNotNameOwne
import { formatDefaultUsername } from 'apps/web/src/utils/usernames';
export type ConfigureFramesProps = {
- params: { username: BaseName };
+ params: { username: Basename };
};
export default async function ConfigureFrames({ params }: ConfigureFramesProps) {
- let username = await formatDefaultUsername(decodeURIComponent(params.username) as BaseName);
+ let username = await formatDefaultUsername(decodeURIComponent(params.username) as Basename);
await redirectIfNotNameOwner(username);
return (
diff --git a/apps/web/app/(basenames)/name/[username]/page.tsx b/apps/web/app/(basenames)/name/[username]/page.tsx
index 503b8f20577..51c34d33e5b 100644
--- a/apps/web/app/(basenames)/name/[username]/page.tsx
+++ b/apps/web/app/(basenames)/name/[username]/page.tsx
@@ -1,4 +1,4 @@
-import { BaseName } from '@coinbase/onchainkit/identity';
+import { Basename } from '@coinbase/onchainkit/identity';
import ProfileProviders from 'apps/web/app/(basenames)/name/[username]/ProfileProviders';
import ErrorsProvider from 'apps/web/contexts/Errors';
import UsernameProfile from 'apps/web/src/components/Basenames/UsernameProfile';
@@ -12,7 +12,7 @@ import classNames from 'classnames';
import { Metadata } from 'next';
export type UsernameProfileProps = {
- params: { username: BaseName };
+ params: { username: Basename };
};
export async function generateMetadata({ params }: UsernameProfileProps): Promise {
@@ -35,7 +35,7 @@ export async function generateMetadata({ params }: UsernameProfileProps): Promis
}
export default async function Username({ params }: UsernameProfileProps) {
- let username = await formatDefaultUsername(decodeURIComponent(params.username) as BaseName);
+ let username = await formatDefaultUsername(decodeURIComponent(params.username) as Basename);
await redirectIfNotNameOwner(username);
const usernameProfilePageClasses = classNames(
diff --git a/apps/web/package.json b/apps/web/package.json
index d94f6f6d682..3c42a50734b 100644
--- a/apps/web/package.json
+++ b/apps/web/package.json
@@ -15,7 +15,7 @@
"dependencies": {
"@coinbase/cookie-banner": "^1.0.3",
"@coinbase/cookie-manager": "^1.1.1",
- "@coinbase/onchainkit": "^0.28.5",
+ "@coinbase/onchainkit": "^0.35.2",
"@datadog/browser-logs": "^5.23.3",
"@datadog/browser-rum": "^5.23.3",
"@frames.js/render": "^0.3.14",
diff --git a/apps/web/pages/api/basenames/metadata/[tokenId].ts b/apps/web/pages/api/basenames/metadata/[tokenId].ts
index c2fb0cef25f..90de95d2f55 100644
--- a/apps/web/pages/api/basenames/metadata/[tokenId].ts
+++ b/apps/web/pages/api/basenames/metadata/[tokenId].ts
@@ -1,4 +1,4 @@
-import { BaseName } from '@coinbase/onchainkit/identity';
+import { Basename } from '@coinbase/onchainkit/identity';
import { premintMapping } from 'apps/web/pages/api/basenames/metadata/premintsMapping';
import L2Resolver from 'apps/web/src/abis/L2Resolver';
import { USERNAME_L2_RESOLVER_ADDRESSES } from 'apps/web/src/addresses/usernames';
@@ -51,7 +51,7 @@ export default async function GET(request: Request) {
args: [namehashNode],
functionName: 'name',
});
- nameExpires = await getBasenameNameExpires(basenameFormatted as BaseName);
+ nameExpires = await getBasenameNameExpires(basenameFormatted as Basename);
} catch (error) {
logger.error('Error getting token metadata', error);
}
diff --git a/apps/web/src/components/BasenameIdentity/index.tsx b/apps/web/src/components/BasenameIdentity/index.tsx
index 66926e6ca27..a1525a4fe4e 100644
--- a/apps/web/src/components/BasenameIdentity/index.tsx
+++ b/apps/web/src/components/BasenameIdentity/index.tsx
@@ -1,12 +1,12 @@
'use client';
-import { BaseName } from '@coinbase/onchainkit/identity';
+import { Basename } from '@coinbase/onchainkit/identity';
import { USERNAME_L2_RESOLVER_ADDRESSES } from 'apps/web/src/addresses/usernames';
import BasenameAvatar from 'apps/web/src/components/Basenames/BasenameAvatar';
import useBasenameChain from 'apps/web/src/hooks/useBasenameChain';
import { truncateMiddle } from 'libs/base-ui/utils/string';
import { useEnsAddress } from 'wagmi';
-export default function BasenameIdentity({ username }: { username: BaseName }) {
+export default function BasenameIdentity({ username }: { username: Basename }) {
const { basenameChain } = useBasenameChain();
const { data: basenameAddress } = useEnsAddress({
diff --git a/apps/web/src/components/Basenames/BasenameAvatar/index.tsx b/apps/web/src/components/Basenames/BasenameAvatar/index.tsx
index e2bd58da7e6..908a45f2606 100644
--- a/apps/web/src/components/Basenames/BasenameAvatar/index.tsx
+++ b/apps/web/src/components/Basenames/BasenameAvatar/index.tsx
@@ -1,7 +1,6 @@
'use client';
-import { BaseName } from '@coinbase/onchainkit/identity';
-
+import { Basename } from '@coinbase/onchainkit/identity';
import LottieAnimation from 'apps/web/src/components/LottieAnimation';
import useBaseEnsAvatar from 'apps/web/src/hooks/useBaseEnsAvatar';
import ImageWithLoading from 'apps/web/src/components/ImageWithLoading';
@@ -14,7 +13,7 @@ export default function BasenameAvatar({
width,
height,
}: {
- basename: BaseName;
+ basename: Basename;
wrapperClassName?: string;
animate?: boolean;
width?: number | `${number}` | undefined;
diff --git a/apps/web/src/components/Basenames/RegistrationContext.tsx b/apps/web/src/components/Basenames/RegistrationContext.tsx
index c3153ce1b9d..7b00fe7e2a7 100644
--- a/apps/web/src/components/Basenames/RegistrationContext.tsx
+++ b/apps/web/src/components/Basenames/RegistrationContext.tsx
@@ -35,7 +35,7 @@ import {
import { BatchCallsStatus } from 'apps/web/src/hooks/useWriteContractsWithLogs';
import { WriteTransactionWithReceiptStatus } from 'apps/web/src/hooks/useWriteContractWithReceipt';
import useBaseEnsName from 'apps/web/src/hooks/useBaseEnsName';
-import { BaseName } from '@coinbase/onchainkit/identity';
+import { Basename } from '@coinbase/onchainkit/identity';
export enum RegistrationSteps {
Search = 'search',
@@ -54,7 +54,7 @@ export type RegistrationContextProps = {
setRegistrationStep: Dispatch>;
selectedName: string;
setSelectedName: Dispatch>;
- selectedNameFormatted: BaseName;
+ selectedNameFormatted: Basename;
years: number;
setYears: Dispatch>;
redirectToProfile: () => void;
diff --git a/apps/web/src/components/Basenames/UsernamePill/types.ts b/apps/web/src/components/Basenames/UsernamePill/types.ts
index 69bd9a29c32..22d68e1f603 100644
--- a/apps/web/src/components/Basenames/UsernamePill/types.ts
+++ b/apps/web/src/components/Basenames/UsernamePill/types.ts
@@ -1,4 +1,4 @@
-import { BaseName } from '@coinbase/onchainkit/identity';
+import { Basename } from '@coinbase/onchainkit/identity';
import { Address } from 'viem';
export enum UsernamePillVariants {
@@ -7,7 +7,7 @@ export enum UsernamePillVariants {
}
export type UsernamePillProps = {
variant: UsernamePillVariants;
- username: BaseName;
+ username: Basename;
address?: Address;
isRegistering?: boolean;
};
diff --git a/apps/web/src/components/Basenames/UsernameProfileContext/index.tsx b/apps/web/src/components/Basenames/UsernameProfileContext/index.tsx
index cd989fb65f6..4b6a9cb5d84 100644
--- a/apps/web/src/components/Basenames/UsernameProfileContext/index.tsx
+++ b/apps/web/src/components/Basenames/UsernameProfileContext/index.tsx
@@ -1,5 +1,5 @@
'use client';
-import { BaseName } from '@coinbase/onchainkit/identity';
+import { Basename } from '@coinbase/onchainkit/identity';
import { USERNAME_L2_RESOLVER_ADDRESSES } from 'apps/web/src/addresses/usernames';
import useBaseEnsName from 'apps/web/src/hooks/useBaseEnsName';
import useBasenameChain from 'apps/web/src/hooks/useBasenameChain';
@@ -24,12 +24,12 @@ export enum UsernameProfileSteps {}
export type UsernameProfileContextProps = {
// Profile details
- profileUsername: BaseName;
+ profileUsername: Basename;
profileAddress?: Address;
// Profile owner
profileEditorAddress?: Address;
- profileOwnerUsername?: BaseName;
+ profileOwnerUsername?: Basename;
profileRefetch: () => Promise;
// State
@@ -67,7 +67,7 @@ export const UsernameProfileContext = createContext
type UsernameProfileProviderProps = {
children: ReactNode;
- username: BaseName;
+ username: Basename;
};
export default function UsernameProfileProvider({
diff --git a/apps/web/src/components/ConnectWalletButton/ConnectWalletButton.tsx b/apps/web/src/components/ConnectWalletButton/ConnectWalletButton.tsx
index ab76e4e33c8..6e936441ab8 100644
--- a/apps/web/src/components/ConnectWalletButton/ConnectWalletButton.tsx
+++ b/apps/web/src/components/ConnectWalletButton/ConnectWalletButton.tsx
@@ -3,7 +3,7 @@ import {
ConnectWallet,
Wallet,
WalletDropdown,
- WalletDropdownBaseName,
+ WalletDropdownBasename,
WalletDropdownDisconnect,
WalletDropdownLink,
} from '@coinbase/onchainkit/wallet';
@@ -156,7 +156,7 @@ export function ConnectWalletButton({
/>
-
+
;
- const ensNameTyped = data ? (data as BaseName) : undefined;
+ const ensNameTyped = data ? (data as Basename) : undefined;
return {
data: ensNameTyped,
diff --git a/apps/web/src/hooks/useBasenameChain.ts b/apps/web/src/hooks/useBasenameChain.ts
index 5ef7f047d5d..382956aa32b 100644
--- a/apps/web/src/hooks/useBasenameChain.ts
+++ b/apps/web/src/hooks/useBasenameChain.ts
@@ -3,7 +3,7 @@ import { useMemo } from 'react';
import { base, baseSepolia, Chain } from 'viem/chains';
import { createPublicClient, http } from 'viem';
import { cdpBaseRpcEndpoint, cdpBaseSepoliaRpcEndpoint } from 'apps/web/src/cdp/constants';
-import { BaseName } from '@coinbase/onchainkit/identity';
+import { Basename } from '@coinbase/onchainkit/identity';
import { getChainForBasename } from 'apps/web/src/utils/usernames';
import { isDevelopment } from 'apps/web/src/constants';
@@ -22,7 +22,7 @@ export function isBasenameSupportedChain(chainId: number) {
return supportedChainIds.includes(chainId);
}
-export default function useBasenameChain(username?: BaseName) {
+export default function useBasenameChain(username?: Basename) {
const { chain: connectedChain } = useAccount();
const basenameChain: Chain = useMemo(() => {
diff --git a/apps/web/src/hooks/useSetPrimaryBasename.ts b/apps/web/src/hooks/useSetPrimaryBasename.ts
index b4d3a62a998..a5350de240c 100644
--- a/apps/web/src/hooks/useSetPrimaryBasename.ts
+++ b/apps/web/src/hooks/useSetPrimaryBasename.ts
@@ -5,7 +5,7 @@ import {
} from 'apps/web/src/addresses/usernames';
import useBasenameChain from 'apps/web/src/hooks/useBasenameChain';
import { useCallback, useEffect } from 'react';
-import { BaseName } from '@coinbase/onchainkit/identity';
+import { Basename } from '@coinbase/onchainkit/identity';
import { useAccount } from 'wagmi';
import useBaseEnsName from 'apps/web/src/hooks/useBaseEnsName';
import { useErrors } from 'apps/web/contexts/Errors';
@@ -22,7 +22,7 @@ import { useUsernameProfile } from 'apps/web/src/components/Basenames/UsernamePr
*/
type UseSetPrimaryBasenameProps = {
- secondaryUsername: BaseName;
+ secondaryUsername: Basename;
};
export default function useSetPrimaryBasename({ secondaryUsername }: UseSetPrimaryBasenameProps) {
diff --git a/apps/web/src/utils/redirectIfNotNameOwner.ts b/apps/web/src/utils/redirectIfNotNameOwner.ts
index 704dcbac440..e3b6ce906bd 100644
--- a/apps/web/src/utils/redirectIfNotNameOwner.ts
+++ b/apps/web/src/utils/redirectIfNotNameOwner.ts
@@ -1,4 +1,4 @@
-import { BaseName } from '@coinbase/onchainkit/identity';
+import { Basename } from '@coinbase/onchainkit/identity';
import {
getBasenameAddress,
getBasenameEditor,
@@ -6,7 +6,7 @@ import {
} from 'apps/web/src/utils/usernames';
import { redirect } from 'next/navigation';
-export async function redirectIfNotNameOwner(username: BaseName) {
+export async function redirectIfNotNameOwner(username: Basename) {
const [address, editor, owner] = await Promise.all([
getBasenameAddress(username),
getBasenameEditor(username),
diff --git a/apps/web/src/utils/usernames.ts b/apps/web/src/utils/usernames.ts
index 8e5c240611c..7ecb1ae17f1 100644
--- a/apps/web/src/utils/usernames.ts
+++ b/apps/web/src/utils/usernames.ts
@@ -17,7 +17,7 @@ import L2ResolverAbi from 'apps/web/src/abis/L2Resolver';
import RegistryAbi from 'apps/web/src/abis/RegistryAbi';
import BaseRegistrarAbi from 'apps/web/src/abis/BaseRegistrarAbi';
import { base, baseSepolia, mainnet } from 'viem/chains';
-import { BaseName } from '@coinbase/onchainkit/identity';
+import { Basename } from '@coinbase/onchainkit/identity';
import {
USERNAME_BASE_REGISTRAR_ADDRESSES,
USERNAME_BASE_REGISTRY_ADDRESSES,
@@ -350,8 +350,8 @@ export const USERNAME_DOMAINS: Record = {
[base.id]: 'base.eth',
};
-export const formatBaseEthDomain = (name: string, chainId: number): BaseName => {
- return `${name}.${USERNAME_DOMAINS[chainId] ?? '.base.eth'}`.toLocaleLowerCase() as BaseName;
+export const formatBaseEthDomain = (name: string, chainId: number): Basename => {
+ return `${name}.${USERNAME_DOMAINS[chainId] ?? '.base.eth'}`.toLocaleLowerCase() as Basename;
};
export const convertChainIdToCoinType = (chainId: number): string => {
@@ -404,7 +404,7 @@ export function isValidDiscount(key: string): key is keyof typeof Discount {
return Object.values(Discount).includes(key as Discount);
}
-export function getChainForBasename(username: BaseName): Chain {
+export function getChainForBasename(username: Basename): Chain {
return username.endsWith(`.${USERNAME_DOMAINS[base.id]}`) ? base : baseSepolia;
}
@@ -419,7 +419,7 @@ export function normalizeName(name: string) {
}
// Assume domainless name to .base.eth
-export async function formatDefaultUsername(username: string | BaseName) {
+export async function formatDefaultUsername(username: string) {
if (
username &&
!username.endsWith(`.${USERNAME_DOMAINS[baseSepolia.id]}`) &&
@@ -428,11 +428,11 @@ export async function formatDefaultUsername(username: string | BaseName) {
return formatBaseEthDomain(username, base.id);
}
- return username as BaseName;
+ return username as Basename;
}
-export const getTokenIdFromBasename = (username: BaseName) => {
- const usernameWithoutDomain = username
+export const getTokenIdFromBasename = (username: Basename) => {
+ const usernameWithoutDomain = (username as string)
.replace(`.${USERNAME_DOMAINS[base.id]}`, '')
.replace(`.${USERNAME_DOMAINS[baseSepolia.id]}`, '');
@@ -551,13 +551,13 @@ export function validateBasenameAvatarUrl(source: string): ValidationResult {
// Get username `addr`
// Get username token `owner`
-export async function getBasenameAddress(username: BaseName) {
+export async function getBasenameAddress(username: Basename) {
const chain = getChainForBasename(username);
try {
const client = getBasenamePublicClient(chain.id);
const ensAddress = await client.getEnsAddress({
- name: normalize(username),
+ name: normalize(username as string),
universalResolverAddress: USERNAME_L2_RESOLVER_ADDRESSES[chain.id],
});
return ensAddress;
@@ -567,17 +567,17 @@ export async function getBasenameAddress(username: BaseName) {
/*
Get username Basename `editor` in the Base Registrar (different from NFT owner)
*/
-export function buildBasenameEditorContract(username: BaseName): ContractFunctionParameters {
+export function buildBasenameEditorContract(username: Basename): ContractFunctionParameters {
const chain = getChainForBasename(username);
return {
abi: RegistryAbi,
address: USERNAME_BASE_REGISTRY_ADDRESSES[chain.id],
- args: [namehash(username)],
+ args: [namehash(username as string)],
functionName: 'owner',
};
}
-export async function getBasenameEditor(username: BaseName) {
+export async function getBasenameEditor(username: Basename) {
const chain = getChainForBasename(username);
try {
@@ -592,7 +592,7 @@ export async function getBasenameEditor(username: BaseName) {
Get username NFT `owner` in the Base Registry (different from Basename editor)
*/
-export function buildBasenameOwnerContract(username: BaseName): ContractFunctionParameters {
+export function buildBasenameOwnerContract(username: Basename): ContractFunctionParameters {
const chain = getChainForBasename(username);
const tokenId = getTokenIdFromBasename(username);
return {
@@ -603,7 +603,7 @@ export function buildBasenameOwnerContract(username: BaseName): ContractFunction
};
}
-export async function getBasenameOwner(username: BaseName) {
+export async function getBasenameOwner(username: Basename) {
const chain = getChainForBasename(username);
try {
@@ -614,7 +614,7 @@ export async function getBasenameOwner(username: BaseName) {
} catch (error) {}
}
-export async function getBasenameNameExpires(username: BaseName) {
+export async function getBasenameNameExpires(username: Basename) {
const chain = getChainForBasename(username);
const tokenId = getTokenIdFromBasename(username);
try {
@@ -656,20 +656,20 @@ export async function getBasenameAvailable(name: string, chain: Chain): Promise<
// Build a TextRecord contract request
export function buildBasenameTextRecordContract(
- username: BaseName,
+ username: Basename,
key: UsernameTextRecordKeys,
): ContractFunctionParameters {
const chain = getChainForBasename(username);
return {
abi: L2ResolverAbi,
address: USERNAME_L2_RESOLVER_ADDRESSES[chain.id],
- args: [namehash(username), key],
+ args: [namehash(username as string), key],
functionName: 'text',
};
}
// Get a single TextRecord
-export async function getBasenameTextRecord(username: BaseName, key: UsernameTextRecordKeys) {
+export async function getBasenameTextRecord(username: Basename, key: UsernameTextRecordKeys) {
const chain = getChainForBasename(username);
try {
const client = getBasenamePublicClient(chain.id);
@@ -680,7 +680,7 @@ export async function getBasenameTextRecord(username: BaseName, key: UsernameTex
}
// Get a all TextRecords
-export async function getBasenameTextRecords(username: BaseName) {
+export async function getBasenameTextRecords(username: Basename) {
const chain = getChainForBasename(username);
try {
const readContracts: ContractFunctionParameters[] = textRecordsKeysEnabled.map((key) => {
@@ -698,7 +698,7 @@ export async function getBasenameTextRecords(username: BaseName) {
Reclaim a Basename contrat write method
*/
export function buildBasenameReclaimContract(
- username: BaseName,
+ username: Basename,
address: Address,
): ContractFunctionParameters {
const chain = getChainForBasename(username);
diff --git a/yarn.lock b/yarn.lock
index e9bb29d77ac..aee88022911 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -361,7 +361,7 @@ __metadata:
dependencies:
"@coinbase/cookie-banner": ^1.0.3
"@coinbase/cookie-manager": ^1.1.1
- "@coinbase/onchainkit": ^0.28.5
+ "@coinbase/onchainkit": ^0.35.2
"@datadog/browser-logs": ^5.23.3
"@datadog/browser-rum": ^5.23.3
"@frames.js/render": ^0.3.14
@@ -2288,9 +2288,9 @@ __metadata:
languageName: node
linkType: hard
-"@coinbase/onchainkit@npm:^0.28.5":
- version: 0.28.7
- resolution: "@coinbase/onchainkit@npm:0.28.7"
+"@coinbase/onchainkit@npm:^0.35.2":
+ version: 0.35.2
+ resolution: "@coinbase/onchainkit@npm:0.35.2"
dependencies:
"@rainbow-me/rainbowkit": ^2.1.3
"@tanstack/react-query": ^5
@@ -2305,7 +2305,7 @@ __metadata:
"@xmtp/frames-validator": ^0.6.0
react: ^18
react-dom: ^18
- checksum: 49c7041ec516f41d2580115a79e0b7af562dfeb9e2a6b7567e8ed96269334d8aa39d1800e7306afcaeda5b33e47938d693532c5108814c514e2e2cd5235be7e8
+ checksum: 34496e95c77654a0aa44a846f554ccaf103e1fe56cccf5cc6097b0ddb4821056b33ef4862a2d83e67cd98b2270a8e88627aa0e15252dc3465d46e83233d19fb6
languageName: node
linkType: hard
From 2c24508c9744740db017201550e69960bfc33689 Mon Sep 17 00:00:00 2001
From: mche-cb <64994051+mche-cb@users.noreply.github.com>
Date: Thu, 31 Oct 2024 19:56:23 -0400
Subject: [PATCH 4/8] docs: Add app blocklist info (#1155)
---
apps/base-docs/docs/security.md | 45 ----------------
apps/base-docs/docs/security/app-blocklist.md | 51 +++++++++++++++++++
apps/base-docs/docs/security/bounty.md | 18 +++++++
apps/base-docs/docs/security/report.md | 29 +++++++++++
apps/base-docs/sidebars.js | 8 ++-
5 files changed, 105 insertions(+), 46 deletions(-)
delete mode 100644 apps/base-docs/docs/security.md
create mode 100644 apps/base-docs/docs/security/app-blocklist.md
create mode 100644 apps/base-docs/docs/security/bounty.md
create mode 100644 apps/base-docs/docs/security/report.md
diff --git a/apps/base-docs/docs/security.md b/apps/base-docs/docs/security.md
deleted file mode 100644
index 3e57f896668..00000000000
--- a/apps/base-docs/docs/security.md
+++ /dev/null
@@ -1,45 +0,0 @@
----
-title: Security
-slug: /security
-description: The Base bug bounty program and procedures for reporting vulnerabilities.
-keywords:
- [
- Base,
- bug bounty program,
- report vulnerability,
- bug report,
- cybersecurity,
- HackerOne,
- Base network,
- Bedrock,
- Optimism,
- vulnerability reporting,
- crypto security,
- open source,
- ]
-hide_table_of_contents: true
----
-
-# Security
-
----
-
-## Bug bounty program
-
-In line with our strategy of being the safest way for users to access crypto:
-
-- Coinbase will be extending our [best-in-industry](https://www.coinbase.com/blog/celebrating-10-years-of-our-bug-bounty-program) million-dollar [HackerOne bug bounty program](https://hackerone.com/coinbase?type=team) to cover the Base network, the Base bridge contracts, and Base infrastructure.
-- Coinbase will be working in tandem with OP Labs to harden the security guarantees of Bedrock and accelerate the timeline for decentralized fault-proofs on the [OP Stack](https://stack.optimism.io/).
-- Coinbase's bug bounty program will run alongside Optimism's existing [Immunefi Bedrock bounty program](https://immunefi.com/bounty/optimism/) to support the open source [Bedrock](https://stack.optimism.io/docs/releases/bedrock/) OP Stack framework.
-
----
-
-## Reporting vulnerabilities
-
-All potential vulnerability reports can be submitted via the [HackerOne](https://hackerone.com/coinbase) platform.
-
-The HackerOne platform allows us to have a centralized and single reporting source for us to deliver optimized SLA's and results. All reports submitted to the platform are triaged around the clock by our team of Coinbase engineers with domain knowledge, assuring the best quality of review.
-
-For more information on reporting vulnerabilities and our HackerOne bug bounty program, view our [security program policies](https://hackerone.com/coinbase?view_policy=true).
-
----
diff --git a/apps/base-docs/docs/security/app-blocklist.md b/apps/base-docs/docs/security/app-blocklist.md
new file mode 100644
index 00000000000..3f8f29ad372
--- /dev/null
+++ b/apps/base-docs/docs/security/app-blocklist.md
@@ -0,0 +1,51 @@
+---
+title: How to avoid getting your app flagged as malicious
+slug: /security/app-blocklist
+description: The Base bug bounty program and procedures for reporting vulnerabilities.
+keywords:
+ [
+ Base,
+ Coinbase Wallet,
+ dapp,
+ app,
+ malicious warning,
+ browser,
+ dapp developer,
+ app developer,
+ best practice,
+ unblock,
+ remove warning,
+ ]
+hide_table_of_contents: true
+---
+
+# How to avoid getting your app flagged as malicious
+
+---
+
+Ensuring that your app is perceived as trustworthy and not flagged as malicious requires attention to best practices. Here’s a quick guide on how to build a secure and compliant app from day one
+
+## Smart Contracts
+
+- **Verify Source Code:** Ensure that the source code of your contracts is verified and publicly available on [block explorers](https://docs.base.org/docs/tools/block-explorers/).
+- **Audit Your Contracts**: Having your contracts audited by a reputable firm is crucial. Publish the audit report and provide a reference link to it, so users can easily find it. Audits show that you’ve taken extra steps to secure your smart contracts.
+- **Limit User Funds Exposure**: Design your contracts to minimize the exposure of user funds. Use efficient design to reduce any unnecessary risk. For example, request the minimum amount needed to fulfill the transaction.
+
+---
+
+## App Best Practices
+
+- **Accessibility Across Regions**: Avoid geo-blocking or access restrictions that prevent certain regions or countries from accessing your app.
+- **Consistent Web2 Behavior**: Avoid rapid or unexplained changes in UI that can make users feel uncertain about the app’s reliability.
+- **Transparent Web3 Interactions**: Make sure your app’s web3 interactions are clear and match the UI actions. For example, a “Mint” button should clearly emit a mint transaction.
+- **Standard Sign-in Methods**: Provide all standard connection methods for users to sign in, such as WalletConnect / WalletLink or popular browser extension wallets.
+
+---
+
+## Verification Request
+
+Once you’ve implemented these best practices, consider submitting a verification request through the following [form](https://report.blockaid.io/). This step helps ensure that your app is recognized as safe and verified by trusted sources in the ecosystem.
+
+By following these recommendations, you’ll significantly reduce the chances of your app being flagged as malicious and foster a secure and trustworthy environment for your users.
+
+---
diff --git a/apps/base-docs/docs/security/bounty.md b/apps/base-docs/docs/security/bounty.md
new file mode 100644
index 00000000000..6b7c2cdfbe4
--- /dev/null
+++ b/apps/base-docs/docs/security/bounty.md
@@ -0,0 +1,18 @@
+---
+title: Bug bounty
+slug: /security/bounty
+description: The Base bug bounty program
+keywords:
+ [Base, HackerOne, bug bounty program, bug report, Base network, Bedrock, Optimism, open source]
+hide_table_of_contents: true
+---
+
+# Bug bounty program
+
+In line with our strategy of being the safest way for users to access crypto:
+
+- Coinbase will be extending our [best-in-industry](https://www.coinbase.com/blog/celebrating-10-years-of-our-bug-bounty-program) million-dollar [HackerOne bug bounty program](https://hackerone.com/coinbase?type=team) to cover the Base network, the Base bridge contracts, and Base infrastructure.
+- Coinbase will be working in tandem with OP Labs to harden the security guarantees of Bedrock and accelerate the timeline for decentralized fault-proofs on the [OP Stack](https://stack.optimism.io/).
+- Coinbase's bug bounty program will run alongside Optimism's existing [Immunefi Bedrock bounty program](https://immunefi.com/bounty/optimism/) to support the open source [Bedrock](https://stack.optimism.io/docs/releases/bedrock/) OP Stack framework.
+
+---
diff --git a/apps/base-docs/docs/security/report.md b/apps/base-docs/docs/security/report.md
new file mode 100644
index 00000000000..f67678a92dd
--- /dev/null
+++ b/apps/base-docs/docs/security/report.md
@@ -0,0 +1,29 @@
+---
+title: Report vulnerability
+slug: /security/report
+description: The Base procedures for reporting vulnerabilities.
+keywords:
+ [
+ Base,
+ report vulnerability,
+ cybersecurity,
+ HackerOne,
+ Base network,
+ Bedrock,
+ Optimism,
+ vulnerability reporting,
+ crypto security,
+ open source,
+ ]
+hide_table_of_contents: true
+---
+
+# Reporting vulnerabilities
+
+All potential vulnerability reports can be submitted via the [HackerOne](https://hackerone.com/coinbase) platform.
+
+The HackerOne platform allows us to have a centralized and single reporting source for us to deliver optimized SLA's and results. All reports submitted to the platform are triaged around the clock by our team of Coinbase engineers with domain knowledge, assuring the best quality of review.
+
+For more information on reporting vulnerabilities and our HackerOne bug bounty program, view our [security program policies](https://hackerone.com/coinbase?view_policy=true).
+
+---
diff --git a/apps/base-docs/sidebars.js b/apps/base-docs/sidebars.js
index ec5243aad76..4bf6b60c602 100644
--- a/apps/base-docs/sidebars.js
+++ b/apps/base-docs/sidebars.js
@@ -86,7 +86,13 @@ module.exports = {
items: ['tokens/token-list', 'tokens/wallet'],
},
['contracts'],
- ['security'],
+ {
+ type: 'category',
+ label: 'Security',
+ collapsible: false,
+ collapsed: false,
+ items: ['security/bounty', 'security/report', 'security/app-blocklist'],
+ },
{
type: 'link',
label: 'Status',
From e7e63f2aea7a936e9f1c84aa03dc4d638d40b68a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?L=C3=A9o=20Galley?=
Date: Mon, 4 Nov 2024 11:28:17 -0500
Subject: [PATCH 5/8] Github action: check for large files (#1199)
* github action: check for large files
* fix action
* comment setup
* fix file checker
---
.github/workflows/file-size-checker.yml | 128 ++++++++++++++++++++++++
1 file changed, 128 insertions(+)
create mode 100644 .github/workflows/file-size-checker.yml
diff --git a/.github/workflows/file-size-checker.yml b/.github/workflows/file-size-checker.yml
new file mode 100644
index 00000000000..18fbc30fc90
--- /dev/null
+++ b/.github/workflows/file-size-checker.yml
@@ -0,0 +1,128 @@
+name: File Size Checker
+
+# Add required permissions
+permissions:
+ contents: read
+ pull-requests: write
+ statuses: write
+
+on:
+ pull_request:
+ types: [opened, synchronize]
+
+jobs:
+ check-file-sizes:
+ name: File Size Check
+ runs-on: ubuntu-latest
+
+ steps:
+ # - name: Setup environment
+ # run: |
+ # apt-get update
+ # apt-get install -y git bc
+
+ - name: Checkout code
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+
+ - name: Check file sizes
+ id: check-sizes
+ run: |
+ # Initialize variables for tracking findings
+ large_files=""
+ huge_files=""
+
+ # Get all files in the PR
+ echo "Files changed in PR:"
+ git diff --name-only ${{ github.event.pull_request.base.sha }} ${{ github.event.pull_request.head.sha }}
+
+ for file in $(git diff --name-only ${{ github.event.pull_request.base.sha }} ${{ github.event.pull_request.head.sha }}); do
+ if [ -f "$file" ]; then
+ size=$(stat -c%s "$file")
+ size_mb=$(echo "scale=2; $size/1048576" | bc)
+
+ echo "Checking $file: ${size_mb}MB"
+
+ # Check for files over 40MB
+ if (( $(echo "$size_mb > 40" | bc -l) )); then
+ huge_files="${huge_files}* ${file} (${size_mb}MB)\n"
+ # Check for files over 10MB
+ elif (( $(echo "$size_mb > 10" | bc -l) )); then
+ large_files="${large_files}* ${file} (${size_mb}MB)\n"
+ fi
+ fi
+ done
+
+ # Print findings for debugging
+ echo "Large files found:"
+ echo -e "$large_files"
+ echo "Huge files found:"
+ echo -e "$huge_files"
+
+ # Set outputs for use in next steps
+ echo "large_files<> $GITHUB_OUTPUT
+ echo -e "$large_files" >> $GITHUB_OUTPUT
+ echo "EOF" >> $GITHUB_OUTPUT
+
+ echo "huge_files<> $GITHUB_OUTPUT
+ echo -e "$huge_files" >> $GITHUB_OUTPUT
+ echo "EOF" >> $GITHUB_OUTPUT
+
+ # Fail if huge files are found
+ if [ ! -z "$huge_files" ]; then
+ echo "❌ Files over 40MB found!"
+ exit 1
+ fi
+
+ - name: Update Status and Comment
+ if: always()
+ uses: actions/github-script@v7
+ with:
+ github-token: ${{ secrets.GITHUB_TOKEN }}
+ script: |
+ const hugeFiles = `${{ steps.check-sizes.outputs.huge_files }}`;
+ const largeFiles = `${{ steps.check-sizes.outputs.large_files }}`;
+
+ try {
+ console.log('Repository:', context.payload.repository.name);
+ console.log('Owner:', context.payload.repository.owner.login);
+ console.log('SHA:', context.payload.pull_request.head.sha);
+
+ // Set status check that will be used by branch protection
+ await github.rest.repos.createCommitStatus({
+ owner: context.payload.repository.owner.login,
+ repo: context.payload.repository.name,
+ sha: context.payload.pull_request.head.sha,
+ state: hugeFiles ? 'failure' : 'success',
+ context: 'File Size Check',
+ description: hugeFiles ? 'Files over 40MB found' : 'All files within size limits',
+ target_url: `https://github.com/${context.payload.repository.owner.login}/${context.payload.repository.name}/actions/runs/${context.runId}`
+ });
+
+ // Only comment if issues were found
+ if (hugeFiles || largeFiles) {
+ let comment = '## ⚠️ File Size Check Results\n\n';
+
+ if (hugeFiles) {
+ comment += '### 🚫 Files over 40MB (Not Allowed):\n' + hugeFiles + '\n';
+ comment += '**These files must be removed from git history before the PR can be merged.**\n\n';
+ }
+
+ if (largeFiles) {
+ comment += '### ⚠️ Large Files (Over 10MB):\n' + largeFiles + '\n';
+ comment += 'Consider reducing the size of these files if possible.\n';
+ }
+
+ await github.rest.issues.createComment({
+ issue_number: context.payload.pull_request.number,
+ owner: context.payload.repository.owner.login,
+ repo: context.payload.repository.name,
+ body: comment
+ });
+ }
+ } catch (error) {
+ console.error('Error:', error);
+ console.error('Context:', JSON.stringify(context.payload, null, 2));
+ core.setFailed(error.message);
+ }
From dc16fec1cd016be8cb25862cc9e2dcf9ff05755a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?L=C3=A9o=20Galley?=
Date: Mon, 4 Nov 2024 15:33:14 -0500
Subject: [PATCH 6/8] Feat: IPFS + Cloudinary integration (#1201)
* IPFS + Cloudinary integration
* faster proxy
* lint
* mb feedback
---
.../name/[username]/opengraph-image.tsx | 36 ++++++++++-----
.../basenames/[name]/assets/cardImage.svg.tsx | 45 ++++++++++++-------
.../RegistrationProfileForm/index.tsx | 3 --
.../Basenames/UsernameProfileCard/index.tsx | 3 +-
.../Basenames/UsernameProfileCasts/index.tsx | 3 +-
.../UsernameProfileSectionFrames/Context.tsx | 3 +-
.../UsernameProfileSettingsAvatar/index.tsx | 3 +-
.../index.tsx | 3 +-
.../UsernameProfileSidebar/index.tsx | 1 -
.../ConnectWalletButton/UserAvatar.tsx | 4 --
.../src/components/WalletIdentity/index.tsx | 4 --
apps/web/src/hooks/useBaseEnsAvatar.ts | 39 ++++++++--------
.../src/hooks/useReadBaseEnsTextRecords.ts | 13 +-----
.../src/hooks/useWriteBaseEnsTextRecords.ts | 5 +--
apps/web/src/utils/images.ts | 9 +++-
apps/web/src/utils/pinata.ts | 2 +-
apps/web/src/utils/urls.ts | 34 ++++++++------
apps/web/src/utils/usernames.ts | 2 +-
18 files changed, 114 insertions(+), 98 deletions(-)
diff --git a/apps/web/app/(basenames)/name/[username]/opengraph-image.tsx b/apps/web/app/(basenames)/name/[username]/opengraph-image.tsx
index bcd0ef107a3..073788206cc 100644
--- a/apps/web/app/(basenames)/name/[username]/opengraph-image.tsx
+++ b/apps/web/app/(basenames)/name/[username]/opengraph-image.tsx
@@ -7,11 +7,16 @@ import { isDevelopment } from 'apps/web/src/constants';
import {
formatBaseEthDomain,
getBasenameImage,
+ getChainForBasename,
USERNAME_DOMAINS,
+ UsernameTextRecordKeys,
} from 'apps/web/src/utils/usernames';
import { base, baseSepolia } from 'viem/chains';
import { USERNAME_L2_RESOLVER_ADDRESSES } from 'apps/web/src/addresses/usernames';
-import { CLOUDFARE_IPFS_PROXY } from 'apps/web/src/utils/urls';
+import { getIpfsGatewayUrl, IpfsUrl, IsValidIpfsUrl } from 'apps/web/src/utils/urls';
+import { Basename } from '@coinbase/onchainkit/identity';
+import { getCloudinaryMediaUrl } from 'apps/web/src/utils/images';
+import { logger } from 'apps/web/src/utils/logger';
export const runtime = 'edge';
const size = {
@@ -63,24 +68,35 @@ export default async function OpenGraphImage(props: ImageRouteProps) {
const domainName = isDevelopment ? `http://localhost:3000` : 'https://www.base.org';
const profilePicture = getBasenameImage(username);
+ const chain = getChainForBasename(username as Basename);
let imageSource = domainName + profilePicture.src;
// NOTE: Do we want to fail if the name doesn't exists?
try {
- const client = getBasenamePublicClient(base.id);
- const avatar = await client.getEnsAvatar({
+ const client = getBasenamePublicClient(chain.id);
+ const avatar = await client.getEnsText({
name: username,
- universalResolverAddress: USERNAME_L2_RESOLVER_ADDRESSES[base.id],
- assetGatewayUrls: {
- ipfs: CLOUDFARE_IPFS_PROXY,
- },
+ key: UsernameTextRecordKeys.Avatar,
+ universalResolverAddress: USERNAME_L2_RESOLVER_ADDRESSES[chain.id],
});
- // Satori Doesn't support webp
- if (avatar && !avatar.endsWith('.webp')) {
+ if (!avatar) return;
+
+ // IPFS Resolution
+ if (IsValidIpfsUrl(avatar)) {
+ const ipfsUrl = getIpfsGatewayUrl(avatar as IpfsUrl);
+ if (ipfsUrl) {
+ imageSource = ipfsUrl;
+ }
+ } else {
imageSource = avatar;
}
- } catch (error) {}
+
+ // Cloudinary resize / fetch
+ imageSource = getCloudinaryMediaUrl({ media: imageSource, format: 'png', width: 80 });
+ } catch (error) {
+ logger.error('Error fetching basename Avatar:', error);
+ }
return new ImageResponse(
(
diff --git a/apps/web/pages/api/basenames/[name]/assets/cardImage.svg.tsx b/apps/web/pages/api/basenames/[name]/assets/cardImage.svg.tsx
index 8119f167c03..deabe8d1994 100644
--- a/apps/web/pages/api/basenames/[name]/assets/cardImage.svg.tsx
+++ b/apps/web/pages/api/basenames/[name]/assets/cardImage.svg.tsx
@@ -1,13 +1,20 @@
import satori from 'satori';
import { NextRequest } from 'next/server';
-import { getBasenameImage } from 'apps/web/src/utils/usernames';
+import {
+ getBasenameImage,
+ getChainForBasename,
+ UsernameTextRecordKeys,
+} from 'apps/web/src/utils/usernames';
import twemoji from 'twemoji';
-import { base } from 'viem/chains';
import { getBasenamePublicClient } from 'apps/web/src/hooks/useBasenameChain';
import { USERNAME_L2_RESOLVER_ADDRESSES } from 'apps/web/src/addresses/usernames';
import { isDevelopment } from 'apps/web/src/constants';
import ImageRaw from 'apps/web/src/components/ImageRaw';
-import { CLOUDFARE_IPFS_PROXY } from 'apps/web/src/utils/urls';
+import { getIpfsGatewayUrl, IpfsUrl, IsValidIpfsUrl } from 'apps/web/src/utils/urls';
+import { logger } from 'apps/web/src/utils/logger';
+import { Basename } from '@coinbase/onchainkit/identity';
+import { getCloudinaryMediaUrl } from 'apps/web/src/utils/images';
+
const emojiCache: Record> = {};
export async function loadEmoji(emojiString: string) {
@@ -37,26 +44,34 @@ export default async function handler(request: NextRequest) {
const username = url.searchParams.get('name') ?? 'yourname';
const domainName = isDevelopment ? `${url.protocol}//${url.host}` : 'https://www.base.org';
const profilePicture = getBasenameImage(username);
- const chainIdFromParams = url.searchParams.get('chainId');
- const chainId = chainIdFromParams ? Number(chainIdFromParams) : base.id;
+ const chain = getChainForBasename(username as Basename);
let imageSource = domainName + profilePicture.src;
- // NOTE: Do we want to fail if the name doesn't exists?
try {
- const client = getBasenamePublicClient(chainId);
- const avatar = await client.getEnsAvatar({
+ const client = getBasenamePublicClient(chain.id);
+ const avatar = await client.getEnsText({
name: username,
- universalResolverAddress: USERNAME_L2_RESOLVER_ADDRESSES[chainId],
- assetGatewayUrls: {
- ipfs: CLOUDFARE_IPFS_PROXY,
- },
+ key: UsernameTextRecordKeys.Avatar,
+ universalResolverAddress: USERNAME_L2_RESOLVER_ADDRESSES[chain.id],
});
- // Satori Doesn't support webp
- if (avatar && !avatar.endsWith('.webp')) {
+ if (!avatar) return;
+
+ // IPFS Resolution
+ if (IsValidIpfsUrl(avatar)) {
+ const ipfsUrl = getIpfsGatewayUrl(avatar as IpfsUrl);
+ if (ipfsUrl) {
+ imageSource = ipfsUrl;
+ }
+ } else {
imageSource = avatar;
}
- } catch (error) {}
+
+ // Cloudinary resize / fetch
+ imageSource = getCloudinaryMediaUrl({ media: imageSource, format: 'png', width: 120 });
+ } catch (error) {
+ logger.error('Error fetching basename Avatar:', error);
+ }
// Using Satori for a SVG response
const svg = await satori(
diff --git a/apps/web/src/components/Basenames/RegistrationProfileForm/index.tsx b/apps/web/src/components/Basenames/RegistrationProfileForm/index.tsx
index 5af3e7d881a..3856b5bfe1c 100644
--- a/apps/web/src/components/Basenames/RegistrationProfileForm/index.tsx
+++ b/apps/web/src/components/Basenames/RegistrationProfileForm/index.tsx
@@ -20,7 +20,6 @@ import {
import classNames from 'classnames';
import { ActionType } from 'libs/base-ui/utils/logEvent';
import { useCallback, useEffect, useState } from 'react';
-import { useAccount } from 'wagmi';
export enum FormSteps {
Description = 'description',
@@ -33,7 +32,6 @@ export default function RegistrationProfileForm() {
const [transitionStep, setTransitionStep] = useState(false);
const { logError } = useErrors();
const { redirectToProfile, selectedNameFormatted } = useRegistration();
- const { address } = useAccount();
const { logEventWithContext } = useAnalytics();
const {
@@ -43,7 +41,6 @@ export default function RegistrationProfileForm() {
writeTextRecordsIsPending,
writeTextRecordsError,
} = useWriteBaseEnsTextRecords({
- address: address,
username: selectedNameFormatted,
onSuccess: () => {
redirectToProfile();
diff --git a/apps/web/src/components/Basenames/UsernameProfileCard/index.tsx b/apps/web/src/components/Basenames/UsernameProfileCard/index.tsx
index c6a5cdf9b31..5f12f8bb874 100644
--- a/apps/web/src/components/Basenames/UsernameProfileCard/index.tsx
+++ b/apps/web/src/components/Basenames/UsernameProfileCard/index.tsx
@@ -12,10 +12,9 @@ import {
import Link from 'next/link';
export default function UsernameProfileCard() {
- const { profileUsername, profileAddress } = useUsernameProfile();
+ const { profileUsername } = useUsernameProfile();
const { existingTextRecords } = useReadBaseEnsTextRecords({
- address: profileAddress,
username: profileUsername,
});
diff --git a/apps/web/src/components/Basenames/UsernameProfileCasts/index.tsx b/apps/web/src/components/Basenames/UsernameProfileCasts/index.tsx
index c64edd61132..cb96899230b 100644
--- a/apps/web/src/components/Basenames/UsernameProfileCasts/index.tsx
+++ b/apps/web/src/components/Basenames/UsernameProfileCasts/index.tsx
@@ -6,10 +6,9 @@ import NeymarCast from 'apps/web/src/components/NeymarCast';
import useReadBaseEnsTextRecords from 'apps/web/src/hooks/useReadBaseEnsTextRecords';
export default function UsernameProfileCasts() {
- const { profileUsername, profileAddress } = useUsernameProfile();
+ const { profileUsername } = useUsernameProfile();
const { existingTextRecords } = useReadBaseEnsTextRecords({
- address: profileAddress,
username: profileUsername,
});
const casts = existingTextRecords.casts.split(',').filter((cast) => !!cast);
diff --git a/apps/web/src/components/Basenames/UsernameProfileSectionFrames/Context.tsx b/apps/web/src/components/Basenames/UsernameProfileSectionFrames/Context.tsx
index 9dfb63af6a0..d92cad22a7f 100644
--- a/apps/web/src/components/Basenames/UsernameProfileSectionFrames/Context.tsx
+++ b/apps/web/src/components/Basenames/UsernameProfileSectionFrames/Context.tsx
@@ -89,10 +89,9 @@ export function FramesProvider({ children }: FramesProviderProps) {
const { logEventWithContext } = useAnalytics();
const { address } = useAccount();
const { logError } = useErrors();
- const { profileUsername, profileAddress, currentWalletIsProfileOwner } = useUsernameProfile();
+ const { profileUsername, currentWalletIsProfileOwner } = useUsernameProfile();
const { existingTextRecords, existingTextRecordsIsLoading, refetchExistingTextRecords } =
useReadBaseEnsTextRecords({
- address: profileAddress,
username: profileUsername,
refetchInterval: currentWalletIsProfileOwner ? 1000 * 5 : Infinity,
});
diff --git a/apps/web/src/components/Basenames/UsernameProfileSettingsAvatar/index.tsx b/apps/web/src/components/Basenames/UsernameProfileSettingsAvatar/index.tsx
index b119fc38dcd..5caa3e98c0b 100644
--- a/apps/web/src/components/Basenames/UsernameProfileSettingsAvatar/index.tsx
+++ b/apps/web/src/components/Basenames/UsernameProfileSettingsAvatar/index.tsx
@@ -13,7 +13,7 @@ import { Icon } from 'apps/web/src/components/Icon/Icon';
import { PinResponse } from 'pinata';
export default function UsernameProfileSettingsAvatar() {
- const { profileUsername, profileAddress, currentWalletIsProfileEditor } = useUsernameProfile();
+ const { profileUsername, currentWalletIsProfileEditor } = useUsernameProfile();
const [avatarFile, setAvatarFile] = useState();
const [avatarIsLoading, setAvatarIsLoading] = useState(false);
@@ -30,7 +30,6 @@ export default function UsernameProfileSettingsAvatar() {
writeTextRecordsIsPending,
hasChanged,
} = useWriteBaseEnsTextRecords({
- address: profileAddress,
username: profileUsername,
onSuccess: () => {
setAvatarFile(undefined);
diff --git a/apps/web/src/components/Basenames/UsernameProfileSettingsManageProfile/index.tsx b/apps/web/src/components/Basenames/UsernameProfileSettingsManageProfile/index.tsx
index 9940f8a2678..ca9d6941c2d 100644
--- a/apps/web/src/components/Basenames/UsernameProfileSettingsManageProfile/index.tsx
+++ b/apps/web/src/components/Basenames/UsernameProfileSettingsManageProfile/index.tsx
@@ -24,7 +24,7 @@ const settingTabClass = classNames(
);
export default function UsernameProfileSettingsManageProfile() {
- const { profileUsername, profileAddress, currentWalletIsProfileEditor, setShowProfileSettings } =
+ const { profileUsername, currentWalletIsProfileEditor, setShowProfileSettings } =
useUsernameProfile();
const { logError } = useErrors();
@@ -42,7 +42,6 @@ export default function UsernameProfileSettingsManageProfile() {
writeTextRecordsError,
hasChanged,
} = useWriteBaseEnsTextRecords({
- address: profileAddress,
username: profileUsername,
onSuccess: closeSettings,
});
diff --git a/apps/web/src/components/Basenames/UsernameProfileSidebar/index.tsx b/apps/web/src/components/Basenames/UsernameProfileSidebar/index.tsx
index c202f00b93a..a4e83c909fa 100644
--- a/apps/web/src/components/Basenames/UsernameProfileSidebar/index.tsx
+++ b/apps/web/src/components/Basenames/UsernameProfileSidebar/index.tsx
@@ -44,7 +44,6 @@ export default function UsernameProfileSidebar() {
]);
const { existingTextRecords } = useReadBaseEnsTextRecords({
- address: profileAddress,
username: profileUsername,
});
diff --git a/apps/web/src/components/ConnectWalletButton/UserAvatar.tsx b/apps/web/src/components/ConnectWalletButton/UserAvatar.tsx
index 726d74b5cce..97158ff3d6a 100644
--- a/apps/web/src/components/ConnectWalletButton/UserAvatar.tsx
+++ b/apps/web/src/components/ConnectWalletButton/UserAvatar.tsx
@@ -3,7 +3,6 @@ import { useAccount, useEnsAvatar, useEnsName } from 'wagmi';
import { mainnet } from 'wagmi/chains';
import useBaseEnsName from 'apps/web/src/hooks/useBaseEnsName';
import ImageWithLoading from 'apps/web/src/components/ImageWithLoading';
-import { CLOUDFARE_IPFS_PROXY } from 'apps/web/src/utils/urls';
import BasenameAvatar from 'apps/web/src/components/Basenames/BasenameAvatar';
export function UserAvatar() {
@@ -21,9 +20,6 @@ export function UserAvatar() {
const { data: ensAvatar, isLoading: ensAvatarIsLoading } = useEnsAvatar({
name: ensName ?? undefined,
chainId: mainnet.id,
- assetGatewayUrls: {
- ipfs: CLOUDFARE_IPFS_PROXY,
- },
query: {
retry: false,
},
diff --git a/apps/web/src/components/WalletIdentity/index.tsx b/apps/web/src/components/WalletIdentity/index.tsx
index 23dd79afa0a..9e525e2874d 100644
--- a/apps/web/src/components/WalletIdentity/index.tsx
+++ b/apps/web/src/components/WalletIdentity/index.tsx
@@ -4,7 +4,6 @@ import BasenameAvatar from 'apps/web/src/components/Basenames/BasenameAvatar';
import useBaseEnsAvatar from 'apps/web/src/hooks/useBaseEnsAvatar';
import useBaseEnsName from 'apps/web/src/hooks/useBaseEnsName';
import useBasenameChain from 'apps/web/src/hooks/useBasenameChain';
-import { CLOUDFARE_IPFS_PROXY } from 'apps/web/src/utils/urls';
import { getBasenameImage } from 'apps/web/src/utils/usernames';
import { truncateMiddle } from 'libs/base-ui/utils/string';
import Image from 'next/image';
@@ -33,9 +32,6 @@ export default function WalletIdentity({ address }: { address: Address }) {
const { data: ensAvatar } = useEnsAvatar({
name: basename ?? undefined,
chainId: mainnet.id,
- assetGatewayUrls: {
- ipfs: CLOUDFARE_IPFS_PROXY,
- },
query: {
retry: false,
},
diff --git a/apps/web/src/hooks/useBaseEnsAvatar.ts b/apps/web/src/hooks/useBaseEnsAvatar.ts
index feb0cf4d438..231e3a6c690 100644
--- a/apps/web/src/hooks/useBaseEnsAvatar.ts
+++ b/apps/web/src/hooks/useBaseEnsAvatar.ts
@@ -1,8 +1,7 @@
-import useBasenameChain from 'apps/web/src/hooks/useBasenameChain';
import { Basename } from '@coinbase/onchainkit/identity';
-import { useEnsAvatar } from 'wagmi';
-import { USERNAME_L2_RESOLVER_ADDRESSES } from 'apps/web/src/addresses/usernames';
-import { CLOUDFARE_IPFS_PROXY } from 'apps/web/src/utils/urls';
+import { getIpfsGatewayUrl, IpfsUrl, IsValidIpfsUrl } from 'apps/web/src/utils/urls';
+import useReadBaseEnsTextRecords from 'apps/web/src/hooks/useReadBaseEnsTextRecords';
+import { UsernameTextRecordKeys } from 'apps/web/src/utils/usernames';
export type UseBaseEnsNameProps = {
name?: BaseEnsNameData;
@@ -10,20 +9,24 @@ export type UseBaseEnsNameProps = {
export type BaseEnsNameData = Basename | undefined;
-// Wrapper around onchainkit's useName
export default function useBaseEnsAvatar({ name }: UseBaseEnsNameProps) {
- const { basenameChain } = useBasenameChain(name);
+ const { existingTextRecords, refetchExistingTextRecords, existingTextRecordsIsLoading } =
+ useReadBaseEnsTextRecords({
+ username: name,
+ });
- return useEnsAvatar({
- name: name,
- chainId: basenameChain.id,
- universalResolverAddress: USERNAME_L2_RESOLVER_ADDRESSES[basenameChain.id],
- assetGatewayUrls: {
- ipfs: CLOUDFARE_IPFS_PROXY,
- },
- query: {
- retry: false,
- enabled: !!name,
- },
- });
+ let avatar = existingTextRecords[UsernameTextRecordKeys.Avatar];
+
+ if (IsValidIpfsUrl(avatar)) {
+ const ipfsUrl = getIpfsGatewayUrl(avatar as IpfsUrl);
+ if (ipfsUrl) {
+ avatar = ipfsUrl;
+ }
+ }
+
+ return {
+ data: avatar,
+ refetch: refetchExistingTextRecords,
+ isLoading: existingTextRecordsIsLoading,
+ };
}
diff --git a/apps/web/src/hooks/useReadBaseEnsTextRecords.ts b/apps/web/src/hooks/useReadBaseEnsTextRecords.ts
index 979737d7a33..27a78aca4d1 100644
--- a/apps/web/src/hooks/useReadBaseEnsTextRecords.ts
+++ b/apps/web/src/hooks/useReadBaseEnsTextRecords.ts
@@ -1,5 +1,4 @@
import { useCallback, useEffect, useMemo, useState } from 'react';
-import { Address } from 'viem';
import {
UsernameTextRecords,
UsernameTextRecordKeys,
@@ -11,13 +10,11 @@ import { BaseEnsNameData } from 'apps/web/src/hooks/useBaseEnsName';
import useBasenameChain from 'apps/web/src/hooks/useBasenameChain';
export type UseReadBaseEnsTextRecordsProps = {
- address?: Address;
username: BaseEnsNameData;
refetchInterval?: number;
};
export default function useReadBaseEnsTextRecords({
- address,
username,
refetchInterval = Infinity,
}: UseReadBaseEnsTextRecordsProps) {
@@ -69,15 +66,9 @@ export default function useReadBaseEnsTextRecords({
refetch: refetchExistingTextRecords,
error: existingTextRecordsError,
} = useQuery({
- queryKey: [
- 'useReadBaseEnsTextRecords',
- address,
- textRecordsKeysEnabled,
- basenameChain.id,
- username,
- ],
+ queryKey: ['useReadBaseEnsTextRecords', textRecordsKeysEnabled, basenameChain.id, username],
queryFn: getExistingTextRecords,
- enabled: !!address && !!username,
+ enabled: !!username,
retry: false,
refetchInterval,
refetchOnWindowFocus: false,
diff --git a/apps/web/src/hooks/useWriteBaseEnsTextRecords.ts b/apps/web/src/hooks/useWriteBaseEnsTextRecords.ts
index d45c7f6fe99..0ea0a9d5821 100644
--- a/apps/web/src/hooks/useWriteBaseEnsTextRecords.ts
+++ b/apps/web/src/hooks/useWriteBaseEnsTextRecords.ts
@@ -8,10 +8,9 @@ import useReadBaseEnsTextRecords from 'apps/web/src/hooks/useReadBaseEnsTextReco
import useWriteContractWithReceipt from 'apps/web/src/hooks/useWriteContractWithReceipt';
import { UsernameTextRecords, UsernameTextRecordKeys } from 'apps/web/src/utils/usernames';
import { useCallback, useEffect, useMemo, useState } from 'react';
-import { namehash, encodeFunctionData, Address } from 'viem';
+import { namehash, encodeFunctionData } from 'viem';
export type UseWriteBaseEnsTextRecordsProps = {
- address?: Address;
username: BaseEnsNameData;
onSuccess?: () => void;
};
@@ -29,7 +28,6 @@ export type UseWriteBaseEnsTextRecordsProps = {
*/
export default function useWriteBaseEnsTextRecords({
- address,
username,
onSuccess,
}: UseWriteBaseEnsTextRecordsProps) {
@@ -39,7 +37,6 @@ export default function useWriteBaseEnsTextRecords({
// Fetch existing TextRecords
const { existingTextRecords, existingTextRecordsIsLoading, refetchExistingTextRecords } =
useReadBaseEnsTextRecords({
- address,
username,
});
diff --git a/apps/web/src/utils/images.ts b/apps/web/src/utils/images.ts
index 4f8f5252c15..809799640f2 100644
--- a/apps/web/src/utils/images.ts
+++ b/apps/web/src/utils/images.ts
@@ -30,13 +30,18 @@ function isDataUrl(url: string) {
type GetCloudinaryMediaUrlParams = {
media: string;
width: number;
+ format?: 'webp' | 'png' | 'jpg';
};
-export function getCloudinaryMediaUrl({ media, width }: GetCloudinaryMediaUrlParams) {
+export function getCloudinaryMediaUrl({
+ media,
+ width,
+ format = 'webp',
+}: GetCloudinaryMediaUrlParams) {
if (isDataUrl(media)) return media;
const imageWidth = `w_${width * 2}`;
- const imageFormat = 'f_webp';
+ const imageFormat = `f_${format}`;
const imageUrl = encodeURIComponent(media);
const fetchOptions = [imageWidth, imageFormat, imageUrl].join('/');
diff --git a/apps/web/src/utils/pinata.ts b/apps/web/src/utils/pinata.ts
index 62555ec85c4..403616bc630 100644
--- a/apps/web/src/utils/pinata.ts
+++ b/apps/web/src/utils/pinata.ts
@@ -2,5 +2,5 @@ import { PinataSDK } from 'pinata';
export const pinata = new PinataSDK({
pinataJwt: `${process.env.PINATA_API_KEY}`,
- pinataGateway: `${process.env.NEXT_PUBLIC_PINATA_GATEWAY_URL}`,
+ pinataGateway: `${process.env.PINATA_GATEWAY_URL}`,
});
diff --git a/apps/web/src/utils/urls.ts b/apps/web/src/utils/urls.ts
index 2bcd097590a..f3e3a4b83fd 100644
--- a/apps/web/src/utils/urls.ts
+++ b/apps/web/src/utils/urls.ts
@@ -3,9 +3,9 @@ import { cid } from 'is-ipfs';
export type IpfsUrl = `ipfs://${string}`;
export const VERCEL_BLOB_HOSTNAME = 'zku9gdedgba48lmr.public.blob.vercel-storage.com';
export const IPFS_URI_PROTOCOL = 'ipfs://';
-export const CLOUDFARE_IPFS_PROXY = process.env.NEXT_PUBLIC_PINATA_GATEWAY_URL
- ? `https://${process.env.NEXT_PUBLIC_PINATA_GATEWAY_URL}`
- : 'https://cloudflare-ipfs.com';
+
+export const PINATA_GATEWAY_URL = process.env.NEXT_PUBLIC_PINATA_GATEWAY_URL ?? undefined;
+export const PINATA_GATEWAY_KEY = process.env.NEXT_PUBLIC_PINATA_GATEWAY_KEY ?? undefined;
export type QueryParams = Record;
@@ -28,13 +28,17 @@ export function isValidUrl(string?: string) {
}
}
-export const IsValidIpfsUrl = (ipfsUrl: IpfsUrl): boolean => {
+export const IsValidIpfsUrl = (ipfsUrl: string): boolean => {
try {
const url = new URL(ipfsUrl);
- const ipfsCid = url.pathname.replace('//', '');
+ if (url.protocol !== 'ipfs:') return false;
+
+ // Get first path segment after hostname as CID
+ const ipfsCid = url.host;
+
+ // Validate the CID directly
const isValidCid = cid(ipfsCid);
- const isValidIpfsUrl = url.protocol === 'ipfs:' && isValidCid;
- return isValidIpfsUrl;
+ return isValidCid;
} catch (error) {
return false;
}
@@ -50,18 +54,20 @@ export const IsValidVercelBlobUrl = (source: string): boolean => {
}
};
-export const getIpfsGatewayUrl = (ipfsUrl?: IpfsUrl): string | undefined => {
+export const getIpfsGatewayUrl = (ipfsUrl: IpfsUrl): string | undefined => {
if (!ipfsUrl) return;
+ if (!IsValidIpfsUrl(ipfsUrl)) return;
try {
const url = new URL(ipfsUrl);
- const ipfsCid = url.pathname.replace('//', '');
-
- const isValidCid = cid(ipfsCid);
- const isValidIpfsUrl = url.protocol === 'ipfs:' && isValidCid;
- if (!isValidIpfsUrl) return;
+ const path = url.host;
+ const pathname = url.pathname;
- return `${CLOUDFARE_IPFS_PROXY}/ipfs/${ipfsCid}`;
+ if (PINATA_GATEWAY_URL && PINATA_GATEWAY_KEY) {
+ return `https://${PINATA_GATEWAY_URL}/ipfs/${path}${pathname}?pinataGatewayToken=${PINATA_GATEWAY_KEY}`;
+ } else {
+ return `https://ipfs.io/ipfs/${path}${pathname}`;
+ }
} catch (error) {
return;
}
diff --git a/apps/web/src/utils/usernames.ts b/apps/web/src/utils/usernames.ts
index 7ecb1ae17f1..7403afeec72 100644
--- a/apps/web/src/utils/usernames.ts
+++ b/apps/web/src/utils/usernames.ts
@@ -508,7 +508,7 @@ export function validateBasenameAvatarUrl(source: string): ValidationResult {
const url = new URL(source);
if (url.protocol === 'ipfs:') {
- const isValid = IsValidIpfsUrl(source as IpfsUrl);
+ const isValid = IsValidIpfsUrl(source);
return {
valid: isValid,
From 76c7bc3cabaf3f868c8817a3e747c03ff9c40896 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?L=C3=A9o=20Galley?=
Date: Tue, 5 Nov 2024 16:18:53 -0500
Subject: [PATCH 7/8] BAPP-765: ERC1155-v2 support for Basename (#1207)
* add address, attestations and hooks for testnet
* around the world
---
.../src/abis/ERC1155DiscountValidatorV2.ts | 58 ++++
apps/web/src/addresses/usernames.ts | 5 +
.../images/base-around-the-world-nft.svg | 20 ++
.../RegistrationLearnMoreModal/index.tsx | 300 +++++++-----------
.../hooks/useAggregatedDiscountValidators.ts | 13 +-
apps/web/src/hooks/useAttestations.ts | 46 +++
apps/web/src/utils/usernames.ts | 1 +
7 files changed, 250 insertions(+), 193 deletions(-)
create mode 100644 apps/web/src/abis/ERC1155DiscountValidatorV2.ts
create mode 100644 apps/web/src/components/Basenames/RegistrationLearnMoreModal/images/base-around-the-world-nft.svg
diff --git a/apps/web/src/abis/ERC1155DiscountValidatorV2.ts b/apps/web/src/abis/ERC1155DiscountValidatorV2.ts
new file mode 100644
index 00000000000..d7caaae4c19
--- /dev/null
+++ b/apps/web/src/abis/ERC1155DiscountValidatorV2.ts
@@ -0,0 +1,58 @@
+export default [
+ {
+ type: 'constructor',
+ inputs: [
+ {
+ name: 'token_',
+ type: 'address',
+ internalType: 'address',
+ },
+ {
+ name: 'tokenIds',
+ type: 'uint256[]',
+ internalType: 'uint256[]',
+ },
+ ],
+ stateMutability: 'nonpayable',
+ },
+ {
+ type: 'function',
+ name: 'isValidDiscountRegistration',
+ inputs: [
+ {
+ name: 'claimer',
+ type: 'address',
+ internalType: 'address',
+ },
+ {
+ name: 'validationData',
+ type: 'bytes',
+ internalType: 'bytes',
+ },
+ ],
+ outputs: [
+ {
+ name: '',
+ type: 'bool',
+ internalType: 'bool',
+ },
+ ],
+ stateMutability: 'view',
+ },
+ {
+ type: 'error',
+ name: 'AddressEmptyCode',
+ inputs: [
+ {
+ name: 'target',
+ type: 'address',
+ internalType: 'address',
+ },
+ ],
+ },
+ {
+ type: 'error',
+ name: 'FailedInnerCall',
+ inputs: [],
+ },
+] as const;
diff --git a/apps/web/src/addresses/usernames.ts b/apps/web/src/addresses/usernames.ts
index ec2077e4d0b..43e6e2f9adf 100644
--- a/apps/web/src/addresses/usernames.ts
+++ b/apps/web/src/addresses/usernames.ts
@@ -96,3 +96,8 @@ export const TALENT_PROTOCOL_DISCOUNT_VALIDATORS: AddressMap = {
[baseSepolia.id]: '0x8b769A3fbC29AC02344218840602615B6c9200e7',
[base.id]: '0xb16A4f14A9dED9e27F0Fe59Dc907D245769de19E',
};
+
+export const BASE_WORLD_DISCOUNT_VALIDATORS: AddressMap = {
+ [baseSepolia.id]: '0xFa69f6167F40247fe3EFF2d8375B25C5d7834c48',
+ [base.id]: '0xfEb00a4EfF372a307fDc556Cf4359f7D679E4d11',
+};
diff --git a/apps/web/src/components/Basenames/RegistrationLearnMoreModal/images/base-around-the-world-nft.svg b/apps/web/src/components/Basenames/RegistrationLearnMoreModal/images/base-around-the-world-nft.svg
new file mode 100644
index 00000000000..b75c9e6e709
--- /dev/null
+++ b/apps/web/src/components/Basenames/RegistrationLearnMoreModal/images/base-around-the-world-nft.svg
@@ -0,0 +1,20 @@
+
diff --git a/apps/web/src/components/Basenames/RegistrationLearnMoreModal/index.tsx b/apps/web/src/components/Basenames/RegistrationLearnMoreModal/index.tsx
index 4b2011840dd..5d8169c427e 100644
--- a/apps/web/src/components/Basenames/RegistrationLearnMoreModal/index.tsx
+++ b/apps/web/src/components/Basenames/RegistrationLearnMoreModal/index.tsx
@@ -13,6 +13,7 @@ import BaseNFT from './images/base-nft.svg';
import TalentProtocolIcon from './images/TalentProtocol.svg';
import coinbaseOneVerification from './images/coinbase-one-verification.svg';
import coinbaseVerification from './images/coinbase-verification.svg';
+import BaseWorldNFT from './images/base-around-the-world-nft.svg';
import { StaticImageData } from 'next/dist/shared/lib/get-img-props';
import ImageWithLoading from 'apps/web/src/components/ImageWithLoading';
@@ -20,6 +21,82 @@ function InfoIcon() {
return ;
}
+type DiscountItem = {
+ discount: Discount;
+ icon: StaticImageData;
+ alt: string;
+ label: string;
+ tooltipContent: string;
+};
+
+const DISCOUNT_ITEMS: DiscountItem[] = [
+ {
+ discount: Discount.COINBASE_VERIFIED_ACCOUNT,
+ icon: coinbaseVerification as StaticImageData,
+ alt: 'icon of coinbase',
+ label: 'Coinbase verification',
+ tooltipContent: 'Verifies you have a valid trading account on Coinbase',
+ },
+ {
+ discount: Discount.CB1,
+ icon: coinbaseOneVerification as StaticImageData,
+ alt: 'icon of coinbase one',
+ label: 'Coinbase One verification',
+ tooltipContent: 'Verifies you have an active Coinbase One subscription',
+ },
+ {
+ discount: Discount.CBID,
+ icon: cbidVerification as StaticImageData,
+ alt: 'icon of CBID',
+ label: 'A cb.id username',
+ tooltipContent: 'cb.id must have been claimed prior to August 9, 2024.',
+ },
+ {
+ discount: Discount.BASE_BUILDATHON_PARTICIPANT,
+ icon: baseBuildathonParticipant as StaticImageData,
+ alt: 'icon of base buildathon',
+ label: 'Base buildathon participant',
+ tooltipContent: 'Available for anyone holding a Base Buildathon participant NFT.',
+ },
+ {
+ discount: Discount.TALENT_PROTOCOL,
+ icon: TalentProtocolIcon as StaticImageData,
+ alt: 'icon of talent protocol',
+ label: 'Builder score 50+',
+ tooltipContent:
+ 'Available for anyone with an onchain builder score 50+. Go to passport.talentprotocol.com to mint yours.',
+ },
+ {
+ discount: Discount.SUMMER_PASS_LVL_3,
+ icon: summerPassLvl3 as StaticImageData,
+ alt: 'icon of summer pass',
+ label: 'Summer Pass Level 3',
+ tooltipContent:
+ 'Available for anyone holding a Summer Pass Level 3 NFT. Go to wallet.coinbase.com/ocs to get your Summer Pass',
+ },
+ {
+ discount: Discount.BNS_NAME,
+ icon: BNSOwnership,
+ alt: 'icon of BNS',
+ label: 'BNS username',
+ tooltipContent: 'BNS (.base) username holders are eligible for a 0.01 ETH discount',
+ },
+ {
+ discount: Discount.BASE_DOT_ETH_NFT,
+ icon: BaseNFT as StaticImageData,
+ alt: 'icon of Base',
+ label: 'Base.eth NFT',
+ tooltipContent: 'Available for anyone holding a base.eth NFT',
+ },
+ {
+ discount: Discount.BASE_WORLD,
+ icon: BaseWorldNFT as StaticImageData,
+ alt: 'icon of Base World',
+ label: 'Base around the world NFT',
+ tooltipContent: 'Available for anyone holding one of the Base around the world NFTs',
+ },
+];
+
export default function RegistrationLearnMoreModal({
isOpen,
toggleModal,
@@ -31,30 +108,6 @@ export default function RegistrationLearnMoreModal({
const hasDiscount = allActiveDiscounts.size > 0;
const rowClasses = 'flex flex-row items-center justify-start';
- const CBRowClasses = classNames(rowClasses, {
- 'opacity-40': hasDiscount && !allActiveDiscounts.has(Discount.COINBASE_VERIFIED_ACCOUNT),
- });
- const CB1RowClasses = classNames(rowClasses, {
- 'opacity-40': hasDiscount && !allActiveDiscounts.has(Discount.CB1),
- });
- const CBIDRowClasses = classNames(rowClasses, {
- 'opacity-40': hasDiscount && !allActiveDiscounts.has(Discount.CBID),
- });
- const BuildathonRowClasses = classNames(rowClasses, {
- 'opacity-40': hasDiscount && !allActiveDiscounts.has(Discount.BASE_BUILDATHON_PARTICIPANT),
- });
- const SummerPassRowClasses = classNames(rowClasses, {
- 'opacity-40': hasDiscount && !allActiveDiscounts.has(Discount.SUMMER_PASS_LVL_3),
- });
- const BNSRowClasses = classNames(rowClasses, {
- 'opacity-40': hasDiscount && !allActiveDiscounts.has(Discount.BNS_NAME),
- });
- const BaseDotEthNFTRowClasses = classNames(rowClasses, {
- 'opacity-40': hasDiscount && !allActiveDiscounts.has(Discount.BASE_DOT_ETH_NFT),
- });
- const TalentProtocolRowClasses = classNames(rowClasses, {
- 'opacity-40': hasDiscount && !allActiveDiscounts.has(Discount.TALENT_PROTOCOL),
- });
const qualifiedClasses = classNames(
'flex flex-row items-center justify-center py-3 px-1 h-5 text-xs bg-green-0 rounded ml-3',
@@ -71,174 +124,37 @@ export default function RegistrationLearnMoreModal({
: "You'll receive a name for free (5+ characters for 1 year) if your wallet has any of the following:"}
- -
-
-
-
-
Coinbase verification
-
-
-
- {allActiveDiscounts.has(Discount.COINBASE_VERIFIED_ACCOUNT) && (
-
- )}
-
- -
-
-
-
-
Coinbase One verification
-
-
-
- {allActiveDiscounts.has(Discount.CB1) && (
-
- )}
-
- -
-
-
-
- {allActiveDiscounts.has(Discount.CBID) && (
-
- )}
-
- -
-
-
-
-
Base buildathon participant
-
-
-
- {allActiveDiscounts.has(Discount.BASE_BUILDATHON_PARTICIPANT) && (
-
- )}
-
- -
-
-
-
-
Builder score 50+
-
-
-
- {allActiveDiscounts.has(Discount.TALENT_PROTOCOL) && (
-
- )}
-
- -
-
-
-
-
Summer Pass Level 3
-
-
-
- {allActiveDiscounts.has(Discount.SUMMER_PASS_LVL_3) && (
-
- )}
-
- -
-
-
-
- {allActiveDiscounts.has(Discount.BNS_NAME) && (
-
- )}
-
- -
-
-
-
- {allActiveDiscounts.has(Discount.BASE_DOT_ETH_NFT) && (
-
- )}
-
+ {DISCOUNT_ITEMS.map(({ discount, icon, alt, label, tooltipContent }) => (
+ -
+
+
+
+ {allActiveDiscounts.has(discount) && (
+
+ )}
+
+ ))}
{!hasDiscount && (
<>
diff --git a/apps/web/src/hooks/useAggregatedDiscountValidators.ts b/apps/web/src/hooks/useAggregatedDiscountValidators.ts
index b4f9e6b8dcf..0e80c6023e1 100644
--- a/apps/web/src/hooks/useAggregatedDiscountValidators.ts
+++ b/apps/web/src/hooks/useAggregatedDiscountValidators.ts
@@ -2,6 +2,7 @@ import {
AttestationData,
useBNSAttestations,
useBaseDotEthAttestations,
+ useBaseWorldAttestations,
useBuildathonAttestations,
useCheckCB1Attestations,
useCheckCBIDAttestations,
@@ -56,6 +57,7 @@ export function useAggregatedDiscountValidators(code?: string) {
useDiscountCodeAttestations(code);
const { data: TalentProtocolData, loading: loadingTalentProtocolAttestations } =
useTalentProtocolAttestations();
+ const { data: BaseWorldData, loading: loadingBaseWorld } = useBaseWorldAttestations();
const loadingDiscounts =
loadingCoinbaseAttestations ||
@@ -68,7 +70,8 @@ export function useAggregatedDiscountValidators(code?: string) {
loadingBaseDotEth ||
loadingBNS ||
loadingDiscountCode ||
- loadingTalentProtocolAttestations;
+ loadingTalentProtocolAttestations ||
+ loadingBaseWorld;
const discountsToAttestationData = useMemo(() => {
const discountMapping: MappedDiscountData = {};
@@ -143,6 +146,13 @@ export function useAggregatedDiscountValidators(code?: string) {
discountKey: validator.key,
};
}
+
+ if (BaseWorldData && validator.discountValidator === BaseWorldData.discountValidatorAddress) {
+ discountMapping[Discount.BASE_WORLD] = {
+ ...BaseWorldData,
+ discountKey: validator.key,
+ };
+ }
});
return discountMapping;
@@ -158,6 +168,7 @@ export function useAggregatedDiscountValidators(code?: string) {
BNSData,
DiscountCodeData,
TalentProtocolData,
+ BaseWorldData,
]);
return {
diff --git a/apps/web/src/hooks/useAttestations.ts b/apps/web/src/hooks/useAttestations.ts
index 19941dff219..194c5a88dd0 100644
--- a/apps/web/src/hooks/useAttestations.ts
+++ b/apps/web/src/hooks/useAttestations.ts
@@ -5,10 +5,12 @@ import AttestationValidatorABI from 'apps/web/src/abis/AttestationValidator';
import CBIDValidatorABI from 'apps/web/src/abis/CBIdDiscountValidator';
import EarlyAccessValidatorABI from 'apps/web/src/abis/EarlyAccessValidator';
import ERC1155DiscountValidator from 'apps/web/src/abis/ERC1155DiscountValidator';
+import ERC1155DiscountValidatorV2 from 'apps/web/src/abis/ERC1155DiscountValidatorV2';
import ERC721ValidatorABI from 'apps/web/src/abis/ERC721DiscountValidator';
import TalentProtocolDiscountValidatorABI from 'apps/web/src/abis/TalentProtocolDiscountValidator';
import {
BASE_DOT_ETH_ERC721_DISCOUNT_VALIDATOR,
+ BASE_WORLD_DISCOUNT_VALIDATORS,
BUILDATHON_ERC721_DISCOUNT_VALIDATOR,
TALENT_PROTOCOL_DISCOUNT_VALIDATORS,
USERNAME_1155_DISCOUNT_VALIDATORS,
@@ -592,3 +594,47 @@ export function useTalentProtocolAttestations() {
}
return { data: null, loading: isLoading, error };
}
+
+const baseWorldTokenIds = [
+ BigInt(0),
+ BigInt(1),
+ BigInt(2),
+ BigInt(3),
+ BigInt(4),
+ BigInt(5),
+ BigInt(6),
+];
+
+export function useBaseWorldAttestations() {
+ const { address } = useAccount();
+ const { basenameChain } = useBasenameChain();
+
+ const discountValidatorAddress = BASE_WORLD_DISCOUNT_VALIDATORS[basenameChain.id];
+
+ const readContractArgs = useMemo(() => {
+ if (!address) {
+ return {};
+ }
+ return {
+ address: discountValidatorAddress,
+ abi: ERC1155DiscountValidatorV2,
+ functionName: 'isValidDiscountRegistration',
+ args: [address, encodeAbiParameters([{ type: 'uint256[]' }], [baseWorldTokenIds])],
+ };
+ }, [address, discountValidatorAddress]);
+
+ const { data: isValid, isLoading, error } = useReadContract({ ...readContractArgs, query: {} });
+ if (isValid && address) {
+ return {
+ data: {
+ discountValidatorAddress,
+ discount: Discount.BASE_WORLD,
+ validationData: '0x0' as `0x${string}`,
+ },
+ loading: false,
+ error: null,
+ };
+ }
+
+ return { data: null, loading: isLoading, error };
+}
diff --git a/apps/web/src/utils/usernames.ts b/apps/web/src/utils/usernames.ts
index 7403afeec72..dc8a7838350 100644
--- a/apps/web/src/utils/usernames.ts
+++ b/apps/web/src/utils/usernames.ts
@@ -398,6 +398,7 @@ export enum Discount {
BASE_DOT_ETH_NFT = 'BASE_DOT_ETH_NFT',
DISCOUNT_CODE = 'DISCOUNT_CODE',
TALENT_PROTOCOL = 'TALENT_PROTOCOL',
+ BASE_WORLD = 'BASE_WORLD',
}
export function isValidDiscount(key: string): key is keyof typeof Discount {
From ca413fe6a09d9a0d3069d2634a87fcb65979a63b Mon Sep 17 00:00:00 2001
From: wbnns
Date: Wed, 6 Nov 2024 23:34:34 +0900
Subject: [PATCH 8/8] chore(ecosystem): Remove inactive project (#1215)
Removes BotFi; inactive since mid-summer (report via community)
---
apps/web/public/images/partners/botfi.webp | Bin 7330 -> 0 bytes
apps/web/src/data/ecosystem.json | 9 ---------
2 files changed, 9 deletions(-)
delete mode 100644 apps/web/public/images/partners/botfi.webp
diff --git a/apps/web/public/images/partners/botfi.webp b/apps/web/public/images/partners/botfi.webp
deleted file mode 100644
index 4a7267cb2ff21bc9560351d3910963280f3ea459..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 7330
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