Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
3f0b934
feat: slashing contracts
hmzakhalid Feb 23, 2026
3a49d3c
chore: trigger CI
hmzakhalid Feb 23, 2026
f5062b3
fix: review comments
hmzakhalid Feb 23, 2026
1839632
fix: remove comments
hmzakhalid Feb 23, 2026
150a167
fix: remove comments
hmzakhalid Feb 23, 2026
6014355
fix: contract addresses
hmzakhalid Feb 23, 2026
a6091cc
Merge branch 'main' into feat/fault-attribution-contracts
hmzakhalid Feb 23, 2026
a4637d0
fix: add retry to metamask
hmzakhalid Feb 23, 2026
7c241a0
fix: review comments
hmzakhalid Feb 23, 2026
23e8225
fix: review comments
hmzakhalid Feb 23, 2026
e602232
fix: contract tests
hmzakhalid Feb 23, 2026
ab4f48c
fix: fix tests
hmzakhalid Feb 23, 2026
5b30e09
fix: contract addresses
hmzakhalid Feb 24, 2026
256a3c0
fix: dev note natspec comment
hmzakhalid Feb 24, 2026
34ed209
feat: route slashed funds
hmzakhalid Feb 24, 2026
2e61eba
Merge branch 'main' into feat/fault-attribution-contracts
hmzakhalid Feb 24, 2026
03e6721
Merge branch 'main' into feat/fault-attribution-contracts
hmzakhalid Feb 25, 2026
5cbb911
fix: contract addresses
hmzakhalid Feb 25, 2026
1cfc287
fix: contract addresses
hmzakhalid Feb 25, 2026
35f3b72
fix: contract addresses
hmzakhalid Feb 25, 2026
14bdbdf
fix: contract addresses
hmzakhalid Feb 25, 2026
45f3e79
fix: route slashed funds after E3 completed
hmzakhalid Feb 25, 2026
1bcb6b7
Merge branch 'main' into feat/fault-attribution-contracts
hmzakhalid Feb 25, 2026
8e85d4b
Merge branch 'main' into feat/fault-attribution-contracts
hmzakhalid Feb 26, 2026
5a0b5cc
Merge branch 'main' into feat/fault-attribution-contracts
hmzakhalid Feb 26, 2026
d661b01
fix: contract addresses
hmzakhalid Feb 26, 2026
430398c
fix: review comments
hmzakhalid Feb 26, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions examples/CRISP/client/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ const App: React.FC = () => {
})
}
})()
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [])

return (
Expand Down
25 changes: 10 additions & 15 deletions examples/CRISP/client/src/components/Cards/Card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
// without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE.

import React, { useEffect, useState } from 'react'
import React, { useMemo, useState } from 'react'

interface CardProps {
children: React.ReactNode
Expand All @@ -17,22 +17,17 @@ interface CardProps {
const Card: React.FC<CardProps> = ({ children, isActive, isDetails, checked, onChecked }) => {
const [isClicked, setIsClicked] = useState<boolean>(checked ?? false)

useEffect(() => {
setIsClicked(checked ?? false)
}, [checked])
const derivedIsClicked = useMemo(() => {
if (isActive) return false
return checked ?? isClicked
}, [isActive, checked, isClicked])

const handleClick = () => {
if (isDetails) return
if (onChecked) onChecked(!isClicked)
setIsClicked(!isClicked)
if (onChecked) onChecked(!derivedIsClicked)
setIsClicked(!derivedIsClicked)
}

useEffect(() => {
if (isActive) {
setIsClicked(false)
}
}, [isActive])

return (
<div
data-test-id='card'
Expand All @@ -44,9 +39,9 @@ const Card: React.FC<CardProps> = ({ children, isActive, isDetails, checked, onC
${!isDetails && 'shadow-md'}
transform
border-2 transition-all duration-300 ease-in-out
${isClicked ? 'scale-105 border-lime-400' : ''}
${isClicked ? 'border-lime-400' : 'border-slate-600/20'}
${isClicked ? 'bg-white' : 'bg-slate-100'}
${derivedIsClicked ? 'scale-105 border-lime-400' : ''}
${derivedIsClicked ? 'border-lime-400' : 'border-slate-600/20'}
${derivedIsClicked ? 'bg-white' : 'bg-slate-100'}
${!isDetails && 'hover:border-lime-300 hover:bg-white hover:shadow-lg'}
flex w-full items-center justify-center
`}
Expand Down
10 changes: 3 additions & 7 deletions examples/CRISP/client/src/components/Cards/PollCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
// without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE.

import React, { useEffect, useState } from 'react'
import React, { useEffect, useMemo, useState } from 'react'
import { useNavigate } from 'react-router-dom'
import { PollOption, PollResult } from '@/model/poll.model'
import { PollResult } from '@/model/poll.model'
import VotesBadge from '@/components/VotesBadge'
import PollCardResult from '@/components/Cards/PollCardResult'
import { formatDate, markWinner } from '@/utils/methods'
Expand All @@ -15,7 +15,6 @@ import { usePublicClient } from 'wagmi'

const PollCard: React.FC<PollResult> = ({ roundId, options, totalVotes, date, endTime }) => {
const navigate = useNavigate()
const [results, setResults] = useState<PollOption[]>(options)
const [isActive, setIsActive] = useState(true)
const { roundState, setPollResult, currentRoundId } = useVoteManagementContext()
const client = usePublicClient()
Expand All @@ -40,10 +39,7 @@ const PollCard: React.FC<PollResult> = ({ roundId, options, totalVotes, date, en
return () => clearInterval(interval)
}, [endTime, client, isActive])

useEffect(() => {
const newPollOptions = markWinner(options)
setResults(newPollOptions)
}, [options])
const results = useMemo(() => markWinner(options), [options])

const handleNavigation = () => {
if (isActive && isCurrentRound) {
Expand Down
18 changes: 12 additions & 6 deletions examples/CRISP/client/src/components/CircularTiles.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,23 @@
// without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE.

import { memo } from 'react'
import { memo, useEffect, useState } from 'react'
import CircularTile from './CircularTile'

const generateRotations = (count: number) => [...Array(count)].map(() => [0, 90, 180, 270][Math.floor(Math.random() * 4)])

const CircularTiles = ({ count = 1, className }: { count?: number; className?: string }) => {
const [rotations, setRotations] = useState(() => generateRotations(count))

useEffect(() => {
setRotations(generateRotations(count))
}, [count])

return (
<>
{[...Array(count)].map((_i, index) => {
const rand_index = Math.floor(Math.random() * 4)
const rotation = [0, 90, 180, 270][rand_index]
return <CircularTile key={index} className={className} rotation={rotation} />
})}
{rotations.map((rotation, index) => (
<CircularTile key={index} className={className} rotation={rotation} />
))}
</>
)
}
Expand Down
25 changes: 14 additions & 11 deletions examples/CRISP/client/src/components/NavMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,16 +35,19 @@ const NavMenu: React.FC = () => {
const [isOpen, setIsOpen] = useState<boolean>(false)
const buttonRef = useRef<HTMLButtonElement>(null)

const handleClickOutside = (event: MouseEvent) => {
if (
isOpen &&
menuRef.current &&
!menuRef.current.contains(event.target as Node) &&
!buttonRef.current?.contains(event.target as Node)
) {
setIsOpen(false)
}
}
const handleClickOutside = React.useCallback(
(event: MouseEvent) => {
if (
isOpen &&
menuRef.current &&
!menuRef.current.contains(event.target as Node) &&
!buttonRef.current?.contains(event.target as Node)
) {
setIsOpen(false)
}
},
[isOpen],
)

const toggleMenu = (event: React.MouseEvent<HTMLButtonElement>) => {
event.stopPropagation()
Expand All @@ -59,7 +62,7 @@ const NavMenu: React.FC = () => {
return () => {
document.removeEventListener('mousedown', handleClickOutside)
}
}, [isOpen])
}, [isOpen, handleClickOutside])

const handleNavigation = (path: string) => {
navigate(path)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,4 +85,5 @@ const NotificationAlertProvider = ({ children }: NotificationAlertProviderProps)
)
}

// eslint-disable-next-line react-refresh/only-export-components
export { useNotificationAlertContext, NotificationAlertProvider }
Original file line number Diff line number Diff line change
Expand Up @@ -236,4 +236,5 @@ const VoteManagementProvider = ({ children }: VoteManagementProviderProps) => {
)
}

// eslint-disable-next-line react-refresh/only-export-components
export { useVoteManagementContext, VoteManagementProvider }
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const ConfirmVote: React.FC<{ confirmationUrl: string }> = ({ confirmationUrl })
return () => {
setTxUrl(undefined)
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [])

return (
Expand Down
2 changes: 2 additions & 0 deletions examples/CRISP/client/src/pages/PollResult/PollResult.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,14 @@ const PollResult: React.FC = () => {
setLoading(false)
}
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [pastPolls, roundId, roundState, activeTotalCount])

useEffect(() => {
if (pollResult && loading) {
setLoading(false)
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [pollResult])

return (
Expand Down
15 changes: 9 additions & 6 deletions examples/CRISP/enclave.config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,20 @@ chains:
rpc_url: "ws://localhost:8545"
contracts:
e3_program:
address: "0xc3e53F4d16Ae77Db1c982e75a937B9f60FE63690"
deploy_block: 35
address: '0x851356ae760d987E095750cCeb3bC6014560891C'
deploy_block: 31
enclave:
address: "0xB7f8BC63BbcaD18155201308C8f3540b07f84F5e"
deploy_block: 21
ciphernode_registry:
address: "0x8A791620dd6260079BF849Dc5567aDC3F2FdC318"
deploy_block: 19
bonding_registry:
address: "0xa513E6E4b8f2a923D98304ec87F64353C4D5C853"
address: '0xa513E6E4b8f2a923D98304ec87F64353C4D5C853'
deploy_block: 14
bonding_registry:
address: '0x8A791620dd6260079BF849Dc5567aDC3F2FdC318'
deploy_block: 10
slashing_manager:
address: '0x5FC8d32690cc91D4c39d9d3abcBD16989F875707'
deploy_block: 10
fee_token:
address: "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512"
deploy_block: 6
Expand Down
1 change: 1 addition & 0 deletions examples/CRISP/packages/crisp-contracts/deploy/deploy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const contractMapping: Record<string, string> = {
Enclave: 'enclave',
CiphernodeRegistryOwnable: 'ciphernode_registry',
BondingRegistry: 'bonding_registry',
SlashingManager: 'slashing_manager',
MockUSDC: 'fee_token',
}

Expand Down
4 changes: 2 additions & 2 deletions examples/CRISP/server/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ CRON_API_KEY=1234567890

# Based on Default Anvil Deployments (Only for testing)
ENCLAVE_ADDRESS="0xB7f8BC63BbcaD18155201308C8f3540b07f84F5e"
CIPHERNODE_REGISTRY_ADDRESS="0x8A791620dd6260079BF849Dc5567aDC3F2FdC318"
E3_PROGRAM_ADDRESS="0xc3e53F4d16Ae77Db1c982e75a937B9f60FE63690"
CIPHERNODE_REGISTRY_ADDRESS="0xa513E6E4b8f2a923D98304ec87F64353C4D5C853"
E3_PROGRAM_ADDRESS="0x851356ae760d987E095750cCeb3bC6014560891C"
FEE_TOKEN_ADDRESS="0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512"

# E3 Config
Expand Down
36 changes: 32 additions & 4 deletions examples/CRISP/test/crisp.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,36 @@ function log(msg: string) {
console.log(`[playwright] ${msg}`)
}

// ConnectKit modal animations + app initialization (initialLoad/switchChain)
// can cause the MetaMask button to be detached from the DOM or the page to
// navigate while the modal is opening. Retry the whole flow up to 3 times.
async function connectWalletWithRetry(page: Page, maxAttempts = 3) {
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
try {
await page.waitForLoadState('load')

const connectWalletBtn = page.locator('button:has-text("Connect Wallet")')
const metamaskBtn = page.locator('button:has-text("MetaMask")')

// Only open the modal if MetaMask option isn't already visible
if (!(await metamaskBtn.isVisible().catch(() => false))) {
log(`clicking Connect Wallet (attempt ${attempt})...`)
await connectWalletBtn.click({ timeout: 10_000 })
}

log(`clicking MetaMask (attempt ${attempt})...`)
await metamaskBtn.click({ timeout: 15_000 })
return
} catch (error) {
if (attempt === maxAttempts) throw error
log(`wallet connect attempt ${attempt} failed, retrying...`)
// Dismiss any open modal before retrying
await page.keyboard.press('Escape').catch(() => {})
await page.waitForTimeout(2_000)
}
}
}

test('CRISP smoke test', async ({ context, page, metamaskPage, extensionId }) => {
page.on('console', (msg: ConsoleMessage) => {
console.log(msg.text())
Expand All @@ -94,10 +124,8 @@ test('CRISP smoke test', async ({ context, page, metamaskPage, extensionId }) =>
log(`ensureHomePageLoaded...`)
await ensureHomePageLoaded(page)

log(`searching for connect button...`)
await page.locator('button:has-text("Connect Wallet")').click()
log(`searching for MetaMask button...`)
await page.locator('button:has-text("MetaMask")').click()
log(`connecting wallet via ConnectKit...`)
await connectWalletWithRetry(page)
log(`connecting to dapp...`)
await metamask.connectToDapp()
log(`clicking try demo...`)
Expand Down
13 changes: 13 additions & 0 deletions packages/enclave-contracts/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,26 @@
.coverage_cache
.coverage_contracts

# Base Dirs

# Base Dirs
/artifacts/
!/artifacts/
/artifacts/**
!/artifacts/contracts/

# Interfaces

# Interfaces
!/artifacts/contracts/interfaces/
!/artifacts/contracts/interfaces/IEnclave.sol/
!/artifacts/contracts/interfaces/ICiphernodeRegistry.sol/
!/artifacts/contracts/interfaces/IBondingRegistry.sol/
!/artifacts/contracts/interfaces/ISlashingManager.sol/
!/artifacts/contracts/interfaces/IEnclave.sol/IEnclave.json
!/artifacts/contracts/interfaces/ICiphernodeRegistry.sol/ICiphernodeRegistry.json
!/artifacts/contracts/interfaces/IBondingRegistry.sol/IBondingRegistry.json
!/artifacts/contracts/interfaces/ISlashingManager.sol/ISlashingManager.json

# Registry
!/artifacts/contracts/registry/
Expand All @@ -26,6 +32,13 @@
!/artifacts/contracts/token/EnclaveTicketToken.sol/
!/artifacts/contracts/token/EnclaveTicketToken.sol/EnclaveTicketToken.json

# Verifier contracts
!/artifacts/contracts/verifier/
!/artifacts/contracts/verifier/DkgPkVerifier.sol/
!/artifacts/contracts/verifier/DkgPkVerifier.sol/DkgPkVerifier.json
!/artifacts/contracts/verifier/DkgPkVerifier.sol/ZKTranscriptLib.json


# Verifier contracts
!/artifacts/contracts/verifier/
!/artifacts/contracts/verifier/DkgPkVerifier.sol/
Expand Down
Loading
Loading