Skip to content

Commit 438f1dd

Browse files
authored
Merge branch 'staging' into updateGrants
2 parents 66e9417 + 7d31832 commit 438f1dd

File tree

81 files changed

+259
-225
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

81 files changed

+259
-225
lines changed

app/[locale]/roadmap/_components/ReleaseCarousel.tsx

Lines changed: 69 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"use client"
22

3-
import { useEffect, useState } from "react"
3+
import { useCallback, useEffect, useMemo, useState } from "react"
4+
import { useLocale } from "next-intl"
45

56
import { Image } from "@/components/Image"
67
import { ButtonLink } from "@/components/ui/buttons/Button"
@@ -16,45 +17,39 @@ import {
1617
import { cn } from "@/lib/utils/cn"
1718
import { formatDate } from "@/lib/utils/date"
1819

19-
import { releasesData } from "@/data/roadmap/releases"
20+
import { Release, releasesData } from "@/data/roadmap/releases"
2021

21-
const findLatestReleaseIndex = () => {
22-
const today = new Date()
23-
const twoMonthsFromNow = new Date()
24-
twoMonthsFromNow.setMonth(today.getMonth() + 2)
22+
const ReleaseCarousel = () => {
23+
const locale = useLocale()
2524

26-
// First try to find a release within the next 2 months
27-
const upcomingReleaseIndex = releasesData.findIndex((release) => {
28-
const releaseDate = new Date(release.releaseDate)
29-
return releaseDate > today && releaseDate <= twoMonthsFromNow
30-
})
25+
const [api1, setApi1] = useState<CarouselApi>()
26+
const [api2, setApi2] = useState<CarouselApi>()
3127

32-
// If no upcoming release found, find the most recent release up to today
33-
if (upcomingReleaseIndex === -1) {
34-
const pastReleases = releasesData.filter(
35-
(release) => new Date(release.releaseDate) <= today
36-
)
37-
if (pastReleases.length > 0) {
38-
const mostRecentRelease = pastReleases[pastReleases.length - 1]
39-
return releasesData.findIndex(
40-
(release) => release.releaseDate === mostRecentRelease.releaseDate
41-
)
42-
}
43-
}
28+
const startIndex = useMemo(() => {
29+
const now = new Date()
4430

45-
return upcomingReleaseIndex
46-
}
31+
// Production: has a releaseDate in the past
32+
const productionReleases = releasesData.filter((release) => {
33+
if (!("releaseDate" in release) || !release.releaseDate) return false
34+
const releaseDate = new Date(release.releaseDate)
35+
return releaseDate <= now
36+
})
4737

48-
const ReleaseCarousel = () => {
49-
const todayDate = new Date()
50-
const twoMonthsFromNow = new Date()
51-
twoMonthsFromNow.setMonth(todayDate.getMonth() + 2)
38+
// Upcoming: has a releaseDate, but is in the future
39+
const upcomingReleases = releasesData.filter((release) => {
40+
if (!("releaseDate" in release) || !release.releaseDate) return false
41+
const releaseDate = new Date(release.releaseDate)
42+
return releaseDate > now
43+
})
5244

53-
const [api1, setApi1] = useState<CarouselApi>()
54-
const [api2, setApi2] = useState<CarouselApi>()
55-
const [currentIndex, setCurrentIndex] = useState(() =>
56-
findLatestReleaseIndex()
57-
)
45+
// If upcoming releases exist, start index after production releases
46+
if (upcomingReleases.length > 0) return productionReleases.length
47+
48+
// If no upcoming releases, start at the last production release
49+
return productionReleases.length - 1
50+
}, [])
51+
52+
const [currentIndex, setCurrentIndex] = useState(startIndex)
5853

5954
useEffect(() => {
6055
if (!api1 || !api2) {
@@ -72,6 +67,27 @@ const ReleaseCarousel = () => {
7267
})
7368
}, [api1, api2])
7469

70+
const getStatus = useCallback((release: Release) => {
71+
if (!("releaseDate" in release) || !release.releaseDate) return "dev"
72+
if (new Date(release.releaseDate) <= new Date()) return "prod"
73+
return "soon"
74+
}, [])
75+
76+
const getDisplayDate = (release: Release): string => {
77+
if (!("releaseDate" in release || "plannedReleaseYear" in release))
78+
return ""
79+
80+
if ("plannedReleaseYear" in release && release.plannedReleaseYear)
81+
return new Intl.DateTimeFormat(locale, {
82+
year: "numeric",
83+
}).format(new Date(Number(release.plannedReleaseYear), 0, 1))
84+
85+
if ("releaseDate" in release && release.releaseDate)
86+
return formatDate(release.releaseDate)
87+
88+
return ""
89+
}
90+
7591
return (
7692
<div className="w-full max-w-[100vw] overflow-hidden">
7793
<div className="mx-auto w-full max-w-screen-2xl px-4 sm:px-6">
@@ -85,29 +101,21 @@ const ReleaseCarousel = () => {
85101
align: "center",
86102
containScroll: false,
87103
loop: false,
88-
startIndex: findLatestReleaseIndex(),
104+
startIndex,
89105
}}
90106
>
91107
<CarouselContent>
92108
{releasesData.map((release, index) => {
93-
const releaseDate = new Date(release.releaseDate)
94-
const nextRelease =
95-
releaseDate > todayDate && releaseDate <= twoMonthsFromNow
96-
const labelType =
97-
releaseDate < todayDate
98-
? 1
99-
: releaseDate < twoMonthsFromNow
100-
? 2
101-
: 3
102-
109+
const status = getStatus(release)
110+
const displayDate = getDisplayDate(release)
103111
return (
104112
<CarouselItem
105113
key={release.releaseName}
106114
className="w-full md:basis-1/3"
107115
>
108116
<div className="flex w-full flex-col items-center justify-center gap-3">
109117
<div className="mb-3 !h-6">
110-
{labelType === 1 && (
118+
{status === "prod" && (
111119
<div
112120
className={cn(
113121
"w-fit rounded-lg bg-primary-low-contrast px-2 py-1",
@@ -117,7 +125,7 @@ const ReleaseCarousel = () => {
117125
<p className="text-sm font-bold">In production</p>
118126
</div>
119127
)}
120-
{labelType === 2 && (
128+
{status === "soon" && (
121129
<div
122130
className={cn(
123131
"w-fit rounded-lg bg-warning-light px-2 py-1",
@@ -129,7 +137,7 @@ const ReleaseCarousel = () => {
129137
</p>
130138
</div>
131139
)}
132-
{labelType === 3 && (
140+
{status === "dev" && (
133141
<div
134142
className={cn(
135143
"w-fit rounded-lg bg-card-gradient-secondary-hover px-2 py-1",
@@ -142,14 +150,15 @@ const ReleaseCarousel = () => {
142150
</div>
143151
)}
144152
</div>
153+
{/* Line-circle-line decoration —•— */}
145154
<div className="flex w-full items-center justify-center text-center">
146155
<div
147156
className={cn(
148157
"flex h-1 flex-1",
149158
index !== 0
150-
? nextRelease
159+
? status === "soon"
151160
? "bg-gradient-to-r from-primary to-primary-low-contrast"
152-
: releaseDate.getTime() < todayDate.getTime()
161+
: status === "prod"
153162
? "bg-primary"
154163
: "bg-primary-low-contrast"
155164
: "bg-transparent"
@@ -158,21 +167,21 @@ const ReleaseCarousel = () => {
158167
<div
159168
className={cn(
160169
"h-7 w-7 rounded-full",
161-
releaseDate.getTime() < todayDate.getTime()
170+
status === "prod"
162171
? "bg-primary"
163172
: "bg-primary-low-contrast",
164-
nextRelease &&
173+
status === "soon" &&
165174
"border-2 border-primary bg-background"
166175
)}
167176
/>
168177
<div
169178
className={cn(
170179
"flex h-1 flex-1",
171-
index !== releasesData.length - 1
172-
? index < findLatestReleaseIndex()
173-
? "bg-primary"
174-
: "bg-primary-low-contrast"
175-
: "bg-transparent"
180+
index < startIndex
181+
? "bg-primary"
182+
: "bg-primary-low-contrast",
183+
index === releasesData.length - 1 &&
184+
"bg-transparent"
176185
)}
177186
/>
178187
</div>
@@ -181,7 +190,7 @@ const ReleaseCarousel = () => {
181190
{release.releaseName}
182191
</p>
183192
<p className="font-mono text-sm text-body-medium">
184-
{formatDate(release.releaseDate)}
193+
{displayDate}
185194
</p>
186195
</div>
187196
</div>
@@ -203,7 +212,7 @@ const ReleaseCarousel = () => {
203212
align: "center",
204213
containScroll: false,
205214
loop: false,
206-
startIndex: findLatestReleaseIndex(),
215+
startIndex,
207216
}}
208217
>
209218
<CarouselContent>
@@ -225,9 +234,7 @@ const ReleaseCarousel = () => {
225234
<h2 className="text-4xl font-bold lg:text-6xl">
226235
{release.releaseName}
227236
</h2>
228-
<p className="text-md">
229-
{formatDate(release.releaseDate)}
230-
</p>
237+
<p className="text-md">{getDisplayDate(release)}</p>
231238
</div>
232239

233240
<div>

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "ethereum-org-website",
3-
"version": "10.3.0",
3+
"version": "10.4.0",
44
"license": "MIT",
55
"private": true,
66
"scripts": {

public/content/ai-agents/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ buttons:
1919
isSecondary: false
2020
---
2121

22-
Imagine navigating Ethereum with an AI assistant that studies on-chain market trends 24/7, answers questions, and even executes transactions on your behalf. Welcome to the world of AI Agents—intelligent systems designed to simplify your digital life.
22+
Imagine navigating Ethereum with an AI assistant that studies onchain market trends 24/7, answers questions, and even executes transactions on your behalf. Welcome to the world of AI Agents—intelligent systems designed to simplify your digital life.
2323

2424
On Ethereum, we’re seeing innovations of AI agents ranging from virtual influencers and autonomous content creators to real-time market analysis platforms, empowering users by delivering insights, entertainment, and operational efficiency.
2525

public/content/enterprise/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ Here are some of the enterprise applications that have been built on top of the
8686
- [ABN AMRO](https://tokeny.com/tokeny-fuels-abn-amro-bank-in-tokenizing-green-bonds-on-polygon/) - _with Tokeny, tokenized green bonds_
8787
- [Anvil](https://anvil.xyz/) - _a system of Ethereum-based smart contracts that manages collateral and issues fully secured credit_
8888
- [Mata Capital](https://consensys.io/blockchain-use-cases/finance/mata-capital) - _real estate investment tokenization_
89-
- [Obligate](https://www.obligate.com/) - _regulated and KYC'd on-chain bonds and commercial paper_
89+
- [Obligate](https://www.obligate.com/) - _regulated and KYC'd onchain bonds and commercial paper_
9090
- [Siemens](https://press.siemens.com/global/en/pressrelease/siemens-remains-pioneer-another-digital-bond-successfully-issued-blockchain) - _bond issuance_
9191
- [Sila](https://silamoney.com/) - _banking and ACH payments infrastructure-as-a-service, using a stablecoin_
9292
- [Societe Generale FORGE](https://www.sgforge.com/product/bonds/) - _bond issuance_

public/content/roadmap/pectra/7702/index.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ For more information:
5757

5858
**Avoiding Vendor Lock-In**: In line with the above, a good implementation is vendor-neutral and interoperable. This often means adhering to emerging standards for smart accounts. For instance, [Alchemy’s Modular Account](https://github.com/alchemyplatform/modular-account) uses the ERC-6900 standard for modular smart accounts and is designed with “permissionless interoperable usage” in mind.
5959

60-
**Privacy Preservation**: While on-chain privacy is limited, a delegation contract should strive to minimize data exposure and linkability. This can be achieved by supporting features like gas payments in ERC-20 tokens (so users need not maintain a public ETH balance, which improves privacy and UX) and one-time session keys (which reduce reliance on a single long-term key). For example, EIP-7702 enables paying gas in tokens via sponsored transactions, and a good implementation will make it easy to integrate such paymasters without leaking more information than necessary. Additionally, off-chain delegation of certain approvals (using signatures that are verified on-chain) means fewer on-chain transactions with the user’s primary key, aiding privacy. Accounts that require using a relayer force users to reveal their IP addresses. PublicMempools improves this, when a transaction/UserOp propagates through the mempool you can't tell whether it originated from the IP that sent it, or just relayed through it via the p2p protocol.
60+
**Privacy Preservation**: While onchain privacy is limited, a delegation contract should strive to minimize data exposure and linkability. This can be achieved by supporting features like gas payments in ERC-20 tokens (so users need not maintain a public ETH balance, which improves privacy and UX) and one-time session keys (which reduce reliance on a single long-term key). For example, EIP-7702 enables paying gas in tokens via sponsored transactions, and a good implementation will make it easy to integrate such paymasters without leaking more information than necessary. Additionally, off-chain delegation of certain approvals (using signatures that are verified onchain) means fewer onchain transactions with the user’s primary key, aiding privacy. Accounts that require using a relayer force users to reveal their IP addresses. PublicMempools improves this, when a transaction/UserOp propagates through the mempool you can't tell whether it originated from the IP that sent it, or just relayed through it via the p2p protocol.
6161

6262
**Extensibility and Modular Security**: Account implementations should be extensible so they can evolve with new features and security improvements. Upgradability is inherently possible with EIP-7702 (since an EOA can always delegate to a new contract in the future to upgrade its logic). Beyond upgradability, a good design allows modularity – e.g. plug-in modules for different signature schemes or spending policies – without needing to redeploy entirely. Alchemy’s Account Kit is a prime example, allowing developers to install validation modules (for different signature types like ECDSA, BLS, etc.) and execution modules for custom logic. To achieve greater flexibility and security in EIP-7702-enabled accounts, developers are encouraged to delegate to a proxy contract rather than directly to a specific implementation. This approach allows for seamless upgrades and modularity without requiring additional EIP-7702 authorizations for each change.
6363

@@ -108,7 +108,7 @@ By adopting these solutions, developers can enhance the security of EIP-7702 del
108108

109109
When users perform delegated signatures, the target contract receiving the delegation should be clearly and prominently displayed to help mitigate phishing risks.
110110

111-
**Minimal Trusted Surface & Security**: While offering flexibility, a delegation contract should keep its core logic minimal and auditable. The contract is effectively an extension of the user’s EOA, so any flaw can be catastrophic. Implementations should follow best practices from the smart contract security community. For instance, constructor or initializer functions must be carefully secured – as highlighted by Alchemy, if using a proxy pattern under 7702, an unprotected initializer could let an attacker take over the account. Teams should aim to keep the on-chain code simple: Ambire’s 7702 contract is only ~200 lines of Solidity, deliberately minimizing complexity to reduce bugs. A balance must be struck between feature-rich logic and the simplicity that eases auditing.
111+
**Minimal Trusted Surface & Security**: While offering flexibility, a delegation contract should keep its core logic minimal and auditable. The contract is effectively an extension of the user’s EOA, so any flaw can be catastrophic. Implementations should follow best practices from the smart contract security community. For instance, constructor or initializer functions must be carefully secured – as highlighted by Alchemy, if using a proxy pattern under 7702, an unprotected initializer could let an attacker take over the account. Teams should aim to keep the onchain code simple: Ambire’s 7702 contract is only ~200 lines of Solidity, deliberately minimizing complexity to reduce bugs. A balance must be struck between feature-rich logic and the simplicity that eases auditing.
112112

113113
### Known implementations {#known-implementations}
114114

src/components/Content/ai-agents/AiAgentProductLists.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import heyanon from "@/public/images/ai-agents/heyanon.png"
1212
import luna from "@/public/images/ai-agents/luna.png"
1313

1414
const AiAgentProductLists = ({ list }: { list: string }) => {
15-
// TODO: LOGOS
15+
// TODO: LOGOS, extract intl strings
1616
const productListSets = {
1717
"ai-agents": [
1818
{
@@ -40,7 +40,7 @@ const AiAgentProductLists = ({ list }: { list: string }) => {
4040
Luna engages with users constantly through own X account and live
4141
stream. You might receive an X reply if you tag her handle or a
4242
voice message if you comment on her stream and own her token! Luna
43-
controls own on-chain wallet.
43+
controls own onchain wallet.
4444
</p>,
4545
<div key="luna-button">
4646
<ButtonLink

src/components/Homepage/useHome.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@ import type { CodeExample } from "@/lib/interfaces"
77

88
import { useBentoBox } from "@/components/Homepage/useBentoBox"
99
import BlockHeap from "@/components/icons/block-heap.svg"
10+
import BuildAppsIcon from "@/components/icons/build-apps.svg"
1011
import EthGlyphIcon from "@/components/icons/eth-glyph.svg"
1112
import EthTokenIcon from "@/components/icons/eth-token.svg"
1213
import PickWalletIcon from "@/components/icons/eth-wallet.svg"
13-
import ChooseNetworkIcon from "@/components/icons/network-layers.svg"
1414
import TryAppsIcon from "@/components/icons/phone-homescreen.svg"
1515
import RoadmapSign from "@/components/icons/roadmap-sign.svg"
1616
import Whitepaper from "@/components/icons/whitepaper.svg"
@@ -103,14 +103,6 @@ export const useHome = () => {
103103
className: "text-accent-a hover:text-accent-a-hover",
104104
eventName: "get eth",
105105
},
106-
{
107-
label: t("page-index:page-index-cta-networks-label"),
108-
description: t("page-index:page-index-cta-networks-description"),
109-
href: "/layer-2/", // TODO: Update with new networks page when ready
110-
Svg: ChooseNetworkIcon,
111-
className: "text-accent-b hover:text-accent-b-hover",
112-
eventName: "L2",
113-
},
114106
{
115107
label: t("page-index:page-index-cta-dapps-label"),
116108
description: t("page-index:page-index-cta-dapps-description"),
@@ -122,6 +114,14 @@ export const useHome = () => {
122114
),
123115
eventName: "dapps",
124116
},
117+
{
118+
label: t("page-index:page-index-cta-build-apps-label"),
119+
description: t("page-index:page-index-cta-build-apps-description"),
120+
href: "/developers/",
121+
Svg: BuildAppsIcon,
122+
className: "text-accent-b hover:text-accent-b-hover",
123+
eventName: "build apps",
124+
},
125125
]
126126

127127
const popularTopics = [

0 commit comments

Comments
 (0)