Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: fix some bugs, and add extra details for seer entries #345

Merged
merged 6 commits into from
Mar 26, 2025
Merged
Changes from 1 commit
Commits
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
Next Next commit
feat: fix some bugs, and add extra details for seer entries
kemuru committed Mar 11, 2025

Verified

This commit was signed with the committer’s verified signature.
kemuru Marino
commit dffb8227b418db834c316954c658f3b7ba8704fd
6 changes: 5 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
@@ -20,4 +20,8 @@ REACT_APP_RPC_URLS={"100":"https://rpc.gnosischain.com","1":"https://mainnet.inf
REACT_APP_FORMATIC_API_KEYS=

# If provided, the welcome modal display the following video.
REACT_APP_INSTRUCTION_VIDEO=https://www.youtube.com/embed/DKPVWzhh8Y8
REACT_APP_INSTRUCTION_VIDEO=https://www.youtube.com/embed/DKPVWzhh8Y8

REACT_APP_SUBGRAPH_MAINNET=https://api.studio.thegraph.com/query/61738/legacy-curate-mainnet/version/latest
REACT_APP_SUBGRAPH_GNOSIS=https://api.studio.thegraph.com/query/61738/legacy-curate-gnosis/version/latest
REACT_APP_SUBGRAPH_SEPOLIA=https://api.studio.thegraph.com/query/61738/legacy-curate-sepolia/version/latest
207 changes: 207 additions & 0 deletions src/components/custom-registries-extra-details/seer-extra-details.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
import React, { useState, useEffect } from 'react'
import { ethers } from 'ethers'

const marketAbi = [
'function marketName() view returns (string)',
'function outcomes(uint256) view returns (string)'
]

interface ISeerExtraDetails {
chainId: string
contractAddress: string
imagesIpfsHash: string
smallDisplay?: boolean
}

interface MarketDetails {
marketName: string
marketImage: string
outcomes: { name: string; image: string }[]
}

const delay = (ms: number) => new Promise(resolve => setTimeout(resolve, ms))

const SeerExtraDetails: React.FC<ISeerExtraDetails> = ({
chainId,
contractAddress,
imagesIpfsHash,
smallDisplay = false
}) => {
const [marketDetails, setMarketDetails] = useState<MarketDetails | null>(null)
const [error, setError] = useState<string | null>(null)

useEffect(() => {
const fetchData = async () => {
try {
const ipfsResponse = await fetch(
`${process.env.REACT_APP_IPFS_GATEWAY}${imagesIpfsHash}`
)
if (!ipfsResponse.ok) throw new Error('Failed to fetch IPFS data')
const ipfsData = await ipfsResponse.json()
const marketImage = ipfsData.market
const outcomeImages = ipfsData.outcomes
const numOutcomes = outcomeImages.length

const rpcUrls = JSON.parse(process.env.REACT_APP_RPC_URLS || '{}')
const rpcUrl = rpcUrls[chainId]
if (!rpcUrl) throw new Error(`No RPC URL found for chainId: ${chainId}`)
const provider = new ethers.providers.JsonRpcProvider(rpcUrl)

const marketContract = new ethers.Contract(
contractAddress,
marketAbi,
provider
)

const marketName = await marketContract.marketName()
await delay(250)

const outcomeNames = []
for (let i = 0; i < numOutcomes; i++) {
const outcome = await marketContract.outcomes(i)
outcomeNames.push(outcome)
if (i < numOutcomes - 1) await delay(250)
}

const outcomes = outcomeNames.map((name: string, index: number) => ({
name,
image: outcomeImages[index] || ''
}))

setMarketDetails({
marketName,
marketImage,
outcomes
})
} catch (err) {
setError(`Failed to load market details: ${err.message}`)
console.error(err)
}
}

fetchData()
}, [chainId, contractAddress, imagesIpfsHash])

if (error)
return (
<p
style={{
color: 'red',
fontFamily: 'Arial, sans-serif',
fontSize: smallDisplay ? '12px' : '14px'
}}
>
{error}
</p>
)

if (!marketDetails)
return (
<p
style={{
fontFamily: 'Arial, sans-serif',
color: '#666',
fontSize: smallDisplay ? '12px' : '14px'
}}
>
Loading Seer details...
</p>
)

const { marketName, marketImage, outcomes } = marketDetails

return (
<div
style={{
fontFamily: 'Arial, sans-serif',
maxWidth: smallDisplay ? '300px' : '600px',
margin: '16px auto',
padding: smallDisplay ? '10px' : '20px',
border: '1px solid #e0e0e0',
borderRadius: '8px',
boxShadow: '0 2px 4px rgba(0, 0, 0, 0.1)'
}}
>
<p style={{ marginBottom: '16px' }}>
<a
href={`https://app.seer.pm/markets/${chainId}/${contractAddress}`}
target="_blank"
rel="noopener noreferrer"
style={{
color: '#007bff',
textDecoration: 'none',
fontWeight: 'bold',
fontSize: smallDisplay ? '14px' : '16px'
}}
onMouseOver={e =>
(e.currentTarget.style.textDecoration = 'underline')
}
onMouseOut={e => (e.currentTarget.style.textDecoration = 'none')}
onFocus={e => (e.currentTarget.style.textDecoration = 'underline')}
onBlur={e => (e.currentTarget.style.textDecoration = 'none')}
>
Go to Seer
</a>
</p>
<img
src={`${process.env.REACT_APP_IPFS_GATEWAY}${marketImage}`}
alt="Market"
style={{
maxWidth: smallDisplay ? '32px' : '48px',
height: 'auto',
borderRadius: '4px',
marginBottom: smallDisplay ? '8px' : '16px'
}}
/>
<h3
style={{
margin: '0 0 12px',
fontSize: smallDisplay ? '1.2em' : '1.5em',
color: '#333'
}}
>
{marketName}
</h3>
<h4
style={{
margin: '0 0 12px',
fontSize: smallDisplay ? '1em' : '1.2em',
color: '#555'
}}
>
Outcomes
</h4>
{outcomes.map((outcome, index) => (
<div
key={index}
style={{
display: 'flex',
alignItems: 'center',
marginBottom: smallDisplay ? '6px' : '12px',
padding: smallDisplay ? '4px' : '8px',
backgroundColor: '#f9f9f9',
borderRadius: '4px'
}}
>
<img
src={`${process.env.REACT_APP_IPFS_GATEWAY}${outcome.image}`}
alt={`Outcome ${index}`}
style={{
maxWidth: smallDisplay ? '24px' : '40px',
height: 'auto',
marginRight: smallDisplay ? '6px' : '12px',
borderRadius: '4px'
}}
/>
<span
style={{ fontSize: smallDisplay ? '0.9em' : '1em', color: '#333' }}
>
{outcome.name}
</span>
</div>
))}
</div>
)
}

export default SeerExtraDetails
2 changes: 1 addition & 1 deletion src/components/display-selector.js
Original file line number Diff line number Diff line change
@@ -27,7 +27,7 @@ const DisplaySelector = ({ type, value, linkImage, allowedFileTypes }) => {
case ItemTypes.GTCR_ADDRESS:
return <GTCRAddress address={value || ZERO_ADDRESS} />
case ItemTypes.ADDRESS:
return <ETHAddress address={value || ZERO_ADDRESS} forceEth />
return <ETHAddress address={value || ZERO_ADDRESS} />
case ItemTypes.RICH_ADDRESS:
return <RichAddress crude={value || pohRichAddress} />
case ItemTypes.TEXT:
11 changes: 3 additions & 8 deletions src/components/eth-address.tsx
Original file line number Diff line number Diff line change
@@ -7,16 +7,11 @@ const StyledA = styled.a`
text-decoration: underline;
`

const ETHAddress: React.FC<{ address: string; forceEth: boolean }> = ({
address,
forceEth
}) => {
const ETHAddress: React.FC<{ address: string }> = ({ address }) => {
const { networkId } = useWeb3Context()
const fullPage = forceEth
? `https://etherscan.io/address/${address}`
: getAddressPage({ networkId, address })
const fullPage = getAddressPage({ networkId, address })
return (
<StyledA href={fullPage}>
<StyledA href={fullPage} target="_blank" rel="noopener noreferrer">
{address.slice(0, 6)}...{address.slice(address.length - 4)}
</StyledA>
)
15 changes: 14 additions & 1 deletion src/components/item-details-card.js
Original file line number Diff line number Diff line change
@@ -4,6 +4,7 @@ import { Card, Icon, Tooltip, Button, Result, Alert } from 'antd'
import PropTypes from 'prop-types'
import DisplaySelector from './display-selector'
import { useWeb3Context } from 'web3-react'
import { useParams } from 'react-router-dom'
import { abi as _batchWithdraw } from '@kleros/tcr/build/contracts/BatchWithdraw.json'
import { bigNumberify } from 'ethers/utils'
import { ethers } from 'ethers'
@@ -13,7 +14,8 @@ import itemPropTypes from '../prop-types/item'
import { WalletContext } from 'contexts/wallet-context'
import TCRMetadataDisplay from './tcr-metadata-display'
import { addPeriod } from '../utils/string'
import { batchWithdrawAddresses } from 'config/tcr-addresses'
import { batchWithdrawAddresses, seerAddresses } from 'config/tcr-addresses'
import SeerExtraDetails from 'components/custom-registries-extra-details/seer-extra-details'

const StyledFields = styled.div`
display: flex;
@@ -45,6 +47,7 @@ const ItemDetailsCard = ({
const [availableRewards, setAvailableRewards] = useState()
const [rewardRef, setRewardRef] = useState()
const BATCH_WITHDRAW_ADDRESS = batchWithdrawAddresses[networkId]
const { chainId, tcrAddress } = useParams()

// Fetch available rewards from fee contributions.
useEffect(() => {
@@ -181,6 +184,16 @@ const ItemDetailsCard = ({
))}
</StyledFields>
)}
{tcrAddress &&
(tcrAddress.toLowerCase() === seerAddresses[1] ||
tcrAddress.toLowerCase() === seerAddresses[100]) &&
item && (
<SeerExtraDetails
chainId={chainId}
contractAddress={item.decodedData[0]}
imagesIpfsHash={item.decodedData[1]}
/>
)}
</Card>
)
}
13 changes: 13 additions & 0 deletions src/components/light-item-card-content.js
Original file line number Diff line number Diff line change
@@ -5,6 +5,8 @@ import PropTypes from 'prop-types'
import DisplaySelector from './display-selector'
import { ItemTypes } from '@kleros/gtcr-encoder'
import useNavigateAndScrollTop from 'hooks/navigate-and-scroll-top'
import { seerAddresses } from 'config/tcr-addresses'
import SeerExtraDetails from 'components/custom-registries-extra-details/seer-extra-details'

export const Container = styled.div`
display: flex;
@@ -44,6 +46,17 @@ const LightItemCardContent = ({ item, chainId, tcrAddress }) => {
/>
</StyledItemCol>
))}
{tcrAddress &&
(tcrAddress.toLowerCase() === seerAddresses[1] ||
tcrAddress.toLowerCase() === seerAddresses[100]) &&
item && (
<SeerExtraDetails
chainId={chainId}
contractAddress={item.columns[1].value}
imagesIpfsHash={item.columns[0].value}
smallDisplay
/>
)}
</div>
<Button
onClick={() =>
5 changes: 5 additions & 0 deletions src/config/tcr-addresses.ts
Original file line number Diff line number Diff line change
@@ -128,6 +128,11 @@ export const txBatcherAddresses = {
'11155111': '0xb5418fc9b536c52c635b4c3a2978de7165b67318'
} as const

export const seerAddresses = {
'1': '0x4a9f8e73b3c4c9d7fa0210b9de457b1c493a3ada',
'100': '0x5aaf9e23a11440f8c1ad6d2e2e5109c7e52cc672'
} as const

export const subgraphUrl = {
'1': process.env.REACT_APP_SUBGRAPH_MAINNET,
'100': process.env.REACT_APP_SUBGRAPH_GNOSIS,