Skip to content

Commit 0165b1d

Browse files
committed
Merge branch 'dev' into feat(web)/commit-reveal
2 parents e64ea3d + f0e01ec commit 0165b1d

Some content is hidden

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

51 files changed

+1699
-116
lines changed

contracts/README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ Smart contracts for Kleros v2
44

55
## Deployments
66

7-
Refresh the list of deployed contracts by running `./scripts/generateDeploymentsMarkdown.sh`.
7+
Refresh the list of deployed contracts by running `./scripts/generateDeploymentsMarkdown.sh` or `./scripts/populateReadme.sh`.
88

99
### Official Testnet
1010

@@ -57,7 +57,7 @@ Refresh the list of deployed contracts by running `./scripts/generateDeployments
5757
- [DisputeKitClassic: proxy](https://sepolia.arbiscan.io/address/0x9426F127116C3652A262AE1eA48391AC8F44D35b), [implementation](https://sepolia.arbiscan.io/address/0x692CC78F2570181FFB99297965FeAA8352ab12E8)
5858
- [DisputeResolver](https://sepolia.arbiscan.io/address/0xB8B36CC43f852f9F0484f53Eb38CaBBA28a81bF6)
5959
- [DisputeTemplateRegistry: proxy](https://sepolia.arbiscan.io/address/0x596D3B09E684D62217682216e9b7a0De75933391), [implementation](https://sepolia.arbiscan.io/address/0xc53b813ed94AaEb6F5518D60bf6a8109954bE3f6)
60-
- [Escrow](https://sepolia.arbiscan.io/address/0xdaf749DABE7be6C6894950AE69af35c20a00ABd9)
60+
- [Escrow](https://sepolia.arbiscan.io/address/0x10f7A6f42Af606553883415bc8862643A6e63fdA)
6161
- [EvidenceModule: proxy](https://sepolia.arbiscan.io/address/0x57fd453FB0d16f8ca174E7386102D7170E17Be09), [implementation](https://sepolia.arbiscan.io/address/0x05AD81f245209b7f91885fd96e57c9da90554824)
6262
- [KlerosCore: proxy](https://sepolia.arbiscan.io/address/0xA54e7A16d7460e38a8F324eF46782FB520d58CE8), [implementation](https://sepolia.arbiscan.io/address/0x91a373BBdE0532F86410682F362e2Cf685e95085)
6363
- [PNKFaucet](https://sepolia.arbiscan.io/address/0x7EFE468003Ad6A858b5350CDE0A67bBED58739dD)

contracts/deployments/arbitrumSepoliaDevnet/Escrow.json

+76-49
Large diffs are not rendered by default.

contracts/scripts/populateReadme.sh

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#!/usr/bin/env bash
2+
3+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"
4+
5+
if [ ! -x "$(command -v envsubst)" ]; then
6+
echo >&2 "error: envsubst not installed"
7+
exit 1
8+
fi
9+
10+
deployments="$($SCRIPT_DIR/generateDeploymentsMarkdown.sh)" \
11+
envsubst '$deployments' \
12+
< README.md.template \
13+
> README.md

contracts/src/arbitration/arbitrables/Escrow.sol

+18-2
Original file line numberDiff line numberDiff line change
@@ -84,14 +84,20 @@ contract Escrow is IArbitrableV2 {
8484

8585
/// @dev Emitted when a transaction is created.
8686
/// @param _transactionID The index of the transaction.
87+
/// @param _transactionUri The IPFS Uri Hash of the transaction.
8788
/// @param _buyer The address of the buyer.
8889
/// @param _seller The address of the seller.
8990
/// @param _amount The initial amount in the transaction.
91+
/// @param _asset The asset used ("native" for native chain token).
92+
/// @param _deadline The deadline of the transaction.
9093
event TransactionCreated(
9194
uint256 indexed _transactionID,
95+
string _transactionUri,
9296
address indexed _buyer,
9397
address indexed _seller,
94-
uint256 _amount
98+
uint256 _amount,
99+
string _asset,
100+
uint256 _deadline
95101
);
96102

97103
/// @dev To be emitted when a transaction is resolved, either by its
@@ -166,12 +172,14 @@ contract Escrow is IArbitrableV2 {
166172

167173
/// @dev Create a transaction.
168174
/// @param _timeoutPayment Time after which a party can automatically execute the arbitrable transaction.
175+
/// @param _transactionUri The IPFS Uri Hash of the transaction.
169176
/// @param _seller The recipient of the transaction.
170177
/// @param _templateData The dispute template data.
171178
/// @param _templateDataMappings The dispute template data mappings.
172179
/// @return transactionID The index of the transaction.
173180
function createTransaction(
174181
uint256 _timeoutPayment,
182+
string memory _transactionUri,
175183
address payable _seller,
176184
string memory _templateData,
177185
string memory _templateDataMappings
@@ -186,7 +194,15 @@ contract Escrow is IArbitrableV2 {
186194

187195
transactionID = transactions.length - 1;
188196

189-
emit TransactionCreated(transactionID, msg.sender, _seller, msg.value);
197+
emit TransactionCreated(
198+
transactionID,
199+
_transactionUri,
200+
msg.sender,
201+
_seller,
202+
msg.value,
203+
"native",
204+
transaction.deadline
205+
);
190206
}
191207

192208
/// @dev Pay seller. To be called if the good or service is provided.

web/src/app.tsx

+15-10
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ import Cases from "./pages/Cases";
1414
import Dashboard from "./pages/Dashboard";
1515
import Courts from "./pages/Courts";
1616
import DisputeTemplateView from "./pages/DisputeTemplateView";
17+
import DisputeResolver from "./pages/Resolver";
18+
import { NewDisputeProvider } from "./context/NewDisputeContext";
1719

1820
const App: React.FC = () => {
1921
return (
@@ -22,16 +24,19 @@ const App: React.FC = () => {
2224
<RefetchOnBlock />
2325
<Web3Provider>
2426
<IsListProvider>
25-
<SentryRoutes>
26-
<Route path="/" element={<Layout />}>
27-
<Route index element={<Home />} />
28-
<Route path="cases/*" element={<Cases />} />
29-
<Route path="courts/*" element={<Courts />} />
30-
<Route path="dashboard/:page/:order/:filter" element={<Dashboard />} />
31-
<Route path="disputeTemplate" element={<DisputeTemplateView />} />
32-
<Route path="*" element={<h1>Justice not found here ¯\_( ͡° ͜ʖ ͡°)_/¯</h1>} />
33-
</Route>
34-
</SentryRoutes>
27+
<NewDisputeProvider>
28+
<SentryRoutes>
29+
<Route path="/" element={<Layout />}>
30+
<Route index element={<Home />} />
31+
<Route path="cases/*" element={<Cases />} />
32+
<Route path="courts/*" element={<Courts />} />
33+
<Route path="dashboard/:page/:order/:filter" element={<Dashboard />} />
34+
<Route path="disputeTemplate" element={<DisputeTemplateView />} />
35+
<Route path="resolver/*" element={<DisputeResolver />} />
36+
<Route path="*" element={<h1>Justice not found here ¯\_( ͡° ͜ʖ ͡°)_/¯</h1>} />
37+
</Route>
38+
</SentryRoutes>
39+
</NewDisputeProvider>
3540
</IsListProvider>
3641
</Web3Provider>
3742
</QueryClientProvider>

web/src/assets/svgs/icons/dispute.svg

+11
Loading

web/src/assets/svgs/icons/ellipse.svg

+3
Loading

web/src/assets/svgs/icons/minus.svg

+3
Loading

web/src/assets/svgs/icons/plus.svg

+10
Loading

web/src/components/ConnectWallet/AccountDisplay.tsx

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { landscapeStyle } from "styles/landscapeStyle";
44
import { useAccount, useNetwork, useEnsAvatar, useEnsName } from "wagmi";
55
import Identicon from "react-identicons";
66
import { shortenAddress } from "utils/shortenAddress";
7+
import { isAddress } from "viem";
78

89
const Container = styled.div`
910
display: flex;
@@ -134,7 +135,7 @@ export const AddressOrName: React.FC<IAddressOrName> = ({ address: propAddress }
134135
chainId: 1,
135136
});
136137

137-
return <label>{data ?? (address && shortenAddress(address))}</label>;
138+
return <label>{data ?? (isAddress(address) ? shortenAddress(address) : address)}</label>;
138139
};
139140

140141
export const ChainDisplay: React.FC = () => {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import React from "react";
2+
import styled from "styled-components";
3+
import { AddressOrName, IdenticonOrAvatar } from "../ConnectWallet/AccountDisplay";
4+
import { Alias } from "context/NewDisputeContext";
5+
import { isUndefined } from "utils/index";
6+
import { useEnsAddress } from "wagmi";
7+
import { isAddress } from "viem";
8+
import Skeleton from "react-loading-skeleton";
9+
10+
const AliasContainer = styled.div`
11+
min-height: 32px;
12+
display: flex;
13+
gap: 8px;
14+
align-items: center;
15+
`;
16+
17+
const TextContainer = styled.div`
18+
display: flex;
19+
> label {
20+
color: ${({ theme }) => theme.primaryText};
21+
font-size: 14px;
22+
}
23+
`;
24+
25+
interface IAlias {
26+
alias: Alias;
27+
}
28+
29+
const AliasDisplay: React.FC<IAlias> = ({ alias }) => {
30+
const { data: addressFromENS, isLoading } = useEnsAddress({
31+
enabled: !isAddress(alias.address), // if alias.address is not an Address, we treat it as ENS and try to fetch address from there
32+
name: alias.address,
33+
chainId: 1,
34+
});
35+
36+
// try fetching ens name, else go with address
37+
const address = addressFromENS ?? alias.address;
38+
39+
return (
40+
<AliasContainer>
41+
{isLoading ? <Skeleton width={30} height={24} /> : <IdenticonOrAvatar address={address} size="24" />}
42+
<TextContainer>
43+
{isLoading ? <Skeleton width={30} height={24} /> : <AddressOrName address={address} />}&nbsp;
44+
{!isUndefined(alias.name) && alias.name !== "" ? <label>({alias.name})</label> : null}
45+
</TextContainer>
46+
</AliasContainer>
47+
);
48+
};
49+
50+
export default AliasDisplay;

web/src/pages/Cases/CaseDetails/Overview/DisputeContext.tsx renamed to web/src/components/DisputePreview/DisputeContext.tsx

+38-25
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ import ReactMarkdown from "components/ReactMarkdown";
33
import styled from "styled-components";
44
import { StyledSkeleton } from "components/StyledSkeleton";
55
import { isUndefined } from "utils/index";
6+
import { Answer as IAnswer, IDisputeTemplate } from "context/NewDisputeContext";
7+
import AliasDisplay from "./Alias";
8+
import { responsiveSize } from "styles/responsiveSize";
69

710
const StyledH1 = styled.h1`
811
margin: 0;
@@ -11,6 +14,10 @@ const StyledH1 = styled.h1`
1114
const QuestionAndDescription = styled.div`
1215
display: flex;
1316
flex-direction: column;
17+
div:first-child p:first-of-type {
18+
font-size: 16px;
19+
font-weight: 600;
20+
}
1421
`;
1522

1623
const StyledReactMarkDown = styled(ReactMarkdown)`
@@ -31,32 +38,24 @@ const AnswersContainer = styled.div`
3138
const Answer = styled.div`
3239
margin: 0px;
3340
display: flex;
34-
gap: 8px;
41+
flex-wrap: wrap;
42+
gap: ${responsiveSize(2, 8)};
3543
`;
3644

37-
interface IAnswer {
38-
id?: string;
39-
title: string;
40-
description?: string;
41-
reserved?: boolean;
42-
}
43-
44-
interface IDisputeTemplate {
45-
answers: IAnswer[];
46-
arbitrableAddress: string;
47-
arbitrableChainID: string;
48-
arbitratorAddress: string;
49-
arbitratorChainID: string;
50-
category?: string;
51-
description: string;
52-
frontendUrl?: string;
53-
lang?: string;
54-
policyURI?: string;
55-
question: string;
56-
specification?: string;
57-
title: string;
58-
}
45+
const AliasesContainer = styled.div`
46+
display: flex;
47+
flex-wrap: wrap;
48+
gap: ${responsiveSize(8, 20)};
49+
`;
5950

51+
const Divider = styled.hr`
52+
width: 100%;
53+
display: flex;
54+
border: none;
55+
height: 1px;
56+
background-color: ${({ theme }) => theme.stroke};
57+
margin: 0;
58+
`;
6059
interface IDisputeContext {
6160
disputeTemplate: IDisputeTemplate;
6261
}
@@ -86,13 +85,27 @@ export const DisputeContext: React.FC<IDisputeContext> = ({ disputeTemplate }) =
8685
{isUndefined(disputeTemplate) ? null : <h3>Voting Options</h3>}
8786
<AnswersContainer>
8887
{disputeTemplate?.answers?.map((answer: IAnswer, i: number) => (
89-
<Answer key={i}>
88+
<Answer key={answer.title}>
9089
<small>Option {i + 1}:</small>
91-
<label>{answer.title}</label>
90+
<label>
91+
{answer.title}
92+
{answer.description ? ` - ${answer.description}` : null}
93+
</label>
9294
</Answer>
9395
))}
9496
</AnswersContainer>
9597
</VotingOptions>
98+
99+
{isUndefined(disputeTemplate?.aliases) ? null : (
100+
<>
101+
<Divider />
102+
<AliasesContainer>
103+
{disputeTemplate.aliases.map((alias) => (
104+
<AliasDisplay alias={alias} key={alias.address} />
105+
))}
106+
</AliasesContainer>
107+
</>
108+
)}
96109
</>
97110
);
98111
};
File renamed without changes.

web/src/components/LabeledInput.tsx

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { Field, FieldProps } from "@kleros/ui-components-library";
2+
import React from "react";
3+
import styled from "styled-components";
4+
import { isUndefined } from "utils/index";
5+
6+
const Container = styled.div`
7+
width: 100%;
8+
display: flex;
9+
flex-direction: column;
10+
`;
11+
const StyledField = styled(Field)`
12+
width: 100%;
13+
> small {
14+
margin-top: 16px;
15+
margin-bottom: 16px;
16+
}
17+
`;
18+
19+
const StyledLabel = styled.label`
20+
width: 100%;
21+
margin-bottom: 12px;
22+
`;
23+
24+
interface ILabeledInput extends FieldProps {
25+
label?: string;
26+
}
27+
const LabeledInput: React.FC<ILabeledInput> = (props) => {
28+
return (
29+
<Container>
30+
{!isUndefined(props.label) ? <StyledLabel id={props.label}>{props.label}</StyledLabel> : null}
31+
<StyledField {...props} id={props?.label} />
32+
</Container>
33+
);
34+
};
35+
36+
export default LabeledInput;

0 commit comments

Comments
 (0)