diff --git a/.github/workflows/contracts-testing.yml b/.github/workflows/contracts-testing.yml
index 47646906c..26e1fb313 100644
--- a/.github/workflows/contracts-testing.yml
+++ b/.github/workflows/contracts-testing.yml
@@ -15,73 +15,129 @@ on:
pull_request:
branches:
- "*"
-
-permissions: # added using https://github.com/step-security/secure-workflows
+
+permissions: # added using https://github.com/step-security/secure-workflows
contents: read
jobs:
- contracts-testing:
+ # *********************************************************************************** #
+ # ******************************* Hardhat Tests ************************************* #
+ # *********************************************************************************** #
+ hardhat-tests:
runs-on: ubuntu-latest
steps:
- - name: Harden Runner
- uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
- with:
- disable-sudo: false
- egress-policy: block
- allowed-endpoints: >
- binaries.soliditylang.org:443
- classic.yarnpkg.com:443
- github.com:443
- nightly.yarnpkg.com:443
- nodejs.org:443
- objects.githubusercontent.com:443
- registry.yarnpkg.com:443
- registry.npmjs.org:443
- 54.185.253.63:443
-
- - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- with:
- submodules: recursive
-
- - name: Set up corepack (for yarn)
- run: |
- corepack enable
- corepack prepare yarn@4.9.2 --activate
- yarn set version 4.9.2
-
- - name: Setup Node.js environment
- uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0
- with:
- node-version: 20.x
- cache: yarn
-
- - name: Cache node modules
- uses: actions/cache@0c907a75c2c80ebcb7f088228285e798b750cf8f # v4.2.1
- env:
- cache-name: cache-node-modules
- with:
- path: |
- ~/.npm
- **/node_modules
- key: ${{ runner.os }}-build-${{ secrets.CACHE_VERSION }}-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json', '**/yarn.lock') }}
- restore-keys: |
- ${{ runner.os }}-build-${{ secrets.CACHE_VERSION }}-${{ env.cache-name }}-
-
- - name: Install contracts dependencies
- run: yarn workspace @kleros/kleros-v2-contracts install
-
- - name: Install Foundry
- uses: foundry-rs/foundry-toolchain@de808b1eea699e761c404bda44ba8f21aba30b2c # v1.3.1
-
- - name: Install lcov
- run: sudo apt-get install -y lcov
-
- - name: Run Hardhat and Foundry tests with coverage
- run: yarn coverage
- working-directory: contracts
-
- - name: Upload a build artifact
- uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4.6.1
- with:
- name: code-coverage-report
- path: contracts/coverage
+ - name: Harden Runner
+ uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
+ with:
+ disable-sudo: false
+ egress-policy: block
+ allowed-endpoints: >
+ binaries.soliditylang.org:443
+ classic.yarnpkg.com:443
+ github.com:443
+ nightly.yarnpkg.com:443
+ nodejs.org:443
+ objects.githubusercontent.com:443
+ registry.yarnpkg.com:443
+ registry.npmjs.org:443
+ 54.185.253.63:443
+
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+ with:
+ submodules: recursive
+
+ - name: Set up corepack (for yarn)
+ run: |
+ corepack enable
+ corepack prepare yarn@4.9.2 --activate
+ yarn set version 4.9.2
+
+ - name: Setup Node.js environment
+ uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0
+ with:
+ node-version: 20.x
+ cache: yarn
+
+ - name: Cache node modules
+ uses: actions/cache@0c907a75c2c80ebcb7f088228285e798b750cf8f # v4.2.1
+ env:
+ cache-name: cache-node-modules
+ with:
+ path: |
+ ~/.npm
+ **/node_modules
+ key: ${{ runner.os }}-build-${{ secrets.CACHE_VERSION }}-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json', '**/yarn.lock') }}
+ restore-keys: |
+ ${{ runner.os }}-build-${{ secrets.CACHE_VERSION }}-${{ env.cache-name }}-
+
+ - name: Install contracts dependencies
+ run: yarn workspace @kleros/kleros-v2-contracts install
+
+ - name: Run Hardhat tests
+ run: yarn test
+ working-directory: contracts
+
+ # *********************************************************************************** #
+ # ******************************* Foundry Tests ************************************* #
+ # *********************************************************************************** #
+ # COMPILATION FAILS 🤬
+ # foundry-tests:
+ # runs-on: ubuntu-latest
+ # steps:
+ # - name: Harden Runner
+ # uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
+ # with:
+ # disable-sudo: false
+ # egress-policy: block
+ # allowed-endpoints: >
+ # binaries.soliditylang.org:443
+ # classic.yarnpkg.com:443
+ # github.com:443
+ # nightly.yarnpkg.com:443
+ # nodejs.org:443
+ # objects.githubusercontent.com:443
+ # registry.yarnpkg.com:443
+ # registry.npmjs.org:443
+ # 54.185.253.63:443
+
+ # - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+ # with:
+ # submodules: recursive
+
+ # - name: Set up corepack (for yarn)
+ # run: |
+ # corepack enable
+ # corepack prepare yarn@4.9.2 --activate
+ # yarn set version 4.9.2
+
+ # - name: Setup Node.js environment
+ # uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0
+ # with:
+ # node-version: 20.x
+ # cache: yarn
+
+ # - name: Cache node modules
+ # uses: actions/cache@0c907a75c2c80ebcb7f088228285e798b750cf8f # v4.2.1
+ # env:
+ # cache-name: cache-node-modules
+ # with:
+ # path: |
+ # ~/.npm
+ # **/node_modules
+ # key: ${{ runner.os }}-build-${{ secrets.CACHE_VERSION }}-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json', '**/yarn.lock') }}
+ # restore-keys: |
+ # ${{ runner.os }}-build-${{ secrets.CACHE_VERSION }}-${{ env.cache-name }}-
+
+ # # - name: Install contracts dependencies
+ # # run: yarn workspace @kleros/kleros-v2-contracts install
+
+ # - name: Install Foundry
+ # uses: foundry-rs/foundry-toolchain@82dee4ba654bd2146511f85f0d013af94670c4de # v1.4.0
+
+ # - name: Run Foundry tests
+ # run: forge test --config-path ./foundry.toml
+ # working-directory: contracts
+
+ # - name: Run snapshot
+ # run: NO_COLOR=1 forge snapshot >> $GITHUB_STEP_SUMMARY
+ # working-directory: contracts
diff --git a/contracts/.solcover.js b/contracts/.solcover.js
index d9911ce98..46bc39e3c 100644
--- a/contracts/.solcover.js
+++ b/contracts/.solcover.js
@@ -7,6 +7,7 @@ const shell = require("shelljs");
module.exports = {
istanbulReporter: ["lcov"],
configureYulOptimizer: true,
+ irMinimum: true,
onCompileComplete: async function (_config) {
await run("typechain");
},
diff --git a/contracts/CHANGELOG.md b/contracts/CHANGELOG.md
index 2e571aa14..11a24ebc9 100644
--- a/contracts/CHANGELOG.md
+++ b/contracts/CHANGELOG.md
@@ -4,7 +4,71 @@ All notable changes to this package will be documented in this file.
The format is based on [Common Changelog](https://common-changelog.org/).
-## [0.11.0] - 2025-08-01
+## [0.13.0] - 2025-08-07 (Not published yet)
+
+### Changed
+
+- **Breaking:** Rename `KlerosCore.TokenAndETHShift` into `KlerosCore.JurorRewardPenalty` ([#2136](https://github.com/kleros/kleros-v2/issues/2136))
+- **Breaking:** Add event parameter `KlerosCore.TokenAndETHShift._degreeOfCoherencyFee` and renamed the other parameters to `_degreeOfCoherencyPnk`, `_amountPnk`, `_amountFee` ([#2097](https://github.com/kleros/kleros-v2/issues/2097))
+- **Breaking:** Move state variable `DisputeKitClassicBase.nbVotes` to the `Round` struct ([#2097](https://github.com/kleros/kleros-v2/issues/2097))
+- **Breaking:** Stake the juror's PNK rewards instead of transferring them out ([#2099](https://github.com/kleros/kleros-v2/issues/2099))
+- **Breaking:** Replace `require()` with `revert()` and custom errors outside KlerosCore for consistency and smaller bytecode ([#2084](https://github.com/kleros/kleros-v2/issues/2084))
+- **Breaking:** Rename the interface from `RNG` to `IRNG` ([#2054](https://github.com/kleros/kleros-v2/issues/2054))
+- **Breaking:** Rename `governor` to `owner` in order to comply with the lightweight ownership standard [ERC-5313](https://eipsinsight.com/ercs/erc-5313) ([#2112](https://github.com/kleros/kleros-v2/issues/2112))
+- **Breaking:** Apply the penalties to the stakes in the Sortition Tree ([#2107](https://github.com/kleros/kleros-v2/issues/2107))
+- **Breaking:** Make `SortitionModule.getJurorBalance().stakedInCourt` include the penalties ([#2107](https://github.com/kleros/kleros-v2/issues/2107))
+- Make `IDisputeKit.draw()` and `ISortitionModule.draw()` return the court ID from which the juror was drawn ([#2107](https://github.com/kleros/kleros-v2/issues/2107))
+- Rename `SortitionModule.setJurorInactive()` to `SortitionModule.forcedUnstakeAllCourts()` ([#2107](https://github.com/kleros/kleros-v2/issues/2107))
+- Make the primary VRF-based RNG fall back to `BlockhashRNG` if the VRF request is not fulfilled within a timeout ([#2054](https://github.com/kleros/kleros-v2/issues/2054))
+- Authenticate the calls to the RNGs to prevent 3rd parties from depleting the Chainlink VRF subscription funds ([#2054](https://github.com/kleros/kleros-v2/issues/2054))
+- Use `block.timestamp` rather than `block.number` for `BlockhashRNG` for better reliability on Arbitrum as block production is sporadic depending on network conditions. ([#2054](https://github.com/kleros/kleros-v2/issues/2054))
+- Replace the `bytes32 _key` parameter in `SortitionTrees.createTree()` and `SortitionTrees.draw()` by `uint96 courtID` ([#2113](https://github.com/kleros/kleros-v2/issues/2113))
+- Extract the sortition sum trees logic into a library `SortitionTrees` ([#2113](https://github.com/kleros/kleros-v2/issues/2113))
+- Make `IDisputeKit.getDegreeOfCoherenceReward()` multi-dimensional so different calculations may be applied to PNK rewards, fee rewards and PNK penalties (future-proofing) ([#2090](https://github.com/kleros/kleros-v2/issues/2090))
+- Consolidate the constant `ALPHA_DIVISOR` with `ONE_BASIS_POINTS` ([#2090](https://github.com/kleros/kleros-v2/issues/2090))
+- Set the Hardhat Solidity version to v0.8.30 and enable the IR pipeline ([#2069](https://github.com/kleros/kleros-v2/issues/2069))
+- Set the Foundry Solidity version to v0.8.30 and enable the IR pipeline ([#2073](https://github.com/kleros/kleros-v2/issues/2073))
+- Widen the allowed solc version to any v0.8.x for the interfaces only ([#2083](https://github.com/kleros/kleros-v2/issues/2083))
+- Bump `hardhat` to v2.26.2 ([#2069](https://github.com/kleros/kleros-v2/issues/2069))
+- Bump `@kleros/vea-contracts` to v0.7.0 ([#2073](https://github.com/kleros/kleros-v2/issues/2073))
+
+### Added
+
+- **Breaking:** Add storage gap arrays to `KlerosCore` structs `Round`, `Dispute` and `Court` ([#2097](https://github.com/kleros/kleros-v2/issues/2097))
+- **Breaking:** Add storage gap arrays to `DisputeKitClassicBase` state variables and to the structs `Round`, `Dispute` and `Vote` ([#2097](https://github.com/kleros/kleros-v2/issues/2097))
+- **Breaking:** Add a new field `drawnJurorFromCourtIDs` to the `Round` struct in `KlerosCoreBase` and `KlerosCoreUniversity` ([#2107](https://github.com/kleros/kleros-v2/issues/2107))
+- **Breaking:** Add a new state variable `jumpDisputeKitID` to the `DisputeKitClassicBase` contract ([#2114](https://github.com/kleros/kleros-v2/issues/2114))
+- **Breaking:** Add a parameter `_recoveryCommit` to the event `DisputeKitShutter.CommitCastShutter` ([#2100](https://github.com/kleros/kleros-v2/issues/2100))
+- **Breaking:** Add a storage variable `recoveryCommitments` to `DisputeKitShutter` ([#2100](https://github.com/kleros/kleros-v2/issues/2100))
+- Allow the Shutter commitment to be recovered by the juror using only the salt and the choice, without having to provide the justification ([#2100](https://github.com/kleros/kleros-v2/issues/2100))
+- Allow the dispute kits to force an early court jump and to override the number of votes after an appeal (future-proofing) ([#2110](https://github.com/kleros/kleros-v2/issues/2110))
+- Allow the dispute kits to specify which new dispute kit to use when a court jump occurs ([#2114](https://github.com/kleros/kleros-v2/issues/2114))
+- Allow stake changes to by-pass delayed stakes when initiated by the SortitionModule by setting the `_noDelay` parameter to `true` in `SortitionModule.validateStake()` ([#2107](https://github.com/kleros/kleros-v2/issues/2107))
+
+### Removed
+
+- **Breaking:** Remove unused event parameters `IArbitrableV2.DisputeRequest._templateUri` ([#2097](https://github.com/kleros/kleros-v2/issues/2097))
+- **Breaking:** Remove deprecated `SortitionModule` state variables `alreadyTransferred`, `randomNumberRequestBlock`, `rngLookahead` and `latestDelayedStakeIndex` ([#2097](https://github.com/kleros/kleros-v2/issues/2097))
+- **Breaking:** Remove struct variable `DisputeKitClassicBase.Round.nbVotes` ([#2097](https://github.com/kleros/kleros-v2/issues/2097))
+- **Breaking:** Remove the `_block` parameter from `IRNG.requestRandomness()` and `IRNG.receiveRandomness()`, not needed for the primary VRF-based RNG ([#2054](https://github.com/kleros/kleros-v2/issues/2054))
+
+### Fixed
+
+- Do not pass to Voting period if all the commits are cast because it breaks the current Shutter auto-reveal process. ([#2085](https://github.com/kleros/kleros-v2/issues/2085))
+- Do not emit the `KlerosCore.TokenAndETHShift` event if the both the PNK and fee amounts are zero ([#2135](https://github.com/kleros/kleros-v2/issues/2135))
+- Do not make PNK or ETH transfers if the amounts are zero ([#2135](https://github.com/kleros/kleros-v2/issues/2135))
+
+## [0.12.0] - 2025-08-05
+
+### Changed
+
+- **Breaking:** Make `viem` a peer dependency, it should be provided by the consuming package ([`4594536`](https://github.com/kleros/kleros-v2/commit/4594536c))
+
+### Added
+
+- Add helper function `getDisputeKitsViem` to retrieve a deployment's available dispute kit infos including their capabilities (`isShutter`, `isGated`) ([`5a81f9e`](https://github.com/kleros/kleros-v2/commit/5a81f9ec))
+
+## [0.11.0] - 2025-08-02
### Changed
@@ -107,6 +171,8 @@ The format is based on [Common Changelog](https://common-changelog.org/).
## [0.8.1] - 2025-04-10
+[0.13.0]: https://github.com/kleros/kleros-v2/releases/tag/@kleros%2Fkleros-v2-contracts@0.13.0
+[0.12.0]: https://github.com/kleros/kleros-v2/releases/tag/@kleros%2Fkleros-v2-contracts@0.12.0
[0.11.0]: https://github.com/kleros/kleros-v2/releases/tag/@kleros%2Fkleros-v2-contracts@0.11.0
[0.10.0]: https://github.com/kleros/kleros-v2/releases/tag/@kleros%2Fkleros-v2-contracts@0.10.0
[0.9.4]: https://github.com/kleros/kleros-v2/releases/tag/@kleros%2Fkleros-v2-contracts@0.9.4
diff --git a/contracts/README.md b/contracts/README.md
index 4f5d6d657..1e6ff14c3 100644
--- a/contracts/README.md
+++ b/contracts/README.md
@@ -74,7 +74,7 @@ Refresh the list of deployed contracts by running `./scripts/generateDeployments
- [WrappedPinakionV2](https://gnosis-chiado.blockscout.com/address/0xD75E27A56AaF9eE7F8d9A472a8C2EF2f65a764dd)
- [xKlerosLiquidV2](https://gnosis-chiado.blockscout.com/address/0x34E520dc1d2Db660113b64724e14CEdCD01Ee879)
-### Devnet
+### V2 Devnet (unstable)
#### Arbitrum Sepolia
@@ -84,25 +84,26 @@ Refresh the list of deployed contracts by running `./scripts/generateDeployments
- [DAI](https://sepolia.arbiscan.io/address/0x593e89704D285B0c3fbF157c7CF2537456CE64b5)
- [DAIFaucet](https://sepolia.arbiscan.io/address/0xB5b39A1bcD2D7097A8824B3cC18Ebd2dFb0D9B5E)
- [DisputeKitClassic: proxy](https://sepolia.arbiscan.io/address/0xeEEbbbff8f377dCFc7d4F7876C531db0d22720e1), [implementation](https://sepolia.arbiscan.io/address/0xc4cC0274E55a9818f8cF42640B1De61d269425ad)
-- [DisputeKitClassicUniversity: proxy](https://sepolia.arbiscan.io/address/0xd6E96b7c993763B5CDDa1139C7387B82A7c8B8B5), [implementation](https://sepolia.arbiscan.io/address/0x87e863b94d2CB79A8aB53bD87Dc4A10E11C0918B)
+- [DisputeKitClassicUniversity: proxy](https://sepolia.arbiscan.io/address/0x82F2089442979A6b56c80274D144575980092F91), [implementation](https://sepolia.arbiscan.io/address/0x602ADa1cE706404BFb5417e497cdDae934436081)
- [DisputeKitGated: proxy](https://sepolia.arbiscan.io/address/0x677dA30B4b27D129354DdA1e219Bcc86802132d1), [implementation](https://sepolia.arbiscan.io/address/0xA27EedcEA916BC1ab91720cE70c56666E854F55e)
- [DisputeKitGatedShutter: proxy](https://sepolia.arbiscan.io/address/0xd86b84eb36Cd48f3f384b4490F255b494385F429), [implementation](https://sepolia.arbiscan.io/address/0x56199F9E5C0ef9251A251a41597A971141199EDF)
- [DisputeKitShutter: proxy](https://sepolia.arbiscan.io/address/0xfE0a958bc744Bb9E224E1822625B53134ac5CB69), [implementation](https://sepolia.arbiscan.io/address/0x6582CE0FdB29B5673E6650e34728C784BafB2139)
- [DisputeResolver](https://sepolia.arbiscan.io/address/0x71f8537e925C753Fe88DA7e69Ae423f9f3a9A292)
- [DisputeResolverRuler](https://sepolia.arbiscan.io/address/0xAEB1bbaE58125BA5F32349c69e4274d15dfD6EC3)
-- [DisputeResolverUniversity](https://sepolia.arbiscan.io/address/0x2Aa1a94307E772BeE42E9EfbD137b1053F1fCfd4)
+- [DisputeResolverUniversity](https://sepolia.arbiscan.io/address/0x8a7902Ef9a5308C7DF0A68A28EEDd6D83436993D)
- [DisputeTemplateRegistry: proxy](https://sepolia.arbiscan.io/address/0xc852F94f90E3B06Da6eCfB61d76561ECfb94613f), [implementation](https://sepolia.arbiscan.io/address/0xBc9B5643C9B1C478DAe1b950e886CC50D8d868b1)
+- [DisputeTemplateRegistryUniversity: proxy](https://sepolia.arbiscan.io/address/0x75A5D16e9A699162506E4d79D68CF646e6600ba1), [implementation](https://sepolia.arbiscan.io/address/0xC3f638389635bF33E019c845FdaF2ed9bca3DF67)
- [EvidenceModule: proxy](https://sepolia.arbiscan.io/address/0xA1F72e0445fc395A393247F5B8c958Ec9b7C0B49), [implementation](https://sepolia.arbiscan.io/address/0x450Aa35da0ad8B282C5d910254055651417C2200)
- [KlerosCore: proxy](https://sepolia.arbiscan.io/address/0x1Bd44c4a4511DbFa7DC1d5BC201635596E7200f9), [implementation](https://sepolia.arbiscan.io/address/0xaBf1AA1D08F98ED800938B1B086d0904c5BF4f0E)
- [KlerosCoreRuler: proxy](https://sepolia.arbiscan.io/address/0x0630e4248a17b506809009F5D88E2f5bEE584c83), [implementation](https://sepolia.arbiscan.io/address/0xb8bF3A32730cEc3B0a8516b87246ceE24ca2eaCF)
- [KlerosCoreSnapshotProxy](https://sepolia.arbiscan.io/address/0xF924ac62b20901914c101Fa089Da1FB6A0585138)
-- [KlerosCoreUniversity: proxy](https://sepolia.arbiscan.io/address/0x5AB37F38778Bc175852fA353056591D91c744ce6), [implementation](https://sepolia.arbiscan.io/address/0xF74DaBfC5F5dbdBD07636637204d9C35326D2906)
+- [KlerosCoreUniversity: proxy](https://sepolia.arbiscan.io/address/0xA34dBBD0E5e1d09bd683455f9dbC393797BC558f), [implementation](https://sepolia.arbiscan.io/address/0xb75b0cc01af4aD0D65D50082ae0717004D479Aa0)
- [KlerosV2NeoEarlyUser](https://sepolia.arbiscan.io/address/0x0d60Ff8bbCF49Bc5352328E7E28e141834d7750F)
- [PinakionV2](https://sepolia.arbiscan.io/address/0x34B944D42cAcfC8266955D07A80181D2054aa225)
- [PNKFaucet](https://sepolia.arbiscan.io/address/0x7EFE468003Ad6A858b5350CDE0A67bBED58739dD)
- [PolicyRegistry: proxy](https://sepolia.arbiscan.io/address/0xd8681dBF525ecBda2F799BFddB96840065075e8A), [implementation](https://sepolia.arbiscan.io/address/0x472846F88D1356bb483a88f97B55026654Fc5deD)
- [SortitionModule: proxy](https://sepolia.arbiscan.io/address/0x6F24A90fBBeabB2B4343Bb9c1eD8ee6AcAa50663), [implementation](https://sepolia.arbiscan.io/address/0x8a26445989c944C58503275ad87Ab4d7b17d4F1e)
-- [SortitionModuleUniversity: proxy](https://sepolia.arbiscan.io/address/0x4B2c2d048921f694cCE3AEa35698c6B1f5fcbb79), [implementation](https://sepolia.arbiscan.io/address/0x5CAD621D69E0535422aCFaCC0017bC32beC7A486)
+- [SortitionModuleUniversity: proxy](https://sepolia.arbiscan.io/address/0x9f55804177e7E44E558616cD7d06B865788214cA), [implementation](https://sepolia.arbiscan.io/address/0x270e3D63d3d275604df0a1Bd312E1255DCd96936)
- [TransactionBatcher](https://sepolia.arbiscan.io/address/0x35f93986950804ac1F93519BF68C2a7Dd776db0E)
- [WETH](https://sepolia.arbiscan.io/address/0x3829A2486d53ee984a0ca2D76552715726b77138)
- [WETHFaucet](https://sepolia.arbiscan.io/address/0x6F8C10E0030aDf5B8030a5E282F026ADdB6525fd)
diff --git a/contracts/audit/METRICS.html b/contracts/audit/METRICS.html
new file mode 100644
index 000000000..31a6b6e73
--- /dev/null
+++ b/contracts/audit/METRICS.html
@@ -0,0 +1,209518 @@
+
+
+
+
+
+
+
+
+ Solidity Metrics
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Rendering Report...Note: This window will update automatically. In case it is not, close the window and try again (vscode
+ bug) :/
+
+
+
+
diff --git a/contracts/audit/METRICS.md b/contracts/audit/METRICS.md
new file mode 100644
index 000000000..ae2620a40
--- /dev/null
+++ b/contracts/audit/METRICS.md
@@ -0,0 +1,654 @@
+[ ](https://consensys.io/diligence)
+
+[[ 🌐 ](https://consensys.io/diligence) [ 📩 ](mailto:diligence@consensys.net) [ 🔥 ](https://consensys.io/diligence/tools/)]
+
+
+# Solidity Metrics for 'CLI'
+
+## Table of contents
+
+- [Scope](#t-scope)
+ - [Source Units in Scope](#t-source-Units-in-Scope)
+ - [Deployable Logic Contracts](#t-deployable-contracts)
+ - [Out of Scope](#t-out-of-scope)
+ - [Excluded Source Units](#t-out-of-scope-excluded-source-units)
+ - [Duplicate Source Units](#t-out-of-scope-duplicate-source-units)
+ - [Doppelganger Contracts](#t-out-of-scope-doppelganger-contracts)
+- [Report Overview](#t-report)
+ - [Risk Summary](#t-risk)
+ - [Source Lines](#t-source-lines)
+ - [Inline Documentation](#t-inline-documentation)
+ - [Components](#t-components)
+ - [Exposed Functions](#t-exposed-functions)
+ - [StateVariables](#t-statevariables)
+ - [Capabilities](#t-capabilities)
+ - [Dependencies](#t-package-imports)
+ - [Totals](#t-totals)
+
+## Scope
+
+This section lists files that are in scope for the metrics report.
+
+- **Project:** `'CLI'`
+- **Included Files:**
+ - ``
+- **Excluded Paths:**
+ - ``
+- **File Limit:** `undefined`
+
+ - **Exclude File list Limit:** `undefined`
+
+- **Workspace Repository:** `unknown` (`undefined`@`undefined`)
+
+### Source Units in Scope
+
+Source Units Analyzed: **`27`**
+Source Units in Scope: **`27`** (**100%**)
+
+| Type | File | Logic Contracts | Interfaces | Lines | nLines | nSLOC | Comment Lines | Complex. Score | Capabilities |
+| -------- | --------------------------------------------------------- | --------------- | ---------- | -------- | -------- | -------- | ------------- | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
+| 📝 | src/arbitration/KlerosCore.sol | 1 | \*\*\*\* | 1333 | 1272 | 869 | 322 | 486 | **🖥 💰 ** |
+| 📝 | src/arbitration/PolicyRegistry.sol | 1 | \*\*\*\* | 90 | 90 | 29 | 43 | 22 | \*\*\*\* |
+| 📝 | src/arbitration/SortitionModule.sol | 1 | \*\*\*\* | 622 | 572 | 325 | 208 | 223 | **🖥 ** |
+| 📝 | src/arbitration/arbitrables/DisputeResolver.sol | 1 | \*\*\*\* | 159 | 144 | 77 | 53 | 50 | **💰 ** |
+| 📝 | src/arbitration/DisputeTemplateRegistry.sol | 1 | \*\*\*\* | 85 | 81 | 29 | 35 | 23 | \*\*\*\* |
+| 📝 | src/arbitration/dispute-kits/DisputeKitClassic.sol | 1 | \*\*\*\* | 48 | 43 | 13 | 22 | 10 | \*\*\*\* |
+| 🎨 | src/arbitration/dispute-kits/DisputeKitClassicBase.sol | 1 | \*\*\*\* | 800 | 705 | 407 | 253 | 228 | **💰 🧮 ** |
+| 📝🔍 | src/arbitration/dispute-kits/DisputeKitGated.sol | 1 | 2 | 119 | 96 | 36 | 52 | 54 | **🖥 🔆 ** |
+| 📝🔍 | src/arbitration/dispute-kits/DisputeKitGatedShutter.sol | 1 | 2 | 256 | 211 | 81 | 104 | 80 | **🖥 🧮 🔆 ** |
+| 📝 | src/arbitration/dispute-kits/DisputeKitShutter.sol | 1 | \*\*\*\* | 189 | 163 | 58 | 77 | 38 | **🧮 ** |
+| 📝🔍 | src/arbitration/dispute-kits/DisputeKitSybilResistant.sol | 1 | 1 | 78 | 59 | 20 | 34 | 16 | **🔆 ** |
+| 📝 | src/arbitration/evidence/EvidenceModule.sol | 1 | \*\*\*\* | 72 | 72 | 25 | 32 | 19 | \*\*\*\* |
+| 🔍 | src/arbitration/interfaces/IArbitrableV2.sol | \*\*\*\* | 1 | 40 | 39 | 12 | 22 | 3 | \*\*\*\* |
+| 🔍 | src/arbitration/interfaces/IArbitratorV2.sol | \*\*\*\* | 1 | 83 | 44 | 9 | 50 | 14 | **💰 ** |
+| 🔍 | src/arbitration/interfaces/IDisputeKit.sol | \*\*\*\* | 1 | 165 | 39 | 11 | 78 | 31 | \*\*\*\* |
+| 🔍 | src/arbitration/interfaces/IDisputeTemplateRegistry.sol | \*\*\*\* | 1 | 25 | 20 | 9 | 8 | 3 | \*\*\*\* |
+| 🔍 | src/arbitration/interfaces/IEvidence.sol | \*\*\*\* | 1 | 12 | 12 | 4 | 6 | 1 | \*\*\*\* |
+| 🔍 | src/arbitration/interfaces/ISortitionModule.sol | \*\*\*\* | 1 | 73 | 16 | 10 | 4 | 37 | \*\*\*\* |
+| | src/libraries/Constants.sol | \*\*\*\* | \*\*\*\* | 42 | 42 | 27 | 14 | 2 | \*\*\*\* |
+| 📚 | src/libraries/SafeERC20.sol | 1 | \*\*\*\* | 47 | 47 | 18 | 24 | 12 | \*\*\*\* |
+| 📚🔍 | src/libraries/SafeSend.sol | 1 | 1 | 24 | 19 | 9 | 7 | 15 | **💰 📤 ** |
+| 📝 | src/rng/RNGWithFallback.sol | 1 | \*\*\*\* | 109 | 109 | 49 | 44 | 38 | \*\*\*\* |
+| 📝 | src/rng/ChainlinkRNG.sol | 1 | \*\*\*\* | 171 | 171 | 83 | 69 | 51 | \*\*\*\* |
+| 🔍 | src/rng/IRNG.sol | \*\*\*\* | 1 | 16 | 8 | 3 | 5 | 5 | \*\*\*\* |
+| 🎨 | src/proxy/UUPSProxiable.sol | 1 | \*\*\*\* | 140 | 122 | 44 | 71 | 46 | **🖥 💰 👥 ♻️ ** |
+| 📝 | src/proxy/UUPSProxy.sol | 1 | \*\*\*\* | 90 | 90 | 38 | 37 | 65 | **🖥 💰 👥 ** |
+| 🎨 | src/proxy/Initializable.sol | 1 | \*\*\*\* | 215 | 215 | 70 | 128 | 31 | **🖥 ** |
+| 📝📚🔍🎨 | **Totals** | **19** | **13** | **5103** | **4501** | **2365** | **1802** | **1603** | **🖥 💰 📤 👥 🧮 🔆 ♻️ ** |
+
+
+Legend: [➕]
+
+
+
+ Lines : total lines of the source unit
+ nLines : normalized lines of the source unit (e.g. normalizes functions spanning multiple lines)
+ nSLOC : normalized source lines of code (only source-code lines; no comments, no blank lines)
+ Comment Lines : lines containing single or block comments
+ Complexity Score : a custom complexity score derived from code statements that are known to introduce code complexity (branches, loops, calls, external interfaces, ...)
+
+
+
+
+
+##### Deployable Logic Contracts
+
+Total: 14
+
+- 📝 `KlerosCore`
+- 📝 `PolicyRegistry`
+- 📝 `SortitionModule`
+- 📝 `DisputeResolver`
+- 📝 `DisputeTemplateRegistry`
+- [➕]
+
+
+ 📝 DisputeKitClassic
+ 📝 DisputeKitGated
+ 📝 DisputeKitGatedShutter
+ 📝 DisputeKitShutter
+ 📝 DisputeKitSybilResistant
+ 📝 EvidenceModule
+ 📝 RNGWithFallback
+ 📝 ChainlinkRNG
+ 📝 UUPSProxy
+
+
+
+#### Out of Scope
+
+##### Excluded Source Units
+
+Source Units Excluded: **`0`**
+
+[➕]
+
+
+| File |
+| ------ |
+| None |
+
+
+
+##### Duplicate Source Units
+
+Duplicate Source Units Excluded: **`0`**
+
+[➕]
+
+
+| File |
+| ------ |
+| None |
+
+
+
+##### Doppelganger Contracts
+
+Doppelganger Contracts: **`3`**
+
+[➕]
+
+
+| File | Contract | Doppelganger |
+| ------ | -------- | ------------ |
+| src/arbitration/dispute-kits/DisputeKitGated.sol | IBalanceHolderERC1155 | (fuzzy) [0](https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/v2.5.0/contracts/introspection/IERC1820Implementer.sol), [1](https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/v3.2.0/contracts/introspection/IERC1820ImplementerUpgradeable.sol), [2](https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/v3.2.2-solc-0.7/contracts/introspection/IERC1820ImplementerUpgradeable.sol), [3](https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/v3.3.0/contracts/introspection/IERC1820ImplementerUpgradeable.sol), [4](https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/v3.3.0-solc-0.7/contracts/introspection/IERC1820ImplementerUpgradeable.sol), [5](https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/v3.4.0/contracts/introspection/IERC1820ImplementerUpgradeable.sol), [6](https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/v3.4.0-solc-0.7/contracts/introspection/IERC1820ImplementerUpgradeable.sol), [7](https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/v4.0.0/contracts/utils/introspection/IERC1820ImplementerUpgradeable.sol), [8](https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/v4.0.0-beta.0/contracts/utils/introspection/IERC1820ImplementerUpgradeable.sol), [9](https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/v4.0.0-rc.0/contracts/utils/introspection/IERC1820ImplementerUpgradeable.sol), [10](https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/v4.1.0/contracts/utils/introspection/IERC1820ImplementerUpgradeable.sol), [11](https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/v4.1.0-rc.0/contracts/utils/introspection/IERC1820ImplementerUpgradeable.sol), [12](https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/v4.2.0/contracts/utils/introspection/IERC1820ImplementerUpgradeable.sol), [13](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v2.3.0/contracts/introspection/IERC1820Implementer.sol), [14](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v2.3.0-rc.0/contracts/drafts/IERC1820Implementer.sol), [15](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v2.3.0-rc.1/contracts/drafts/IERC1820Implementer.sol), [16](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v2.3.0-rc.2/contracts/introspection/IERC1820Implementer.sol), [17](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v2.3.0-rc.3/contracts/introspection/IERC1820Implementer.sol), [18](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v2.4.0/contracts/introspection/IERC1820Implementer.sol), [19](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v2.4.0-beta.0/contracts/introspection/IERC1820Implementer.sol), [20](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v2.4.0-beta.1/contracts/introspection/IERC1820Implementer.sol), [21](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v2.4.0-beta.2/contracts/introspection/IERC1820Implementer.sol), [22](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v2.5.0/contracts/introspection/IERC1820Implementer.sol), [23](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v2.5.0-rc.0/contracts/introspection/IERC1820Implementer.sol), [24](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v2.5.1/contracts/introspection/IERC1820Implementer.sol), [25](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.0.0/contracts/introspection/IERC1820Implementer.sol), [26](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.0.0-beta.0/contracts/introspection/IERC1820Implementer.sol), [27](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.0.0-rc.0/contracts/introspection/IERC1820Implementer.sol), [28](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.0.0-rc.1/contracts/introspection/IERC1820Implementer.sol), [29](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.0.1/contracts/introspection/IERC1820Implementer.sol), [30](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.0.2/contracts/introspection/IERC1820Implementer.sol), [31](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.1.0/contracts/introspection/IERC1820Implementer.sol), [32](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.1.0-rc.0/contracts/introspection/IERC1820Implementer.sol), [33](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.2.0/contracts/introspection/IERC1820Implementer.sol), [34](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.2.0-rc.0/contracts/introspection/IERC1820Implementer.sol), [35](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.2.1-solc-0.7/contracts/introspection/IERC1820Implementer.sol), [36](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.2.2-solc-0.7/contracts/introspection/IERC1820Implementer.sol) |
+| src/arbitration/dispute-kits/DisputeKitGatedShutter.sol | IBalanceHolderERC1155 | (fuzzy) [0](https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/v2.5.0/contracts/introspection/IERC1820Implementer.sol), [1](https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/v3.2.0/contracts/introspection/IERC1820ImplementerUpgradeable.sol), [2](https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/v3.2.2-solc-0.7/contracts/introspection/IERC1820ImplementerUpgradeable.sol), [3](https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/v3.3.0/contracts/introspection/IERC1820ImplementerUpgradeable.sol), [4](https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/v3.3.0-solc-0.7/contracts/introspection/IERC1820ImplementerUpgradeable.sol), [5](https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/v3.4.0/contracts/introspection/IERC1820ImplementerUpgradeable.sol), [6](https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/v3.4.0-solc-0.7/contracts/introspection/IERC1820ImplementerUpgradeable.sol), [7](https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/v4.0.0/contracts/utils/introspection/IERC1820ImplementerUpgradeable.sol), [8](https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/v4.0.0-beta.0/contracts/utils/introspection/IERC1820ImplementerUpgradeable.sol), [9](https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/v4.0.0-rc.0/contracts/utils/introspection/IERC1820ImplementerUpgradeable.sol), [10](https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/v4.1.0/contracts/utils/introspection/IERC1820ImplementerUpgradeable.sol), [11](https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/v4.1.0-rc.0/contracts/utils/introspection/IERC1820ImplementerUpgradeable.sol), [12](https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/v4.2.0/contracts/utils/introspection/IERC1820ImplementerUpgradeable.sol), [13](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v2.3.0/contracts/introspection/IERC1820Implementer.sol), [14](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v2.3.0-rc.0/contracts/drafts/IERC1820Implementer.sol), [15](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v2.3.0-rc.1/contracts/drafts/IERC1820Implementer.sol), [16](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v2.3.0-rc.2/contracts/introspection/IERC1820Implementer.sol), [17](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v2.3.0-rc.3/contracts/introspection/IERC1820Implementer.sol), [18](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v2.4.0/contracts/introspection/IERC1820Implementer.sol), [19](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v2.4.0-beta.0/contracts/introspection/IERC1820Implementer.sol), [20](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v2.4.0-beta.1/contracts/introspection/IERC1820Implementer.sol), [21](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v2.4.0-beta.2/contracts/introspection/IERC1820Implementer.sol), [22](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v2.5.0/contracts/introspection/IERC1820Implementer.sol), [23](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v2.5.0-rc.0/contracts/introspection/IERC1820Implementer.sol), [24](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v2.5.1/contracts/introspection/IERC1820Implementer.sol), [25](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.0.0/contracts/introspection/IERC1820Implementer.sol), [26](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.0.0-beta.0/contracts/introspection/IERC1820Implementer.sol), [27](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.0.0-rc.0/contracts/introspection/IERC1820Implementer.sol), [28](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.0.0-rc.1/contracts/introspection/IERC1820Implementer.sol), [29](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.0.1/contracts/introspection/IERC1820Implementer.sol), [30](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.0.2/contracts/introspection/IERC1820Implementer.sol), [31](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.1.0/contracts/introspection/IERC1820Implementer.sol), [32](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.1.0-rc.0/contracts/introspection/IERC1820Implementer.sol), [33](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.2.0/contracts/introspection/IERC1820Implementer.sol), [34](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.2.0-rc.0/contracts/introspection/IERC1820Implementer.sol), [35](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.2.1-solc-0.7/contracts/introspection/IERC1820Implementer.sol), [36](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.2.2-solc-0.7/contracts/introspection/IERC1820Implementer.sol) |
+| src/arbitration/dispute-kits/DisputeKitSybilResistant.sol | IProofOfHumanity | (fuzzy) [0](https://github.com/smartcontractkit/chainlink/blob/explorer-v0.8.5/evm-contracts/src/v0.6/interfaces/BlockHashStoreInterface.sol), [1](https://github.com/smartcontractkit/chainlink/blob/upgrade/evm-contracts/src/v0.6/interfaces/BlockHashStoreInterface.sol), [2](https://github.com/smartcontractkit/chainlink/blob/v.0.8.12/evm-contracts/src/v0.6/interfaces/BlockHashStoreInterface.sol), [3](https://github.com/smartcontractkit/chainlink/blob/v0.8.12/evm-contracts/src/v0.6/interfaces/BlockHashStoreInterface.sol), [4](https://github.com/smartcontractkit/chainlink/blob/v0.8.13/evm-contracts/src/v0.6/interfaces/BlockHashStoreInterface.sol), [5](https://github.com/smartcontractkit/chainlink/blob/v0.8.14/evm-contracts/src/v0.6/interfaces/BlockHashStoreInterface.sol), [6](https://github.com/smartcontractkit/chainlink/blob/v0.8.15/evm-contracts/src/v0.6/interfaces/BlockHashStoreInterface.sol), [7](https://github.com/smartcontractkit/chainlink/blob/v0.8.16/evm-contracts/src/v0.6/interfaces/BlockHashStoreInterface.sol), [8](https://github.com/smartcontractkit/chainlink/blob/v0.8.17/evm-contracts/src/v0.6/interfaces/BlockHashStoreInterface.sol), [9](https://github.com/smartcontractkit/chainlink/blob/v0.8.18/evm-contracts/src/v0.6/interfaces/BlockHashStoreInterface.sol), [10](https://github.com/smartcontractkit/chainlink/blob/v0.9.0/evm-contracts/src/v0.6/interfaces/BlockHashStoreInterface.sol), [11](https://github.com/smartcontractkit/chainlink/blob/v0.9.2/evm-contracts/src/v0.6/interfaces/BlockHashStoreInterface.sol), [12](https://github.com/smartcontractkit/chainlink/blob/v0.9.3/evm-contracts/src/v0.6/interfaces/BlockHashStoreInterface.sol), [13](https://github.com/smartcontractkit/chainlink/blob/v0.9.4/evm-contracts/src/v0.6/interfaces/BlockHashStoreInterface.sol), [14](https://github.com/smartcontractkit/chainlink/blob/v0.9.5/evm-contracts/src/v0.6/interfaces/BlockHashStoreInterface.sol), [15](https://github.com/smartcontractkit/chainlink/blob/v0.9.6/evm-contracts/src/v0.6/interfaces/BlockHashStoreInterface.sol), [16](https://github.com/smartcontractkit/chainlink/blob/v0.9.7/evm-contracts/src/v0.6/interfaces/BlockHashStoreInterface.sol), [17](https://github.com/smartcontractkit/chainlink/blob/v0.9.8/evm-contracts/src/v0.6/interfaces/BlockHashStoreInterface.sol), [18](https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/v2.0.0/contracts/introspection/IERC165.sol), [19](https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/v2.0.1/contracts/introspection/IERC165.sol), [20](https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/v2.0.2/contracts/introspection/IERC165.sol), [21](https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/v2.1.2/contracts/introspection/IERC165.sol), [22](https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/v2.1.3/contracts/introspection/IERC165.sol), [23](https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/v2.2.1/contracts/introspection/IERC165.sol), [24](https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/v2.2.2/contracts/introspection/IERC165.sol), [25](https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/v2.2.3/contracts/introspection/IERC165.sol), [26](https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/v2.5.0/contracts/introspection/IERC165.sol), [27](https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/v3.2.0/contracts/introspection/IERC165Upgradeable.sol), [28](https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/v3.2.2-solc-0.7/contracts/introspection/IERC165Upgradeable.sol), [29](https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/v3.3.0/contracts/introspection/IERC165Upgradeable.sol), [30](https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/v3.3.0-solc-0.7/contracts/introspection/IERC165Upgradeable.sol), [31](https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/v3.4.0/contracts/introspection/IERC165Upgradeable.sol), [32](https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/v3.4.0-solc-0.7/contracts/introspection/IERC165Upgradeable.sol), [33](https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/v4.0.0/contracts/utils/introspection/IERC165Upgradeable.sol), [34](https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/v4.0.0-beta.0/contracts/utils/introspection/IERC165Upgradeable.sol), [35](https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/v4.0.0-rc.0/contracts/utils/introspection/IERC165Upgradeable.sol), [36](https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/v4.1.0/contracts/utils/introspection/IERC165Upgradeable.sol), [37](https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/v4.1.0-rc.0/contracts/utils/introspection/IERC165Upgradeable.sol), [38](https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/v4.2.0/contracts/utils/introspection/IERC165Upgradeable.sol), [39](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v2.0.0/contracts/introspection/IERC165.sol), [40](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v2.0.0-rc.1/contracts/introspection/IERC165.sol), [41](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v2.0.0-rc.2/contracts/introspection/IERC165.sol), [42](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v2.0.0-rc.3/contracts/introspection/IERC165.sol), [43](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v2.0.0-rc.4/contracts/introspection/IERC165.sol), [44](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v2.0.1/contracts/introspection/IERC165.sol), [45](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v2.1.0-rc.1/contracts/introspection/IERC165.sol), [46](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v2.1.0-rc.2/contracts/introspection/IERC165.sol), [47](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v2.1.1/contracts/introspection/IERC165.sol), [48](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v2.1.2/contracts/introspection/IERC165.sol), [49](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v2.1.3/contracts/introspection/IERC165.sol), [50](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v2.2.0/contracts/introspection/IERC165.sol), [51](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v2.2.0-rc.1/contracts/introspection/IERC165.sol), [52](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v2.3.0/contracts/introspection/IERC165.sol), [53](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v2.3.0-rc.0/contracts/introspection/IERC165.sol), [54](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v2.3.0-rc.1/contracts/introspection/IERC165.sol), [55](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v2.3.0-rc.2/contracts/introspection/IERC165.sol), [56](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v2.3.0-rc.3/contracts/introspection/IERC165.sol), [57](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v2.4.0/contracts/introspection/IERC165.sol), [58](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v2.4.0-beta.0/contracts/introspection/IERC165.sol), [59](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v2.4.0-beta.1/contracts/introspection/IERC165.sol), [60](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v2.4.0-beta.2/contracts/introspection/IERC165.sol), [61](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v2.5.0/contracts/introspection/IERC165.sol), [62](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v2.5.0-rc.0/contracts/introspection/IERC165.sol), [63](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v2.5.1/contracts/introspection/IERC165.sol), [64](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.0.0/contracts/introspection/IERC165.sol), [65](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.0.0-beta.0/contracts/introspection/IERC165.sol), [66](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.0.0-rc.0/contracts/introspection/IERC165.sol), [67](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.0.0-rc.1/contracts/introspection/IERC165.sol), [68](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.0.1/contracts/introspection/IERC165.sol), [69](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.0.2/contracts/introspection/IERC165.sol), [70](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.1.0/contracts/introspection/IERC165.sol), [71](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.1.0-rc.0/contracts/introspection/IERC165.sol), [72](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.2.0/contracts/introspection/IERC165.sol), [73](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.2.0-rc.0/contracts/introspection/IERC165.sol), [74](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.2.1-solc-0.7/contracts/introspection/IERC165.sol), [75](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.2.2-solc-0.7/contracts/introspection/IERC165.sol) |
+
+
+
+## Report
+
+### Overview
+
+The analysis finished with **`0`** errors and **`0`** duplicate files.
+
+#### Risk
+
+
+
+
+
+#### Source Lines (sloc vs. nsloc)
+
+
+
+
+
+#### Inline Documentation
+
+- **Comment-to-Source Ratio:** On average there are`1.56` code lines per comment (lower=better).
+- **ToDo's:** `3`
+
+#### Components
+
+| 📝Contracts | 📚Libraries | 🔍Interfaces | 🎨Abstract |
+| ----------- | ----------- | ------------ | ---------- |
+| 14 | 2 | 13 | 3 |
+
+#### Exposed Functions
+
+This section lists functions that are explicitly declared public or payable. Please note that getter methods for public stateVars are not included.
+
+| 🌐Public | 💰Payable |
+| -------- | --------- |
+| 191 | 10 |
+
+| External | Internal | Private | Pure | View |
+| -------- | -------- | ------- | ---- | ---- |
+| 175 | 197 | 1 | 9 | 92 |
+
+#### StateVariables
+
+| Total | 🌐Public |
+| ----- | -------- |
+| 88 | 82 |
+
+#### Capabilities
+
+| Solidity Versions observed | 🧪 Experimental Features | 💰 Can Receive Funds | 🖥 Uses Assembly | 💣 Has Destroyable Contracts |
+| -------------------------------------------- | ------------------------ | -------------------- | -------------------------- | ---------------------------- |
+| `^0.8.24` `^0.8.28` `>=0.8.0 <0.9.0` | | `yes` | `yes` (10 asm blocks) | \*\*\*\* |
+
+| 📤 Transfers ETH | ⚡ Low-Level Calls | 👥 DelegateCall | 🧮 Uses Hash Functions | 🔖 ECRecover | 🌀 New/Create/Create2 |
+| ---------------- | ------------------ | --------------- | ---------------------- | ------------ | --------------------- |
+| `yes` | \*\*\*\* | `yes` | `yes` | \*\*\*\* | \*\*\*\* |
+
+| ♻️ TryCatch | Σ Unchecked |
+| ----------- | ----------- |
+| `yes` | \*\*\*\* |
+
+#### Dependencies / External Imports
+
+| Dependency / Import Path | Count |
+| ------------------------------------------------------------------- | ----- |
+| @chainlink/contracts/src/v0.8/vrf/dev/libraries/VRFV2PlusClient.sol | 1 |
+| @openzeppelin/contracts/token/ERC20/IERC20.sol | 3 |
+| @openzeppelin/contracts/token/ERC721/IERC721.sol | 1 |
+
+#### Totals
+
+##### Summary
+
+
+
+
+
+##### AST Node Statistics
+
+###### Function Calls
+
+
+
+
+
+###### Assembly Calls
+
+
+
+
+
+###### AST Total
+
+
+
+
+
+##### Inheritance Graph
+
+[➕]
+
+
+
+##### CallGraph
+
+[➕]
+
+
+
+###### Contract Summary
+
+[➕]
+
+
+
+Files Description Table
+
+| File Name | SHA-1 Hash |
+| --------------------------------------------------------- | ---------------------------------------- |
+| src/arbitration/KlerosCore.sol | 383e209070883ddd480ef42f775d9c46dd3a9312 |
+| src/arbitration/PolicyRegistry.sol | 513ee51fc5262e41bf1ee58c19011b2166bb8281 |
+| src/arbitration/SortitionModule.sol | 455986084175670bcd15911f4f04cbf64203da41 |
+| src/arbitration/arbitrables/DisputeResolver.sol | 985b9082c8187d8c4d35e1c88c54f954532cd94f |
+| src/arbitration/DisputeTemplateRegistry.sol | 3cc2892233d940bf4523414680e361869f6df054 |
+| src/arbitration/dispute-kits/DisputeKitClassic.sol | b7a6a3c1e021f11c8f6f8ae7c184e947a7cd45d9 |
+| src/arbitration/dispute-kits/DisputeKitClassicBase.sol | c0d30028020e75203758df5241cdaf1138464b75 |
+| src/arbitration/dispute-kits/DisputeKitGated.sol | c98ed7a48f251debdd88a325245dcb8e04926311 |
+| src/arbitration/dispute-kits/DisputeKitGatedShutter.sol | bfe8f9e2598454027643644e246140623d5c73a8 |
+| src/arbitration/dispute-kits/DisputeKitShutter.sol | b77e1e9ddfcf19c31570f0bfbf01c18086c99f56 |
+| src/arbitration/dispute-kits/DisputeKitSybilResistant.sol | 8bba9bb201d66fc07abc436b7830701a92e0ffb6 |
+| src/arbitration/evidence/EvidenceModule.sol | 0098cc5e9939d1193f152890dfc94729a0d8bbd4 |
+| src/arbitration/interfaces/IArbitrableV2.sol | ce54b7140a6109b2d919cea38ff94ac2ad775398 |
+| src/arbitration/interfaces/IArbitratorV2.sol | 4e0baa0ff6155737540105f9fdb5b54ba2905d2c |
+| src/arbitration/interfaces/IDisputeKit.sol | 06e3c893fca325de50367a1a862036771295885b |
+| src/arbitration/interfaces/IDisputeTemplateRegistry.sol | 8d0351ebeee1ebd8603af9cf50c2ab62f6e8fecb |
+| src/arbitration/interfaces/IEvidence.sol | 12ee130f67f5d38afbcc810129b030cf7f58f058 |
+| src/arbitration/interfaces/ISortitionModule.sol | ea2526039c8675ddbc387198b29600a49c3584c1 |
+| src/libraries/Constants.sol | 6ce9e86c301042de2d32f9a3a5cfc2d65c34fa47 |
+| src/libraries/SafeERC20.sol | 68e49603280eab2b68eabc554dc310ff3313a64c |
+| src/libraries/SafeSend.sol | 9d282cf6456950471debec28103fcb99638fa83d |
+| src/rng/RNGWithFallback.sol | 0d90b33bb4fdeb9492d5b2474135790cd0c986e5 |
+| src/rng/ChainlinkRNG.sol | 54f081a26e78c5aa0d58207372944a603eae5cf7 |
+| src/rng/IRNG.sol | 25eee63b46a76183c24b39d81ae85044474a6a02 |
+| src/proxy/UUPSProxiable.sol | 80d46ace20ea4c9c6a0cbc1093d6e88eb19aeb12 |
+| src/proxy/UUPSProxy.sol | 18a2a570a8ef2ec5f02d59bd1c03a176203e8ccf |
+| src/proxy/Initializable.sol | bf3ba9453bab903eda4247e90e39376e20744353 |
+
+Contracts Description Table
+
+| Contract | Type | Bases | | |
+| :--------------------------: | :-------------------------------------: | :----------------------------------------------------: | :------------: | :---------------------------------: |
+| └ | **Function Name** | **Visibility** | **Mutability** | **Modifiers** |
+| | | | | |
+| **KlerosCore** | Implementation | IArbitratorV2, Initializable, UUPSProxiable | | |
+| └ | | Public ❗️ | 🛑 | NO❗️ |
+| └ | initialize | External ❗️ | 🛑 | initializer |
+| └ | \_authorizeUpgrade | Internal 🔒 | | onlyByOwner |
+| └ | pause | External ❗️ | 🛑 | onlyByGuardianOrOwner whenNotPaused |
+| └ | unpause | External ❗️ | 🛑 | onlyByOwner whenPaused |
+| └ | executeOwnerProposal | External ❗️ | 🛑 | onlyByOwner |
+| └ | changeOwner | External ❗️ | 🛑 | onlyByOwner |
+| └ | changeGuardian | External ❗️ | 🛑 | onlyByOwner |
+| └ | changePinakion | External ❗️ | 🛑 | onlyByOwner |
+| └ | changeJurorProsecutionModule | External ❗️ | 🛑 | onlyByOwner |
+| └ | changeSortitionModule | External ❗️ | 🛑 | onlyByOwner |
+| └ | addNewDisputeKit | External ❗️ | 🛑 | onlyByOwner |
+| └ | createCourt | External ❗️ | 🛑 | onlyByOwner |
+| └ | changeCourtParameters | External ❗️ | 🛑 | onlyByOwner |
+| └ | enableDisputeKits | External ❗️ | 🛑 | onlyByOwner |
+| └ | changeAcceptedFeeTokens | External ❗️ | 🛑 | onlyByOwner |
+| └ | changeCurrencyRates | External ❗️ | 🛑 | onlyByOwner |
+| └ | changeJurorNft | External ❗️ | 🛑 | onlyByOwner |
+| └ | changeArbitrableWhitelist | External ❗️ | 🛑 | onlyByOwner |
+| └ | changeArbitrableWhitelistEnabled | External ❗️ | 🛑 | onlyByOwner |
+| └ | setStake | External ❗️ | 🛑 | whenNotPaused |
+| └ | setStakeBySortitionModule | External ❗️ | 🛑 | NO❗️ |
+| └ | transferBySortitionModule | External ❗️ | 🛑 | NO❗️ |
+| └ | createDispute | External ❗️ | 💵 | NO❗️ |
+| └ | createDispute | External ❗️ | 🛑 | NO❗️ |
+| └ | \_createDispute | Internal 🔒 | 🛑 | |
+| └ | passPeriod | External ❗️ | 🛑 | NO❗️ |
+| └ | draw | External ❗️ | 🛑 | NO❗️ |
+| └ | appeal | External ❗️ | 💵 | NO❗️ |
+| └ | execute | External ❗️ | 🛑 | whenNotPaused |
+| └ | \_executePenalties | Internal 🔒 | 🛑 | |
+| └ | \_executeRewards | Internal 🔒 | 🛑 | |
+| └ | executeRuling | External ❗️ | 🛑 | NO❗️ |
+| └ | arbitrationCost | Public ❗️ | | NO❗️ |
+| └ | arbitrationCost | Public ❗️ | | NO❗️ |
+| └ | appealCost | Public ❗️ | | NO❗️ |
+| └ | appealPeriod | External ❗️ | | NO❗️ |
+| └ | currentRuling | Public ❗️ | | NO❗️ |
+| └ | getRoundInfo | External ❗️ | | NO❗️ |
+| └ | getPnkAtStakePerJuror | External ❗️ | | NO❗️ |
+| └ | getNumberOfRounds | External ❗️ | | NO❗️ |
+| └ | isSupported | External ❗️ | | NO❗️ |
+| └ | getTimesPerPeriod | External ❗️ | | NO❗️ |
+| └ | getNumberOfVotes | External ❗️ | | NO❗️ |
+| └ | isDisputeKitJumping | External ❗️ | | NO❗️ |
+| └ | getDisputeKitsLength | External ❗️ | | NO❗️ |
+| └ | convertEthToTokenAmount | Public ❗️ | | NO❗️ |
+| └ | \_isCourtJumping | Internal 🔒 | | |
+| └ | \_getCourtAndDisputeKitJumps | Internal 🔒 | | |
+| └ | \_transferFeeToken | Internal 🔒 | 🛑 | |
+| └ | \_applyCoherence | Internal 🔒 | | |
+| └ | \_calculatePnkAtStake | Internal 🔒 | | |
+| └ | \_enableDisputeKit | Internal 🔒 | 🛑 | |
+| └ | \_setStake | Internal 🔒 | 🛑 | |
+| └ | \_stakingFailed | Internal 🔒 | | |
+| └ | \_extraDataToCourtIDMinJurorsDisputeKit | Internal 🔒 | | |
+| | | | | |
+| **PolicyRegistry** | Implementation | UUPSProxiable, Initializable | | |
+| └ | | Public ❗️ | 🛑 | NO❗️ |
+| └ | initialize | External ❗️ | 🛑 | initializer |
+| └ | \_authorizeUpgrade | Internal 🔒 | | onlyByOwner |
+| └ | changeOwner | External ❗️ | 🛑 | onlyByOwner |
+| └ | setPolicy | External ❗️ | 🛑 | onlyByOwner |
+| | | | | |
+| **SortitionModule** | Implementation | ISortitionModule, Initializable, UUPSProxiable | | |
+| └ | | Public ❗️ | 🛑 | NO❗️ |
+| └ | initialize | External ❗️ | 🛑 | initializer |
+| └ | \_authorizeUpgrade | Internal 🔒 | | onlyByOwner |
+| └ | changeOwner | External ❗️ | 🛑 | onlyByOwner |
+| └ | changeMinStakingTime | External ❗️ | 🛑 | onlyByOwner |
+| └ | changeMaxDrawingTime | External ❗️ | 🛑 | onlyByOwner |
+| └ | changeRandomNumberGenerator | External ❗️ | 🛑 | onlyByOwner |
+| └ | changeMaxStakePerJuror | External ❗️ | 🛑 | onlyByOwner |
+| └ | changeMaxTotalStaked | External ❗️ | 🛑 | onlyByOwner |
+| └ | passPhase | External ❗️ | 🛑 | NO❗️ |
+| └ | createTree | External ❗️ | 🛑 | onlyByCore |
+| └ | executeDelayedStakes | External ❗️ | 🛑 | NO❗️ |
+| └ | createDisputeHook | External ❗️ | 🛑 | onlyByCore |
+| └ | postDrawHook | External ❗️ | 🛑 | onlyByCore |
+| └ | notifyRandomNumber | Public ❗️ | 🛑 | NO❗️ |
+| └ | validateStake | External ❗️ | 🛑 | onlyByCore |
+| └ | \_validateStake | Internal 🔒 | 🛑 | |
+| └ | setStake | External ❗️ | 🛑 | onlyByCore |
+| └ | setStakePenalty | External ❗️ | 🛑 | onlyByCore |
+| └ | setStakeReward | External ❗️ | 🛑 | onlyByCore |
+| └ | \_setStake | Internal 🔒 | 🛑 | |
+| └ | lockStake | External ❗️ | 🛑 | onlyByCore |
+| └ | unlockStake | External ❗️ | 🛑 | onlyByCore |
+| └ | forcedUnstakeAllCourts | External ❗️ | 🛑 | onlyByCore |
+| └ | forcedUnstake | External ❗️ | 🛑 | onlyByCore |
+| └ | withdrawLeftoverPNK | External ❗️ | 🛑 | NO❗️ |
+| └ | draw | Public ❗️ | | NO❗️ |
+| └ | stakeOf | Public ❗️ | | NO❗️ |
+| └ | getJurorBalance | External ❗️ | | NO❗️ |
+| └ | getJurorCourtIDs | Public ❗️ | | NO❗️ |
+| └ | isJurorStaked | External ❗️ | | NO❗️ |
+| └ | getJurorLeftoverPNK | Public ❗️ | | NO❗️ |
+| └ | \_extraDataToTreeK | Internal 🔒 | | |
+| | | | | |
+| **DisputeResolver** | Implementation | IArbitrableV2 | | |
+| └ | | Public ❗️ | 🛑 | NO❗️ |
+| └ | changeOwner | External ❗️ | 🛑 | NO❗️ |
+| └ | changeArbitrator | External ❗️ | 🛑 | NO❗️ |
+| └ | changeTemplateRegistry | External ❗️ | 🛑 | NO❗️ |
+| └ | createDisputeForTemplate | External ❗️ | 💵 | NO❗️ |
+| └ | createDisputeForTemplateUri | External ❗️ | 💵 | NO❗️ |
+| └ | rule | External ❗️ | 🛑 | NO❗️ |
+| └ | \_createDispute | Internal 🔒 | 🛑 | |
+| | | | | |
+| **DisputeTemplateRegistry** | Implementation | IDisputeTemplateRegistry, UUPSProxiable, Initializable | | |
+| └ | | Public ❗️ | 🛑 | NO❗️ |
+| └ | initialize | External ❗️ | 🛑 | initializer |
+| └ | \_authorizeUpgrade | Internal 🔒 | | onlyByOwner |
+| └ | changeOwner | External ❗️ | 🛑 | onlyByOwner |
+| └ | setDisputeTemplate | External ❗️ | 🛑 | NO❗️ |
+| | | | | |
+| **DisputeKitClassic** | Implementation | DisputeKitClassicBase | | |
+| └ | | Public ❗️ | 🛑 | NO❗️ |
+| └ | initialize | External ❗️ | 🛑 | initializer |
+| └ | \_authorizeUpgrade | Internal 🔒 | | onlyByOwner |
+| | | | | |
+| **DisputeKitClassicBase** | Implementation | IDisputeKit, Initializable, UUPSProxiable | | |
+| └ | \_\_DisputeKitClassicBase_initialize | Internal 🔒 | 🛑 | onlyInitializing |
+| └ | executeOwnerProposal | External ❗️ | 🛑 | onlyByOwner |
+| └ | changeOwner | External ❗️ | 🛑 | onlyByOwner |
+| └ | changeCore | External ❗️ | 🛑 | onlyByOwner |
+| └ | changeJumpDisputeKitID | External ❗️ | 🛑 | onlyByOwner |
+| └ | createDispute | External ❗️ | 🛑 | onlyByCore |
+| └ | draw | External ❗️ | 🛑 | onlyByCore notJumped |
+| └ | castCommit | External ❗️ | 🛑 | NO❗️ |
+| └ | \_castCommit | Internal 🔒 | 🛑 | notJumped |
+| └ | castVote | External ❗️ | 🛑 | NO❗️ |
+| └ | \_castVote | Internal 🔒 | 🛑 | notJumped |
+| └ | fundAppeal | External ❗️ | 💵 | notJumped |
+| └ | withdrawFeesAndRewards | External ❗️ | 🛑 | NO❗️ |
+| └ | hashVote | Public ❗️ | | NO❗️ |
+| └ | getFundedChoices | Public ❗️ | | NO❗️ |
+| └ | currentRuling | External ❗️ | | NO❗️ |
+| └ | getDegreeOfCoherenceReward | External ❗️ | | NO❗️ |
+| └ | getDegreeOfCoherencePenalty | External ❗️ | | NO❗️ |
+| └ | \_getDegreeOfCoherence | Internal 🔒 | | |
+| └ | getCoherentCount | External ❗️ | | NO❗️ |
+| └ | areCommitsAllCast | External ❗️ | | NO❗️ |
+| └ | areVotesAllCast | External ❗️ | | NO❗️ |
+| └ | isAppealFunded | External ❗️ | | NO❗️ |
+| └ | earlyCourtJump | External ❗️ | | NO❗️ |
+| └ | getNbVotesAfterAppeal | External ❗️ | | NO❗️ |
+| └ | getJumpDisputeKitID | External ❗️ | | NO❗️ |
+| └ | isVoteActive | External ❗️ | | NO❗️ |
+| └ | getRoundInfo | External ❗️ | | NO❗️ |
+| └ | getNumberOfRounds | External ❗️ | | NO❗️ |
+| └ | getLocalDisputeRoundID | External ❗️ | | NO❗️ |
+| └ | getVoteInfo | External ❗️ | | NO❗️ |
+| └ | \_getExpectedVoteHash | Internal 🔒 | | |
+| └ | \_postDrawCheck | Internal 🔒 | | |
+| | | | | |
+| **IBalanceHolder** | Interface | | | |
+| └ | balanceOf | External ❗️ | | NO❗️ |
+| | | | | |
+| **IBalanceHolderERC1155** | Interface | | | |
+| └ | balanceOf | External ❗️ | | NO❗️ |
+| | | | | |
+| **DisputeKitGated** | Implementation | DisputeKitClassicBase | | |
+| └ | | Public ❗️ | 🛑 | NO❗️ |
+| └ | initialize | External ❗️ | 🛑 | initializer |
+| └ | \_authorizeUpgrade | Internal 🔒 | | onlyByOwner |
+| └ | extraDataToTokenInfo | Public ❗️ | | NO❗️ |
+| └ | \_postDrawCheck | Internal 🔒 | | |
+| | | | | |
+| **IBalanceHolder** | Interface | | | |
+| └ | balanceOf | External ❗️ | | NO❗️ |
+| | | | | |
+| **IBalanceHolderERC1155** | Interface | | | |
+| └ | balanceOf | External ❗️ | | NO❗️ |
+| | | | | |
+| **DisputeKitGatedShutter** | Implementation | DisputeKitClassicBase | | |
+| └ | | Public ❗️ | 🛑 | NO❗️ |
+| └ | initialize | External ❗️ | 🛑 | initializer |
+| └ | \_authorizeUpgrade | Internal 🔒 | | onlyByOwner |
+| └ | castCommitShutter | External ❗️ | 🛑 | notJumped |
+| └ | castVoteShutter | External ❗️ | 🛑 | NO❗️ |
+| └ | hashVote | Public ❗️ | | NO❗️ |
+| └ | \_getExpectedVoteHash | Internal 🔒 | | |
+| └ | \_extraDataToTokenInfo | Internal 🔒 | | |
+| └ | \_postDrawCheck | Internal 🔒 | | |
+| | | | | |
+| **DisputeKitShutter** | Implementation | DisputeKitClassicBase | | |
+| └ | | Public ❗️ | 🛑 | NO❗️ |
+| └ | initialize | External ❗️ | 🛑 | initializer |
+| └ | \_authorizeUpgrade | Internal 🔒 | | onlyByOwner |
+| └ | castCommitShutter | External ❗️ | 🛑 | notJumped |
+| └ | castVoteShutter | External ❗️ | 🛑 | NO❗️ |
+| └ | hashVote | Public ❗️ | | NO❗️ |
+| └ | \_getExpectedVoteHash | Internal 🔒 | | |
+| | | | | |
+| **IProofOfHumanity** | Interface | | | |
+| └ | isRegistered | External ❗️ | | NO❗️ |
+| | | | | |
+| **DisputeKitSybilResistant** | Implementation | DisputeKitClassicBase | | |
+| └ | | Public ❗️ | 🛑 | NO❗️ |
+| └ | initialize | External ❗️ | 🛑 | initializer |
+| └ | \_authorizeUpgrade | Internal 🔒 | | onlyByOwner |
+| └ | \_postDrawCheck | Internal 🔒 | | |
+| | | | | |
+| **EvidenceModule** | Implementation | IEvidence, Initializable, UUPSProxiable | | |
+| └ | | Public ❗️ | 🛑 | NO❗️ |
+| └ | initialize | External ❗️ | 🛑 | initializer |
+| └ | \_authorizeUpgrade | Internal 🔒 | | onlyByOwner |
+| └ | submitEvidence | External ❗️ | 🛑 | NO❗️ |
+| | | | | |
+| **IArbitrableV2** | Interface | | | |
+| └ | rule | External ❗️ | 🛑 | NO❗️ |
+| | | | | |
+| **IArbitratorV2** | Interface | | | |
+| └ | createDispute | External ❗️ | 💵 | NO❗️ |
+| └ | createDispute | External ❗️ | 🛑 | NO❗️ |
+| └ | arbitrationCost | External ❗️ | | NO❗️ |
+| └ | arbitrationCost | External ❗️ | | NO❗️ |
+| └ | currentRuling | External ❗️ | | NO❗️ |
+| | | | | |
+| **IDisputeKit** | Interface | | | |
+| └ | createDispute | External ❗️ | 🛑 | NO❗️ |
+| └ | draw | External ❗️ | 🛑 | NO❗️ |
+| └ | currentRuling | External ❗️ | | NO❗️ |
+| └ | getDegreeOfCoherenceReward | External ❗️ | | NO❗️ |
+| └ | getDegreeOfCoherencePenalty | External ❗️ | | NO❗️ |
+| └ | getCoherentCount | External ❗️ | | NO❗️ |
+| └ | areCommitsAllCast | External ❗️ | | NO❗️ |
+| └ | areVotesAllCast | External ❗️ | | NO❗️ |
+| └ | isAppealFunded | External ❗️ | | NO❗️ |
+| └ | earlyCourtJump | External ❗️ | | NO❗️ |
+| └ | getNbVotesAfterAppeal | External ❗️ | | NO❗️ |
+| └ | getJumpDisputeKitID | External ❗️ | | NO❗️ |
+| └ | isVoteActive | External ❗️ | | NO❗️ |
+| └ | getRoundInfo | External ❗️ | | NO❗️ |
+| └ | getVoteInfo | External ❗️ | | NO❗️ |
+| | | | | |
+| **IDisputeTemplateRegistry** | Interface | | | |
+| └ | setDisputeTemplate | External ❗️ | 🛑 | NO❗️ |
+| | | | | |
+| **IEvidence** | Interface | | | |
+| | | | | |
+| **ISortitionModule** | Interface | | | |
+| └ | createTree | External ❗️ | 🛑 | NO❗️ |
+| └ | validateStake | External ❗️ | 🛑 | NO❗️ |
+| └ | setStake | External ❗️ | 🛑 | NO❗️ |
+| └ | setStakePenalty | External ❗️ | 🛑 | NO❗️ |
+| └ | setStakeReward | External ❗️ | 🛑 | NO❗️ |
+| └ | forcedUnstakeAllCourts | External ❗️ | 🛑 | NO❗️ |
+| └ | forcedUnstake | External ❗️ | 🛑 | NO❗️ |
+| └ | lockStake | External ❗️ | 🛑 | NO❗️ |
+| └ | unlockStake | External ❗️ | 🛑 | NO❗️ |
+| └ | notifyRandomNumber | External ❗️ | 🛑 | NO❗️ |
+| └ | draw | External ❗️ | | NO❗️ |
+| └ | getJurorBalance | External ❗️ | | NO❗️ |
+| └ | getJurorCourtIDs | External ❗️ | | NO❗️ |
+| └ | isJurorStaked | External ❗️ | | NO❗️ |
+| └ | getJurorLeftoverPNK | External ❗️ | | NO❗️ |
+| └ | createDisputeHook | External ❗️ | 🛑 | NO❗️ |
+| └ | postDrawHook | External ❗️ | 🛑 | NO❗️ |
+| └ | withdrawLeftoverPNK | External ❗️ | 🛑 | NO❗️ |
+| | | | | |
+| **SafeERC20** | Library | | | |
+| └ | increaseAllowance | Internal 🔒 | 🛑 | |
+| └ | safeTransfer | Internal 🔒 | 🛑 | |
+| └ | safeTransferFrom | Internal 🔒 | 🛑 | |
+| | | | | |
+| **WethLike** | Interface | | | |
+| └ | deposit | External ❗️ | 💵 | NO❗️ |
+| └ | transfer | External ❗️ | 🛑 | NO❗️ |
+| | | | | |
+| **SafeSend** | Library | | | |
+| └ | safeSend | Internal 🔒 | 🛑 | |
+| | | | | |
+| **RNGWithFallback** | Implementation | IRNG | | |
+| └ | | Public ❗️ | 🛑 | NO❗️ |
+| └ | changeOwner | External ❗️ | 🛑 | onlyByOwner |
+| └ | changeConsumer | External ❗️ | 🛑 | onlyByOwner |
+| └ | changeFallbackTimeout | External ❗️ | 🛑 | onlyByOwner |
+| └ | requestRandomness | External ❗️ | 🛑 | onlyByConsumer |
+| └ | receiveRandomness | External ❗️ | 🛑 | onlyByConsumer |
+| | | | | |
+| **ChainlinkRNG** | Implementation | IRNG, VRFConsumerBaseV2Plus | | |
+| └ | | Public ❗️ | 🛑 | VRFConsumerBaseV2Plus |
+| └ | changeOwner | External ❗️ | 🛑 | onlyByOwner |
+| └ | changeConsumer | External ❗️ | 🛑 | onlyByOwner |
+| └ | changeVrfCoordinator | External ❗️ | 🛑 | onlyByOwner |
+| └ | changeKeyHash | External ❗️ | 🛑 | onlyByOwner |
+| └ | changeSubscriptionId | External ❗️ | 🛑 | onlyByOwner |
+| └ | changeRequestConfirmations | External ❗️ | 🛑 | onlyByOwner |
+| └ | changeCallbackGasLimit | External ❗️ | 🛑 | onlyByOwner |
+| └ | requestRandomness | External ❗️ | 🛑 | onlyByConsumer |
+| └ | fulfillRandomWords | Internal 🔒 | 🛑 | |
+| └ | receiveRandomness | External ❗️ | | NO❗️ |
+| | | | | |
+| **IRNG** | Interface | | | |
+| └ | requestRandomness | External ❗️ | 🛑 | NO❗️ |
+| └ | receiveRandomness | External ❗️ | 🛑 | NO❗️ |
+| | | | | |
+| **UUPSProxiable** | Implementation | | | |
+| └ | \_authorizeUpgrade | Internal 🔒 | 🛑 | |
+| └ | upgradeToAndCall | Public ❗️ | 💵 | NO❗️ |
+| └ | proxiableUUID | External ❗️ | | NO❗️ |
+| └ | version | External ❗️ | | NO❗️ |
+| └ | \_getImplementation | Internal 🔒 | | |
+| | | | | |
+| **UUPSProxy** | Implementation | | | |
+| └ | | Public ❗️ | 🛑 | NO❗️ |
+| └ | \_delegate | Internal 🔒 | 🛑 | |
+| └ | \_getImplementation | Internal 🔒 | | |
+| └ | | External ❗️ | 💵 | NO❗️ |
+| └ | | External ❗️ | 💵 | NO❗️ |
+| | | | | |
+| **Initializable** | Implementation | | | |
+| └ | \_checkInitializing | Internal 🔒 | | |
+| └ | \_disableInitializers | Internal 🔒 | 🛑 | |
+| └ | \_getInitializedVersion | Internal 🔒 | | |
+| └ | \_isInitializing | Internal 🔒 | | |
+| └ | \_getInitializableStorage | Private 🔐 | | |
+
+Legend
+
+| Symbol | Meaning |
+| :----: | ------------------------- |
+| 🛑 | Function can modify state |
+| 💵 | Function is payable |
+
+
+____
+
+Thinking about smart contract security? We can provide training, ongoing advice, and smart contract auditing. [Contact us](https://consensys.io/diligence/contact/).
+
diff --git a/contracts/config/courts.v2.mainnet-neo.json b/contracts/config/courts.v2.mainnet.json
similarity index 100%
rename from contracts/config/courts.v2.mainnet-neo.json
rename to contracts/config/courts.v2.mainnet.json
diff --git a/contracts/config/policies.v2.mainnet-neo.json b/contracts/config/policies.v2.mainnet.json
similarity index 100%
rename from contracts/config/policies.v2.mainnet-neo.json
rename to contracts/config/policies.v2.mainnet.json
diff --git a/contracts/deploy/00-ethereum-pnk.ts b/contracts/deploy/00-ethereum-pnk.ts
deleted file mode 100644
index 85c674fb7..000000000
--- a/contracts/deploy/00-ethereum-pnk.ts
+++ /dev/null
@@ -1,31 +0,0 @@
-import { HardhatRuntimeEnvironment } from "hardhat/types";
-import { DeployFunction } from "hardhat-deploy/types";
-import { ForeignChains, HardhatChain, isSkipped } from "./utils";
-
-enum Chains {
- SEPOLIA = ForeignChains.ETHEREUM_SEPOLIA,
- HARDHAT = HardhatChain.HARDHAT,
-}
-
-const deployArbitration: DeployFunction = async (hre: HardhatRuntimeEnvironment) => {
- const { deployments, getNamedAccounts, getChainId } = hre;
- const { deploy } = deployments;
-
- // fallback to hardhat node signers on local network
- const deployer = (await getNamedAccounts()).deployer ?? (await hre.ethers.getSigners())[0].address;
- const chainId = Number(await getChainId());
- console.log("deploying to %s with deployer %s", Chains[chainId], deployer);
-
- await deploy("PinakionV2", {
- from: deployer,
- args: [],
- log: true,
- });
-};
-
-deployArbitration.tags = ["Pinakion"];
-deployArbitration.skip = async ({ network }) => {
- return isSkipped(network, !Chains[network.config.chainId ?? 0]);
-};
-
-export default deployArbitration;
diff --git a/contracts/deploy/00-home-chain-arbitration-neo.ts b/contracts/deploy/00-home-chain-arbitration-mainnet.ts
similarity index 75%
rename from contracts/deploy/00-home-chain-arbitration-neo.ts
rename to contracts/deploy/00-home-chain-arbitration-mainnet.ts
index 45a6a7d15..a3d87f51f 100644
--- a/contracts/deploy/00-home-chain-arbitration-neo.ts
+++ b/contracts/deploy/00-home-chain-arbitration-mainnet.ts
@@ -6,13 +6,12 @@ import { changeCurrencyRate } from "./utils/klerosCoreHelper";
import { HomeChains, isSkipped, isDevnet, PNK, ETH } from "./utils";
import { getContractOrDeploy, getContractOrDeployUpgradable } from "./utils/getContractOrDeploy";
import { deployERC20AndFaucet, deployERC721 } from "./utils/deployTokens";
-import { ChainlinkRNG, DisputeKitClassic, KlerosCoreNeo } from "../typechain-types";
+import { DisputeKitClassic, KlerosCore, RNGWithFallback } from "../typechain-types";
const deployArbitration: DeployFunction = async (hre: HardhatRuntimeEnvironment) => {
const { ethers, deployments, getNamedAccounts, getChainId } = hre;
const { deploy } = deployments;
const { ZeroAddress } = hre.ethers;
- const RNG_LOOKAHEAD = 20;
// fallback to hardhat node signers on local network
const deployer = (await getNamedAccounts()).deployer ?? (await hre.ethers.getSigners())[0].address;
@@ -29,34 +28,33 @@ const deployArbitration: DeployFunction = async (hre: HardhatRuntimeEnvironment)
await deployUpgradable(deployments, "EvidenceModule", { from: deployer, args: [deployer], log: true });
- const disputeKit = await deployUpgradable(deployments, "DisputeKitClassicNeo", {
+ const classicDisputeKitID = 1; // Classic DK
+ const disputeKit = await deployUpgradable(deployments, "DisputeKitClassic", {
from: deployer,
- contract: "DisputeKitClassic",
- args: [deployer, ZeroAddress, weth.target],
+ args: [deployer, ZeroAddress, weth.target, classicDisputeKitID],
log: true,
});
- let klerosCoreAddress = await deployments.getOrNull("KlerosCoreNeo").then((deployment) => deployment?.address);
+ let klerosCoreAddress = await deployments.getOrNull("KlerosCore").then((deployment) => deployment?.address);
if (!klerosCoreAddress) {
const nonce = await ethers.provider.getTransactionCount(deployer);
klerosCoreAddress = getContractAddress(deployer, nonce + 3); // deployed on the 4th tx (nonce+3): SortitionModule Impl tx, SortitionModule Proxy tx, KlerosCore Impl tx, KlerosCore Proxy tx
- console.log("calculated future KlerosCoreNeo address for nonce %d: %s", nonce + 3, klerosCoreAddress);
+ console.log("calculated future KlerosCore address for nonce %d: %s", nonce + 3, klerosCoreAddress);
}
const devnet = isDevnet(hre.network);
const minStakingTime = devnet ? 180 : 1800;
const maxFreezingTime = devnet ? 600 : 1800;
- const rng = (await ethers.getContract("ChainlinkRNG")) as ChainlinkRNG;
+ const rngWithFallback = await ethers.getContract("RNGWithFallback");
const maxStakePerJuror = PNK(2_000);
const maxTotalStaked = PNK(2_000_000);
- const sortitionModule = await deployUpgradable(deployments, "SortitionModuleNeo", {
+ const sortitionModule = await deployUpgradable(deployments, "SortitionModule", {
from: deployer,
args: [
deployer,
klerosCoreAddress,
minStakingTime,
maxFreezingTime,
- rng.target,
- RNG_LOOKAHEAD,
+ rngWithFallback.target,
maxStakePerJuror,
maxTotalStaked,
],
@@ -67,7 +65,7 @@ const deployArbitration: DeployFunction = async (hre: HardhatRuntimeEnvironment)
const alpha = 10000;
const feeForJuror = ETH(0.1);
const jurorsForCourtJump = 256;
- const klerosCore = await deployUpgradable(deployments, "KlerosCoreNeo", {
+ const klerosCore = await deployUpgradable(deployments, "KlerosCore", {
from: deployer,
args: [
deployer,
@@ -80,28 +78,28 @@ const deployArbitration: DeployFunction = async (hre: HardhatRuntimeEnvironment)
[0, 0, 0, 10], // evidencePeriod, commitPeriod, votePeriod, appealPeriod
ethers.toBeHex(5), // Extra data for sortition module will return the default value of K
sortitionModule.address,
- nft.target,
weth.target,
+ nft.target,
],
log: true,
}); // nonce+2 (implementation), nonce+3 (proxy)
// disputeKit.changeCore() only if necessary
- const disputeKitContract = (await hre.ethers.getContract("DisputeKitClassicNeo")) as DisputeKitClassic;
+ const disputeKitContract = await hre.ethers.getContract("DisputeKitClassic");
const currentCore = await disputeKitContract.core();
if (currentCore !== klerosCore.address) {
console.log(`disputeKit.changeCore(${klerosCore.address})`);
await disputeKitContract.changeCore(klerosCore.address);
}
- // rng.changeSortitionModule() only if necessary
- const rngSortitionModule = await rng.sortitionModule();
- if (rngSortitionModule !== sortitionModule.address) {
- console.log(`rng.changeSortitionModule(${sortitionModule.address})`);
- await rng.changeSortitionModule(sortitionModule.address);
+ // rngWithFallback.changeConsumer() only if necessary
+ const rngConsumer = await rngWithFallback.consumer();
+ if (rngConsumer !== sortitionModule.address) {
+ console.log(`rngWithFallback.changeConsumer(${sortitionModule.address})`);
+ await rngWithFallback.changeConsumer(sortitionModule.address);
}
- const core = (await hre.ethers.getContract("KlerosCoreNeo")) as KlerosCoreNeo;
+ const core = await hre.ethers.getContract("KlerosCore");
try {
await changeCurrencyRate(core, await weth.getAddress(), true, 1, 1);
} catch (e) {
@@ -114,36 +112,40 @@ const deployArbitration: DeployFunction = async (hre: HardhatRuntimeEnvironment)
log: true,
});
- const resolver = await deploy("DisputeResolverNeo", {
+ const resolver = await deploy("DisputeResolver", {
from: deployer,
- contract: "DisputeResolver",
args: [core.target, disputeTemplateRegistry.target],
log: true,
});
+ console.log(`core.changeArbitrableWhitelistEnabled(true)`);
+ await core.changeArbitrableWhitelistEnabled(true);
console.log(`core.changeArbitrableWhitelist(${resolver.address}, true)`);
await core.changeArbitrableWhitelist(resolver.address, true);
// Extra dispute kits
const disputeKitShutter = await deployUpgradable(deployments, "DisputeKitShutter", {
from: deployer,
- args: [deployer, core.target, weth.target],
+ args: [deployer, core.target, weth.target, classicDisputeKitID],
log: true,
});
await core.addNewDisputeKit(disputeKitShutter.address);
+ const disputeKitShutterID = (await core.getDisputeKitsLength()) - 1n;
const disputeKitGated = await deployUpgradable(deployments, "DisputeKitGated", {
from: deployer,
- args: [deployer, core.target, weth.target],
+ args: [deployer, core.target, weth.target, classicDisputeKitID],
log: true,
});
await core.addNewDisputeKit(disputeKitGated.address);
+ const disputeKitGatedID = (await core.getDisputeKitsLength()) - 1n;
const disputeKitGatedShutter = await deployUpgradable(deployments, "DisputeKitGatedShutter", {
from: deployer,
- args: [deployer, core.target, weth.target],
+ args: [deployer, core.target, weth.target, disputeKitShutterID], // Does not jump to DKClassic
log: true,
});
await core.addNewDisputeKit(disputeKitGatedShutter.address);
+ const disputeKitGatedShutterID = (await core.getDisputeKitsLength()) - 1n;
// Snapshot proxy
await deploy("KlerosCoreSnapshotProxy", {
@@ -153,7 +155,7 @@ const deployArbitration: DeployFunction = async (hre: HardhatRuntimeEnvironment)
});
};
-deployArbitration.tags = ["ArbitrationNeo"];
+deployArbitration.tags = ["ArbitrationMainnet"];
deployArbitration.dependencies = ["ChainlinkRNG"];
deployArbitration.skip = async ({ network }) => {
return isSkipped(network, !HomeChains[network.config.chainId ?? 0]);
diff --git a/contracts/deploy/00-home-chain-arbitration-ruler.ts b/contracts/deploy/00-home-chain-arbitration-ruler.ts
index d49431c46..a9077dbe6 100644
--- a/contracts/deploy/00-home-chain-arbitration-ruler.ts
+++ b/contracts/deploy/00-home-chain-arbitration-ruler.ts
@@ -29,13 +29,13 @@ const deployArbitration: DeployFunction = async (hre: HardhatRuntimeEnvironment)
await deployUpgradable(deployments, "KlerosCoreRuler", {
from: deployer,
args: [
- deployer, // governor
+ deployer, // owner
pnk.target,
[minStake, alpha, feeForJuror, jurorsForCourtJump],
],
log: true,
});
- const core = (await hre.ethers.getContract("KlerosCoreRuler")) as KlerosCoreRuler;
+ const core = await hre.ethers.getContract("KlerosCoreRuler");
try {
await changeCurrencyRate(core, await pnk.getAddress(), true, 12225583, 12);
diff --git a/contracts/deploy/00-home-chain-arbitration-university.ts b/contracts/deploy/00-home-chain-arbitration-university.ts
index 81267ca91..057e69cfe 100644
--- a/contracts/deploy/00-home-chain-arbitration-university.ts
+++ b/contracts/deploy/00-home-chain-arbitration-university.ts
@@ -24,10 +24,17 @@ const deployArbitration: DeployFunction = async (hre: HardhatRuntimeEnvironment)
await getContractOrDeploy(hre, "TransactionBatcher", { from: deployer, args: [], log: true });
+ const disputeTemplateRegistry = await deployUpgradable(deployments, "DisputeTemplateRegistryUniversity", {
+ from: deployer,
+ contract: "DisputeTemplateRegistry",
+ args: [deployer],
+ log: true,
+ });
+
const disputeKit = await deployUpgradable(deployments, "DisputeKitClassicUniversity", {
from: deployer,
contract: "DisputeKitClassic",
- args: [deployer, ZeroAddress, weth.target],
+ args: [deployer, ZeroAddress, weth.target, 1],
log: true,
});
@@ -50,7 +57,7 @@ const deployArbitration: DeployFunction = async (hre: HardhatRuntimeEnvironment)
const klerosCore = await deployUpgradable(deployments, "KlerosCoreUniversity", {
from: deployer,
args: [
- deployer, // governor
+ deployer, // owner
deployer, // instructor
pnk.target,
ZeroAddress, // KlerosCore is configured later
@@ -64,14 +71,14 @@ const deployArbitration: DeployFunction = async (hre: HardhatRuntimeEnvironment)
}); // nonce+2 (implementation), nonce+3 (proxy)
// disputeKit.changeCore() only if necessary
- const disputeKitContract = (await ethers.getContract("DisputeKitClassicUniversity")) as DisputeKitClassic;
+ const disputeKitContract = await ethers.getContract("DisputeKitClassicUniversity");
const currentCore = await disputeKitContract.core();
if (currentCore !== klerosCore.address) {
console.log(`disputeKit.changeCore(${klerosCore.address})`);
await disputeKitContract.changeCore(klerosCore.address);
}
- const core = (await hre.ethers.getContract("KlerosCoreUniversity")) as KlerosCoreUniversity;
+ const core = await hre.ethers.getContract("KlerosCoreUniversity");
try {
await changeCurrencyRate(core, await pnk.getAddress(), true, 12225583, 12);
await changeCurrencyRate(core, await dai.getAddress(), true, 60327783, 11);
@@ -80,16 +87,10 @@ const deployArbitration: DeployFunction = async (hre: HardhatRuntimeEnvironment)
console.error("Failed to change currency rates for token, with error:", e);
}
- const disputeTemplateRegistry = await getContractOrDeployUpgradable(hre, "DisputeTemplateRegistry", {
- from: deployer,
- args: [deployer],
- log: true,
- });
-
await deploy("DisputeResolverUniversity", {
from: deployer,
contract: "DisputeResolver",
- args: [core.target, disputeTemplateRegistry.target],
+ args: [core.target, disputeTemplateRegistry.address],
log: true,
});
};
diff --git a/contracts/deploy/00-home-chain-arbitration.ts b/contracts/deploy/00-home-chain-arbitration.ts
index c22a1b960..1c4c29695 100644
--- a/contracts/deploy/00-home-chain-arbitration.ts
+++ b/contracts/deploy/00-home-chain-arbitration.ts
@@ -6,13 +6,12 @@ import { changeCurrencyRate } from "./utils/klerosCoreHelper";
import { HomeChains, isSkipped, isDevnet, PNK, ETH, Courts } from "./utils";
import { getContractOrDeploy, getContractOrDeployUpgradable } from "./utils/getContractOrDeploy";
import { deployERC20AndFaucet } from "./utils/deployTokens";
-import { ChainlinkRNG, DisputeKitClassic, KlerosCore } from "../typechain-types";
+import { DisputeKitClassic, KlerosCore, RNGWithFallback } from "../typechain-types";
const deployArbitration: DeployFunction = async (hre: HardhatRuntimeEnvironment) => {
const { ethers, deployments, getNamedAccounts, getChainId } = hre;
const { deploy } = deployments;
const { ZeroAddress } = hre.ethers;
- const RNG_LOOKAHEAD = 20;
// fallback to hardhat node signers on local network
const deployer = (await getNamedAccounts()).deployer ?? (await hre.ethers.getSigners())[0].address;
@@ -35,9 +34,10 @@ const deployArbitration: DeployFunction = async (hre: HardhatRuntimeEnvironment)
log: true,
});
+ const classicDisputeKitID = 1; // Classic DK
const disputeKit = await deployUpgradable(deployments, "DisputeKitClassic", {
from: deployer,
- args: [deployer, ZeroAddress, weth.target],
+ args: [deployer, ZeroAddress, weth.target, classicDisputeKitID],
log: true,
});
@@ -50,10 +50,18 @@ const deployArbitration: DeployFunction = async (hre: HardhatRuntimeEnvironment)
const devnet = isDevnet(hre.network);
const minStakingTime = devnet ? 180 : 1800;
const maxFreezingTime = devnet ? 600 : 1800;
- const rng = (await ethers.getContract("ChainlinkRNG")) as ChainlinkRNG;
+ const rngWithFallback = await ethers.getContract("RNGWithFallback");
const sortitionModule = await deployUpgradable(deployments, "SortitionModule", {
from: deployer,
- args: [deployer, klerosCoreAddress, minStakingTime, maxFreezingTime, rng.target, RNG_LOOKAHEAD],
+ args: [
+ deployer,
+ klerosCoreAddress,
+ minStakingTime,
+ maxFreezingTime,
+ rngWithFallback.target,
+ ethers.MaxUint256, // maxStakePerJuror
+ ethers.MaxUint256, // maxTotalStaked
+ ],
log: true,
}); // nonce (implementation), nonce+1 (proxy)
@@ -75,26 +83,27 @@ const deployArbitration: DeployFunction = async (hre: HardhatRuntimeEnvironment)
ethers.toBeHex(5), // Extra data for sortition module will return the default value of K
sortitionModule.address,
weth.target,
+ ZeroAddress, // jurorNft
],
log: true,
}); // nonce+2 (implementation), nonce+3 (proxy)
// disputeKit.changeCore() only if necessary
- const disputeKitContract = (await ethers.getContract("DisputeKitClassic")) as DisputeKitClassic;
+ const disputeKitContract = await ethers.getContract("DisputeKitClassic");
const currentCore = await disputeKitContract.core();
if (currentCore !== klerosCore.address) {
console.log(`disputeKit.changeCore(${klerosCore.address})`);
await disputeKitContract.changeCore(klerosCore.address);
}
- // rng.changeSortitionModule() only if necessary
- const rngSortitionModule = await rng.sortitionModule();
- if (rngSortitionModule !== sortitionModule.address) {
- console.log(`rng.changeSortitionModule(${sortitionModule.address})`);
- await rng.changeSortitionModule(sortitionModule.address);
+ // rngWithFallback.changeConsumer() only if necessary
+ const rngConsumer = await rngWithFallback.consumer();
+ if (rngConsumer !== sortitionModule.address) {
+ console.log(`rngWithFallback.changeConsumer(${sortitionModule.address})`);
+ await rngWithFallback.changeConsumer(sortitionModule.address);
}
- const core = (await hre.ethers.getContract("KlerosCore")) as KlerosCore;
+ const core = await hre.ethers.getContract("KlerosCore");
try {
await changeCurrencyRate(core, await pnk.getAddress(), true, 12225583, 12);
await changeCurrencyRate(core, await dai.getAddress(), true, 60327783, 11);
@@ -106,27 +115,30 @@ const deployArbitration: DeployFunction = async (hre: HardhatRuntimeEnvironment)
// Extra dispute kits
const disputeKitShutter = await deployUpgradable(deployments, "DisputeKitShutter", {
from: deployer,
- args: [deployer, core.target, weth.target],
+ args: [deployer, core.target, weth.target, classicDisputeKitID],
log: true,
});
await core.addNewDisputeKit(disputeKitShutter.address);
- await core.enableDisputeKits(Courts.GENERAL, [2], true); // enable disputeKitShutter on the General Court
+ const disputeKitShutterID = (await core.getDisputeKitsLength()) - 1n;
+ await core.enableDisputeKits(Courts.GENERAL, [disputeKitShutterID], true); // enable disputeKitShutter on the General Court
const disputeKitGated = await deployUpgradable(deployments, "DisputeKitGated", {
from: deployer,
- args: [deployer, core.target, weth.target],
+ args: [deployer, core.target, weth.target, classicDisputeKitID],
log: true,
});
await core.addNewDisputeKit(disputeKitGated.address);
- await core.enableDisputeKits(Courts.GENERAL, [3], true); // enable disputeKitGated on the General Court
+ const disputeKitGatedID = (await core.getDisputeKitsLength()) - 1n;
+ await core.enableDisputeKits(Courts.GENERAL, [disputeKitGatedID], true); // enable disputeKitGated on the General Court
const disputeKitGatedShutter = await deployUpgradable(deployments, "DisputeKitGatedShutter", {
from: deployer,
- args: [deployer, core.target, weth.target],
+ args: [deployer, core.target, weth.target, disputeKitShutterID], // Does not jump to DKClassic
log: true,
});
await core.addNewDisputeKit(disputeKitGatedShutter.address);
- await core.enableDisputeKits(Courts.GENERAL, [4], true); // enable disputeKitGatedShutter on the General Court
+ const disputeKitGatedShutterID = (await core.getDisputeKitsLength()) - 1n;
+ await core.enableDisputeKits(Courts.GENERAL, [disputeKitGatedShutterID], true); // enable disputeKitGatedShutter on the General Court
// Snapshot proxy
await deploy("KlerosCoreSnapshotProxy", {
diff --git a/contracts/deploy/00-home-chain-pnk-faucet.ts b/contracts/deploy/00-home-chain-pnk-faucet.ts
deleted file mode 100644
index e10eb93bf..000000000
--- a/contracts/deploy/00-home-chain-pnk-faucet.ts
+++ /dev/null
@@ -1,36 +0,0 @@
-import { HardhatRuntimeEnvironment } from "hardhat/types";
-import { DeployFunction } from "hardhat-deploy/types";
-import { HomeChains, isSkipped } from "./utils";
-
-const pnkByChain = new Map([
- [HomeChains.ARBITRUM_ONE, "0x330bD769382cFc6d50175903434CCC8D206DCAE5"],
- [HomeChains.ARBITRUM_SEPOLIA, "INSERT ARBITRUM SEPOLIA PNK TOKEN ADDRESS HERE"],
-]);
-
-const deployArbitration: DeployFunction = async (hre: HardhatRuntimeEnvironment) => {
- const { deployments, getNamedAccounts, getChainId } = hre;
- const { deploy, execute } = deployments;
-
- // fallback to hardhat node signers on local network
- const deployer = (await getNamedAccounts()).deployer ?? (await hre.ethers.getSigners())[0].address;
- const chainId = Number(await getChainId());
- console.log("deploying to %s with deployer %s", HomeChains[chainId], deployer);
-
- const pnkAddress = pnkByChain.get(chainId);
- if (pnkAddress) {
- await deploy("PNKFaucet", {
- from: deployer,
- contract: "Faucet",
- args: [pnkAddress],
- log: true,
- });
- await execute("PNKFaucet", { from: deployer, log: true }, "changeAmount", hre.ethers.parseUnits("10000", "ether"));
- }
-};
-
-deployArbitration.tags = ["PnkFaucet"];
-deployArbitration.skip = async ({ network }) => {
- return isSkipped(network, !HomeChains[network.config.chainId ?? 0]);
-};
-
-export default deployArbitration;
diff --git a/contracts/deploy/00-home-chain-resolver.ts b/contracts/deploy/00-home-chain-resolver.ts
index d7d2186ef..64d3431f6 100644
--- a/contracts/deploy/00-home-chain-resolver.ts
+++ b/contracts/deploy/00-home-chain-resolver.ts
@@ -1,7 +1,7 @@
import { HardhatRuntimeEnvironment } from "hardhat/types";
import { DeployFunction } from "hardhat-deploy/types";
import { HomeChains, isSkipped } from "./utils";
-import { deployUpgradable } from "./utils/deployUpgradable";
+import { getContractOrDeploy } from "./utils/getContractOrDeploy";
const deployArbitration: DeployFunction = async (hre: HardhatRuntimeEnvironment) => {
const { deployments, getNamedAccounts, getChainId } = hre;
@@ -15,7 +15,7 @@ const deployArbitration: DeployFunction = async (hre: HardhatRuntimeEnvironment)
const klerosCore = await deployments.get("KlerosCore");
const disputeTemplateRegistry = await deployments.get("DisputeTemplateRegistry");
- await deploy("DisputeResolver", {
+ await getContractOrDeploy(hre, "DisputeResolver", {
from: deployer,
args: [klerosCore.address, disputeTemplateRegistry.address],
log: true,
diff --git a/contracts/deploy/00-chainlink-rng.ts b/contracts/deploy/00-rng-chainlink.ts
similarity index 76%
rename from contracts/deploy/00-chainlink-rng.ts
rename to contracts/deploy/00-rng-chainlink.ts
index 1062fe936..78a1c5e87 100644
--- a/contracts/deploy/00-chainlink-rng.ts
+++ b/contracts/deploy/00-rng-chainlink.ts
@@ -2,10 +2,10 @@ import { HardhatRuntimeEnvironment } from "hardhat/types";
import { DeployFunction } from "hardhat-deploy/types";
import { HomeChains, isSkipped } from "./utils";
import { getContractOrDeploy } from "./utils/getContractOrDeploy";
+import { RNGWithFallback } from "../typechain-types";
const deployRng: DeployFunction = async (hre: HardhatRuntimeEnvironment) => {
- const { deployments, getNamedAccounts, getChainId } = hre;
- const { deploy } = deployments;
+ const { getNamedAccounts, getChainId, ethers } = hre;
// fallback to hardhat node signers on local network
const deployer = (await getNamedAccounts()).deployer ?? (await hre.ethers.getSigners())[0].address;
@@ -57,11 +57,16 @@ const deployRng: DeployFunction = async (hre: HardhatRuntimeEnvironment) => {
const requestConfirmations = 200; // between 1 and 200 L2 blocks
const callbackGasLimit = 100000;
- await deploy("ChainlinkRNG", {
+ const oldRng = await ethers.getContractOrNull("ChainlinkRNG");
+ if (!oldRng) {
+ console.log("Register this Chainlink consumer here: http://vrf.chain.link/");
+ }
+
+ const rng = await getContractOrDeploy(hre, "ChainlinkRNG", {
from: deployer,
args: [
deployer,
- deployer, // The consumer is configured as the SortitionModule later
+ deployer, // The consumer is configured as the RNGWithFallback later
ChainlinkVRFCoordinator.target,
keyHash,
subscriptionId,
@@ -70,6 +75,26 @@ const deployRng: DeployFunction = async (hre: HardhatRuntimeEnvironment) => {
],
log: true,
});
+
+ const fallbackTimeoutSeconds = 30 * 60; // 30 minutes
+ await getContractOrDeploy(hre, "RNGWithFallback", {
+ from: deployer,
+ args: [
+ deployer,
+ deployer, // The consumer is configured as the SortitionModule later
+ fallbackTimeoutSeconds,
+ rng.target,
+ ],
+ log: true,
+ });
+
+ // rng.changeConsumer() only if necessary
+ const rngWithFallback = await ethers.getContract("RNGWithFallback");
+ const rngConsumer = await rng.consumer();
+ if (rngConsumer !== rngWithFallback.target) {
+ console.log(`rng.changeConsumer(${rngWithFallback.target})`);
+ await rng.changeConsumer(rngWithFallback.target);
+ }
};
deployRng.tags = ["ChainlinkRNG"];
diff --git a/contracts/deploy/00-randomizer-rng.ts b/contracts/deploy/00-rng-randomizer.ts
similarity index 54%
rename from contracts/deploy/00-randomizer-rng.ts
rename to contracts/deploy/00-rng-randomizer.ts
index c28dc3cda..8413b39f6 100644
--- a/contracts/deploy/00-randomizer-rng.ts
+++ b/contracts/deploy/00-rng-randomizer.ts
@@ -2,10 +2,10 @@ import { HardhatRuntimeEnvironment } from "hardhat/types";
import { DeployFunction } from "hardhat-deploy/types";
import { HomeChains, isSkipped } from "./utils";
import { getContractOrDeploy } from "./utils/getContractOrDeploy";
+import { RNGWithFallback } from "../typechain-types";
const deployRng: DeployFunction = async (hre: HardhatRuntimeEnvironment) => {
- const { deployments, getNamedAccounts, getChainId } = hre;
- const { deploy } = deployments;
+ const { getNamedAccounts, getChainId, ethers } = hre;
// fallback to hardhat node signers on local network
const deployer = (await getNamedAccounts()).deployer ?? (await hre.ethers.getSigners())[0].address;
@@ -20,11 +20,35 @@ const deployRng: DeployFunction = async (hre: HardhatRuntimeEnvironment) => {
log: true,
});
- await getContractOrDeploy(hre, "RandomizerRNG", {
+ const rng = await getContractOrDeploy(hre, "RandomizerRNG", {
from: deployer,
- args: [deployer, deployer, randomizerOracle.target], // The consumer is configured as the SortitionModule later
+ args: [
+ deployer,
+ deployer, // The consumer is configured as the RNGWithFallback later
+ randomizerOracle.target,
+ ],
log: true,
});
+
+ const fallbackTimeoutSeconds = 30 * 60; // 30 minutes
+ await getContractOrDeploy(hre, "RNGWithFallback", {
+ from: deployer,
+ args: [
+ deployer,
+ deployer, // The consumer is configured as the SortitionModule later
+ fallbackTimeoutSeconds,
+ rng.target,
+ ],
+ log: true,
+ });
+
+ // rng.changeConsumer() only if necessary
+ const rngWithFallback = await ethers.getContract("RNGWithFallback");
+ const rngConsumer = await rng.consumer();
+ if (rngConsumer !== rngWithFallback.target) {
+ console.log(`rng.changeConsumer(${rngWithFallback.target})`);
+ await rng.changeConsumer(rngWithFallback.target);
+ }
};
deployRng.tags = ["RandomizerRNG"];
diff --git a/contracts/deploy/00-rng.ts b/contracts/deploy/00-rng.ts
deleted file mode 100644
index 2489406c1..000000000
--- a/contracts/deploy/00-rng.ts
+++ /dev/null
@@ -1,47 +0,0 @@
-import { HardhatRuntimeEnvironment } from "hardhat/types";
-import { DeployFunction } from "hardhat-deploy/types";
-import { SortitionModule } from "../typechain-types";
-import { HomeChains, isMainnet, isSkipped } from "./utils";
-import { deployUpgradable } from "./utils/deployUpgradable";
-import { getContractOrDeploy } from "./utils/getContractOrDeploy";
-
-const deployArbitration: DeployFunction = async (hre: HardhatRuntimeEnvironment) => {
- const { deployments, getNamedAccounts, getChainId, ethers } = hre;
- const { deploy } = deployments;
- const RNG_LOOKAHEAD = 20;
-
- // fallback to hardhat node signers on local network
- const deployer = (await getNamedAccounts()).deployer ?? (await hre.ethers.getSigners())[0].address;
- const chainId = Number(await getChainId());
- console.log("deploying to %s with deployer %s", HomeChains[chainId], deployer);
-
- const sortitionModule = (await ethers.getContract("SortitionModuleNeo")) as SortitionModule;
-
- const randomizerOracle = await getContractOrDeploy(hre, "RandomizerOracle", {
- from: deployer,
- contract: "RandomizerMock",
- args: [],
- log: true,
- });
-
- const rng1 = await deploy("RandomizerRNG", {
- from: deployer,
- args: [deployer, sortitionModule.target, randomizerOracle.address],
- log: true,
- });
-
- const rng2 = await deploy("BlockHashRNG", {
- from: deployer,
- args: [],
- log: true,
- });
-
- await sortitionModule.changeRandomNumberGenerator(rng2.address, RNG_LOOKAHEAD);
-};
-
-deployArbitration.tags = ["RNG"];
-deployArbitration.skip = async ({ network }) => {
- return isSkipped(network, isMainnet(network));
-};
-
-export default deployArbitration;
diff --git a/contracts/deploy/05-arbitrable-dispute-template.ts b/contracts/deploy/change-arbitrable-dispute-template.ts
similarity index 94%
rename from contracts/deploy/05-arbitrable-dispute-template.ts
rename to contracts/deploy/change-arbitrable-dispute-template.ts
index 0ac04fba8..8b41ce2d2 100644
--- a/contracts/deploy/05-arbitrable-dispute-template.ts
+++ b/contracts/deploy/change-arbitrable-dispute-template.ts
@@ -31,7 +31,7 @@ const deployResolver: DeployFunction = async (hre: HardhatRuntimeEnvironment) =>
"specification": "KIP88"
}`;
- const arbitrable = (await ethers.getContract("ArbitrableExample")) as ArbitrableExample;
+ const arbitrable = await ethers.getContract("ArbitrableExample");
let tx = await (await arbitrable.changeDisputeTemplate(template, "disputeTemplateMapping: TODO")).wait();
tx?.logs?.forEach((event) => {
if (event instanceof EventLog) console.log("event: %O", event.args);
diff --git a/contracts/deploy/change-sortition-module-rng.ts b/contracts/deploy/change-sortition-module-rng.ts
index a9573e6be..986e408ec 100644
--- a/contracts/deploy/change-sortition-module-rng.ts
+++ b/contracts/deploy/change-sortition-module-rng.ts
@@ -1,8 +1,8 @@
import { HardhatRuntimeEnvironment } from "hardhat/types";
import { DeployFunction } from "hardhat-deploy/types";
-import { HomeChains, isMainnet, isSkipped } from "./utils";
+import { HomeChains, isSkipped } from "./utils";
import { ethers } from "hardhat";
-import { ChainlinkRNG, SortitionModule, SortitionModuleNeo } from "../typechain-types";
+import { ChainlinkRNG, SortitionModule } from "../typechain-types";
const task: DeployFunction = async (hre: HardhatRuntimeEnvironment) => {
const { getNamedAccounts, getChainId } = hre;
@@ -13,21 +13,13 @@ const task: DeployFunction = async (hre: HardhatRuntimeEnvironment) => {
console.log("deploying to %s with deployer %s", HomeChains[chainId], deployer);
const chainlinkRng = await ethers.getContract("ChainlinkRNG");
+ const sortitionModule = await ethers.getContract("SortitionModule");
- let sortitionModule: SortitionModule | SortitionModuleNeo;
- if (isMainnet(hre.network)) {
- console.log("Using SortitionModuleNeo");
- sortitionModule = await ethers.getContract("SortitionModuleNeo");
- } else {
- console.log("Using SortitionModule");
- sortitionModule = await ethers.getContract("SortitionModule");
- }
+ console.log(`chainlinkRng.changeConsumer(${sortitionModule.target})`);
+ await chainlinkRng.changeConsumer(sortitionModule.target);
- console.log(`chainlinkRng.changeSortitionModule(${sortitionModule.target})`);
- await chainlinkRng.changeSortitionModule(sortitionModule.target);
-
- console.log(`sortitionModule.changeRandomNumberGenerator(${chainlinkRng.target}, 0)`);
- await sortitionModule.changeRandomNumberGenerator(chainlinkRng.target, 0);
+ console.log(`sortitionModule.changeRandomNumberGenerator(${chainlinkRng.target})`);
+ await sortitionModule.changeRandomNumberGenerator(chainlinkRng.target);
};
task.tags = ["ChangeSortitionModuleRNG"];
diff --git a/contracts/deploy/upgrade-all.ts b/contracts/deploy/upgrade-all.ts
index 74433c413..572ed7187 100644
--- a/contracts/deploy/upgrade-all.ts
+++ b/contracts/deploy/upgrade-all.ts
@@ -3,7 +3,7 @@ import { DeployFunction } from "hardhat-deploy/types";
import { prompt, print } from "gluegun";
import { deployUpgradable } from "./utils/deployUpgradable";
import { HomeChains, isSkipped } from "./utils";
-import { getContractNames, getContractNamesFromNetwork } from "../scripts/utils/contracts";
+import { getContractNamesFromNetwork } from "../scripts/utils/contracts";
const { bold } = print.colors;
@@ -36,21 +36,7 @@ const deployUpgradeAll: DeployFunction = async (hre: HardhatRuntimeEnvironment)
try {
print.highlight(`🔍 Validating upgrade of ${bold(contractName)}`);
- const contractNameWithoutNeo = contractName.replace(/Neo.*$/, "");
let compareStorageOptions = { contract: contractName } as any;
- if (hre.network.name === "arbitrum") {
- switch (contractName) {
- case "KlerosCoreNeo":
- case "SortitionModuleNeo":
- compareStorageOptions = { deployedArtifact: `${contractName}_Implementation`, contract: contractName };
- break;
- default:
- compareStorageOptions = {
- deployedArtifact: `${contractName}_Implementation`,
- contract: contractNameWithoutNeo,
- };
- }
- }
await hre.run("compare-storage", compareStorageOptions);
print.newline();
print.highlight(`💣 Upgrading ${bold(contractName)}`);
@@ -65,25 +51,12 @@ const deployUpgradeAll: DeployFunction = async (hre: HardhatRuntimeEnvironment)
}
print.info(`Upgrading ${contractName}...`);
- switch (contractName) {
- case "DisputeKitClassicNeo":
- case "DisputeResolverNeo":
- await deployUpgradable(deployments, contractName, {
- contract: contractName,
- newImplementation: contractNameWithoutNeo,
- initializer,
- from: deployer,
- args, // Warning: do not reinitialize existing state variables, only the new ones
- });
- break;
- default:
- await deployUpgradable(deployments, contractName, {
- newImplementation: contractName,
- initializer,
- from: deployer,
- args, // Warning: do not reinitialize existing state variables, only the new ones
- });
- }
+ await deployUpgradable(deployments, contractName, {
+ newImplementation: contractName,
+ initializer,
+ from: deployer,
+ args, // Warning: do not reinitialize existing state variables, only the new ones
+ });
print.info(`Verifying ${contractName} on Etherscan...`);
await hre.run("etherscan-verify", { contractName: `${contractName}_Implementation` });
} catch (err) {
@@ -98,11 +71,11 @@ const deployUpgradeAll: DeployFunction = async (hre: HardhatRuntimeEnvironment)
await upgrade(disputeKitShutter, "reinitialize", [wETH.address]);
await upgrade(disputeKitGated, "reinitialize", [wETH.address]);
await upgrade(disputeKitGatedShutter, "reinitialize", [wETH.address]);
- await upgrade(disputeTemplateRegistry, "initialize2", []);
- await upgrade(evidence, "initialize2", []);
+ await upgrade(disputeTemplateRegistry, "reinitialize", []);
+ await upgrade(evidence, "reinitialize", []);
await upgrade(core, "reinitialize", [wETH.address]);
- await upgrade(policyRegistry, "initialize2", []);
- await upgrade(sortition, "initialize4", []);
+ await upgrade(policyRegistry, "reinitialize", []);
+ await upgrade(sortition, "reinitialize", []);
};
deployUpgradeAll.tags = ["UpgradeAll"];
diff --git a/contracts/deploy/utils/klerosCoreHelper.ts b/contracts/deploy/utils/klerosCoreHelper.ts
index 3419ae64e..3325652a3 100644
--- a/contracts/deploy/utils/klerosCoreHelper.ts
+++ b/contracts/deploy/utils/klerosCoreHelper.ts
@@ -1,8 +1,8 @@
-import { KlerosCore, KlerosCoreNeo, KlerosCoreRuler, KlerosCoreUniversity } from "../../typechain-types";
+import { KlerosCore, KlerosCoreRuler, KlerosCoreUniversity } from "../../typechain-types";
import { BigNumberish, toBigInt } from "ethers";
export const changeCurrencyRate = async (
- core: KlerosCore | KlerosCoreNeo | KlerosCoreRuler | KlerosCoreUniversity,
+ core: KlerosCore | KlerosCoreRuler | KlerosCoreUniversity,
erc20: string,
accepted: boolean,
rateInEth: BigNumberish,
diff --git a/contracts/deployments/arbitrum.ts b/contracts/deployments/arbitrum.ts
index b0b8e8fd8..2b5d6eb3f 100644
--- a/contracts/deployments/arbitrum.ts
+++ b/contracts/deployments/arbitrum.ts
@@ -2793,7 +2793,7 @@ export default {
},
],
},
- DisputeKitClassicNeo: {
+ DisputeKitClassic: {
address: "0x70B464be85A547144C72485eBa2577E5D3A45421",
abi: [
{
@@ -3943,7 +3943,7 @@ export default {
},
],
},
- DisputeKitClassicNeo_Implementation: {
+ DisputeKitClassic_Implementation: {
address: "0x371Aa4B1AE5b5f9422f3Ff1d105029AAd1D319BC",
abi: [
{
@@ -5074,7 +5074,7 @@ export default {
},
],
},
- DisputeKitClassicNeo_Proxy: {
+ DisputeKitClassic_Proxy: {
address: "0x70B464be85A547144C72485eBa2577E5D3A45421",
abi: [
{
@@ -5103,7 +5103,7 @@ export default {
},
],
},
- DisputeKitGatedNeo: {
+ DisputeKitGated: {
address: "0xaE1eed20C125B739b64c948820C61F809ad9a925",
abi: [
{
@@ -6282,13 +6282,16 @@ export default {
},
],
},
- DisputeKitGatedNeo_Implementation: {
- address: "0xEA7863E6dE863e8E6d037D8693ad5dA45Db7790a",
+ DisputeKitGatedShutter: {
+ address: "0x788330092B9704809C19858E39EB9Ac402c2E47b",
abi: [
{
- inputs: [],
- stateMutability: "nonpayable",
- type: "constructor",
+ stateMutability: "payable",
+ type: "fallback",
+ },
+ {
+ stateMutability: "payable",
+ type: "receive",
},
{
inputs: [],
@@ -6388,6 +6391,43 @@ export default {
name: "CommitCast",
type: "event",
},
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: "uint256",
+ name: "_coreDisputeID",
+ type: "uint256",
+ },
+ {
+ indexed: true,
+ internalType: "address",
+ name: "_juror",
+ type: "address",
+ },
+ {
+ indexed: true,
+ internalType: "bytes32",
+ name: "_commit",
+ type: "bytes32",
+ },
+ {
+ indexed: false,
+ internalType: "bytes32",
+ name: "_identity",
+ type: "bytes32",
+ },
+ {
+ indexed: false,
+ internalType: "bytes",
+ name: "_encryptedVote",
+ type: "bytes",
+ },
+ ],
+ name: "CommitCastShutter",
+ type: "event",
+ },
{
anonymous: false,
inputs: [
@@ -6692,6 +6732,39 @@ export default {
stateMutability: "nonpayable",
type: "function",
},
+ {
+ inputs: [
+ {
+ internalType: "uint256",
+ name: "_coreDisputeID",
+ type: "uint256",
+ },
+ {
+ internalType: "uint256[]",
+ name: "_voteIDs",
+ type: "uint256[]",
+ },
+ {
+ internalType: "bytes32",
+ name: "_commit",
+ type: "bytes32",
+ },
+ {
+ internalType: "bytes32",
+ name: "_identity",
+ type: "bytes32",
+ },
+ {
+ internalType: "bytes",
+ name: "_encryptedVote",
+ type: "bytes",
+ },
+ ],
+ name: "castCommitShutter",
+ outputs: [],
+ stateMutability: "nonpayable",
+ type: "function",
+ },
{
inputs: [
{
@@ -6725,6 +6798,39 @@ export default {
stateMutability: "nonpayable",
type: "function",
},
+ {
+ inputs: [
+ {
+ internalType: "uint256",
+ name: "_coreDisputeID",
+ type: "uint256",
+ },
+ {
+ internalType: "uint256[]",
+ name: "_voteIDs",
+ type: "uint256[]",
+ },
+ {
+ internalType: "uint256",
+ name: "_choice",
+ type: "uint256",
+ },
+ {
+ internalType: "uint256",
+ name: "_salt",
+ type: "uint256",
+ },
+ {
+ internalType: "string",
+ name: "_justification",
+ type: "string",
+ },
+ ],
+ name: "castVoteShutter",
+ outputs: [],
+ stateMutability: "nonpayable",
+ type: "function",
+ },
{
inputs: [
{
@@ -6935,35 +7041,6 @@ export default {
stateMutability: "nonpayable",
type: "function",
},
- {
- inputs: [
- {
- internalType: "bytes",
- name: "_extraData",
- type: "bytes",
- },
- ],
- name: "extraDataToTokenInfo",
- outputs: [
- {
- internalType: "address",
- name: "tokenGate",
- type: "address",
- },
- {
- internalType: "bool",
- name: "isERC1155",
- type: "bool",
- },
- {
- internalType: "uint256",
- name: "tokenId",
- type: "uint256",
- },
- ],
- stateMutability: "pure",
- type: "function",
- },
{
inputs: [
{
@@ -7440,11 +7517,6 @@ export default {
stateMutability: "nonpayable",
type: "function",
},
- ],
- },
- DisputeKitGatedNeo_Proxy: {
- address: "0xaE1eed20C125B739b64c948820C61F809ad9a925",
- abi: [
{
inputs: [
{
@@ -7461,26 +7533,15 @@ export default {
stateMutability: "nonpayable",
type: "constructor",
},
- {
- stateMutability: "payable",
- type: "fallback",
- },
- {
- stateMutability: "payable",
- type: "receive",
- },
],
},
- DisputeKitGatedShutterNeo: {
- address: "0x788330092B9704809C19858E39EB9Ac402c2E47b",
+ DisputeKitGatedShutter_Implementation: {
+ address: "0xb12EB4c0716d3A9861a9AC471c6CdDB808d61b32",
abi: [
{
- stateMutability: "payable",
- type: "fallback",
- },
- {
- stateMutability: "payable",
- type: "receive",
+ inputs: [],
+ stateMutability: "nonpayable",
+ type: "constructor",
},
{
inputs: [],
@@ -8706,6 +8767,11 @@ export default {
stateMutability: "nonpayable",
type: "function",
},
+ ],
+ },
+ DisputeKitGatedShutter_Proxy: {
+ address: "0x788330092B9704809C19858E39EB9Ac402c2E47b",
+ abi: [
{
inputs: [
{
@@ -8722,10 +8788,18 @@ export default {
stateMutability: "nonpayable",
type: "constructor",
},
+ {
+ stateMutability: "payable",
+ type: "fallback",
+ },
+ {
+ stateMutability: "payable",
+ type: "receive",
+ },
],
},
- DisputeKitGatedShutterNeo_Implementation: {
- address: "0xb12EB4c0716d3A9861a9AC471c6CdDB808d61b32",
+ DisputeKitGated_Implementation: {
+ address: "0xEA7863E6dE863e8E6d037D8693ad5dA45Db7790a",
abi: [
{
inputs: [],
@@ -8830,43 +8904,6 @@ export default {
name: "CommitCast",
type: "event",
},
- {
- anonymous: false,
- inputs: [
- {
- indexed: true,
- internalType: "uint256",
- name: "_coreDisputeID",
- type: "uint256",
- },
- {
- indexed: true,
- internalType: "address",
- name: "_juror",
- type: "address",
- },
- {
- indexed: true,
- internalType: "bytes32",
- name: "_commit",
- type: "bytes32",
- },
- {
- indexed: false,
- internalType: "bytes32",
- name: "_identity",
- type: "bytes32",
- },
- {
- indexed: false,
- internalType: "bytes",
- name: "_encryptedVote",
- type: "bytes",
- },
- ],
- name: "CommitCastShutter",
- type: "event",
- },
{
anonymous: false,
inputs: [
@@ -9171,39 +9208,6 @@ export default {
stateMutability: "nonpayable",
type: "function",
},
- {
- inputs: [
- {
- internalType: "uint256",
- name: "_coreDisputeID",
- type: "uint256",
- },
- {
- internalType: "uint256[]",
- name: "_voteIDs",
- type: "uint256[]",
- },
- {
- internalType: "bytes32",
- name: "_commit",
- type: "bytes32",
- },
- {
- internalType: "bytes32",
- name: "_identity",
- type: "bytes32",
- },
- {
- internalType: "bytes",
- name: "_encryptedVote",
- type: "bytes",
- },
- ],
- name: "castCommitShutter",
- outputs: [],
- stateMutability: "nonpayable",
- type: "function",
- },
{
inputs: [
{
@@ -9240,42 +9244,9 @@ export default {
{
inputs: [
{
- internalType: "uint256",
- name: "_coreDisputeID",
- type: "uint256",
- },
- {
- internalType: "uint256[]",
- name: "_voteIDs",
- type: "uint256[]",
- },
- {
- internalType: "uint256",
- name: "_choice",
- type: "uint256",
- },
- {
- internalType: "uint256",
- name: "_salt",
- type: "uint256",
- },
- {
- internalType: "string",
- name: "_justification",
- type: "string",
- },
- ],
- name: "castVoteShutter",
- outputs: [],
- stateMutability: "nonpayable",
- type: "function",
- },
- {
- inputs: [
- {
- internalType: "address",
- name: "_core",
- type: "address",
+ internalType: "address",
+ name: "_core",
+ type: "address",
},
],
name: "changeCore",
@@ -9480,6 +9451,35 @@ export default {
stateMutability: "nonpayable",
type: "function",
},
+ {
+ inputs: [
+ {
+ internalType: "bytes",
+ name: "_extraData",
+ type: "bytes",
+ },
+ ],
+ name: "extraDataToTokenInfo",
+ outputs: [
+ {
+ internalType: "address",
+ name: "tokenGate",
+ type: "address",
+ },
+ {
+ internalType: "bool",
+ name: "isERC1155",
+ type: "bool",
+ },
+ {
+ internalType: "uint256",
+ name: "tokenId",
+ type: "uint256",
+ },
+ ],
+ stateMutability: "pure",
+ type: "function",
+ },
{
inputs: [
{
@@ -9958,8 +9958,8 @@ export default {
},
],
},
- DisputeKitGatedShutterNeo_Proxy: {
- address: "0x788330092B9704809C19858E39EB9Ac402c2E47b",
+ DisputeKitGated_Proxy: {
+ address: "0xaE1eed20C125B739b64c948820C61F809ad9a925",
abi: [
{
inputs: [
@@ -9987,7 +9987,7 @@ export default {
},
],
},
- DisputeKitShutterNeo: {
+ DisputeKitShutter: {
address: "0x9D3e3f1765744c2a1BC6F6088549770444BBC768",
abi: [
{
@@ -11240,7 +11240,7 @@ export default {
},
],
},
- DisputeKitShutterNeo_Implementation: {
+ DisputeKitShutter_Implementation: {
address: "0xF3103B46403A0bBd4551648BFb29BCC2b8783947",
abi: [
{
@@ -12474,7 +12474,7 @@ export default {
},
],
},
- DisputeKitShutterNeo_Proxy: {
+ DisputeKitShutter_Proxy: {
address: "0x9D3e3f1765744c2a1BC6F6088549770444BBC768",
abi: [
{
@@ -12503,7 +12503,7 @@ export default {
},
],
},
- DisputeResolverNeo: {
+ DisputeResolver: {
address: "0xb5526D022962A1fFf6eD32C93e8b714c901F4323",
abi: [
{
@@ -12798,7 +12798,7 @@ export default {
},
],
},
- DisputeResolverRulerNeo: {
+ DisputeResolverRuler: {
address: "0xb3a5FdEAF461c42caCe148e978e6FBCa97bE6140",
abi: [
{
@@ -14027,7 +14027,7 @@ export default {
},
],
},
- KlerosCoreNeo: {
+ KlerosCore: {
address: "0x991d2df165670b9cac3B022f4B68D65b664222ea",
abi: [
{
@@ -16069,32 +16069,25 @@ export default {
},
],
},
- KlerosCoreNeo_Implementation: {
- address: "0xC1210493804eEF123096F9581Ee82B915150E54c",
+ KlerosCoreRuler: {
+ address: "0xc0169e0B19aE02ac4fADD689260CF038726DFE13",
abi: [
{
- inputs: [],
- stateMutability: "nonpayable",
- type: "constructor",
- },
- {
- inputs: [],
- name: "AlreadyInitialized",
- type: "error",
+ stateMutability: "payable",
+ type: "fallback",
},
{
- inputs: [],
- name: "AppealFeesNotEnough",
- type: "error",
+ stateMutability: "payable",
+ type: "receive",
},
{
inputs: [],
- name: "AppealPeriodNotPassed",
+ name: "AlreadyInitialized",
type: "error",
},
{
inputs: [],
- name: "ArbitrableNotWhitelisted",
+ name: "AppealFeesNotEnough",
type: "error",
},
{
@@ -16102,46 +16095,11 @@ export default {
name: "ArbitrationFeesNotEnough",
type: "error",
},
- {
- inputs: [],
- name: "CannotDisableClassicDK",
- type: "error",
- },
- {
- inputs: [],
- name: "CommitPeriodNotPassed",
- type: "error",
- },
- {
- inputs: [],
- name: "DisputeKitNotSupportedByCourt",
- type: "error",
- },
- {
- inputs: [],
- name: "DisputeKitOnly",
- type: "error",
- },
{
inputs: [],
name: "DisputeNotAppealable",
type: "error",
},
- {
- inputs: [],
- name: "DisputePeriodIsFinal",
- type: "error",
- },
- {
- inputs: [],
- name: "DisputeStillDrawing",
- type: "error",
- },
- {
- inputs: [],
- name: "EvidenceNotPassedAndNotAppeal",
- type: "error",
- },
{
inputs: [],
name: "FailedDelegateCall",
@@ -16154,12 +16112,7 @@ export default {
},
{
inputs: [],
- name: "GuardianOrGovernorOnly",
- type: "error",
- },
- {
- inputs: [],
- name: "InvalidDisputKitParent",
+ name: "GovernorOrInstructorOnly",
type: "error",
},
{
@@ -16180,27 +16133,7 @@ export default {
},
{
inputs: [],
- name: "MinStakeLowerThanParentCourt",
- type: "error",
- },
- {
- inputs: [],
- name: "MustSupportDisputeKitClassic",
- type: "error",
- },
- {
- inputs: [],
- name: "NotEligibleForStaking",
- type: "error",
- },
- {
- inputs: [],
- name: "NotEvidencePeriod",
- type: "error",
- },
- {
- inputs: [],
- name: "NotExecutionPeriod",
+ name: "NoRulerSet",
type: "error",
},
{
@@ -16210,47 +16143,17 @@ export default {
},
{
inputs: [],
- name: "RulingAlreadyExecuted",
- type: "error",
- },
- {
- inputs: [],
- name: "SortitionModuleOnly",
- type: "error",
- },
- {
- inputs: [],
- name: "StakingInTooManyCourts",
- type: "error",
- },
- {
- inputs: [],
- name: "StakingLessThanCourtMinStake",
- type: "error",
- },
- {
- inputs: [],
- name: "StakingMoreThanMaxStakePerJuror",
- type: "error",
- },
- {
- inputs: [],
- name: "StakingMoreThanMaxTotalStaked",
- type: "error",
- },
- {
- inputs: [],
- name: "StakingNotPossibleInThisCourt",
+ name: "RulerOnly",
type: "error",
},
{
inputs: [],
- name: "StakingTransferFailed",
+ name: "RulingAlreadyExecuted",
type: "error",
},
{
inputs: [],
- name: "StakingZeroWhenNoStake",
+ name: "RulingModeNotSet",
type: "error",
},
{
@@ -16279,41 +16182,11 @@ export default {
name: "UUPSUnsupportedProxiableUUID",
type: "error",
},
- {
- inputs: [],
- name: "UnstakingTransferFailed",
- type: "error",
- },
{
inputs: [],
name: "UnsuccessfulCall",
type: "error",
},
- {
- inputs: [],
- name: "UnsupportedDisputeKit",
- type: "error",
- },
- {
- inputs: [],
- name: "VotePeriodNotPassed",
- type: "error",
- },
- {
- inputs: [],
- name: "WhenNotPausedOnly",
- type: "error",
- },
- {
- inputs: [],
- name: "WhenPausedOnly",
- type: "error",
- },
- {
- inputs: [],
- name: "WrongDisputeKitIndex",
- type: "error",
- },
{
anonymous: false,
inputs: [
@@ -16376,60 +16249,42 @@ export default {
inputs: [
{
indexed: true,
- internalType: "uint96",
- name: "_courtID",
- type: "uint96",
+ internalType: "contract IArbitrableV2",
+ name: "_arbitrable",
+ type: "address",
},
{
indexed: true,
- internalType: "uint96",
- name: "_parent",
- type: "uint96",
- },
- {
- indexed: false,
- internalType: "bool",
- name: "_hiddenVotes",
- type: "bool",
+ internalType: "enum KlerosCoreRuler.RulingMode",
+ name: "mode",
+ type: "uint8",
},
{
- indexed: false,
+ indexed: true,
internalType: "uint256",
- name: "_minStake",
+ name: "_disputeID",
type: "uint256",
},
{
indexed: false,
internalType: "uint256",
- name: "_alpha",
+ name: "_ruling",
type: "uint256",
},
{
indexed: false,
- internalType: "uint256",
- name: "_feeForJuror",
- type: "uint256",
+ internalType: "bool",
+ name: "tied",
+ type: "bool",
},
{
indexed: false,
- internalType: "uint256",
- name: "_jurorsForCourtJump",
- type: "uint256",
- },
- {
- indexed: false,
- internalType: "uint256[4]",
- name: "_timesPerPeriod",
- type: "uint256[4]",
- },
- {
- indexed: false,
- internalType: "uint256[]",
- name: "_supportedDisputeKits",
- type: "uint256[]",
+ internalType: "bool",
+ name: "overridden",
+ type: "bool",
},
],
- name: "CourtCreated",
+ name: "AutoRuled",
type: "event",
},
{
@@ -16438,38 +16293,13 @@ export default {
{
indexed: true,
internalType: "uint256",
- name: "_disputeID",
- type: "uint256",
- },
- {
- indexed: true,
- internalType: "uint256",
- name: "_roundID",
+ name: "_courtID",
type: "uint256",
},
{
indexed: true,
internalType: "uint96",
- name: "_fromCourtID",
- type: "uint96",
- },
- {
- indexed: false,
- internalType: "uint96",
- name: "_toCourtID",
- type: "uint96",
- },
- ],
- name: "CourtJump",
- type: "event",
- },
- {
- anonymous: false,
- inputs: [
- {
- indexed: true,
- internalType: "uint96",
- name: "_courtID",
+ name: "_parent",
type: "uint96",
},
{
@@ -16509,7 +16339,7 @@ export default {
type: "uint256[4]",
},
],
- name: "CourtModified",
+ name: "CourtCreated",
type: "event",
},
{
@@ -16521,33 +16351,26 @@ export default {
name: "_disputeID",
type: "uint256",
},
- {
- indexed: true,
- internalType: "contract IArbitrableV2",
- name: "_arbitrable",
- type: "address",
- },
- ],
- name: "DisputeCreation",
- type: "event",
- },
- {
- anonymous: false,
- inputs: [
{
indexed: true,
internalType: "uint256",
- name: "_disputeKitID",
+ name: "_roundID",
type: "uint256",
},
{
indexed: true,
- internalType: "contract IDisputeKit",
- name: "_disputeKitAddress",
- type: "address",
+ internalType: "uint96",
+ name: "_fromCourtID",
+ type: "uint96",
+ },
+ {
+ indexed: false,
+ internalType: "uint96",
+ name: "_toCourtID",
+ type: "uint96",
},
],
- name: "DisputeKitCreated",
+ name: "CourtJump",
type: "event",
},
{
@@ -16560,61 +16383,48 @@ export default {
type: "uint96",
},
{
- indexed: true,
- internalType: "uint256",
- name: "_disputeKitID",
- type: "uint256",
- },
- {
- indexed: true,
+ indexed: false,
internalType: "bool",
- name: "_enable",
+ name: "_hiddenVotes",
type: "bool",
},
- ],
- name: "DisputeKitEnabled",
- type: "event",
- },
- {
- anonymous: false,
- inputs: [
{
- indexed: true,
+ indexed: false,
internalType: "uint256",
- name: "_disputeID",
+ name: "_minStake",
type: "uint256",
},
{
- indexed: true,
+ indexed: false,
internalType: "uint256",
- name: "_roundID",
+ name: "_alpha",
type: "uint256",
},
{
- indexed: true,
+ indexed: false,
internalType: "uint256",
- name: "_fromDisputeKitID",
+ name: "_feeForJuror",
type: "uint256",
},
{
indexed: false,
internalType: "uint256",
- name: "_toDisputeKitID",
+ name: "_jurorsForCourtJump",
type: "uint256",
},
+ {
+ indexed: false,
+ internalType: "uint256[4]",
+ name: "_timesPerPeriod",
+ type: "uint256[4]",
+ },
],
- name: "DisputeKitJump",
+ name: "CourtModified",
type: "event",
},
{
anonymous: false,
inputs: [
- {
- indexed: true,
- internalType: "address",
- name: "_address",
- type: "address",
- },
{
indexed: true,
internalType: "uint256",
@@ -16622,19 +16432,13 @@ export default {
type: "uint256",
},
{
- indexed: false,
- internalType: "uint256",
- name: "_roundID",
- type: "uint256",
- },
- {
- indexed: false,
- internalType: "uint256",
- name: "_voteID",
- type: "uint256",
+ indexed: true,
+ internalType: "contract IArbitrableV2",
+ name: "_arbitrable",
+ type: "address",
},
],
- name: "Draw",
+ name: "DisputeCreation",
type: "event",
},
{
@@ -16723,7 +16527,7 @@ export default {
},
{
indexed: false,
- internalType: "enum KlerosCoreBase.Period",
+ internalType: "enum KlerosCoreRuler.Period",
name: "_period",
type: "uint8",
},
@@ -16733,8 +16537,68 @@ export default {
},
{
anonymous: false,
- inputs: [],
- name: "Paused",
+ inputs: [
+ {
+ indexed: true,
+ internalType: "contract IArbitrableV2",
+ name: "_arbitrable",
+ type: "address",
+ },
+ {
+ indexed: true,
+ internalType: "address",
+ name: "_oldRuler",
+ type: "address",
+ },
+ {
+ indexed: true,
+ internalType: "address",
+ name: "_newRuler",
+ type: "address",
+ },
+ ],
+ name: "RulerChanged",
+ type: "event",
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: "contract IArbitrableV2",
+ name: "_arbitrable",
+ type: "address",
+ },
+ {
+ components: [
+ {
+ internalType: "enum KlerosCoreRuler.RulingMode",
+ name: "rulingMode",
+ type: "uint8",
+ },
+ {
+ internalType: "uint256",
+ name: "presetRuling",
+ type: "uint256",
+ },
+ {
+ internalType: "bool",
+ name: "presetTied",
+ type: "bool",
+ },
+ {
+ internalType: "bool",
+ name: "presetOverridden",
+ type: "bool",
+ },
+ ],
+ indexed: false,
+ internalType: "struct KlerosCoreRuler.RulerSettings",
+ name: "_settings",
+ type: "tuple",
+ },
+ ],
+ name: "RulerSettingsChanged",
type: "event",
},
{
@@ -16811,12 +16675,6 @@ export default {
name: "TokenAndETHShift",
type: "event",
},
- {
- anonymous: false,
- inputs: [],
- name: "Unpaused",
- type: "event",
- },
{
anonymous: false,
inputs: [
@@ -16830,19 +16688,6 @@ export default {
name: "Upgraded",
type: "event",
},
- {
- inputs: [
- {
- internalType: "contract IDisputeKit",
- name: "_disputeKitAddress",
- type: "address",
- },
- ],
- name: "addNewDisputeKit",
- outputs: [],
- stateMutability: "nonpayable",
- type: "function",
- },
{
inputs: [
{
@@ -16857,9 +16702,14 @@ export default {
},
{
internalType: "bytes",
- name: "_extraData",
+ name: "",
type: "bytes",
},
+ {
+ internalType: "bool",
+ name: "_jump",
+ type: "bool",
+ },
],
name: "appeal",
outputs: [],
@@ -16873,6 +16723,11 @@ export default {
name: "_disputeID",
type: "uint256",
},
+ {
+ internalType: "bool",
+ name: "_jump",
+ type: "bool",
+ },
],
name: "appealCost",
outputs: [
@@ -16888,21 +16743,21 @@ export default {
{
inputs: [
{
- internalType: "uint256",
- name: "_disputeID",
- type: "uint256",
+ internalType: "bytes",
+ name: "_extraData",
+ type: "bytes",
},
- ],
- name: "appealPeriod",
- outputs: [
{
- internalType: "uint256",
- name: "start",
- type: "uint256",
+ internalType: "contract IERC20",
+ name: "_feeToken",
+ type: "address",
},
+ ],
+ name: "arbitrationCost",
+ outputs: [
{
internalType: "uint256",
- name: "end",
+ name: "cost",
type: "uint256",
},
],
@@ -16912,55 +16767,12 @@ export default {
{
inputs: [
{
- internalType: "address",
- name: "",
- type: "address",
+ internalType: "bytes",
+ name: "_extraData",
+ type: "bytes",
},
],
- name: "arbitrableWhitelist",
- outputs: [
- {
- internalType: "bool",
- name: "",
- type: "bool",
- },
- ],
- stateMutability: "view",
- type: "function",
- },
- {
- inputs: [
- {
- internalType: "bytes",
- name: "_extraData",
- type: "bytes",
- },
- {
- internalType: "contract IERC20",
- name: "_feeToken",
- type: "address",
- },
- ],
- name: "arbitrationCost",
- outputs: [
- {
- internalType: "uint256",
- name: "cost",
- type: "uint256",
- },
- ],
- stateMutability: "view",
- type: "function",
- },
- {
- inputs: [
- {
- internalType: "bytes",
- name: "_extraData",
- type: "bytes",
- },
- ],
- name: "arbitrationCost",
+ name: "arbitrationCost",
outputs: [
{
internalType: "uint256",
@@ -16989,24 +16801,6 @@ export default {
stateMutability: "nonpayable",
type: "function",
},
- {
- inputs: [
- {
- internalType: "address",
- name: "_arbitrable",
- type: "address",
- },
- {
- internalType: "bool",
- name: "_allowed",
- type: "bool",
- },
- ],
- name: "changeArbitrableWhitelist",
- outputs: [],
- stateMutability: "nonpayable",
- type: "function",
- },
{
inputs: [
{
@@ -17089,12 +16883,12 @@ export default {
{
inputs: [
{
- internalType: "address",
- name: "_guardian",
+ internalType: "contract IERC20",
+ name: "_pinakion",
type: "address",
},
],
- name: "changeGuardian",
+ name: "changePinakion",
outputs: [],
stateMutability: "nonpayable",
type: "function",
@@ -17102,12 +16896,17 @@ export default {
{
inputs: [
{
- internalType: "contract IERC721",
- name: "_jurorNft",
+ internalType: "contract IArbitrableV2",
+ name: "_arbitrable",
+ type: "address",
+ },
+ {
+ internalType: "address",
+ name: "_newRuler",
type: "address",
},
],
- name: "changeJurorNft",
+ name: "changeRuler",
outputs: [],
stateMutability: "nonpayable",
type: "function",
@@ -17115,12 +16914,27 @@ export default {
{
inputs: [
{
- internalType: "address",
- name: "_jurorProsecutionModule",
+ internalType: "contract IArbitrableV2",
+ name: "_arbitrable",
type: "address",
},
+ {
+ internalType: "uint256",
+ name: "_presetRuling",
+ type: "uint256",
+ },
+ {
+ internalType: "bool",
+ name: "_presetTied",
+ type: "bool",
+ },
+ {
+ internalType: "bool",
+ name: "_presetOverridden",
+ type: "bool",
+ },
],
- name: "changeJurorProsecutionModule",
+ name: "changeRulingModeToAutomaticPreset",
outputs: [],
stateMutability: "nonpayable",
type: "function",
@@ -17128,12 +16942,12 @@ export default {
{
inputs: [
{
- internalType: "contract IERC20",
- name: "_pinakion",
+ internalType: "contract IArbitrableV2",
+ name: "_arbitrable",
type: "address",
},
],
- name: "changePinakion",
+ name: "changeRulingModeToAutomaticRandom",
outputs: [],
stateMutability: "nonpayable",
type: "function",
@@ -17141,12 +16955,12 @@ export default {
{
inputs: [
{
- internalType: "contract ISortitionModule",
- name: "_sortitionModule",
+ internalType: "contract IArbitrableV2",
+ name: "_arbitrable",
type: "address",
},
],
- name: "changeSortitionModule",
+ name: "changeRulingModeToManual",
outputs: [],
stateMutability: "nonpayable",
type: "function",
@@ -17261,16 +17075,6 @@ export default {
name: "_timesPerPeriod",
type: "uint256[4]",
},
- {
- internalType: "bytes",
- name: "_sortitionExtraData",
- type: "bytes",
- },
- {
- internalType: "uint256[]",
- name: "_supportedDisputeKits",
- type: "uint256[]",
- },
],
name: "createCourt",
outputs: [],
@@ -17393,25 +17197,6 @@ export default {
stateMutability: "view",
type: "function",
},
- {
- inputs: [
- {
- internalType: "uint256",
- name: "",
- type: "uint256",
- },
- ],
- name: "disputeKits",
- outputs: [
- {
- internalType: "contract IDisputeKit",
- name: "",
- type: "address",
- },
- ],
- stateMutability: "view",
- type: "function",
- },
{
inputs: [
{
@@ -17433,7 +17218,7 @@ export default {
type: "address",
},
{
- internalType: "enum KlerosCoreBase.Period",
+ internalType: "enum KlerosCoreRuler.Period",
name: "period",
type: "uint8",
},
@@ -17442,62 +17227,10 @@ export default {
name: "ruled",
type: "bool",
},
- {
- internalType: "uint256",
- name: "lastPeriodChange",
- type: "uint256",
- },
],
stateMutability: "view",
type: "function",
},
- {
- inputs: [
- {
- internalType: "uint256",
- name: "_disputeID",
- type: "uint256",
- },
- {
- internalType: "uint256",
- name: "_iterations",
- type: "uint256",
- },
- ],
- name: "draw",
- outputs: [
- {
- internalType: "uint256",
- name: "nbDrawnJurors",
- type: "uint256",
- },
- ],
- stateMutability: "nonpayable",
- type: "function",
- },
- {
- inputs: [
- {
- internalType: "uint96",
- name: "_courtID",
- type: "uint96",
- },
- {
- internalType: "uint256[]",
- name: "_disputeKitIDs",
- type: "uint256[]",
- },
- {
- internalType: "bool",
- name: "_enable",
- type: "bool",
- },
- ],
- name: "enableDisputeKits",
- outputs: [],
- stateMutability: "nonpayable",
- type: "function",
- },
{
inputs: [
{
@@ -17510,11 +17243,6 @@ export default {
name: "_round",
type: "uint256",
},
- {
- internalType: "uint256",
- name: "_iterations",
- type: "uint256",
- },
],
name: "execute",
outputs: [],
@@ -17551,6 +17279,21 @@ export default {
name: "_disputeID",
type: "uint256",
},
+ {
+ internalType: "uint256",
+ name: "_ruling",
+ type: "uint256",
+ },
+ {
+ internalType: "bool",
+ name: "tied",
+ type: "bool",
+ },
+ {
+ internalType: "bool",
+ name: "overridden",
+ type: "bool",
+ },
],
name: "executeRuling",
outputs: [],
@@ -17559,7 +17302,7 @@ export default {
},
{
inputs: [],
- name: "getDisputeKitsLength",
+ name: "getNextDisputeID",
outputs: [
{
internalType: "uint256",
@@ -17621,12 +17364,29 @@ export default {
type: "uint256",
},
],
- name: "getPnkAtStakePerJuror",
+ name: "getRoundInfo",
outputs: [
{
- internalType: "uint256",
+ components: [
+ {
+ internalType: "uint256",
+ name: "totalFeesForJurors",
+ type: "uint256",
+ },
+ {
+ internalType: "uint256",
+ name: "sumFeeRewardPaid",
+ type: "uint256",
+ },
+ {
+ internalType: "contract IERC20",
+ name: "feeToken",
+ type: "address",
+ },
+ ],
+ internalType: "struct KlerosCoreRuler.Round",
name: "",
- type: "uint256",
+ type: "tuple",
},
],
stateMutability: "view",
@@ -17635,93 +17395,12 @@ export default {
{
inputs: [
{
- internalType: "uint256",
- name: "_disputeID",
- type: "uint256",
- },
- {
- internalType: "uint256",
- name: "_round",
- type: "uint256",
+ internalType: "uint96",
+ name: "_courtID",
+ type: "uint96",
},
],
- name: "getRoundInfo",
- outputs: [
- {
- components: [
- {
- internalType: "uint256",
- name: "disputeKitID",
- type: "uint256",
- },
- {
- internalType: "uint256",
- name: "pnkAtStakePerJuror",
- type: "uint256",
- },
- {
- internalType: "uint256",
- name: "totalFeesForJurors",
- type: "uint256",
- },
- {
- internalType: "uint256",
- name: "nbVotes",
- type: "uint256",
- },
- {
- internalType: "uint256",
- name: "repartitions",
- type: "uint256",
- },
- {
- internalType: "uint256",
- name: "pnkPenalties",
- type: "uint256",
- },
- {
- internalType: "address[]",
- name: "drawnJurors",
- type: "address[]",
- },
- {
- internalType: "uint256",
- name: "sumFeeRewardPaid",
- type: "uint256",
- },
- {
- internalType: "uint256",
- name: "sumPnkRewardPaid",
- type: "uint256",
- },
- {
- internalType: "contract IERC20",
- name: "feeToken",
- type: "address",
- },
- {
- internalType: "uint256",
- name: "drawIterations",
- type: "uint256",
- },
- ],
- internalType: "struct KlerosCoreBase.Round",
- name: "",
- type: "tuple",
- },
- ],
- stateMutability: "view",
- type: "function",
- },
- {
- inputs: [
- {
- internalType: "uint96",
- name: "_courtID",
- type: "uint96",
- },
- ],
- name: "getTimesPerPeriod",
+ name: "getTimesPerPeriod",
outputs: [
{
internalType: "uint256[4]",
@@ -17745,19 +17424,6 @@ export default {
stateMutability: "view",
type: "function",
},
- {
- inputs: [],
- name: "guardian",
- outputs: [
- {
- internalType: "address",
- name: "",
- type: "address",
- },
- ],
- stateMutability: "view",
- type: "function",
- },
{
inputs: [
{
@@ -17765,61 +17431,16 @@ export default {
name: "_governor",
type: "address",
},
- {
- internalType: "address",
- name: "_guardian",
- type: "address",
- },
{
internalType: "contract IERC20",
name: "_pinakion",
type: "address",
},
- {
- internalType: "address",
- name: "_jurorProsecutionModule",
- type: "address",
- },
- {
- internalType: "contract IDisputeKit",
- name: "_disputeKit",
- type: "address",
- },
- {
- internalType: "bool",
- name: "_hiddenVotes",
- type: "bool",
- },
{
internalType: "uint256[4]",
name: "_courtParameters",
type: "uint256[4]",
},
- {
- internalType: "uint256[4]",
- name: "_timesPerPeriod",
- type: "uint256[4]",
- },
- {
- internalType: "bytes",
- name: "_sortitionExtraData",
- type: "bytes",
- },
- {
- internalType: "contract ISortitionModule",
- name: "_sortitionModuleAddress",
- type: "address",
- },
- {
- internalType: "contract IERC721",
- name: "_jurorNft",
- type: "address",
- },
- {
- internalType: "address",
- name: "_wNative",
- type: "address",
- },
],
name: "initialize",
outputs: [],
@@ -17827,68 +17448,44 @@ export default {
type: "function",
},
{
- inputs: [
- {
- internalType: "uint256",
- name: "_disputeID",
- type: "uint256",
- },
- ],
- name: "isDisputeKitJumping",
+ inputs: [],
+ name: "pinakion",
outputs: [
{
- internalType: "bool",
+ internalType: "contract IERC20",
name: "",
- type: "bool",
+ type: "address",
},
],
stateMutability: "view",
type: "function",
},
{
- inputs: [
- {
- internalType: "uint96",
- name: "_courtID",
- type: "uint96",
- },
- {
- internalType: "uint256",
- name: "_disputeKitID",
- type: "uint256",
- },
- ],
- name: "isSupported",
+ inputs: [],
+ name: "proxiableUUID",
outputs: [
{
- internalType: "bool",
+ internalType: "bytes32",
name: "",
- type: "bool",
+ type: "bytes32",
},
],
stateMutability: "view",
type: "function",
},
{
- inputs: [],
- name: "jurorNft",
- outputs: [
+ inputs: [
{
- internalType: "contract IERC721",
- name: "",
+ internalType: "contract IArbitrableV2",
+ name: "arbitrable",
type: "address",
},
],
- stateMutability: "view",
- type: "function",
- },
- {
- inputs: [],
- name: "jurorProsecutionModule",
+ name: "rulers",
outputs: [
{
internalType: "address",
- name: "",
+ name: "ruler",
type: "address",
},
],
@@ -17899,56 +17496,26 @@ export default {
inputs: [
{
internalType: "uint256",
- name: "_disputeID",
+ name: "disputeID",
type: "uint256",
},
],
- name: "passPeriod",
- outputs: [],
- stateMutability: "nonpayable",
- type: "function",
- },
- {
- inputs: [],
- name: "pause",
- outputs: [],
- stateMutability: "nonpayable",
- type: "function",
- },
- {
- inputs: [],
- name: "paused",
+ name: "rulingResults",
outputs: [
{
- internalType: "bool",
- name: "",
- type: "bool",
+ internalType: "uint256",
+ name: "ruling",
+ type: "uint256",
},
- ],
- stateMutability: "view",
- type: "function",
- },
- {
- inputs: [],
- name: "pinakion",
- outputs: [
{
- internalType: "contract IERC20",
- name: "",
- type: "address",
+ internalType: "bool",
+ name: "tied",
+ type: "bool",
},
- ],
- stateMutability: "view",
- type: "function",
- },
- {
- inputs: [],
- name: "proxiableUUID",
- outputs: [
{
- internalType: "bytes32",
- name: "",
- type: "bytes32",
+ internalType: "bool",
+ name: "overridden",
+ type: "bool",
},
],
stateMutability: "view",
@@ -17957,93 +17524,35 @@ export default {
{
inputs: [
{
- internalType: "address",
- name: "_wNative",
- type: "address",
- },
- ],
- name: "reinitialize",
- outputs: [],
- stateMutability: "nonpayable",
- type: "function",
- },
- {
- inputs: [
- {
- internalType: "uint96",
- name: "_courtID",
- type: "uint96",
- },
- {
- internalType: "uint256",
- name: "_newStake",
- type: "uint256",
- },
- ],
- name: "setStake",
- outputs: [],
- stateMutability: "nonpayable",
- type: "function",
- },
- {
- inputs: [
- {
- internalType: "address",
- name: "_account",
+ internalType: "contract IArbitrableV2",
+ name: "arbitrable",
type: "address",
},
- {
- internalType: "uint96",
- name: "_courtID",
- type: "uint96",
- },
- {
- internalType: "uint256",
- name: "_newStake",
- type: "uint256",
- },
],
- name: "setStakeBySortitionModule",
- outputs: [],
- stateMutability: "nonpayable",
- type: "function",
- },
- {
- inputs: [],
- name: "sortitionModule",
+ name: "settings",
outputs: [
{
- internalType: "contract ISortitionModule",
- name: "",
- type: "address",
- },
- ],
- stateMutability: "view",
- type: "function",
- },
- {
- inputs: [
- {
- internalType: "address",
- name: "_account",
- type: "address",
+ internalType: "enum KlerosCoreRuler.RulingMode",
+ name: "rulingMode",
+ type: "uint8",
},
{
internalType: "uint256",
- name: "_amount",
+ name: "presetRuling",
type: "uint256",
},
- ],
- name: "transferBySortitionModule",
- outputs: [],
- stateMutability: "nonpayable",
- type: "function",
- },
- {
- inputs: [],
- name: "unpause",
- outputs: [],
- stateMutability: "nonpayable",
+ {
+ internalType: "bool",
+ name: "presetTied",
+ type: "bool",
+ },
+ {
+ internalType: "bool",
+ name: "presetOverridden",
+ type: "bool",
+ },
+ ],
+ stateMutability: "view",
type: "function",
},
{
@@ -18064,37 +17573,6 @@ export default {
stateMutability: "payable",
type: "function",
},
- {
- inputs: [],
- name: "version",
- outputs: [
- {
- internalType: "string",
- name: "",
- type: "string",
- },
- ],
- stateMutability: "view",
- type: "function",
- },
- {
- inputs: [],
- name: "wNative",
- outputs: [
- {
- internalType: "address",
- name: "",
- type: "address",
- },
- ],
- stateMutability: "view",
- type: "function",
- },
- ],
- },
- KlerosCoreNeo_Proxy: {
- address: "0x991d2df165670b9cac3B022f4B68D65b664222ea",
- abi: [
{
inputs: [
{
@@ -18111,26 +17589,15 @@ export default {
stateMutability: "nonpayable",
type: "constructor",
},
- {
- stateMutability: "payable",
- type: "fallback",
- },
- {
- stateMutability: "payable",
- type: "receive",
- },
],
},
- KlerosCoreRulerNeo: {
- address: "0xc0169e0B19aE02ac4fADD689260CF038726DFE13",
+ KlerosCoreRuler_Implementation: {
+ address: "0x85093b5EDa4F2e2E2fEDae34Da91239D6a08e324",
abi: [
{
- stateMutability: "payable",
- type: "fallback",
- },
- {
- stateMutability: "payable",
- type: "receive",
+ inputs: [],
+ stateMutability: "nonpayable",
+ type: "constructor",
},
{
inputs: [],
@@ -19625,50 +19092,239 @@ export default {
stateMutability: "payable",
type: "function",
},
+ ],
+ },
+ KlerosCoreRuler_Proxy: {
+ address: "0xc0169e0B19aE02ac4fADD689260CF038726DFE13",
+ abi: [
+ {
+ inputs: [
+ {
+ internalType: "address",
+ name: "_implementation",
+ type: "address",
+ },
+ {
+ internalType: "bytes",
+ name: "_data",
+ type: "bytes",
+ },
+ ],
+ stateMutability: "nonpayable",
+ type: "constructor",
+ },
+ {
+ stateMutability: "payable",
+ type: "fallback",
+ },
+ {
+ stateMutability: "payable",
+ type: "receive",
+ },
+ ],
+ },
+ KlerosCoreSnapshotProxy: {
+ address: "0xEF719a5B3352F607e6C4E17b7e0cDAd8322fEC95",
+ abi: [
+ {
+ inputs: [
+ {
+ internalType: "address",
+ name: "_governor",
+ type: "address",
+ },
+ {
+ internalType: "contract IKlerosCore",
+ name: "_core",
+ type: "address",
+ },
+ ],
+ stateMutability: "nonpayable",
+ type: "constructor",
+ },
+ {
+ inputs: [
+ {
+ internalType: "address",
+ name: "_account",
+ type: "address",
+ },
+ ],
+ name: "balanceOf",
+ outputs: [
+ {
+ internalType: "uint256",
+ name: "totalStaked",
+ type: "uint256",
+ },
+ ],
+ stateMutability: "view",
+ type: "function",
+ },
+ {
+ inputs: [
+ {
+ internalType: "contract IKlerosCore",
+ name: "_core",
+ type: "address",
+ },
+ ],
+ name: "changeCore",
+ outputs: [],
+ stateMutability: "nonpayable",
+ type: "function",
+ },
+ {
+ inputs: [
+ {
+ internalType: "address",
+ name: "_governor",
+ type: "address",
+ },
+ ],
+ name: "changeGovernor",
+ outputs: [],
+ stateMutability: "nonpayable",
+ type: "function",
+ },
+ {
+ inputs: [],
+ name: "core",
+ outputs: [
+ {
+ internalType: "contract IKlerosCore",
+ name: "",
+ type: "address",
+ },
+ ],
+ stateMutability: "view",
+ type: "function",
+ },
+ {
+ inputs: [],
+ name: "decimals",
+ outputs: [
+ {
+ internalType: "uint8",
+ name: "",
+ type: "uint8",
+ },
+ ],
+ stateMutability: "view",
+ type: "function",
+ },
+ {
+ inputs: [],
+ name: "governor",
+ outputs: [
+ {
+ internalType: "address",
+ name: "",
+ type: "address",
+ },
+ ],
+ stateMutability: "view",
+ type: "function",
+ },
+ {
+ inputs: [],
+ name: "name",
+ outputs: [
+ {
+ internalType: "string",
+ name: "",
+ type: "string",
+ },
+ ],
+ stateMutability: "view",
+ type: "function",
+ },
+ {
+ inputs: [],
+ name: "symbol",
+ outputs: [
+ {
+ internalType: "string",
+ name: "",
+ type: "string",
+ },
+ ],
+ stateMutability: "view",
+ type: "function",
+ },
+ ],
+ },
+ KlerosCore_Implementation: {
+ address: "0xC1210493804eEF123096F9581Ee82B915150E54c",
+ abi: [
+ {
+ inputs: [],
+ stateMutability: "nonpayable",
+ type: "constructor",
+ },
+ {
+ inputs: [],
+ name: "AlreadyInitialized",
+ type: "error",
+ },
+ {
+ inputs: [],
+ name: "AppealFeesNotEnough",
+ type: "error",
+ },
+ {
+ inputs: [],
+ name: "AppealPeriodNotPassed",
+ type: "error",
+ },
+ {
+ inputs: [],
+ name: "ArbitrableNotWhitelisted",
+ type: "error",
+ },
+ {
+ inputs: [],
+ name: "ArbitrationFeesNotEnough",
+ type: "error",
+ },
+ {
+ inputs: [],
+ name: "CannotDisableClassicDK",
+ type: "error",
+ },
{
- inputs: [
- {
- internalType: "address",
- name: "_implementation",
- type: "address",
- },
- {
- internalType: "bytes",
- name: "_data",
- type: "bytes",
- },
- ],
- stateMutability: "nonpayable",
- type: "constructor",
+ inputs: [],
+ name: "CommitPeriodNotPassed",
+ type: "error",
},
- ],
- },
- KlerosCoreRulerNeo_Implementation: {
- address: "0x85093b5EDa4F2e2E2fEDae34Da91239D6a08e324",
- abi: [
{
inputs: [],
- stateMutability: "nonpayable",
- type: "constructor",
+ name: "DisputeKitNotSupportedByCourt",
+ type: "error",
},
{
inputs: [],
- name: "AlreadyInitialized",
+ name: "DisputeKitOnly",
type: "error",
},
{
inputs: [],
- name: "AppealFeesNotEnough",
+ name: "DisputeNotAppealable",
type: "error",
},
{
inputs: [],
- name: "ArbitrationFeesNotEnough",
+ name: "DisputePeriodIsFinal",
type: "error",
},
{
inputs: [],
- name: "DisputeNotAppealable",
+ name: "DisputeStillDrawing",
+ type: "error",
+ },
+ {
+ inputs: [],
+ name: "EvidenceNotPassedAndNotAppeal",
type: "error",
},
{
@@ -19683,7 +19339,12 @@ export default {
},
{
inputs: [],
- name: "GovernorOrInstructorOnly",
+ name: "GuardianOrGovernorOnly",
+ type: "error",
+ },
+ {
+ inputs: [],
+ name: "InvalidDisputKitParent",
type: "error",
},
{
@@ -19704,17 +19365,32 @@ export default {
},
{
inputs: [],
- name: "NoRulerSet",
+ name: "MinStakeLowerThanParentCourt",
type: "error",
},
{
inputs: [],
- name: "NotInitializing",
+ name: "MustSupportDisputeKitClassic",
type: "error",
},
{
inputs: [],
- name: "RulerOnly",
+ name: "NotEligibleForStaking",
+ type: "error",
+ },
+ {
+ inputs: [],
+ name: "NotEvidencePeriod",
+ type: "error",
+ },
+ {
+ inputs: [],
+ name: "NotExecutionPeriod",
+ type: "error",
+ },
+ {
+ inputs: [],
+ name: "NotInitializing",
type: "error",
},
{
@@ -19724,7 +19400,42 @@ export default {
},
{
inputs: [],
- name: "RulingModeNotSet",
+ name: "SortitionModuleOnly",
+ type: "error",
+ },
+ {
+ inputs: [],
+ name: "StakingInTooManyCourts",
+ type: "error",
+ },
+ {
+ inputs: [],
+ name: "StakingLessThanCourtMinStake",
+ type: "error",
+ },
+ {
+ inputs: [],
+ name: "StakingMoreThanMaxStakePerJuror",
+ type: "error",
+ },
+ {
+ inputs: [],
+ name: "StakingMoreThanMaxTotalStaked",
+ type: "error",
+ },
+ {
+ inputs: [],
+ name: "StakingNotPossibleInThisCourt",
+ type: "error",
+ },
+ {
+ inputs: [],
+ name: "StakingTransferFailed",
+ type: "error",
+ },
+ {
+ inputs: [],
+ name: "StakingZeroWhenNoStake",
type: "error",
},
{
@@ -19753,11 +19464,41 @@ export default {
name: "UUPSUnsupportedProxiableUUID",
type: "error",
},
+ {
+ inputs: [],
+ name: "UnstakingTransferFailed",
+ type: "error",
+ },
{
inputs: [],
name: "UnsuccessfulCall",
type: "error",
},
+ {
+ inputs: [],
+ name: "UnsupportedDisputeKit",
+ type: "error",
+ },
+ {
+ inputs: [],
+ name: "VotePeriodNotPassed",
+ type: "error",
+ },
+ {
+ inputs: [],
+ name: "WhenNotPausedOnly",
+ type: "error",
+ },
+ {
+ inputs: [],
+ name: "WhenPausedOnly",
+ type: "error",
+ },
+ {
+ inputs: [],
+ name: "WrongDisputeKitIndex",
+ type: "error",
+ },
{
anonymous: false,
inputs: [
@@ -19820,42 +19561,60 @@ export default {
inputs: [
{
indexed: true,
- internalType: "contract IArbitrableV2",
- name: "_arbitrable",
- type: "address",
+ internalType: "uint96",
+ name: "_courtID",
+ type: "uint96",
},
{
indexed: true,
- internalType: "enum KlerosCoreRuler.RulingMode",
- name: "mode",
- type: "uint8",
+ internalType: "uint96",
+ name: "_parent",
+ type: "uint96",
},
{
- indexed: true,
+ indexed: false,
+ internalType: "bool",
+ name: "_hiddenVotes",
+ type: "bool",
+ },
+ {
+ indexed: false,
internalType: "uint256",
- name: "_disputeID",
+ name: "_minStake",
type: "uint256",
},
{
indexed: false,
internalType: "uint256",
- name: "_ruling",
+ name: "_alpha",
type: "uint256",
},
{
indexed: false,
- internalType: "bool",
- name: "tied",
- type: "bool",
+ internalType: "uint256",
+ name: "_feeForJuror",
+ type: "uint256",
},
{
indexed: false,
- internalType: "bool",
- name: "overridden",
- type: "bool",
+ internalType: "uint256",
+ name: "_jurorsForCourtJump",
+ type: "uint256",
+ },
+ {
+ indexed: false,
+ internalType: "uint256[4]",
+ name: "_timesPerPeriod",
+ type: "uint256[4]",
+ },
+ {
+ indexed: false,
+ internalType: "uint256[]",
+ name: "_supportedDisputeKits",
+ type: "uint256[]",
},
],
- name: "AutoRuled",
+ name: "CourtCreated",
type: "event",
},
{
@@ -19864,13 +19623,38 @@ export default {
{
indexed: true,
internalType: "uint256",
- name: "_courtID",
+ name: "_disputeID",
+ type: "uint256",
+ },
+ {
+ indexed: true,
+ internalType: "uint256",
+ name: "_roundID",
type: "uint256",
},
{
indexed: true,
internalType: "uint96",
- name: "_parent",
+ name: "_fromCourtID",
+ type: "uint96",
+ },
+ {
+ indexed: false,
+ internalType: "uint96",
+ name: "_toCourtID",
+ type: "uint96",
+ },
+ ],
+ name: "CourtJump",
+ type: "event",
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: "uint96",
+ name: "_courtID",
type: "uint96",
},
{
@@ -19910,7 +19694,7 @@ export default {
type: "uint256[4]",
},
],
- name: "CourtCreated",
+ name: "CourtModified",
type: "event",
},
{
@@ -19924,24 +19708,31 @@ export default {
},
{
indexed: true,
- internalType: "uint256",
- name: "_roundID",
- type: "uint256",
+ internalType: "contract IArbitrableV2",
+ name: "_arbitrable",
+ type: "address",
},
+ ],
+ name: "DisputeCreation",
+ type: "event",
+ },
+ {
+ anonymous: false,
+ inputs: [
{
indexed: true,
- internalType: "uint96",
- name: "_fromCourtID",
- type: "uint96",
+ internalType: "uint256",
+ name: "_disputeKitID",
+ type: "uint256",
},
{
- indexed: false,
- internalType: "uint96",
- name: "_toCourtID",
- type: "uint96",
+ indexed: true,
+ internalType: "contract IDisputeKit",
+ name: "_disputeKitAddress",
+ type: "address",
},
],
- name: "CourtJump",
+ name: "DisputeKitCreated",
type: "event",
},
{
@@ -19954,48 +19745,61 @@ export default {
type: "uint96",
},
{
- indexed: false,
+ indexed: true,
+ internalType: "uint256",
+ name: "_disputeKitID",
+ type: "uint256",
+ },
+ {
+ indexed: true,
internalType: "bool",
- name: "_hiddenVotes",
+ name: "_enable",
type: "bool",
},
+ ],
+ name: "DisputeKitEnabled",
+ type: "event",
+ },
+ {
+ anonymous: false,
+ inputs: [
{
- indexed: false,
+ indexed: true,
internalType: "uint256",
- name: "_minStake",
+ name: "_disputeID",
type: "uint256",
},
{
- indexed: false,
+ indexed: true,
internalType: "uint256",
- name: "_alpha",
+ name: "_roundID",
type: "uint256",
},
{
- indexed: false,
+ indexed: true,
internalType: "uint256",
- name: "_feeForJuror",
+ name: "_fromDisputeKitID",
type: "uint256",
},
{
indexed: false,
internalType: "uint256",
- name: "_jurorsForCourtJump",
+ name: "_toDisputeKitID",
type: "uint256",
},
- {
- indexed: false,
- internalType: "uint256[4]",
- name: "_timesPerPeriod",
- type: "uint256[4]",
- },
],
- name: "CourtModified",
+ name: "DisputeKitJump",
type: "event",
},
{
anonymous: false,
inputs: [
+ {
+ indexed: true,
+ internalType: "address",
+ name: "_address",
+ type: "address",
+ },
{
indexed: true,
internalType: "uint256",
@@ -20003,13 +19807,19 @@ export default {
type: "uint256",
},
{
- indexed: true,
- internalType: "contract IArbitrableV2",
- name: "_arbitrable",
- type: "address",
+ indexed: false,
+ internalType: "uint256",
+ name: "_roundID",
+ type: "uint256",
+ },
+ {
+ indexed: false,
+ internalType: "uint256",
+ name: "_voteID",
+ type: "uint256",
},
],
- name: "DisputeCreation",
+ name: "Draw",
type: "event",
},
{
@@ -20098,7 +19908,7 @@ export default {
},
{
indexed: false,
- internalType: "enum KlerosCoreRuler.Period",
+ internalType: "enum KlerosCoreBase.Period",
name: "_period",
type: "uint8",
},
@@ -20108,68 +19918,8 @@ export default {
},
{
anonymous: false,
- inputs: [
- {
- indexed: true,
- internalType: "contract IArbitrableV2",
- name: "_arbitrable",
- type: "address",
- },
- {
- indexed: true,
- internalType: "address",
- name: "_oldRuler",
- type: "address",
- },
- {
- indexed: true,
- internalType: "address",
- name: "_newRuler",
- type: "address",
- },
- ],
- name: "RulerChanged",
- type: "event",
- },
- {
- anonymous: false,
- inputs: [
- {
- indexed: true,
- internalType: "contract IArbitrableV2",
- name: "_arbitrable",
- type: "address",
- },
- {
- components: [
- {
- internalType: "enum KlerosCoreRuler.RulingMode",
- name: "rulingMode",
- type: "uint8",
- },
- {
- internalType: "uint256",
- name: "presetRuling",
- type: "uint256",
- },
- {
- internalType: "bool",
- name: "presetTied",
- type: "bool",
- },
- {
- internalType: "bool",
- name: "presetOverridden",
- type: "bool",
- },
- ],
- indexed: false,
- internalType: "struct KlerosCoreRuler.RulerSettings",
- name: "_settings",
- type: "tuple",
- },
- ],
- name: "RulerSettingsChanged",
+ inputs: [],
+ name: "Paused",
type: "event",
},
{
@@ -20246,6 +19996,12 @@ export default {
name: "TokenAndETHShift",
type: "event",
},
+ {
+ anonymous: false,
+ inputs: [],
+ name: "Unpaused",
+ type: "event",
+ },
{
anonymous: false,
inputs: [
@@ -20259,6 +20015,19 @@ export default {
name: "Upgraded",
type: "event",
},
+ {
+ inputs: [
+ {
+ internalType: "contract IDisputeKit",
+ name: "_disputeKitAddress",
+ type: "address",
+ },
+ ],
+ name: "addNewDisputeKit",
+ outputs: [],
+ stateMutability: "nonpayable",
+ type: "function",
+ },
{
inputs: [
{
@@ -20273,14 +20042,9 @@ export default {
},
{
internalType: "bytes",
- name: "",
+ name: "_extraData",
type: "bytes",
},
- {
- internalType: "bool",
- name: "_jump",
- type: "bool",
- },
],
name: "appeal",
outputs: [],
@@ -20294,11 +20058,6 @@ export default {
name: "_disputeID",
type: "uint256",
},
- {
- internalType: "bool",
- name: "_jump",
- type: "bool",
- },
],
name: "appealCost",
outputs: [
@@ -20311,6 +20070,49 @@ export default {
stateMutability: "view",
type: "function",
},
+ {
+ inputs: [
+ {
+ internalType: "uint256",
+ name: "_disputeID",
+ type: "uint256",
+ },
+ ],
+ name: "appealPeriod",
+ outputs: [
+ {
+ internalType: "uint256",
+ name: "start",
+ type: "uint256",
+ },
+ {
+ internalType: "uint256",
+ name: "end",
+ type: "uint256",
+ },
+ ],
+ stateMutability: "view",
+ type: "function",
+ },
+ {
+ inputs: [
+ {
+ internalType: "address",
+ name: "",
+ type: "address",
+ },
+ ],
+ name: "arbitrableWhitelist",
+ outputs: [
+ {
+ internalType: "bool",
+ name: "",
+ type: "bool",
+ },
+ ],
+ stateMutability: "view",
+ type: "function",
+ },
{
inputs: [
{
@@ -20372,6 +20174,24 @@ export default {
stateMutability: "nonpayable",
type: "function",
},
+ {
+ inputs: [
+ {
+ internalType: "address",
+ name: "_arbitrable",
+ type: "address",
+ },
+ {
+ internalType: "bool",
+ name: "_allowed",
+ type: "bool",
+ },
+ ],
+ name: "changeArbitrableWhitelist",
+ outputs: [],
+ stateMutability: "nonpayable",
+ type: "function",
+ },
{
inputs: [
{
@@ -20454,12 +20274,12 @@ export default {
{
inputs: [
{
- internalType: "contract IERC20",
- name: "_pinakion",
+ internalType: "address",
+ name: "_guardian",
type: "address",
},
],
- name: "changePinakion",
+ name: "changeGuardian",
outputs: [],
stateMutability: "nonpayable",
type: "function",
@@ -20467,17 +20287,12 @@ export default {
{
inputs: [
{
- internalType: "contract IArbitrableV2",
- name: "_arbitrable",
- type: "address",
- },
- {
- internalType: "address",
- name: "_newRuler",
+ internalType: "contract IERC721",
+ name: "_jurorNft",
type: "address",
},
],
- name: "changeRuler",
+ name: "changeJurorNft",
outputs: [],
stateMutability: "nonpayable",
type: "function",
@@ -20485,27 +20300,12 @@ export default {
{
inputs: [
{
- internalType: "contract IArbitrableV2",
- name: "_arbitrable",
+ internalType: "address",
+ name: "_jurorProsecutionModule",
type: "address",
},
- {
- internalType: "uint256",
- name: "_presetRuling",
- type: "uint256",
- },
- {
- internalType: "bool",
- name: "_presetTied",
- type: "bool",
- },
- {
- internalType: "bool",
- name: "_presetOverridden",
- type: "bool",
- },
],
- name: "changeRulingModeToAutomaticPreset",
+ name: "changeJurorProsecutionModule",
outputs: [],
stateMutability: "nonpayable",
type: "function",
@@ -20513,12 +20313,12 @@ export default {
{
inputs: [
{
- internalType: "contract IArbitrableV2",
- name: "_arbitrable",
+ internalType: "contract IERC20",
+ name: "_pinakion",
type: "address",
},
],
- name: "changeRulingModeToAutomaticRandom",
+ name: "changePinakion",
outputs: [],
stateMutability: "nonpayable",
type: "function",
@@ -20526,12 +20326,12 @@ export default {
{
inputs: [
{
- internalType: "contract IArbitrableV2",
- name: "_arbitrable",
+ internalType: "contract ISortitionModule",
+ name: "_sortitionModule",
type: "address",
},
],
- name: "changeRulingModeToManual",
+ name: "changeSortitionModule",
outputs: [],
stateMutability: "nonpayable",
type: "function",
@@ -20646,6 +20446,16 @@ export default {
name: "_timesPerPeriod",
type: "uint256[4]",
},
+ {
+ internalType: "bytes",
+ name: "_sortitionExtraData",
+ type: "bytes",
+ },
+ {
+ internalType: "uint256[]",
+ name: "_supportedDisputeKits",
+ type: "uint256[]",
+ },
],
name: "createCourt",
outputs: [],
@@ -20768,6 +20578,25 @@ export default {
stateMutability: "view",
type: "function",
},
+ {
+ inputs: [
+ {
+ internalType: "uint256",
+ name: "",
+ type: "uint256",
+ },
+ ],
+ name: "disputeKits",
+ outputs: [
+ {
+ internalType: "contract IDisputeKit",
+ name: "",
+ type: "address",
+ },
+ ],
+ stateMutability: "view",
+ type: "function",
+ },
{
inputs: [
{
@@ -20789,7 +20618,7 @@ export default {
type: "address",
},
{
- internalType: "enum KlerosCoreRuler.Period",
+ internalType: "enum KlerosCoreBase.Period",
name: "period",
type: "uint8",
},
@@ -20798,10 +20627,62 @@ export default {
name: "ruled",
type: "bool",
},
+ {
+ internalType: "uint256",
+ name: "lastPeriodChange",
+ type: "uint256",
+ },
],
stateMutability: "view",
type: "function",
},
+ {
+ inputs: [
+ {
+ internalType: "uint256",
+ name: "_disputeID",
+ type: "uint256",
+ },
+ {
+ internalType: "uint256",
+ name: "_iterations",
+ type: "uint256",
+ },
+ ],
+ name: "draw",
+ outputs: [
+ {
+ internalType: "uint256",
+ name: "nbDrawnJurors",
+ type: "uint256",
+ },
+ ],
+ stateMutability: "nonpayable",
+ type: "function",
+ },
+ {
+ inputs: [
+ {
+ internalType: "uint96",
+ name: "_courtID",
+ type: "uint96",
+ },
+ {
+ internalType: "uint256[]",
+ name: "_disputeKitIDs",
+ type: "uint256[]",
+ },
+ {
+ internalType: "bool",
+ name: "_enable",
+ type: "bool",
+ },
+ ],
+ name: "enableDisputeKits",
+ outputs: [],
+ stateMutability: "nonpayable",
+ type: "function",
+ },
{
inputs: [
{
@@ -20814,6 +20695,11 @@ export default {
name: "_round",
type: "uint256",
},
+ {
+ internalType: "uint256",
+ name: "_iterations",
+ type: "uint256",
+ },
],
name: "execute",
outputs: [],
@@ -20850,21 +20736,6 @@ export default {
name: "_disputeID",
type: "uint256",
},
- {
- internalType: "uint256",
- name: "_ruling",
- type: "uint256",
- },
- {
- internalType: "bool",
- name: "tied",
- type: "bool",
- },
- {
- internalType: "bool",
- name: "overridden",
- type: "bool",
- },
],
name: "executeRuling",
outputs: [],
@@ -20873,7 +20744,7 @@ export default {
},
{
inputs: [],
- name: "getNextDisputeID",
+ name: "getDisputeKitsLength",
outputs: [
{
internalType: "uint256",
@@ -20922,6 +20793,30 @@ export default {
stateMutability: "view",
type: "function",
},
+ {
+ inputs: [
+ {
+ internalType: "uint256",
+ name: "_disputeID",
+ type: "uint256",
+ },
+ {
+ internalType: "uint256",
+ name: "_round",
+ type: "uint256",
+ },
+ ],
+ name: "getPnkAtStakePerJuror",
+ outputs: [
+ {
+ internalType: "uint256",
+ name: "",
+ type: "uint256",
+ },
+ ],
+ stateMutability: "view",
+ type: "function",
+ },
{
inputs: [
{
@@ -20939,23 +20834,63 @@ export default {
outputs: [
{
components: [
+ {
+ internalType: "uint256",
+ name: "disputeKitID",
+ type: "uint256",
+ },
+ {
+ internalType: "uint256",
+ name: "pnkAtStakePerJuror",
+ type: "uint256",
+ },
{
internalType: "uint256",
name: "totalFeesForJurors",
type: "uint256",
},
+ {
+ internalType: "uint256",
+ name: "nbVotes",
+ type: "uint256",
+ },
+ {
+ internalType: "uint256",
+ name: "repartitions",
+ type: "uint256",
+ },
+ {
+ internalType: "uint256",
+ name: "pnkPenalties",
+ type: "uint256",
+ },
+ {
+ internalType: "address[]",
+ name: "drawnJurors",
+ type: "address[]",
+ },
{
internalType: "uint256",
name: "sumFeeRewardPaid",
type: "uint256",
},
+ {
+ internalType: "uint256",
+ name: "sumPnkRewardPaid",
+ type: "uint256",
+ },
{
internalType: "contract IERC20",
name: "feeToken",
type: "address",
},
+ {
+ internalType: "uint256",
+ name: "drawIterations",
+ type: "uint256",
+ },
],
- internalType: "struct KlerosCoreRuler.Round",
+ internalType: "struct KlerosCoreBase.Round",
name: "",
type: "tuple",
},
@@ -20995,6 +20930,19 @@ export default {
stateMutability: "view",
type: "function",
},
+ {
+ inputs: [],
+ name: "guardian",
+ outputs: [
+ {
+ internalType: "address",
+ name: "",
+ type: "address",
+ },
+ ],
+ stateMutability: "view",
+ type: "function",
+ },
{
inputs: [
{
@@ -21002,16 +20950,61 @@ export default {
name: "_governor",
type: "address",
},
+ {
+ internalType: "address",
+ name: "_guardian",
+ type: "address",
+ },
{
internalType: "contract IERC20",
name: "_pinakion",
type: "address",
},
+ {
+ internalType: "address",
+ name: "_jurorProsecutionModule",
+ type: "address",
+ },
+ {
+ internalType: "contract IDisputeKit",
+ name: "_disputeKit",
+ type: "address",
+ },
+ {
+ internalType: "bool",
+ name: "_hiddenVotes",
+ type: "bool",
+ },
{
internalType: "uint256[4]",
name: "_courtParameters",
type: "uint256[4]",
},
+ {
+ internalType: "uint256[4]",
+ name: "_timesPerPeriod",
+ type: "uint256[4]",
+ },
+ {
+ internalType: "bytes",
+ name: "_sortitionExtraData",
+ type: "bytes",
+ },
+ {
+ internalType: "contract ISortitionModule",
+ name: "_sortitionModuleAddress",
+ type: "address",
+ },
+ {
+ internalType: "contract IERC721",
+ name: "_jurorNft",
+ type: "address",
+ },
+ {
+ internalType: "address",
+ name: "_wNative",
+ type: "address",
+ },
],
name: "initialize",
outputs: [],
@@ -21019,13 +21012,43 @@ export default {
type: "function",
},
{
- inputs: [],
- name: "pinakion",
+ inputs: [
+ {
+ internalType: "uint256",
+ name: "_disputeID",
+ type: "uint256",
+ },
+ ],
+ name: "isDisputeKitJumping",
+ outputs: [
+ {
+ internalType: "bool",
+ name: "",
+ type: "bool",
+ },
+ ],
+ stateMutability: "view",
+ type: "function",
+ },
+ {
+ inputs: [
+ {
+ internalType: "uint96",
+ name: "_courtID",
+ type: "uint96",
+ },
+ {
+ internalType: "uint256",
+ name: "_disputeKitID",
+ type: "uint256",
+ },
+ ],
+ name: "isSupported",
outputs: [
{
- internalType: "contract IERC20",
+ internalType: "bool",
name: "",
- type: "address",
+ type: "bool",
},
],
stateMutability: "view",
@@ -21033,30 +21056,24 @@ export default {
},
{
inputs: [],
- name: "proxiableUUID",
+ name: "jurorNft",
outputs: [
{
- internalType: "bytes32",
+ internalType: "contract IERC721",
name: "",
- type: "bytes32",
+ type: "address",
},
],
stateMutability: "view",
type: "function",
},
{
- inputs: [
- {
- internalType: "contract IArbitrableV2",
- name: "arbitrable",
- type: "address",
- },
- ],
- name: "rulers",
+ inputs: [],
+ name: "jurorProsecutionModule",
outputs: [
{
internalType: "address",
- name: "ruler",
+ name: "",
type: "address",
},
],
@@ -21067,25 +21084,29 @@ export default {
inputs: [
{
internalType: "uint256",
- name: "disputeID",
+ name: "_disputeID",
type: "uint256",
},
],
- name: "rulingResults",
+ name: "passPeriod",
+ outputs: [],
+ stateMutability: "nonpayable",
+ type: "function",
+ },
+ {
+ inputs: [],
+ name: "pause",
+ outputs: [],
+ stateMutability: "nonpayable",
+ type: "function",
+ },
+ {
+ inputs: [],
+ name: "paused",
outputs: [
- {
- internalType: "uint256",
- name: "ruling",
- type: "uint256",
- },
- {
- internalType: "bool",
- name: "tied",
- type: "bool",
- },
{
internalType: "bool",
- name: "overridden",
+ name: "",
type: "bool",
},
],
@@ -21093,34 +21114,26 @@ export default {
type: "function",
},
{
- inputs: [
+ inputs: [],
+ name: "pinakion",
+ outputs: [
{
- internalType: "contract IArbitrableV2",
- name: "arbitrable",
+ internalType: "contract IERC20",
+ name: "",
type: "address",
},
],
- name: "settings",
+ stateMutability: "view",
+ type: "function",
+ },
+ {
+ inputs: [],
+ name: "proxiableUUID",
outputs: [
{
- internalType: "enum KlerosCoreRuler.RulingMode",
- name: "rulingMode",
- type: "uint8",
- },
- {
- internalType: "uint256",
- name: "presetRuling",
- type: "uint256",
- },
- {
- internalType: "bool",
- name: "presetTied",
- type: "bool",
- },
- {
- internalType: "bool",
- name: "presetOverridden",
- type: "bool",
+ internalType: "bytes32",
+ name: "",
+ type: "bytes32",
},
],
stateMutability: "view",
@@ -21130,69 +21143,68 @@ export default {
inputs: [
{
internalType: "address",
- name: "newImplementation",
+ name: "_wNative",
type: "address",
},
- {
- internalType: "bytes",
- name: "data",
- type: "bytes",
- },
],
- name: "upgradeToAndCall",
+ name: "reinitialize",
outputs: [],
- stateMutability: "payable",
+ stateMutability: "nonpayable",
type: "function",
},
- ],
- },
- KlerosCoreRulerNeo_Proxy: {
- address: "0xc0169e0B19aE02ac4fADD689260CF038726DFE13",
- abi: [
{
inputs: [
{
- internalType: "address",
- name: "_implementation",
- type: "address",
+ internalType: "uint96",
+ name: "_courtID",
+ type: "uint96",
},
{
- internalType: "bytes",
- name: "_data",
- type: "bytes",
+ internalType: "uint256",
+ name: "_newStake",
+ type: "uint256",
},
],
+ name: "setStake",
+ outputs: [],
stateMutability: "nonpayable",
- type: "constructor",
- },
- {
- stateMutability: "payable",
- type: "fallback",
- },
- {
- stateMutability: "payable",
- type: "receive",
+ type: "function",
},
- ],
- },
- KlerosCoreSnapshotProxy: {
- address: "0xEF719a5B3352F607e6C4E17b7e0cDAd8322fEC95",
- abi: [
{
inputs: [
{
internalType: "address",
- name: "_governor",
+ name: "_account",
type: "address",
},
{
- internalType: "contract IKlerosCore",
- name: "_core",
- type: "address",
+ internalType: "uint96",
+ name: "_courtID",
+ type: "uint96",
+ },
+ {
+ internalType: "uint256",
+ name: "_newStake",
+ type: "uint256",
},
],
+ name: "setStakeBySortitionModule",
+ outputs: [],
stateMutability: "nonpayable",
- type: "constructor",
+ type: "function",
+ },
+ {
+ inputs: [],
+ name: "sortitionModule",
+ outputs: [
+ {
+ internalType: "contract ISortitionModule",
+ name: "",
+ type: "address",
+ },
+ ],
+ stateMutability: "view",
+ type: "function",
},
{
inputs: [
@@ -21201,27 +21213,20 @@ export default {
name: "_account",
type: "address",
},
- ],
- name: "balanceOf",
- outputs: [
{
internalType: "uint256",
- name: "totalStaked",
+ name: "_amount",
type: "uint256",
},
],
- stateMutability: "view",
+ name: "transferBySortitionModule",
+ outputs: [],
+ stateMutability: "nonpayable",
type: "function",
},
{
- inputs: [
- {
- internalType: "contract IKlerosCore",
- name: "_core",
- type: "address",
- },
- ],
- name: "changeCore",
+ inputs: [],
+ name: "unpause",
outputs: [],
stateMutability: "nonpayable",
type: "function",
@@ -21230,23 +21235,28 @@ export default {
inputs: [
{
internalType: "address",
- name: "_governor",
+ name: "newImplementation",
type: "address",
},
+ {
+ internalType: "bytes",
+ name: "data",
+ type: "bytes",
+ },
],
- name: "changeGovernor",
+ name: "upgradeToAndCall",
outputs: [],
- stateMutability: "nonpayable",
+ stateMutability: "payable",
type: "function",
},
{
inputs: [],
- name: "core",
+ name: "version",
outputs: [
{
- internalType: "contract IKlerosCore",
+ internalType: "string",
name: "",
- type: "address",
+ type: "string",
},
],
stateMutability: "view",
@@ -21254,55 +21264,45 @@ export default {
},
{
inputs: [],
- name: "decimals",
+ name: "wNative",
outputs: [
{
- internalType: "uint8",
+ internalType: "address",
name: "",
- type: "uint8",
+ type: "address",
},
],
stateMutability: "view",
type: "function",
},
+ ],
+ },
+ KlerosCore_Proxy: {
+ address: "0x991d2df165670b9cac3B022f4B68D65b664222ea",
+ abi: [
{
- inputs: [],
- name: "governor",
- outputs: [
+ inputs: [
{
internalType: "address",
- name: "",
+ name: "_implementation",
type: "address",
},
- ],
- stateMutability: "view",
- type: "function",
- },
- {
- inputs: [],
- name: "name",
- outputs: [
{
- internalType: "string",
- name: "",
- type: "string",
+ internalType: "bytes",
+ name: "_data",
+ type: "bytes",
},
],
- stateMutability: "view",
- type: "function",
+ stateMutability: "nonpayable",
+ type: "constructor",
},
{
- inputs: [],
- name: "symbol",
- outputs: [
- {
- internalType: "string",
- name: "",
- type: "string",
- },
- ],
- stateMutability: "view",
- type: "function",
+ stateMutability: "payable",
+ type: "fallback",
+ },
+ {
+ stateMutability: "payable",
+ type: "receive",
},
],
},
@@ -23898,7 +23898,7 @@ export default {
},
],
},
- SortitionModuleNeo: {
+ SortitionModule: {
address: "0x21A9402aDb818744B296e1d1BE58C804118DC03D",
abi: [
{
@@ -25022,7 +25022,7 @@ export default {
},
],
},
- SortitionModuleNeo_Implementation: {
+ SortitionModule_Implementation: {
address: "0x3f6D0daeD166b64FCfBb9bc7c9E26423c6C08eEE",
abi: [
{
@@ -26127,7 +26127,7 @@ export default {
},
],
},
- SortitionModuleNeo_Proxy: {
+ SortitionModule_Proxy: {
address: "0x21A9402aDb818744B296e1d1BE58C804118DC03D",
abi: [
{
diff --git a/contracts/deployments/arbitrum/DisputeKitClassicNeo.json b/contracts/deployments/arbitrum/DisputeKitClassic.json
similarity index 100%
rename from contracts/deployments/arbitrum/DisputeKitClassicNeo.json
rename to contracts/deployments/arbitrum/DisputeKitClassic.json
diff --git a/contracts/deployments/arbitrum/DisputeKitClassicNeo_Implementation.json b/contracts/deployments/arbitrum/DisputeKitClassic_Implementation.json
similarity index 100%
rename from contracts/deployments/arbitrum/DisputeKitClassicNeo_Implementation.json
rename to contracts/deployments/arbitrum/DisputeKitClassic_Implementation.json
diff --git a/contracts/deployments/arbitrum/DisputeKitClassicNeo_Proxy.json b/contracts/deployments/arbitrum/DisputeKitClassic_Proxy.json
similarity index 100%
rename from contracts/deployments/arbitrum/DisputeKitClassicNeo_Proxy.json
rename to contracts/deployments/arbitrum/DisputeKitClassic_Proxy.json
diff --git a/contracts/deployments/arbitrum/DisputeKitGatedNeo.json b/contracts/deployments/arbitrum/DisputeKitGated.json
similarity index 100%
rename from contracts/deployments/arbitrum/DisputeKitGatedNeo.json
rename to contracts/deployments/arbitrum/DisputeKitGated.json
diff --git a/contracts/deployments/arbitrum/DisputeKitGatedShutterNeo.json b/contracts/deployments/arbitrum/DisputeKitGatedShutter.json
similarity index 100%
rename from contracts/deployments/arbitrum/DisputeKitGatedShutterNeo.json
rename to contracts/deployments/arbitrum/DisputeKitGatedShutter.json
diff --git a/contracts/deployments/arbitrum/DisputeKitGatedShutterNeo_Implementation.json b/contracts/deployments/arbitrum/DisputeKitGatedShutter_Implementation.json
similarity index 100%
rename from contracts/deployments/arbitrum/DisputeKitGatedShutterNeo_Implementation.json
rename to contracts/deployments/arbitrum/DisputeKitGatedShutter_Implementation.json
diff --git a/contracts/deployments/arbitrum/DisputeKitGatedShutterNeo_Proxy.json b/contracts/deployments/arbitrum/DisputeKitGatedShutter_Proxy.json
similarity index 100%
rename from contracts/deployments/arbitrum/DisputeKitGatedShutterNeo_Proxy.json
rename to contracts/deployments/arbitrum/DisputeKitGatedShutter_Proxy.json
diff --git a/contracts/deployments/arbitrum/DisputeKitGatedNeo_Implementation.json b/contracts/deployments/arbitrum/DisputeKitGated_Implementation.json
similarity index 100%
rename from contracts/deployments/arbitrum/DisputeKitGatedNeo_Implementation.json
rename to contracts/deployments/arbitrum/DisputeKitGated_Implementation.json
diff --git a/contracts/deployments/arbitrum/DisputeKitGatedNeo_Proxy.json b/contracts/deployments/arbitrum/DisputeKitGated_Proxy.json
similarity index 100%
rename from contracts/deployments/arbitrum/DisputeKitGatedNeo_Proxy.json
rename to contracts/deployments/arbitrum/DisputeKitGated_Proxy.json
diff --git a/contracts/deployments/arbitrum/DisputeKitShutterNeo.json b/contracts/deployments/arbitrum/DisputeKitShutter.json
similarity index 100%
rename from contracts/deployments/arbitrum/DisputeKitShutterNeo.json
rename to contracts/deployments/arbitrum/DisputeKitShutter.json
diff --git a/contracts/deployments/arbitrum/DisputeKitShutterNeo_Implementation.json b/contracts/deployments/arbitrum/DisputeKitShutter_Implementation.json
similarity index 100%
rename from contracts/deployments/arbitrum/DisputeKitShutterNeo_Implementation.json
rename to contracts/deployments/arbitrum/DisputeKitShutter_Implementation.json
diff --git a/contracts/deployments/arbitrum/DisputeKitShutterNeo_Proxy.json b/contracts/deployments/arbitrum/DisputeKitShutter_Proxy.json
similarity index 100%
rename from contracts/deployments/arbitrum/DisputeKitShutterNeo_Proxy.json
rename to contracts/deployments/arbitrum/DisputeKitShutter_Proxy.json
diff --git a/contracts/deployments/arbitrum/DisputeResolverNeo.json b/contracts/deployments/arbitrum/DisputeResolver.json
similarity index 100%
rename from contracts/deployments/arbitrum/DisputeResolverNeo.json
rename to contracts/deployments/arbitrum/DisputeResolver.json
diff --git a/contracts/deployments/arbitrum/DisputeResolverRulerNeo.json b/contracts/deployments/arbitrum/DisputeResolverRuler.json
similarity index 100%
rename from contracts/deployments/arbitrum/DisputeResolverRulerNeo.json
rename to contracts/deployments/arbitrum/DisputeResolverRuler.json
diff --git a/contracts/deployments/arbitrum/KlerosCoreNeo.json b/contracts/deployments/arbitrum/KlerosCore.json
similarity index 100%
rename from contracts/deployments/arbitrum/KlerosCoreNeo.json
rename to contracts/deployments/arbitrum/KlerosCore.json
diff --git a/contracts/deployments/arbitrum/KlerosCoreRulerNeo.json b/contracts/deployments/arbitrum/KlerosCoreRuler.json
similarity index 100%
rename from contracts/deployments/arbitrum/KlerosCoreRulerNeo.json
rename to contracts/deployments/arbitrum/KlerosCoreRuler.json
diff --git a/contracts/deployments/arbitrum/KlerosCoreRulerNeo_Implementation.json b/contracts/deployments/arbitrum/KlerosCoreRuler_Implementation.json
similarity index 100%
rename from contracts/deployments/arbitrum/KlerosCoreRulerNeo_Implementation.json
rename to contracts/deployments/arbitrum/KlerosCoreRuler_Implementation.json
diff --git a/contracts/deployments/arbitrum/KlerosCoreRulerNeo_Proxy.json b/contracts/deployments/arbitrum/KlerosCoreRuler_Proxy.json
similarity index 100%
rename from contracts/deployments/arbitrum/KlerosCoreRulerNeo_Proxy.json
rename to contracts/deployments/arbitrum/KlerosCoreRuler_Proxy.json
diff --git a/contracts/deployments/arbitrum/KlerosCoreNeo_Implementation.json b/contracts/deployments/arbitrum/KlerosCore_Implementation.json
similarity index 100%
rename from contracts/deployments/arbitrum/KlerosCoreNeo_Implementation.json
rename to contracts/deployments/arbitrum/KlerosCore_Implementation.json
diff --git a/contracts/deployments/arbitrum/KlerosCoreNeo_Proxy.json b/contracts/deployments/arbitrum/KlerosCore_Proxy.json
similarity index 100%
rename from contracts/deployments/arbitrum/KlerosCoreNeo_Proxy.json
rename to contracts/deployments/arbitrum/KlerosCore_Proxy.json
diff --git a/contracts/deployments/arbitrum/SortitionModuleNeo.json b/contracts/deployments/arbitrum/SortitionModule.json
similarity index 100%
rename from contracts/deployments/arbitrum/SortitionModuleNeo.json
rename to contracts/deployments/arbitrum/SortitionModule.json
diff --git a/contracts/deployments/arbitrum/SortitionModuleNeo_Implementation.json b/contracts/deployments/arbitrum/SortitionModule_Implementation.json
similarity index 100%
rename from contracts/deployments/arbitrum/SortitionModuleNeo_Implementation.json
rename to contracts/deployments/arbitrum/SortitionModule_Implementation.json
diff --git a/contracts/deployments/arbitrum/SortitionModuleNeo_Proxy.json b/contracts/deployments/arbitrum/SortitionModule_Proxy.json
similarity index 100%
rename from contracts/deployments/arbitrum/SortitionModuleNeo_Proxy.json
rename to contracts/deployments/arbitrum/SortitionModule_Proxy.json
diff --git a/contracts/deployments/arbitrumSepoliaDevnet.ts b/contracts/deployments/arbitrumSepoliaDevnet.ts
index bd581ea30..037880be7 100644
--- a/contracts/deployments/arbitrumSepoliaDevnet.ts
+++ b/contracts/deployments/arbitrumSepoliaDevnet.ts
@@ -4221,7 +4221,7 @@ export default {
],
},
DisputeKitClassicUniversity: {
- address: "0xd6E96b7c993763B5CDDa1139C7387B82A7c8B8B5",
+ address: "0x82F2089442979A6b56c80274D144575980092F91",
abi: [
{
stateMutability: "payable",
@@ -4236,11 +4236,61 @@ export default {
name: "AlreadyInitialized",
type: "error",
},
+ {
+ inputs: [],
+ name: "AppealFeeIsAlreadyPaid",
+ type: "error",
+ },
+ {
+ inputs: [],
+ name: "AppealPeriodIsOver",
+ type: "error",
+ },
+ {
+ inputs: [],
+ name: "AppealPeriodIsOverForLoser",
+ type: "error",
+ },
+ {
+ inputs: [],
+ name: "ChoiceOutOfBounds",
+ type: "error",
+ },
+ {
+ inputs: [],
+ name: "CoreIsPaused",
+ type: "error",
+ },
+ {
+ inputs: [],
+ name: "DisputeJumpedToParentDK",
+ type: "error",
+ },
+ {
+ inputs: [],
+ name: "DisputeNotResolved",
+ type: "error",
+ },
+ {
+ inputs: [],
+ name: "EmptyCommit",
+ type: "error",
+ },
+ {
+ inputs: [],
+ name: "EmptyVoteIDs",
+ type: "error",
+ },
{
inputs: [],
name: "FailedDelegateCall",
type: "error",
},
+ {
+ inputs: [],
+ name: "HashDoesNotMatchHiddenVoteCommitment",
+ type: "error",
+ },
{
inputs: [
{
@@ -4252,11 +4302,41 @@ export default {
name: "InvalidImplementation",
type: "error",
},
+ {
+ inputs: [],
+ name: "JurorHasToOwnTheVote",
+ type: "error",
+ },
+ {
+ inputs: [],
+ name: "KlerosCoreOnly",
+ type: "error",
+ },
+ {
+ inputs: [],
+ name: "NotActiveForCoreDisputeID",
+ type: "error",
+ },
+ {
+ inputs: [],
+ name: "NotCommitPeriod",
+ type: "error",
+ },
{
inputs: [],
name: "NotInitializing",
type: "error",
},
+ {
+ inputs: [],
+ name: "NotVotePeriod",
+ type: "error",
+ },
+ {
+ inputs: [],
+ name: "OwnerOnly",
+ type: "error",
+ },
{
inputs: [],
name: "UUPSUnauthorizedCallContext",
@@ -4273,6 +4353,16 @@ export default {
name: "UUPSUnsupportedProxiableUUID",
type: "error",
},
+ {
+ inputs: [],
+ name: "UnsuccessfulCall",
+ type: "error",
+ },
+ {
+ inputs: [],
+ name: "VoteAlreadyCast",
+ type: "error",
+ },
{
anonymous: false,
inputs: [
@@ -4517,19 +4607,6 @@ export default {
stateMutability: "view",
type: "function",
},
- {
- inputs: [],
- name: "ONE_BASIS_POINT",
- outputs: [
- {
- internalType: "uint256",
- name: "",
- type: "uint256",
- },
- ],
- stateMutability: "view",
- type: "function",
- },
{
inputs: [],
name: "WINNER_STAKE_MULTIPLIER",
@@ -4650,15 +4727,28 @@ export default {
stateMutability: "nonpayable",
type: "function",
},
+ {
+ inputs: [
+ {
+ internalType: "uint256",
+ name: "_jumpDisputeKitID",
+ type: "uint256",
+ },
+ ],
+ name: "changeJumpDisputeKitID",
+ outputs: [],
+ stateMutability: "nonpayable",
+ type: "function",
+ },
{
inputs: [
{
internalType: "address payable",
- name: "_governor",
+ name: "_owner",
type: "address",
},
],
- name: "changeGovernor",
+ name: "changeOwner",
outputs: [],
stateMutability: "nonpayable",
type: "function",
@@ -4676,6 +4766,25 @@ export default {
stateMutability: "view",
type: "function",
},
+ {
+ inputs: [
+ {
+ internalType: "uint256",
+ name: "coreDisputeID",
+ type: "uint256",
+ },
+ ],
+ name: "coreDisputeIDToActive",
+ outputs: [
+ {
+ internalType: "bool",
+ name: "",
+ type: "bool",
+ },
+ ],
+ stateMutability: "view",
+ type: "function",
+ },
{
inputs: [
{
@@ -4714,7 +4823,7 @@ export default {
},
{
internalType: "uint256",
- name: "_nbVotes",
+ name: "",
type: "uint256",
},
],
@@ -4801,10 +4910,34 @@ export default {
name: "drawnAddress",
type: "address",
},
+ {
+ internalType: "uint96",
+ name: "fromSubcourtID",
+ type: "uint96",
+ },
],
stateMutability: "nonpayable",
type: "function",
},
+ {
+ inputs: [
+ {
+ internalType: "uint256",
+ name: "",
+ type: "uint256",
+ },
+ ],
+ name: "earlyCourtJump",
+ outputs: [
+ {
+ internalType: "bool",
+ name: "",
+ type: "bool",
+ },
+ ],
+ stateMutability: "pure",
+ type: "function",
+ },
{
inputs: [
{
@@ -4823,7 +4956,7 @@ export default {
type: "bytes",
},
],
- name: "executeGovernorProposal",
+ name: "executeOwnerProposal",
outputs: [],
stateMutability: "nonpayable",
type: "function",
@@ -4898,14 +5031,58 @@ export default {
type: "uint256",
},
],
- name: "getDegreeOfCoherence",
+ name: "getDegreeOfCoherencePenalty",
outputs: [
+ {
+ internalType: "uint256",
+ name: "pnkCoherence",
+ type: "uint256",
+ },
+ ],
+ stateMutability: "view",
+ type: "function",
+ },
+ {
+ inputs: [
+ {
+ internalType: "uint256",
+ name: "_coreDisputeID",
+ type: "uint256",
+ },
+ {
+ internalType: "uint256",
+ name: "_coreRoundID",
+ type: "uint256",
+ },
+ {
+ internalType: "uint256",
+ name: "_voteID",
+ type: "uint256",
+ },
+ {
+ internalType: "uint256",
+ name: "",
+ type: "uint256",
+ },
{
internalType: "uint256",
name: "",
type: "uint256",
},
],
+ name: "getDegreeOfCoherenceReward",
+ outputs: [
+ {
+ internalType: "uint256",
+ name: "pnkCoherence",
+ type: "uint256",
+ },
+ {
+ internalType: "uint256",
+ name: "feeCoherence",
+ type: "uint256",
+ },
+ ],
stateMutability: "view",
type: "function",
},
@@ -4928,6 +5105,19 @@ export default {
stateMutability: "view",
type: "function",
},
+ {
+ inputs: [],
+ name: "getJumpDisputeKitID",
+ outputs: [
+ {
+ internalType: "uint256",
+ name: "",
+ type: "uint256",
+ },
+ ],
+ stateMutability: "view",
+ type: "function",
+ },
{
inputs: [
{
@@ -4940,42 +5130,60 @@ export default {
name: "_coreRoundID",
type: "uint256",
},
+ ],
+ name: "getLocalDisputeRoundID",
+ outputs: [
{
internalType: "uint256",
- name: "_choice",
+ name: "localDisputeID",
type: "uint256",
},
- ],
- name: "getRoundInfo",
- outputs: [
{
internalType: "uint256",
- name: "winningChoice",
+ name: "localRoundID",
type: "uint256",
},
+ ],
+ stateMutability: "view",
+ type: "function",
+ },
+ {
+ inputs: [
{
- internalType: "bool",
- name: "tied",
- type: "bool",
+ internalType: "contract IDisputeKit",
+ name: "",
+ type: "address",
},
{
internalType: "uint256",
- name: "totalVoted",
+ name: "_currentNbVotes",
type: "uint256",
},
+ ],
+ name: "getNbVotesAfterAppeal",
+ outputs: [
{
internalType: "uint256",
- name: "totalCommited",
+ name: "",
type: "uint256",
},
+ ],
+ stateMutability: "pure",
+ type: "function",
+ },
+ {
+ inputs: [
{
internalType: "uint256",
- name: "nbVoters",
+ name: "_localDisputeID",
type: "uint256",
},
+ ],
+ name: "getNumberOfRounds",
+ outputs: [
{
internalType: "uint256",
- name: "choiceCount",
+ name: "",
type: "uint256",
},
],
@@ -4996,29 +5204,83 @@ export default {
},
{
internalType: "uint256",
- name: "_voteID",
+ name: "_choice",
type: "uint256",
},
],
- name: "getVoteInfo",
+ name: "getRoundInfo",
outputs: [
{
- internalType: "address",
- name: "account",
- type: "address",
+ internalType: "uint256",
+ name: "winningChoice",
+ type: "uint256",
},
{
- internalType: "bytes32",
- name: "commit",
- type: "bytes32",
+ internalType: "bool",
+ name: "tied",
+ type: "bool",
},
{
internalType: "uint256",
- name: "choice",
+ name: "totalVoted",
type: "uint256",
},
{
- internalType: "bool",
+ internalType: "uint256",
+ name: "totalCommitted",
+ type: "uint256",
+ },
+ {
+ internalType: "uint256",
+ name: "nbVoters",
+ type: "uint256",
+ },
+ {
+ internalType: "uint256",
+ name: "choiceCount",
+ type: "uint256",
+ },
+ ],
+ stateMutability: "view",
+ type: "function",
+ },
+ {
+ inputs: [
+ {
+ internalType: "uint256",
+ name: "_coreDisputeID",
+ type: "uint256",
+ },
+ {
+ internalType: "uint256",
+ name: "_coreRoundID",
+ type: "uint256",
+ },
+ {
+ internalType: "uint256",
+ name: "_voteID",
+ type: "uint256",
+ },
+ ],
+ name: "getVoteInfo",
+ outputs: [
+ {
+ internalType: "address",
+ name: "account",
+ type: "address",
+ },
+ {
+ internalType: "bytes32",
+ name: "commit",
+ type: "bytes32",
+ },
+ {
+ internalType: "uint256",
+ name: "choice",
+ type: "uint256",
+ },
+ {
+ internalType: "bool",
name: "voted",
type: "bool",
},
@@ -5027,13 +5289,29 @@ export default {
type: "function",
},
{
- inputs: [],
- name: "governor",
+ inputs: [
+ {
+ internalType: "uint256",
+ name: "_choice",
+ type: "uint256",
+ },
+ {
+ internalType: "uint256",
+ name: "_salt",
+ type: "uint256",
+ },
+ {
+ internalType: "string",
+ name: "",
+ type: "string",
+ },
+ ],
+ name: "hashVote",
outputs: [
{
- internalType: "address",
+ internalType: "bytes32",
name: "",
- type: "address",
+ type: "bytes32",
},
],
stateMutability: "view",
@@ -5043,7 +5321,7 @@ export default {
inputs: [
{
internalType: "address",
- name: "_governor",
+ name: "_owner",
type: "address",
},
{
@@ -5051,12 +5329,41 @@ export default {
name: "_core",
type: "address",
},
+ {
+ internalType: "address",
+ name: "_wNative",
+ type: "address",
+ },
+ {
+ internalType: "uint256",
+ name: "_jumpDisputeKitID",
+ type: "uint256",
+ },
],
name: "initialize",
outputs: [],
stateMutability: "nonpayable",
type: "function",
},
+ {
+ inputs: [
+ {
+ internalType: "uint256",
+ name: "_coreDisputeID",
+ type: "uint256",
+ },
+ ],
+ name: "isAppealFunded",
+ outputs: [
+ {
+ internalType: "bool",
+ name: "",
+ type: "bool",
+ },
+ ],
+ stateMutability: "view",
+ type: "function",
+ },
{
inputs: [
{
@@ -5086,6 +5393,32 @@ export default {
stateMutability: "view",
type: "function",
},
+ {
+ inputs: [],
+ name: "jumpDisputeKitID",
+ outputs: [
+ {
+ internalType: "uint256",
+ name: "",
+ type: "uint256",
+ },
+ ],
+ stateMutability: "view",
+ type: "function",
+ },
+ {
+ inputs: [],
+ name: "owner",
+ outputs: [
+ {
+ internalType: "address",
+ name: "",
+ type: "address",
+ },
+ ],
+ stateMutability: "view",
+ type: "function",
+ },
{
inputs: [],
name: "proxiableUUID",
@@ -5099,6 +5432,19 @@ export default {
stateMutability: "view",
type: "function",
},
+ {
+ inputs: [],
+ name: "singleDrawPerJuror",
+ outputs: [
+ {
+ internalType: "bool",
+ name: "",
+ type: "bool",
+ },
+ ],
+ stateMutability: "view",
+ type: "function",
+ },
{
inputs: [
{
@@ -5117,6 +5463,32 @@ export default {
stateMutability: "payable",
type: "function",
},
+ {
+ inputs: [],
+ name: "version",
+ outputs: [
+ {
+ internalType: "string",
+ name: "",
+ type: "string",
+ },
+ ],
+ stateMutability: "view",
+ type: "function",
+ },
+ {
+ inputs: [],
+ name: "wNative",
+ outputs: [
+ {
+ internalType: "address",
+ name: "",
+ type: "address",
+ },
+ ],
+ stateMutability: "view",
+ type: "function",
+ },
{
inputs: [
{
@@ -5170,7 +5542,7 @@ export default {
],
},
DisputeKitClassicUniversity_Implementation: {
- address: "0x87e863b94d2CB79A8aB53bD87Dc4A10E11C0918B",
+ address: "0x602ADa1cE706404BFb5417e497cdDae934436081",
abi: [
{
inputs: [],
@@ -5182,11 +5554,61 @@ export default {
name: "AlreadyInitialized",
type: "error",
},
+ {
+ inputs: [],
+ name: "AppealFeeIsAlreadyPaid",
+ type: "error",
+ },
+ {
+ inputs: [],
+ name: "AppealPeriodIsOver",
+ type: "error",
+ },
+ {
+ inputs: [],
+ name: "AppealPeriodIsOverForLoser",
+ type: "error",
+ },
+ {
+ inputs: [],
+ name: "ChoiceOutOfBounds",
+ type: "error",
+ },
+ {
+ inputs: [],
+ name: "CoreIsPaused",
+ type: "error",
+ },
+ {
+ inputs: [],
+ name: "DisputeJumpedToParentDK",
+ type: "error",
+ },
+ {
+ inputs: [],
+ name: "DisputeNotResolved",
+ type: "error",
+ },
+ {
+ inputs: [],
+ name: "EmptyCommit",
+ type: "error",
+ },
+ {
+ inputs: [],
+ name: "EmptyVoteIDs",
+ type: "error",
+ },
{
inputs: [],
name: "FailedDelegateCall",
type: "error",
},
+ {
+ inputs: [],
+ name: "HashDoesNotMatchHiddenVoteCommitment",
+ type: "error",
+ },
{
inputs: [
{
@@ -5198,11 +5620,41 @@ export default {
name: "InvalidImplementation",
type: "error",
},
+ {
+ inputs: [],
+ name: "JurorHasToOwnTheVote",
+ type: "error",
+ },
+ {
+ inputs: [],
+ name: "KlerosCoreOnly",
+ type: "error",
+ },
+ {
+ inputs: [],
+ name: "NotActiveForCoreDisputeID",
+ type: "error",
+ },
+ {
+ inputs: [],
+ name: "NotCommitPeriod",
+ type: "error",
+ },
{
inputs: [],
name: "NotInitializing",
type: "error",
},
+ {
+ inputs: [],
+ name: "NotVotePeriod",
+ type: "error",
+ },
+ {
+ inputs: [],
+ name: "OwnerOnly",
+ type: "error",
+ },
{
inputs: [],
name: "UUPSUnauthorizedCallContext",
@@ -5219,6 +5671,16 @@ export default {
name: "UUPSUnsupportedProxiableUUID",
type: "error",
},
+ {
+ inputs: [],
+ name: "UnsuccessfulCall",
+ type: "error",
+ },
+ {
+ inputs: [],
+ name: "VoteAlreadyCast",
+ type: "error",
+ },
{
anonymous: false,
inputs: [
@@ -5465,7 +5927,7 @@ export default {
},
{
inputs: [],
- name: "ONE_BASIS_POINT",
+ name: "WINNER_STAKE_MULTIPLIER",
outputs: [
{
internalType: "uint256",
@@ -5477,23 +5939,10 @@ export default {
type: "function",
},
{
- inputs: [],
- name: "WINNER_STAKE_MULTIPLIER",
- outputs: [
+ inputs: [
{
internalType: "uint256",
- name: "",
- type: "uint256",
- },
- ],
- stateMutability: "view",
- type: "function",
- },
- {
- inputs: [
- {
- internalType: "uint256",
- name: "_coreDisputeID",
+ name: "_coreDisputeID",
type: "uint256",
},
],
@@ -5596,15 +6045,28 @@ export default {
stateMutability: "nonpayable",
type: "function",
},
+ {
+ inputs: [
+ {
+ internalType: "uint256",
+ name: "_jumpDisputeKitID",
+ type: "uint256",
+ },
+ ],
+ name: "changeJumpDisputeKitID",
+ outputs: [],
+ stateMutability: "nonpayable",
+ type: "function",
+ },
{
inputs: [
{
internalType: "address payable",
- name: "_governor",
+ name: "_owner",
type: "address",
},
],
- name: "changeGovernor",
+ name: "changeOwner",
outputs: [],
stateMutability: "nonpayable",
type: "function",
@@ -5622,6 +6084,25 @@ export default {
stateMutability: "view",
type: "function",
},
+ {
+ inputs: [
+ {
+ internalType: "uint256",
+ name: "coreDisputeID",
+ type: "uint256",
+ },
+ ],
+ name: "coreDisputeIDToActive",
+ outputs: [
+ {
+ internalType: "bool",
+ name: "",
+ type: "bool",
+ },
+ ],
+ stateMutability: "view",
+ type: "function",
+ },
{
inputs: [
{
@@ -5660,7 +6141,7 @@ export default {
},
{
internalType: "uint256",
- name: "_nbVotes",
+ name: "",
type: "uint256",
},
],
@@ -5747,10 +6228,34 @@ export default {
name: "drawnAddress",
type: "address",
},
+ {
+ internalType: "uint96",
+ name: "fromSubcourtID",
+ type: "uint96",
+ },
],
stateMutability: "nonpayable",
type: "function",
},
+ {
+ inputs: [
+ {
+ internalType: "uint256",
+ name: "",
+ type: "uint256",
+ },
+ ],
+ name: "earlyCourtJump",
+ outputs: [
+ {
+ internalType: "bool",
+ name: "",
+ type: "bool",
+ },
+ ],
+ stateMutability: "pure",
+ type: "function",
+ },
{
inputs: [
{
@@ -5769,7 +6274,7 @@ export default {
type: "bytes",
},
],
- name: "executeGovernorProposal",
+ name: "executeOwnerProposal",
outputs: [],
stateMutability: "nonpayable",
type: "function",
@@ -5844,14 +6349,58 @@ export default {
type: "uint256",
},
],
- name: "getDegreeOfCoherence",
+ name: "getDegreeOfCoherencePenalty",
outputs: [
+ {
+ internalType: "uint256",
+ name: "pnkCoherence",
+ type: "uint256",
+ },
+ ],
+ stateMutability: "view",
+ type: "function",
+ },
+ {
+ inputs: [
+ {
+ internalType: "uint256",
+ name: "_coreDisputeID",
+ type: "uint256",
+ },
+ {
+ internalType: "uint256",
+ name: "_coreRoundID",
+ type: "uint256",
+ },
+ {
+ internalType: "uint256",
+ name: "_voteID",
+ type: "uint256",
+ },
+ {
+ internalType: "uint256",
+ name: "",
+ type: "uint256",
+ },
{
internalType: "uint256",
name: "",
type: "uint256",
},
],
+ name: "getDegreeOfCoherenceReward",
+ outputs: [
+ {
+ internalType: "uint256",
+ name: "pnkCoherence",
+ type: "uint256",
+ },
+ {
+ internalType: "uint256",
+ name: "feeCoherence",
+ type: "uint256",
+ },
+ ],
stateMutability: "view",
type: "function",
},
@@ -5874,6 +6423,91 @@ export default {
stateMutability: "view",
type: "function",
},
+ {
+ inputs: [],
+ name: "getJumpDisputeKitID",
+ outputs: [
+ {
+ internalType: "uint256",
+ name: "",
+ type: "uint256",
+ },
+ ],
+ stateMutability: "view",
+ type: "function",
+ },
+ {
+ inputs: [
+ {
+ internalType: "uint256",
+ name: "_coreDisputeID",
+ type: "uint256",
+ },
+ {
+ internalType: "uint256",
+ name: "_coreRoundID",
+ type: "uint256",
+ },
+ ],
+ name: "getLocalDisputeRoundID",
+ outputs: [
+ {
+ internalType: "uint256",
+ name: "localDisputeID",
+ type: "uint256",
+ },
+ {
+ internalType: "uint256",
+ name: "localRoundID",
+ type: "uint256",
+ },
+ ],
+ stateMutability: "view",
+ type: "function",
+ },
+ {
+ inputs: [
+ {
+ internalType: "contract IDisputeKit",
+ name: "",
+ type: "address",
+ },
+ {
+ internalType: "uint256",
+ name: "_currentNbVotes",
+ type: "uint256",
+ },
+ ],
+ name: "getNbVotesAfterAppeal",
+ outputs: [
+ {
+ internalType: "uint256",
+ name: "",
+ type: "uint256",
+ },
+ ],
+ stateMutability: "pure",
+ type: "function",
+ },
+ {
+ inputs: [
+ {
+ internalType: "uint256",
+ name: "_localDisputeID",
+ type: "uint256",
+ },
+ ],
+ name: "getNumberOfRounds",
+ outputs: [
+ {
+ internalType: "uint256",
+ name: "",
+ type: "uint256",
+ },
+ ],
+ stateMutability: "view",
+ type: "function",
+ },
{
inputs: [
{
@@ -5911,7 +6545,7 @@ export default {
},
{
internalType: "uint256",
- name: "totalCommited",
+ name: "totalCommitted",
type: "uint256",
},
{
@@ -5973,13 +6607,29 @@ export default {
type: "function",
},
{
- inputs: [],
- name: "governor",
+ inputs: [
+ {
+ internalType: "uint256",
+ name: "_choice",
+ type: "uint256",
+ },
+ {
+ internalType: "uint256",
+ name: "_salt",
+ type: "uint256",
+ },
+ {
+ internalType: "string",
+ name: "",
+ type: "string",
+ },
+ ],
+ name: "hashVote",
outputs: [
{
- internalType: "address",
+ internalType: "bytes32",
name: "",
- type: "address",
+ type: "bytes32",
},
],
stateMutability: "view",
@@ -5989,7 +6639,7 @@ export default {
inputs: [
{
internalType: "address",
- name: "_governor",
+ name: "_owner",
type: "address",
},
{
@@ -5997,12 +6647,41 @@ export default {
name: "_core",
type: "address",
},
+ {
+ internalType: "address",
+ name: "_wNative",
+ type: "address",
+ },
+ {
+ internalType: "uint256",
+ name: "_jumpDisputeKitID",
+ type: "uint256",
+ },
],
name: "initialize",
outputs: [],
stateMutability: "nonpayable",
type: "function",
},
+ {
+ inputs: [
+ {
+ internalType: "uint256",
+ name: "_coreDisputeID",
+ type: "uint256",
+ },
+ ],
+ name: "isAppealFunded",
+ outputs: [
+ {
+ internalType: "bool",
+ name: "",
+ type: "bool",
+ },
+ ],
+ stateMutability: "view",
+ type: "function",
+ },
{
inputs: [
{
@@ -6034,27 +6713,66 @@ export default {
},
{
inputs: [],
- name: "proxiableUUID",
+ name: "jumpDisputeKitID",
outputs: [
{
- internalType: "bytes32",
+ internalType: "uint256",
name: "",
- type: "bytes32",
+ type: "uint256",
},
],
stateMutability: "view",
type: "function",
},
{
- inputs: [
+ inputs: [],
+ name: "owner",
+ outputs: [
{
internalType: "address",
- name: "newImplementation",
+ name: "",
type: "address",
},
- {
- internalType: "bytes",
- name: "data",
+ ],
+ stateMutability: "view",
+ type: "function",
+ },
+ {
+ inputs: [],
+ name: "proxiableUUID",
+ outputs: [
+ {
+ internalType: "bytes32",
+ name: "",
+ type: "bytes32",
+ },
+ ],
+ stateMutability: "view",
+ type: "function",
+ },
+ {
+ inputs: [],
+ name: "singleDrawPerJuror",
+ outputs: [
+ {
+ internalType: "bool",
+ name: "",
+ type: "bool",
+ },
+ ],
+ stateMutability: "view",
+ type: "function",
+ },
+ {
+ inputs: [
+ {
+ internalType: "address",
+ name: "newImplementation",
+ type: "address",
+ },
+ {
+ internalType: "bytes",
+ name: "data",
type: "bytes",
},
],
@@ -6063,6 +6781,32 @@ export default {
stateMutability: "payable",
type: "function",
},
+ {
+ inputs: [],
+ name: "version",
+ outputs: [
+ {
+ internalType: "string",
+ name: "",
+ type: "string",
+ },
+ ],
+ stateMutability: "view",
+ type: "function",
+ },
+ {
+ inputs: [],
+ name: "wNative",
+ outputs: [
+ {
+ internalType: "address",
+ name: "",
+ type: "address",
+ },
+ ],
+ stateMutability: "view",
+ type: "function",
+ },
{
inputs: [
{
@@ -6100,7 +6844,7 @@ export default {
],
},
DisputeKitClassicUniversity_Proxy: {
- address: "0xd6E96b7c993763B5CDDa1139C7387B82A7c8B8B5",
+ address: "0x82F2089442979A6b56c80274D144575980092F91",
abi: [
{
inputs: [
@@ -15279,7 +16023,7 @@ export default {
],
},
DisputeResolverUniversity: {
- address: "0x2Aa1a94307E772BeE42E9EfbD137b1053F1fCfd4",
+ address: "0x8a7902Ef9a5308C7DF0A68A28EEDd6D83436993D",
abi: [
{
inputs: [
@@ -15297,6 +16041,31 @@ export default {
stateMutability: "nonpayable",
type: "constructor",
},
+ {
+ inputs: [],
+ name: "ArbitratorOnly",
+ type: "error",
+ },
+ {
+ inputs: [],
+ name: "DisputeAlreadyRuled",
+ type: "error",
+ },
+ {
+ inputs: [],
+ name: "OwnerOnly",
+ type: "error",
+ },
+ {
+ inputs: [],
+ name: "RulingOutOfBounds",
+ type: "error",
+ },
+ {
+ inputs: [],
+ name: "ShouldBeAtLeastTwoRulingOptions",
+ type: "error",
+ },
{
anonymous: false,
inputs: [
@@ -15324,12 +16093,6 @@ export default {
name: "_templateId",
type: "uint256",
},
- {
- indexed: false,
- internalType: "string",
- name: "_templateUri",
- type: "string",
- },
],
name: "DisputeRequest",
type: "event",
@@ -15408,11 +16171,11 @@ export default {
inputs: [
{
internalType: "address",
- name: "_governor",
+ name: "_owner",
type: "address",
},
],
- name: "changeGovernor",
+ name: "changeOwner",
outputs: [],
stateMutability: "nonpayable",
type: "function",
@@ -15464,35 +16227,6 @@ export default {
stateMutability: "payable",
type: "function",
},
- {
- inputs: [
- {
- internalType: "bytes",
- name: "_arbitratorExtraData",
- type: "bytes",
- },
- {
- internalType: "string",
- name: "_disputeTemplateUri",
- type: "string",
- },
- {
- internalType: "uint256",
- name: "_numberOfRulingOptions",
- type: "uint256",
- },
- ],
- name: "createDisputeForTemplateUri",
- outputs: [
- {
- internalType: "uint256",
- name: "disputeID",
- type: "uint256",
- },
- ],
- stateMutability: "payable",
- type: "function",
- },
{
inputs: [
{
@@ -15529,7 +16263,7 @@ export default {
},
{
inputs: [],
- name: "governor",
+ name: "owner",
outputs: [
{
internalType: "address",
@@ -15833,13 +16567,16 @@ export default {
},
],
},
- DisputeTemplateRegistry_Implementation: {
- address: "0xBc9B5643C9B1C478DAe1b950e886CC50D8d868b1",
+ DisputeTemplateRegistryUniversity: {
+ address: "0x75A5D16e9A699162506E4d79D68CF646e6600ba1",
abi: [
{
- inputs: [],
- stateMutability: "nonpayable",
- type: "constructor",
+ stateMutability: "payable",
+ type: "fallback",
+ },
+ {
+ stateMutability: "payable",
+ type: "receive",
},
{
inputs: [],
@@ -15867,6 +16604,11 @@ export default {
name: "NotInitializing",
type: "error",
},
+ {
+ inputs: [],
+ name: "OwnerOnly",
+ type: "error",
+ },
{
inputs: [],
name: "UUPSUnauthorizedCallContext",
@@ -15944,33 +16686,20 @@ export default {
inputs: [
{
internalType: "address",
- name: "_governor",
+ name: "_owner",
type: "address",
},
],
- name: "changeGovernor",
+ name: "changeOwner",
outputs: [],
stateMutability: "nonpayable",
type: "function",
},
- {
- inputs: [],
- name: "governor",
- outputs: [
- {
- internalType: "address",
- name: "",
- type: "address",
- },
- ],
- stateMutability: "view",
- type: "function",
- },
{
inputs: [
{
internalType: "address",
- name: "_governor",
+ name: "_owner",
type: "address",
},
],
@@ -15981,9 +16710,15 @@ export default {
},
{
inputs: [],
- name: "initialize2",
- outputs: [],
- stateMutability: "nonpayable",
+ name: "owner",
+ outputs: [
+ {
+ internalType: "address",
+ name: "",
+ type: "address",
+ },
+ ],
+ stateMutability: "view",
type: "function",
},
{
@@ -16072,11 +16807,6 @@ export default {
stateMutability: "view",
type: "function",
},
- ],
- },
- DisputeTemplateRegistry_Proxy: {
- address: "0xc852F94f90E3B06Da6eCfB61d76561ECfb94613f",
- abi: [
{
inputs: [
{
@@ -16093,26 +16823,15 @@ export default {
stateMutability: "nonpayable",
type: "constructor",
},
- {
- stateMutability: "payable",
- type: "fallback",
- },
- {
- stateMutability: "payable",
- type: "receive",
- },
],
},
- EvidenceModule: {
- address: "0xA1F72e0445fc395A393247F5B8c958Ec9b7C0B49",
+ DisputeTemplateRegistryUniversity_Implementation: {
+ address: "0xC3f638389635bF33E019c845FdaF2ed9bca3DF67",
abi: [
{
- stateMutability: "payable",
- type: "fallback",
- },
- {
- stateMutability: "payable",
- type: "receive",
+ inputs: [],
+ stateMutability: "nonpayable",
+ type: "constructor",
},
{
inputs: [],
@@ -16140,6 +16859,11 @@ export default {
name: "NotInitializing",
type: "error",
},
+ {
+ inputs: [],
+ name: "OwnerOnly",
+ type: "error",
+ },
{
inputs: [],
name: "UUPSUnauthorizedCallContext",
@@ -16162,23 +16886,29 @@ export default {
{
indexed: true,
internalType: "uint256",
- name: "_externalDisputeID",
+ name: "_templateId",
type: "uint256",
},
{
indexed: true,
- internalType: "address",
- name: "_party",
- type: "address",
+ internalType: "string",
+ name: "_templateTag",
+ type: "string",
},
{
indexed: false,
internalType: "string",
- name: "_evidence",
+ name: "_templateData",
+ type: "string",
+ },
+ {
+ indexed: false,
+ internalType: "string",
+ name: "_templateDataMappings",
type: "string",
},
],
- name: "Evidence",
+ name: "DisputeTemplate",
type: "event",
},
{
@@ -16208,23 +16938,23 @@ export default {
type: "event",
},
{
- inputs: [],
- name: "governor",
- outputs: [
+ inputs: [
{
internalType: "address",
- name: "",
+ name: "_owner",
type: "address",
},
],
- stateMutability: "view",
+ name: "changeOwner",
+ outputs: [],
+ stateMutability: "nonpayable",
type: "function",
},
{
inputs: [
{
internalType: "address",
- name: "_governor",
+ name: "_owner",
type: "address",
},
],
@@ -16235,9 +16965,15 @@ export default {
},
{
inputs: [],
- name: "initialize2",
- outputs: [],
- stateMutability: "nonpayable",
+ name: "owner",
+ outputs: [
+ {
+ internalType: "address",
+ name: "",
+ type: "address",
+ },
+ ],
+ stateMutability: "view",
type: "function",
},
{
@@ -16256,26 +16992,550 @@ export default {
{
inputs: [
{
- internalType: "uint256",
- name: "_externalDisputeID",
- type: "uint256",
+ internalType: "string",
+ name: "_templateTag",
+ type: "string",
},
{
internalType: "string",
- name: "_evidence",
+ name: "_templateData",
type: "string",
},
- ],
- name: "submitEvidence",
- outputs: [],
- stateMutability: "nonpayable",
- type: "function",
- },
- {
- inputs: [
{
- internalType: "address",
- name: "newImplementation",
+ internalType: "string",
+ name: "_templateDataMappings",
+ type: "string",
+ },
+ ],
+ name: "setDisputeTemplate",
+ outputs: [
+ {
+ internalType: "uint256",
+ name: "templateId",
+ type: "uint256",
+ },
+ ],
+ stateMutability: "nonpayable",
+ type: "function",
+ },
+ {
+ inputs: [],
+ name: "templates",
+ outputs: [
+ {
+ internalType: "uint256",
+ name: "",
+ type: "uint256",
+ },
+ ],
+ stateMutability: "view",
+ type: "function",
+ },
+ {
+ inputs: [
+ {
+ internalType: "address",
+ name: "newImplementation",
+ type: "address",
+ },
+ {
+ internalType: "bytes",
+ name: "data",
+ type: "bytes",
+ },
+ ],
+ name: "upgradeToAndCall",
+ outputs: [],
+ stateMutability: "payable",
+ type: "function",
+ },
+ {
+ inputs: [],
+ name: "version",
+ outputs: [
+ {
+ internalType: "string",
+ name: "",
+ type: "string",
+ },
+ ],
+ stateMutability: "view",
+ type: "function",
+ },
+ ],
+ },
+ DisputeTemplateRegistryUniversity_Proxy: {
+ address: "0x75A5D16e9A699162506E4d79D68CF646e6600ba1",
+ abi: [
+ {
+ inputs: [
+ {
+ internalType: "address",
+ name: "_implementation",
+ type: "address",
+ },
+ {
+ internalType: "bytes",
+ name: "_data",
+ type: "bytes",
+ },
+ ],
+ stateMutability: "nonpayable",
+ type: "constructor",
+ },
+ {
+ stateMutability: "payable",
+ type: "fallback",
+ },
+ {
+ stateMutability: "payable",
+ type: "receive",
+ },
+ ],
+ },
+ DisputeTemplateRegistry_Implementation: {
+ address: "0xBc9B5643C9B1C478DAe1b950e886CC50D8d868b1",
+ abi: [
+ {
+ inputs: [],
+ stateMutability: "nonpayable",
+ type: "constructor",
+ },
+ {
+ inputs: [],
+ name: "AlreadyInitialized",
+ type: "error",
+ },
+ {
+ inputs: [],
+ name: "FailedDelegateCall",
+ type: "error",
+ },
+ {
+ inputs: [
+ {
+ internalType: "address",
+ name: "implementation",
+ type: "address",
+ },
+ ],
+ name: "InvalidImplementation",
+ type: "error",
+ },
+ {
+ inputs: [],
+ name: "NotInitializing",
+ type: "error",
+ },
+ {
+ inputs: [],
+ name: "UUPSUnauthorizedCallContext",
+ type: "error",
+ },
+ {
+ inputs: [
+ {
+ internalType: "bytes32",
+ name: "slot",
+ type: "bytes32",
+ },
+ ],
+ name: "UUPSUnsupportedProxiableUUID",
+ type: "error",
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: "uint256",
+ name: "_templateId",
+ type: "uint256",
+ },
+ {
+ indexed: true,
+ internalType: "string",
+ name: "_templateTag",
+ type: "string",
+ },
+ {
+ indexed: false,
+ internalType: "string",
+ name: "_templateData",
+ type: "string",
+ },
+ {
+ indexed: false,
+ internalType: "string",
+ name: "_templateDataMappings",
+ type: "string",
+ },
+ ],
+ name: "DisputeTemplate",
+ type: "event",
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: false,
+ internalType: "uint64",
+ name: "version",
+ type: "uint64",
+ },
+ ],
+ name: "Initialized",
+ type: "event",
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: "address",
+ name: "newImplementation",
+ type: "address",
+ },
+ ],
+ name: "Upgraded",
+ type: "event",
+ },
+ {
+ inputs: [
+ {
+ internalType: "address",
+ name: "_governor",
+ type: "address",
+ },
+ ],
+ name: "changeGovernor",
+ outputs: [],
+ stateMutability: "nonpayable",
+ type: "function",
+ },
+ {
+ inputs: [],
+ name: "governor",
+ outputs: [
+ {
+ internalType: "address",
+ name: "",
+ type: "address",
+ },
+ ],
+ stateMutability: "view",
+ type: "function",
+ },
+ {
+ inputs: [
+ {
+ internalType: "address",
+ name: "_governor",
+ type: "address",
+ },
+ ],
+ name: "initialize",
+ outputs: [],
+ stateMutability: "nonpayable",
+ type: "function",
+ },
+ {
+ inputs: [],
+ name: "initialize2",
+ outputs: [],
+ stateMutability: "nonpayable",
+ type: "function",
+ },
+ {
+ inputs: [],
+ name: "proxiableUUID",
+ outputs: [
+ {
+ internalType: "bytes32",
+ name: "",
+ type: "bytes32",
+ },
+ ],
+ stateMutability: "view",
+ type: "function",
+ },
+ {
+ inputs: [
+ {
+ internalType: "string",
+ name: "_templateTag",
+ type: "string",
+ },
+ {
+ internalType: "string",
+ name: "_templateData",
+ type: "string",
+ },
+ {
+ internalType: "string",
+ name: "_templateDataMappings",
+ type: "string",
+ },
+ ],
+ name: "setDisputeTemplate",
+ outputs: [
+ {
+ internalType: "uint256",
+ name: "templateId",
+ type: "uint256",
+ },
+ ],
+ stateMutability: "nonpayable",
+ type: "function",
+ },
+ {
+ inputs: [],
+ name: "templates",
+ outputs: [
+ {
+ internalType: "uint256",
+ name: "",
+ type: "uint256",
+ },
+ ],
+ stateMutability: "view",
+ type: "function",
+ },
+ {
+ inputs: [
+ {
+ internalType: "address",
+ name: "newImplementation",
+ type: "address",
+ },
+ {
+ internalType: "bytes",
+ name: "data",
+ type: "bytes",
+ },
+ ],
+ name: "upgradeToAndCall",
+ outputs: [],
+ stateMutability: "payable",
+ type: "function",
+ },
+ {
+ inputs: [],
+ name: "version",
+ outputs: [
+ {
+ internalType: "string",
+ name: "",
+ type: "string",
+ },
+ ],
+ stateMutability: "view",
+ type: "function",
+ },
+ ],
+ },
+ DisputeTemplateRegistry_Proxy: {
+ address: "0xc852F94f90E3B06Da6eCfB61d76561ECfb94613f",
+ abi: [
+ {
+ inputs: [
+ {
+ internalType: "address",
+ name: "_implementation",
+ type: "address",
+ },
+ {
+ internalType: "bytes",
+ name: "_data",
+ type: "bytes",
+ },
+ ],
+ stateMutability: "nonpayable",
+ type: "constructor",
+ },
+ {
+ stateMutability: "payable",
+ type: "fallback",
+ },
+ {
+ stateMutability: "payable",
+ type: "receive",
+ },
+ ],
+ },
+ EvidenceModule: {
+ address: "0xA1F72e0445fc395A393247F5B8c958Ec9b7C0B49",
+ abi: [
+ {
+ stateMutability: "payable",
+ type: "fallback",
+ },
+ {
+ stateMutability: "payable",
+ type: "receive",
+ },
+ {
+ inputs: [],
+ name: "AlreadyInitialized",
+ type: "error",
+ },
+ {
+ inputs: [],
+ name: "FailedDelegateCall",
+ type: "error",
+ },
+ {
+ inputs: [
+ {
+ internalType: "address",
+ name: "implementation",
+ type: "address",
+ },
+ ],
+ name: "InvalidImplementation",
+ type: "error",
+ },
+ {
+ inputs: [],
+ name: "NotInitializing",
+ type: "error",
+ },
+ {
+ inputs: [],
+ name: "UUPSUnauthorizedCallContext",
+ type: "error",
+ },
+ {
+ inputs: [
+ {
+ internalType: "bytes32",
+ name: "slot",
+ type: "bytes32",
+ },
+ ],
+ name: "UUPSUnsupportedProxiableUUID",
+ type: "error",
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: "uint256",
+ name: "_externalDisputeID",
+ type: "uint256",
+ },
+ {
+ indexed: true,
+ internalType: "address",
+ name: "_party",
+ type: "address",
+ },
+ {
+ indexed: false,
+ internalType: "string",
+ name: "_evidence",
+ type: "string",
+ },
+ ],
+ name: "Evidence",
+ type: "event",
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: false,
+ internalType: "uint64",
+ name: "version",
+ type: "uint64",
+ },
+ ],
+ name: "Initialized",
+ type: "event",
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: "address",
+ name: "newImplementation",
+ type: "address",
+ },
+ ],
+ name: "Upgraded",
+ type: "event",
+ },
+ {
+ inputs: [],
+ name: "governor",
+ outputs: [
+ {
+ internalType: "address",
+ name: "",
+ type: "address",
+ },
+ ],
+ stateMutability: "view",
+ type: "function",
+ },
+ {
+ inputs: [
+ {
+ internalType: "address",
+ name: "_governor",
+ type: "address",
+ },
+ ],
+ name: "initialize",
+ outputs: [],
+ stateMutability: "nonpayable",
+ type: "function",
+ },
+ {
+ inputs: [],
+ name: "initialize2",
+ outputs: [],
+ stateMutability: "nonpayable",
+ type: "function",
+ },
+ {
+ inputs: [],
+ name: "proxiableUUID",
+ outputs: [
+ {
+ internalType: "bytes32",
+ name: "",
+ type: "bytes32",
+ },
+ ],
+ stateMutability: "view",
+ type: "function",
+ },
+ {
+ inputs: [
+ {
+ internalType: "uint256",
+ name: "_externalDisputeID",
+ type: "uint256",
+ },
+ {
+ internalType: "string",
+ name: "_evidence",
+ type: "string",
+ },
+ ],
+ name: "submitEvidence",
+ outputs: [],
+ stateMutability: "nonpayable",
+ type: "function",
+ },
+ {
+ inputs: [
+ {
+ internalType: "address",
+ name: "newImplementation",
type: "address",
},
{
@@ -21727,7 +22987,7 @@ export default {
],
},
KlerosCoreUniversity: {
- address: "0x5AB37F38778Bc175852fA353056591D91c744ce6",
+ address: "0xA34dBBD0E5e1d09bd683455f9dbC393797BC558f",
abi: [
{
stateMutability: "payable",
@@ -21762,11 +23022,6 @@ export default {
name: "ArbitrationFeesNotEnough",
type: "error",
},
- {
- inputs: [],
- name: "ArraysLengthMismatch",
- type: "error",
- },
{
inputs: [],
name: "CannotDisableClassicDK",
@@ -21777,11 +23032,6 @@ export default {
name: "CommitPeriodNotPassed",
type: "error",
},
- {
- inputs: [],
- name: "DepthLevelMax",
- type: "error",
- },
{
inputs: [],
name: "DisputeKitNotSupportedByCourt",
@@ -21817,16 +23067,6 @@ export default {
name: "FailedDelegateCall",
type: "error",
},
- {
- inputs: [],
- name: "GovernorOnly",
- type: "error",
- },
- {
- inputs: [],
- name: "GovernorOrInstructorOnly",
- type: "error",
- },
{
inputs: [],
name: "InstructorOnly",
@@ -21883,6 +23123,16 @@ export default {
name: "NotInitializing",
type: "error",
},
+ {
+ inputs: [],
+ name: "OwnerOnly",
+ type: "error",
+ },
+ {
+ inputs: [],
+ name: "OwnerOrInstructorOnly",
+ type: "error",
+ },
{
inputs: [],
name: "RulingAlreadyExecuted",
@@ -21905,7 +23155,7 @@ export default {
},
{
inputs: [],
- name: "StakingNotPossibeInThisCourt",
+ name: "StakingNotPossibleInThisCourt",
type: "error",
},
{
@@ -21913,6 +23163,11 @@ export default {
name: "StakingTransferFailed",
type: "error",
},
+ {
+ inputs: [],
+ name: "StakingZeroWhenNoStake",
+ type: "error",
+ },
{
inputs: [],
name: "TokenNotAccepted",
@@ -22026,9 +23281,9 @@ export default {
inputs: [
{
indexed: true,
- internalType: "uint256",
+ internalType: "uint96",
name: "_courtID",
- type: "uint256",
+ type: "uint96",
},
{
indexed: true,
@@ -22303,6 +23558,12 @@ export default {
{
anonymous: false,
inputs: [
+ {
+ indexed: true,
+ internalType: "address",
+ name: "_account",
+ type: "address",
+ },
{
indexed: true,
internalType: "uint256",
@@ -22318,13 +23579,62 @@ export default {
{
indexed: false,
internalType: "uint256",
- name: "_pnkAmount",
+ name: "_degreeOfCoherencyPnk",
type: "uint256",
},
{
indexed: false,
internalType: "uint256",
- name: "_feeAmount",
+ name: "_degreeOfCoherencyFee",
+ type: "uint256",
+ },
+ {
+ indexed: false,
+ internalType: "int256",
+ name: "_amountPnk",
+ type: "int256",
+ },
+ {
+ indexed: false,
+ internalType: "int256",
+ name: "_amountFee",
+ type: "int256",
+ },
+ {
+ indexed: false,
+ internalType: "contract IERC20",
+ name: "_feeToken",
+ type: "address",
+ },
+ ],
+ name: "JurorRewardPenalty",
+ type: "event",
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: "uint256",
+ name: "_disputeID",
+ type: "uint256",
+ },
+ {
+ indexed: true,
+ internalType: "uint256",
+ name: "_roundID",
+ type: "uint256",
+ },
+ {
+ indexed: false,
+ internalType: "uint256",
+ name: "_amountPnk",
+ type: "uint256",
+ },
+ {
+ indexed: false,
+ internalType: "uint256",
+ name: "_amountFee",
type: "uint256",
},
{
@@ -22383,76 +23693,27 @@ export default {
},
{
anonymous: false,
- inputs: [
- {
- indexed: true,
- internalType: "contract IArbitrableV2",
- name: "_arbitrable",
- type: "address",
- },
- {
- indexed: true,
- internalType: "uint256",
- name: "_disputeID",
- type: "uint256",
- },
- {
- indexed: false,
- internalType: "uint256",
- name: "_ruling",
- type: "uint256",
- },
- ],
- name: "Ruling",
- type: "event",
- },
- {
- anonymous: false,
- inputs: [
- {
- indexed: true,
- internalType: "address",
- name: "_account",
- type: "address",
- },
+ inputs: [
{
indexed: true,
- internalType: "uint256",
- name: "_disputeID",
- type: "uint256",
+ internalType: "contract IArbitrableV2",
+ name: "_arbitrable",
+ type: "address",
},
{
indexed: true,
internalType: "uint256",
- name: "_roundID",
+ name: "_disputeID",
type: "uint256",
},
{
indexed: false,
internalType: "uint256",
- name: "_degreeOfCoherency",
+ name: "_ruling",
type: "uint256",
},
- {
- indexed: false,
- internalType: "int256",
- name: "_pnkAmount",
- type: "int256",
- },
- {
- indexed: false,
- internalType: "int256",
- name: "_feeAmount",
- type: "int256",
- },
- {
- indexed: false,
- internalType: "contract IERC20",
- name: "_feeToken",
- type: "address",
- },
],
- name: "TokenAndETHShift",
+ name: "Ruling",
type: "event",
},
{
@@ -22677,12 +23938,12 @@ export default {
{
inputs: [
{
- internalType: "address payable",
- name: "_governor",
+ internalType: "address",
+ name: "_instructor",
type: "address",
},
],
- name: "changeGovernor",
+ name: "changeInstructor",
outputs: [],
stateMutability: "nonpayable",
type: "function",
@@ -22691,11 +23952,11 @@ export default {
inputs: [
{
internalType: "address",
- name: "_instructor",
+ name: "_jurorProsecutionModule",
type: "address",
},
],
- name: "changeInstructor",
+ name: "changeJurorProsecutionModule",
outputs: [],
stateMutability: "nonpayable",
type: "function",
@@ -22703,12 +23964,12 @@ export default {
{
inputs: [
{
- internalType: "address",
- name: "_jurorProsecutionModule",
+ internalType: "address payable",
+ name: "_owner",
type: "address",
},
],
- name: "changeJurorProsecutionModule",
+ name: "changeOwner",
outputs: [],
stateMutability: "nonpayable",
type: "function",
@@ -22803,11 +24064,6 @@ export default {
name: "jurorsForCourtJump",
type: "uint256",
},
- {
- internalType: "bool",
- name: "disabled",
- type: "bool",
- },
],
stateMutability: "view",
type: "function",
@@ -23116,7 +24372,7 @@ export default {
type: "bytes",
},
],
- name: "executeGovernorProposal",
+ name: "executeOwnerProposal",
outputs: [],
stateMutability: "nonpayable",
type: "function",
@@ -23185,6 +24441,30 @@ export default {
stateMutability: "view",
type: "function",
},
+ {
+ inputs: [
+ {
+ internalType: "uint256",
+ name: "_disputeID",
+ type: "uint256",
+ },
+ {
+ internalType: "uint256",
+ name: "_round",
+ type: "uint256",
+ },
+ ],
+ name: "getPnkAtStakePerJuror",
+ outputs: [
+ {
+ internalType: "uint256",
+ name: "",
+ type: "uint256",
+ },
+ ],
+ stateMutability: "view",
+ type: "function",
+ },
{
inputs: [
{
@@ -23237,6 +24517,11 @@ export default {
name: "drawnJurors",
type: "address[]",
},
+ {
+ internalType: "uint96[]",
+ name: "drawnJurorFromCourtIDs",
+ type: "uint96[]",
+ },
{
internalType: "uint256",
name: "sumFeeRewardPaid",
@@ -23257,6 +24542,11 @@ export default {
name: "drawIterations",
type: "uint256",
},
+ {
+ internalType: "uint256[10]",
+ name: "__gap",
+ type: "uint256[10]",
+ },
],
internalType: "struct KlerosCoreUniversity.Round",
name: "",
@@ -23285,24 +24575,11 @@ export default {
stateMutability: "view",
type: "function",
},
- {
- inputs: [],
- name: "governor",
- outputs: [
- {
- internalType: "address",
- name: "",
- type: "address",
- },
- ],
- stateMutability: "view",
- type: "function",
- },
{
inputs: [
{
internalType: "address",
- name: "_governor",
+ name: "_owner",
type: "address",
},
{
@@ -23420,6 +24697,19 @@ export default {
stateMutability: "view",
type: "function",
},
+ {
+ inputs: [],
+ name: "owner",
+ outputs: [
+ {
+ internalType: "address",
+ name: "",
+ type: "address",
+ },
+ ],
+ stateMutability: "view",
+ type: "function",
+ },
{
inputs: [
{
@@ -23494,11 +24784,6 @@ export default {
name: "_newStake",
type: "uint256",
},
- {
- internalType: "bool",
- name: "_alreadyTransferred",
- type: "bool",
- },
],
name: "setStakeBySortitionModule",
outputs: [],
@@ -23518,6 +24803,24 @@ export default {
stateMutability: "view",
type: "function",
},
+ {
+ inputs: [
+ {
+ internalType: "address",
+ name: "_account",
+ type: "address",
+ },
+ {
+ internalType: "uint256",
+ name: "_amount",
+ type: "uint256",
+ },
+ ],
+ name: "transferBySortitionModule",
+ outputs: [],
+ stateMutability: "nonpayable",
+ type: "function",
+ },
{
inputs: [
{
@@ -23536,6 +24839,19 @@ export default {
stateMutability: "payable",
type: "function",
},
+ {
+ inputs: [],
+ name: "version",
+ outputs: [
+ {
+ internalType: "string",
+ name: "",
+ type: "string",
+ },
+ ],
+ stateMutability: "view",
+ type: "function",
+ },
{
inputs: [
{
@@ -23555,7 +24871,7 @@ export default {
],
},
KlerosCoreUniversity_Implementation: {
- address: "0xF74DaBfC5F5dbdBD07636637204d9C35326D2906",
+ address: "0xb75b0cc01af4aD0D65D50082ae0717004D479Aa0",
abi: [
{
inputs: [],
@@ -23587,11 +24903,6 @@ export default {
name: "ArbitrationFeesNotEnough",
type: "error",
},
- {
- inputs: [],
- name: "ArraysLengthMismatch",
- type: "error",
- },
{
inputs: [],
name: "CannotDisableClassicDK",
@@ -23602,11 +24913,6 @@ export default {
name: "CommitPeriodNotPassed",
type: "error",
},
- {
- inputs: [],
- name: "DepthLevelMax",
- type: "error",
- },
{
inputs: [],
name: "DisputeKitNotSupportedByCourt",
@@ -23642,16 +24948,6 @@ export default {
name: "FailedDelegateCall",
type: "error",
},
- {
- inputs: [],
- name: "GovernorOnly",
- type: "error",
- },
- {
- inputs: [],
- name: "GovernorOrInstructorOnly",
- type: "error",
- },
{
inputs: [],
name: "InstructorOnly",
@@ -23708,6 +25004,16 @@ export default {
name: "NotInitializing",
type: "error",
},
+ {
+ inputs: [],
+ name: "OwnerOnly",
+ type: "error",
+ },
+ {
+ inputs: [],
+ name: "OwnerOrInstructorOnly",
+ type: "error",
+ },
{
inputs: [],
name: "RulingAlreadyExecuted",
@@ -23730,7 +25036,7 @@ export default {
},
{
inputs: [],
- name: "StakingNotPossibeInThisCourt",
+ name: "StakingNotPossibleInThisCourt",
type: "error",
},
{
@@ -23738,6 +25044,11 @@ export default {
name: "StakingTransferFailed",
type: "error",
},
+ {
+ inputs: [],
+ name: "StakingZeroWhenNoStake",
+ type: "error",
+ },
{
inputs: [],
name: "TokenNotAccepted",
@@ -23851,9 +25162,9 @@ export default {
inputs: [
{
indexed: true,
- internalType: "uint256",
+ internalType: "uint96",
name: "_courtID",
- type: "uint256",
+ type: "uint96",
},
{
indexed: true,
@@ -24128,6 +25439,12 @@ export default {
{
anonymous: false,
inputs: [
+ {
+ indexed: true,
+ internalType: "address",
+ name: "_account",
+ type: "address",
+ },
{
indexed: true,
internalType: "uint256",
@@ -24143,15 +25460,27 @@ export default {
{
indexed: false,
internalType: "uint256",
- name: "_pnkAmount",
+ name: "_degreeOfCoherencyPnk",
type: "uint256",
},
{
indexed: false,
internalType: "uint256",
- name: "_feeAmount",
+ name: "_degreeOfCoherencyFee",
type: "uint256",
},
+ {
+ indexed: false,
+ internalType: "int256",
+ name: "_amountPnk",
+ type: "int256",
+ },
+ {
+ indexed: false,
+ internalType: "int256",
+ name: "_amountFee",
+ type: "int256",
+ },
{
indexed: false,
internalType: "contract IERC20",
@@ -24159,7 +25488,7 @@ export default {
type: "address",
},
],
- name: "LeftoverRewardSent",
+ name: "JurorRewardPenalty",
type: "event",
},
{
@@ -24167,24 +25496,36 @@ export default {
inputs: [
{
indexed: true,
- internalType: "contract IERC20",
- name: "_feeToken",
- type: "address",
+ internalType: "uint256",
+ name: "_disputeID",
+ type: "uint256",
+ },
+ {
+ indexed: true,
+ internalType: "uint256",
+ name: "_roundID",
+ type: "uint256",
},
{
indexed: false,
- internalType: "uint64",
- name: "_rateInEth",
- type: "uint64",
+ internalType: "uint256",
+ name: "_amountPnk",
+ type: "uint256",
},
{
indexed: false,
- internalType: "uint8",
- name: "_rateDecimals",
- type: "uint8",
+ internalType: "uint256",
+ name: "_amountFee",
+ type: "uint256",
+ },
+ {
+ indexed: false,
+ internalType: "contract IERC20",
+ name: "_feeToken",
+ type: "address",
},
],
- name: "NewCurrencyRate",
+ name: "LeftoverRewardSent",
type: "event",
},
{
@@ -24192,43 +25533,43 @@ export default {
inputs: [
{
indexed: true,
- internalType: "uint256",
- name: "_disputeID",
- type: "uint256",
+ internalType: "contract IERC20",
+ name: "_feeToken",
+ type: "address",
},
{
indexed: false,
- internalType: "enum KlerosCoreUniversity.Period",
- name: "_period",
+ internalType: "uint64",
+ name: "_rateInEth",
+ type: "uint64",
+ },
+ {
+ indexed: false,
+ internalType: "uint8",
+ name: "_rateDecimals",
type: "uint8",
},
],
- name: "NewPeriod",
+ name: "NewCurrencyRate",
type: "event",
},
{
anonymous: false,
inputs: [
- {
- indexed: true,
- internalType: "contract IArbitrableV2",
- name: "_arbitrable",
- type: "address",
- },
{
indexed: true,
internalType: "uint256",
name: "_disputeID",
type: "uint256",
},
- {
- indexed: false,
- internalType: "uint256",
- name: "_ruling",
- type: "uint256",
+ {
+ indexed: false,
+ internalType: "enum KlerosCoreUniversity.Period",
+ name: "_period",
+ type: "uint8",
},
],
- name: "Ruling",
+ name: "NewPeriod",
type: "event",
},
{
@@ -24236,8 +25577,8 @@ export default {
inputs: [
{
indexed: true,
- internalType: "address",
- name: "_account",
+ internalType: "contract IArbitrableV2",
+ name: "_arbitrable",
type: "address",
},
{
@@ -24246,38 +25587,14 @@ export default {
name: "_disputeID",
type: "uint256",
},
- {
- indexed: true,
- internalType: "uint256",
- name: "_roundID",
- type: "uint256",
- },
{
indexed: false,
internalType: "uint256",
- name: "_degreeOfCoherency",
+ name: "_ruling",
type: "uint256",
},
- {
- indexed: false,
- internalType: "int256",
- name: "_pnkAmount",
- type: "int256",
- },
- {
- indexed: false,
- internalType: "int256",
- name: "_feeAmount",
- type: "int256",
- },
- {
- indexed: false,
- internalType: "contract IERC20",
- name: "_feeToken",
- type: "address",
- },
],
- name: "TokenAndETHShift",
+ name: "Ruling",
type: "event",
},
{
@@ -24502,12 +25819,12 @@ export default {
{
inputs: [
{
- internalType: "address payable",
- name: "_governor",
+ internalType: "address",
+ name: "_instructor",
type: "address",
},
],
- name: "changeGovernor",
+ name: "changeInstructor",
outputs: [],
stateMutability: "nonpayable",
type: "function",
@@ -24516,11 +25833,11 @@ export default {
inputs: [
{
internalType: "address",
- name: "_instructor",
+ name: "_jurorProsecutionModule",
type: "address",
},
],
- name: "changeInstructor",
+ name: "changeJurorProsecutionModule",
outputs: [],
stateMutability: "nonpayable",
type: "function",
@@ -24528,12 +25845,12 @@ export default {
{
inputs: [
{
- internalType: "address",
- name: "_jurorProsecutionModule",
+ internalType: "address payable",
+ name: "_owner",
type: "address",
},
],
- name: "changeJurorProsecutionModule",
+ name: "changeOwner",
outputs: [],
stateMutability: "nonpayable",
type: "function",
@@ -24628,11 +25945,6 @@ export default {
name: "jurorsForCourtJump",
type: "uint256",
},
- {
- internalType: "bool",
- name: "disabled",
- type: "bool",
- },
],
stateMutability: "view",
type: "function",
@@ -24941,7 +26253,7 @@ export default {
type: "bytes",
},
],
- name: "executeGovernorProposal",
+ name: "executeOwnerProposal",
outputs: [],
stateMutability: "nonpayable",
type: "function",
@@ -25010,6 +26322,30 @@ export default {
stateMutability: "view",
type: "function",
},
+ {
+ inputs: [
+ {
+ internalType: "uint256",
+ name: "_disputeID",
+ type: "uint256",
+ },
+ {
+ internalType: "uint256",
+ name: "_round",
+ type: "uint256",
+ },
+ ],
+ name: "getPnkAtStakePerJuror",
+ outputs: [
+ {
+ internalType: "uint256",
+ name: "",
+ type: "uint256",
+ },
+ ],
+ stateMutability: "view",
+ type: "function",
+ },
{
inputs: [
{
@@ -25062,6 +26398,11 @@ export default {
name: "drawnJurors",
type: "address[]",
},
+ {
+ internalType: "uint96[]",
+ name: "drawnJurorFromCourtIDs",
+ type: "uint96[]",
+ },
{
internalType: "uint256",
name: "sumFeeRewardPaid",
@@ -25082,6 +26423,11 @@ export default {
name: "drawIterations",
type: "uint256",
},
+ {
+ internalType: "uint256[10]",
+ name: "__gap",
+ type: "uint256[10]",
+ },
],
internalType: "struct KlerosCoreUniversity.Round",
name: "",
@@ -25110,24 +26456,11 @@ export default {
stateMutability: "view",
type: "function",
},
- {
- inputs: [],
- name: "governor",
- outputs: [
- {
- internalType: "address",
- name: "",
- type: "address",
- },
- ],
- stateMutability: "view",
- type: "function",
- },
{
inputs: [
{
internalType: "address",
- name: "_governor",
+ name: "_owner",
type: "address",
},
{
@@ -25245,6 +26578,19 @@ export default {
stateMutability: "view",
type: "function",
},
+ {
+ inputs: [],
+ name: "owner",
+ outputs: [
+ {
+ internalType: "address",
+ name: "",
+ type: "address",
+ },
+ ],
+ stateMutability: "view",
+ type: "function",
+ },
{
inputs: [
{
@@ -25319,11 +26665,6 @@ export default {
name: "_newStake",
type: "uint256",
},
- {
- internalType: "bool",
- name: "_alreadyTransferred",
- type: "bool",
- },
],
name: "setStakeBySortitionModule",
outputs: [],
@@ -25343,6 +26684,24 @@ export default {
stateMutability: "view",
type: "function",
},
+ {
+ inputs: [
+ {
+ internalType: "address",
+ name: "_account",
+ type: "address",
+ },
+ {
+ internalType: "uint256",
+ name: "_amount",
+ type: "uint256",
+ },
+ ],
+ name: "transferBySortitionModule",
+ outputs: [],
+ stateMutability: "nonpayable",
+ type: "function",
+ },
{
inputs: [
{
@@ -25361,10 +26720,23 @@ export default {
stateMutability: "payable",
type: "function",
},
+ {
+ inputs: [],
+ name: "version",
+ outputs: [
+ {
+ internalType: "string",
+ name: "",
+ type: "string",
+ },
+ ],
+ stateMutability: "view",
+ type: "function",
+ },
],
},
KlerosCoreUniversity_Proxy: {
- address: "0x5AB37F38778Bc175852fA353056591D91c744ce6",
+ address: "0xA34dBBD0E5e1d09bd683455f9dbC393797BC558f",
abi: [
{
inputs: [
@@ -30005,7 +31377,7 @@ export default {
],
},
SortitionModuleUniversity: {
- address: "0x4B2c2d048921f694cCE3AEa35698c6B1f5fcbb79",
+ address: "0x9f55804177e7E44E558616cD7d06B865788214cA",
abi: [
{
stateMutability: "payable",
@@ -30036,11 +31408,26 @@ export default {
name: "InvalidImplementation",
type: "error",
},
+ {
+ inputs: [],
+ name: "KlerosCoreOnly",
+ type: "error",
+ },
+ {
+ inputs: [],
+ name: "NotEligibleForWithdrawal",
+ type: "error",
+ },
{
inputs: [],
name: "NotInitializing",
type: "error",
},
+ {
+ inputs: [],
+ name: "OwnerOnly",
+ type: "error",
+ },
{
inputs: [],
name: "UUPSUnauthorizedCallContext",
@@ -30070,6 +31457,44 @@ export default {
name: "Initialized",
type: "event",
},
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: "address",
+ name: "_account",
+ type: "address",
+ },
+ {
+ indexed: false,
+ internalType: "uint256",
+ name: "_amount",
+ type: "uint256",
+ },
+ ],
+ name: "LeftoverPNK",
+ type: "event",
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: "address",
+ name: "_account",
+ type: "address",
+ },
+ {
+ indexed: false,
+ internalType: "uint256",
+ name: "_amount",
+ type: "uint256",
+ },
+ ],
+ name: "LeftoverPNKWithdrawn",
+ type: "event",
+ },
{
anonymous: false,
inputs: [
@@ -30129,6 +31554,12 @@ export default {
name: "_amount",
type: "uint256",
},
+ {
+ indexed: false,
+ internalType: "uint256",
+ name: "_amountAllCourts",
+ type: "uint256",
+ },
],
name: "StakeSet",
type: "event",
@@ -30180,9 +31611,9 @@ export default {
{
inputs: [
{
- internalType: "bytes32",
- name: "_key",
- type: "bytes32",
+ internalType: "uint96",
+ name: "_courtID",
+ type: "uint96",
},
{
internalType: "bytes",
@@ -30201,40 +31632,89 @@ export default {
outputs: [
{
internalType: "uint256",
- name: "",
+ name: "",
+ type: "uint256",
+ },
+ ],
+ stateMutability: "view",
+ type: "function",
+ },
+ {
+ inputs: [
+ {
+ internalType: "uint96",
+ name: "",
+ type: "uint96",
+ },
+ {
+ internalType: "uint256",
+ name: "",
+ type: "uint256",
+ },
+ {
+ internalType: "uint256",
+ name: "",
+ type: "uint256",
+ },
+ ],
+ name: "draw",
+ outputs: [
+ {
+ internalType: "address",
+ name: "drawnAddress",
+ type: "address",
+ },
+ {
+ internalType: "uint96",
+ name: "fromSubcourtID",
+ type: "uint96",
+ },
+ ],
+ stateMutability: "view",
+ type: "function",
+ },
+ {
+ inputs: [
+ {
+ internalType: "uint256",
+ name: "_iterations",
type: "uint256",
},
],
- stateMutability: "view",
+ name: "executeDelayedStakes",
+ outputs: [],
+ stateMutability: "nonpayable",
type: "function",
},
{
inputs: [
{
- internalType: "bytes32",
- name: "",
- type: "bytes32",
- },
- {
- internalType: "uint256",
- name: "",
- type: "uint256",
+ internalType: "address",
+ name: "_account",
+ type: "address",
},
{
- internalType: "uint256",
- name: "",
- type: "uint256",
+ internalType: "uint96",
+ name: "_courtID",
+ type: "uint96",
},
],
- name: "draw",
- outputs: [
+ name: "forcedUnstake",
+ outputs: [],
+ stateMutability: "nonpayable",
+ type: "function",
+ },
+ {
+ inputs: [
{
internalType: "address",
- name: "drawnAddress",
+ name: "_account",
type: "address",
},
],
- stateMutability: "view",
+ name: "forcedUnstakeAllCourts",
+ outputs: [],
+ stateMutability: "nonpayable",
type: "function",
},
{
@@ -30296,15 +31776,21 @@ export default {
type: "function",
},
{
- inputs: [],
- name: "governor",
- outputs: [
+ inputs: [
{
internalType: "address",
- name: "",
+ name: "_juror",
type: "address",
},
],
+ name: "getJurorLeftoverPNK",
+ outputs: [
+ {
+ internalType: "uint256",
+ name: "",
+ type: "uint256",
+ },
+ ],
stateMutability: "view",
type: "function",
},
@@ -30312,7 +31798,7 @@ export default {
inputs: [
{
internalType: "address",
- name: "_governor",
+ name: "_owner",
type: "address",
},
{
@@ -30388,32 +31874,21 @@ export default {
type: "function",
},
{
- inputs: [
+ inputs: [],
+ name: "owner",
+ outputs: [
{
- internalType: "uint256",
- name: "_randomNumber",
- type: "uint256",
+ internalType: "address",
+ name: "",
+ type: "address",
},
],
- name: "notifyRandomNumber",
- outputs: [],
- stateMutability: "nonpayable",
+ stateMutability: "view",
type: "function",
},
{
- inputs: [
- {
- internalType: "address",
- name: "_account",
- type: "address",
- },
- {
- internalType: "uint256",
- name: "_relativeAmount",
- type: "uint256",
- },
- ],
- name: "penalizeStake",
+ inputs: [],
+ name: "passPhase",
outputs: [],
stateMutability: "nonpayable",
type: "function",
@@ -30456,8 +31931,28 @@ export default {
name: "_account",
type: "address",
},
+ {
+ internalType: "uint96",
+ name: "_courtID",
+ type: "uint96",
+ },
+ {
+ internalType: "uint256",
+ name: "_pnkDeposit",
+ type: "uint256",
+ },
+ {
+ internalType: "uint256",
+ name: "_pnkWithdrawal",
+ type: "uint256",
+ },
+ {
+ internalType: "uint256",
+ name: "_newStake",
+ type: "uint256",
+ },
],
- name: "setJurorInactive",
+ name: "setStake",
outputs: [],
stateMutability: "nonpayable",
type: "function",
@@ -30476,31 +31971,55 @@ export default {
},
{
internalType: "uint256",
- name: "_newStake",
+ name: "_penalty",
type: "uint256",
},
- {
- internalType: "bool",
- name: "_alreadyTransferred",
- type: "bool",
- },
],
- name: "setStake",
+ name: "setStakePenalty",
outputs: [
{
internalType: "uint256",
- name: "pnkDeposit",
+ name: "pnkBalance",
type: "uint256",
},
{
internalType: "uint256",
- name: "pnkWithdrawal",
+ name: "newCourtStake",
type: "uint256",
},
{
- internalType: "enum StakingResult",
- name: "stakingResult",
- type: "uint8",
+ internalType: "uint256",
+ name: "availablePenalty",
+ type: "uint256",
+ },
+ ],
+ stateMutability: "nonpayable",
+ type: "function",
+ },
+ {
+ inputs: [
+ {
+ internalType: "address",
+ name: "_account",
+ type: "address",
+ },
+ {
+ internalType: "uint96",
+ name: "_courtID",
+ type: "uint96",
+ },
+ {
+ internalType: "uint256",
+ name: "_reward",
+ type: "uint256",
+ },
+ ],
+ name: "setStakeReward",
+ outputs: [
+ {
+ internalType: "bool",
+ name: "success",
+ type: "bool",
},
],
stateMutability: "nonpayable",
@@ -30555,6 +32074,76 @@ export default {
stateMutability: "payable",
type: "function",
},
+ {
+ inputs: [
+ {
+ internalType: "address",
+ name: "_account",
+ type: "address",
+ },
+ {
+ internalType: "uint96",
+ name: "_courtID",
+ type: "uint96",
+ },
+ {
+ internalType: "uint256",
+ name: "_newStake",
+ type: "uint256",
+ },
+ {
+ internalType: "bool",
+ name: "",
+ type: "bool",
+ },
+ ],
+ name: "validateStake",
+ outputs: [
+ {
+ internalType: "uint256",
+ name: "pnkDeposit",
+ type: "uint256",
+ },
+ {
+ internalType: "uint256",
+ name: "pnkWithdrawal",
+ type: "uint256",
+ },
+ {
+ internalType: "enum StakingResult",
+ name: "stakingResult",
+ type: "uint8",
+ },
+ ],
+ stateMutability: "view",
+ type: "function",
+ },
+ {
+ inputs: [],
+ name: "version",
+ outputs: [
+ {
+ internalType: "string",
+ name: "",
+ type: "string",
+ },
+ ],
+ stateMutability: "view",
+ type: "function",
+ },
+ {
+ inputs: [
+ {
+ internalType: "address",
+ name: "_account",
+ type: "address",
+ },
+ ],
+ name: "withdrawLeftoverPNK",
+ outputs: [],
+ stateMutability: "nonpayable",
+ type: "function",
+ },
{
inputs: [
{
@@ -30574,7 +32163,7 @@ export default {
],
},
SortitionModuleUniversity_Implementation: {
- address: "0x5CAD621D69E0535422aCFaCC0017bC32beC7A486",
+ address: "0x270e3D63d3d275604df0a1Bd312E1255DCd96936",
abi: [
{
inputs: [],
@@ -30602,11 +32191,26 @@ export default {
name: "InvalidImplementation",
type: "error",
},
+ {
+ inputs: [],
+ name: "KlerosCoreOnly",
+ type: "error",
+ },
+ {
+ inputs: [],
+ name: "NotEligibleForWithdrawal",
+ type: "error",
+ },
{
inputs: [],
name: "NotInitializing",
type: "error",
},
+ {
+ inputs: [],
+ name: "OwnerOnly",
+ type: "error",
+ },
{
inputs: [],
name: "UUPSUnauthorizedCallContext",
@@ -30628,12 +32232,50 @@ export default {
inputs: [
{
indexed: false,
- internalType: "uint64",
- name: "version",
- type: "uint64",
+ internalType: "uint64",
+ name: "version",
+ type: "uint64",
+ },
+ ],
+ name: "Initialized",
+ type: "event",
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: "address",
+ name: "_account",
+ type: "address",
+ },
+ {
+ indexed: false,
+ internalType: "uint256",
+ name: "_amount",
+ type: "uint256",
+ },
+ ],
+ name: "LeftoverPNK",
+ type: "event",
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: "address",
+ name: "_account",
+ type: "address",
+ },
+ {
+ indexed: false,
+ internalType: "uint256",
+ name: "_amount",
+ type: "uint256",
},
],
- name: "Initialized",
+ name: "LeftoverPNKWithdrawn",
type: "event",
},
{
@@ -30695,6 +32337,12 @@ export default {
name: "_amount",
type: "uint256",
},
+ {
+ indexed: false,
+ internalType: "uint256",
+ name: "_amountAllCourts",
+ type: "uint256",
+ },
],
name: "StakeSet",
type: "event",
@@ -30746,9 +32394,9 @@ export default {
{
inputs: [
{
- internalType: "bytes32",
- name: "_key",
- type: "bytes32",
+ internalType: "uint96",
+ name: "_courtID",
+ type: "uint96",
},
{
internalType: "bytes",
@@ -30777,9 +32425,9 @@ export default {
{
inputs: [
{
- internalType: "bytes32",
+ internalType: "uint96",
name: "",
- type: "bytes32",
+ type: "uint96",
},
{
internalType: "uint256",
@@ -30799,10 +32447,59 @@ export default {
name: "drawnAddress",
type: "address",
},
+ {
+ internalType: "uint96",
+ name: "fromSubcourtID",
+ type: "uint96",
+ },
],
stateMutability: "view",
type: "function",
},
+ {
+ inputs: [
+ {
+ internalType: "uint256",
+ name: "_iterations",
+ type: "uint256",
+ },
+ ],
+ name: "executeDelayedStakes",
+ outputs: [],
+ stateMutability: "nonpayable",
+ type: "function",
+ },
+ {
+ inputs: [
+ {
+ internalType: "address",
+ name: "_account",
+ type: "address",
+ },
+ {
+ internalType: "uint96",
+ name: "_courtID",
+ type: "uint96",
+ },
+ ],
+ name: "forcedUnstake",
+ outputs: [],
+ stateMutability: "nonpayable",
+ type: "function",
+ },
+ {
+ inputs: [
+ {
+ internalType: "address",
+ name: "_account",
+ type: "address",
+ },
+ ],
+ name: "forcedUnstakeAllCourts",
+ outputs: [],
+ stateMutability: "nonpayable",
+ type: "function",
+ },
{
inputs: [
{
@@ -30862,15 +32559,21 @@ export default {
type: "function",
},
{
- inputs: [],
- name: "governor",
- outputs: [
+ inputs: [
{
internalType: "address",
- name: "",
+ name: "_juror",
type: "address",
},
],
+ name: "getJurorLeftoverPNK",
+ outputs: [
+ {
+ internalType: "uint256",
+ name: "",
+ type: "uint256",
+ },
+ ],
stateMutability: "view",
type: "function",
},
@@ -30878,7 +32581,7 @@ export default {
inputs: [
{
internalType: "address",
- name: "_governor",
+ name: "_owner",
type: "address",
},
{
@@ -30954,32 +32657,21 @@ export default {
type: "function",
},
{
- inputs: [
+ inputs: [],
+ name: "owner",
+ outputs: [
{
- internalType: "uint256",
- name: "_randomNumber",
- type: "uint256",
+ internalType: "address",
+ name: "",
+ type: "address",
},
],
- name: "notifyRandomNumber",
- outputs: [],
- stateMutability: "nonpayable",
+ stateMutability: "view",
type: "function",
},
{
- inputs: [
- {
- internalType: "address",
- name: "_account",
- type: "address",
- },
- {
- internalType: "uint256",
- name: "_relativeAmount",
- type: "uint256",
- },
- ],
- name: "penalizeStake",
+ inputs: [],
+ name: "passPhase",
outputs: [],
stateMutability: "nonpayable",
type: "function",
@@ -31022,8 +32714,28 @@ export default {
name: "_account",
type: "address",
},
+ {
+ internalType: "uint96",
+ name: "_courtID",
+ type: "uint96",
+ },
+ {
+ internalType: "uint256",
+ name: "_pnkDeposit",
+ type: "uint256",
+ },
+ {
+ internalType: "uint256",
+ name: "_pnkWithdrawal",
+ type: "uint256",
+ },
+ {
+ internalType: "uint256",
+ name: "_newStake",
+ type: "uint256",
+ },
],
- name: "setJurorInactive",
+ name: "setStake",
outputs: [],
stateMutability: "nonpayable",
type: "function",
@@ -31042,31 +32754,55 @@ export default {
},
{
internalType: "uint256",
- name: "_newStake",
+ name: "_penalty",
type: "uint256",
},
- {
- internalType: "bool",
- name: "_alreadyTransferred",
- type: "bool",
- },
],
- name: "setStake",
+ name: "setStakePenalty",
outputs: [
{
internalType: "uint256",
- name: "pnkDeposit",
+ name: "pnkBalance",
type: "uint256",
},
{
internalType: "uint256",
- name: "pnkWithdrawal",
+ name: "newCourtStake",
type: "uint256",
},
{
- internalType: "enum StakingResult",
- name: "stakingResult",
- type: "uint8",
+ internalType: "uint256",
+ name: "availablePenalty",
+ type: "uint256",
+ },
+ ],
+ stateMutability: "nonpayable",
+ type: "function",
+ },
+ {
+ inputs: [
+ {
+ internalType: "address",
+ name: "_account",
+ type: "address",
+ },
+ {
+ internalType: "uint96",
+ name: "_courtID",
+ type: "uint96",
+ },
+ {
+ internalType: "uint256",
+ name: "_reward",
+ type: "uint256",
+ },
+ ],
+ name: "setStakeReward",
+ outputs: [
+ {
+ internalType: "bool",
+ name: "success",
+ type: "bool",
},
],
stateMutability: "nonpayable",
@@ -31121,10 +32857,80 @@ export default {
stateMutability: "payable",
type: "function",
},
+ {
+ inputs: [
+ {
+ internalType: "address",
+ name: "_account",
+ type: "address",
+ },
+ {
+ internalType: "uint96",
+ name: "_courtID",
+ type: "uint96",
+ },
+ {
+ internalType: "uint256",
+ name: "_newStake",
+ type: "uint256",
+ },
+ {
+ internalType: "bool",
+ name: "",
+ type: "bool",
+ },
+ ],
+ name: "validateStake",
+ outputs: [
+ {
+ internalType: "uint256",
+ name: "pnkDeposit",
+ type: "uint256",
+ },
+ {
+ internalType: "uint256",
+ name: "pnkWithdrawal",
+ type: "uint256",
+ },
+ {
+ internalType: "enum StakingResult",
+ name: "stakingResult",
+ type: "uint8",
+ },
+ ],
+ stateMutability: "view",
+ type: "function",
+ },
+ {
+ inputs: [],
+ name: "version",
+ outputs: [
+ {
+ internalType: "string",
+ name: "",
+ type: "string",
+ },
+ ],
+ stateMutability: "view",
+ type: "function",
+ },
+ {
+ inputs: [
+ {
+ internalType: "address",
+ name: "_account",
+ type: "address",
+ },
+ ],
+ name: "withdrawLeftoverPNK",
+ outputs: [],
+ stateMutability: "nonpayable",
+ type: "function",
+ },
],
},
SortitionModuleUniversity_Proxy: {
- address: "0x4B2c2d048921f694cCE3AEa35698c6B1f5fcbb79",
+ address: "0x9f55804177e7E44E558616cD7d06B865788214cA",
abi: [
{
inputs: [
@@ -32953,7 +34759,7 @@ export default {
],
},
VeaInboxArbToEthTestnet: {
- address: "0xE12daFE59Bc3A996362d54b37DFd2BA9279cAd06",
+ address: "0xAA4F00c86bf956C0Fae603D030CBc2dA7f8B7C5B",
abi: [
{
inputs: [
@@ -33502,7 +35308,7 @@ export default {
],
},
VeaInboxArbToGnosisTestnet: {
- address: "0x62403e9Fbac618301175C89fb21920e4FF235A6a",
+ address: "0xa0d410b202D69C36871d5135ce42fC7D379BBB1c",
abi: [
{
inputs: [
diff --git a/contracts/deployments/arbitrumSepoliaDevnet/DisputeKitClassicUniversity.json b/contracts/deployments/arbitrumSepoliaDevnet/DisputeKitClassicUniversity.json
index 19f34b347..baac41f51 100644
--- a/contracts/deployments/arbitrumSepoliaDevnet/DisputeKitClassicUniversity.json
+++ b/contracts/deployments/arbitrumSepoliaDevnet/DisputeKitClassicUniversity.json
@@ -1,5 +1,5 @@
{
- "address": "0xd6E96b7c993763B5CDDa1139C7387B82A7c8B8B5",
+ "address": "0x82F2089442979A6b56c80274D144575980092F91",
"abi": [
{
"stateMutability": "payable",
@@ -14,11 +14,61 @@
"name": "AlreadyInitialized",
"type": "error"
},
+ {
+ "inputs": [],
+ "name": "AppealFeeIsAlreadyPaid",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "AppealPeriodIsOver",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "AppealPeriodIsOverForLoser",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "ChoiceOutOfBounds",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "CoreIsPaused",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "DisputeJumpedToParentDK",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "DisputeNotResolved",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "EmptyCommit",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "EmptyVoteIDs",
+ "type": "error"
+ },
{
"inputs": [],
"name": "FailedDelegateCall",
"type": "error"
},
+ {
+ "inputs": [],
+ "name": "HashDoesNotMatchHiddenVoteCommitment",
+ "type": "error"
+ },
{
"inputs": [
{
@@ -30,11 +80,41 @@
"name": "InvalidImplementation",
"type": "error"
},
+ {
+ "inputs": [],
+ "name": "JurorHasToOwnTheVote",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "KlerosCoreOnly",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "NotActiveForCoreDisputeID",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "NotCommitPeriod",
+ "type": "error"
+ },
{
"inputs": [],
"name": "NotInitializing",
"type": "error"
},
+ {
+ "inputs": [],
+ "name": "NotVotePeriod",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "OwnerOnly",
+ "type": "error"
+ },
{
"inputs": [],
"name": "UUPSUnauthorizedCallContext",
@@ -51,6 +131,16 @@
"name": "UUPSUnsupportedProxiableUUID",
"type": "error"
},
+ {
+ "inputs": [],
+ "name": "UnsuccessfulCall",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "VoteAlreadyCast",
+ "type": "error"
+ },
{
"anonymous": false,
"inputs": [
@@ -295,19 +385,6 @@
"stateMutability": "view",
"type": "function"
},
- {
- "inputs": [],
- "name": "ONE_BASIS_POINT",
- "outputs": [
- {
- "internalType": "uint256",
- "name": "",
- "type": "uint256"
- }
- ],
- "stateMutability": "view",
- "type": "function"
- },
{
"inputs": [],
"name": "WINNER_STAKE_MULTIPLIER",
@@ -428,15 +505,28 @@
"stateMutability": "nonpayable",
"type": "function"
},
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "_jumpDisputeKitID",
+ "type": "uint256"
+ }
+ ],
+ "name": "changeJumpDisputeKitID",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
{
"inputs": [
{
"internalType": "address payable",
- "name": "_governor",
+ "name": "_owner",
"type": "address"
}
],
- "name": "changeGovernor",
+ "name": "changeOwner",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
@@ -454,6 +544,25 @@
"stateMutability": "view",
"type": "function"
},
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "coreDisputeID",
+ "type": "uint256"
+ }
+ ],
+ "name": "coreDisputeIDToActive",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
{
"inputs": [
{
@@ -492,7 +601,7 @@
},
{
"internalType": "uint256",
- "name": "_nbVotes",
+ "name": "",
"type": "uint256"
}
],
@@ -578,11 +687,35 @@
"internalType": "address",
"name": "drawnAddress",
"type": "address"
+ },
+ {
+ "internalType": "uint96",
+ "name": "fromSubcourtID",
+ "type": "uint96"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "name": "earlyCourtJump",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "pure",
+ "type": "function"
+ },
{
"inputs": [
{
@@ -601,7 +734,7 @@
"type": "bytes"
}
],
- "name": "executeGovernorProposal",
+ "name": "executeOwnerProposal",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
@@ -676,14 +809,58 @@
"type": "uint256"
}
],
- "name": "getDegreeOfCoherence",
+ "name": "getDegreeOfCoherencePenalty",
"outputs": [
+ {
+ "internalType": "uint256",
+ "name": "pnkCoherence",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "_coreDisputeID",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "_coreRoundID",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "_voteID",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ },
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
+ "name": "getDegreeOfCoherenceReward",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "pnkCoherence",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "feeCoherence",
+ "type": "uint256"
+ }
+ ],
"stateMutability": "view",
"type": "function"
},
@@ -706,6 +883,91 @@
"stateMutability": "view",
"type": "function"
},
+ {
+ "inputs": [],
+ "name": "getJumpDisputeKitID",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "_coreDisputeID",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "_coreRoundID",
+ "type": "uint256"
+ }
+ ],
+ "name": "getLocalDisputeRoundID",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "localDisputeID",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "localRoundID",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "contract IDisputeKit",
+ "name": "",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "_currentNbVotes",
+ "type": "uint256"
+ }
+ ],
+ "name": "getNbVotesAfterAppeal",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "pure",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "_localDisputeID",
+ "type": "uint256"
+ }
+ ],
+ "name": "getNumberOfRounds",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
{
"inputs": [
{
@@ -743,7 +1005,7 @@
},
{
"internalType": "uint256",
- "name": "totalCommited",
+ "name": "totalCommitted",
"type": "uint256"
},
{
@@ -805,13 +1067,29 @@
"type": "function"
},
{
- "inputs": [],
- "name": "governor",
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "_choice",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "_salt",
+ "type": "uint256"
+ },
+ {
+ "internalType": "string",
+ "name": "",
+ "type": "string"
+ }
+ ],
+ "name": "hashVote",
"outputs": [
{
- "internalType": "address",
+ "internalType": "bytes32",
"name": "",
- "type": "address"
+ "type": "bytes32"
}
],
"stateMutability": "view",
@@ -821,13 +1099,23 @@
"inputs": [
{
"internalType": "address",
- "name": "_governor",
+ "name": "_owner",
"type": "address"
},
{
"internalType": "contract KlerosCore",
"name": "_core",
"type": "address"
+ },
+ {
+ "internalType": "address",
+ "name": "_wNative",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "_jumpDisputeKitID",
+ "type": "uint256"
}
],
"name": "initialize",
@@ -835,6 +1123,25 @@
"stateMutability": "nonpayable",
"type": "function"
},
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "_coreDisputeID",
+ "type": "uint256"
+ }
+ ],
+ "name": "isAppealFunded",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
{
"inputs": [
{
@@ -864,6 +1171,32 @@
"stateMutability": "view",
"type": "function"
},
+ {
+ "inputs": [],
+ "name": "jumpDisputeKitID",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "owner",
+ "outputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
{
"inputs": [],
"name": "proxiableUUID",
@@ -877,6 +1210,19 @@
"stateMutability": "view",
"type": "function"
},
+ {
+ "inputs": [],
+ "name": "singleDrawPerJuror",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
{
"inputs": [
{
@@ -895,6 +1241,32 @@
"stateMutability": "payable",
"type": "function"
},
+ {
+ "inputs": [],
+ "name": "version",
+ "outputs": [
+ {
+ "internalType": "string",
+ "name": "",
+ "type": "string"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "wNative",
+ "outputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
{
"inputs": [
{
@@ -946,52 +1318,54 @@
"type": "constructor"
}
],
- "transactionHash": "0xbe90d4066f62381a1a2c725364c3d35093e1ff685736f3fa0a7b75c3b0e82f93",
+ "transactionHash": "0xbc5117fa79c44f4304b16dfe26f072d80a71dce7cf9986f10f363c6e20457bd5",
"receipt": {
"to": null,
"from": "0xf1C7c037891525E360C59f708739Ac09A7670c59",
- "contractAddress": "0xd6E96b7c993763B5CDDa1139C7387B82A7c8B8B5",
- "transactionIndex": 1,
- "gasUsed": "189732",
- "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000004000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
- "blockHash": "0x1e4647532736ec4a239971727f05a17b1bb50fc89c0ec7a8da6e34f4f5bfcc90",
- "transactionHash": "0xbe90d4066f62381a1a2c725364c3d35093e1ff685736f3fa0a7b75c3b0e82f93",
+ "contractAddress": "0x82F2089442979A6b56c80274D144575980092F91",
+ "transactionIndex": 2,
+ "gasUsed": "205891",
+ "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000080000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ "blockHash": "0x11a1f340150df5f9ad32caef5cb1157e97be0914fb56af4c3835a86a743a5184",
+ "transactionHash": "0xbc5117fa79c44f4304b16dfe26f072d80a71dce7cf9986f10f363c6e20457bd5",
"logs": [
{
- "transactionIndex": 1,
- "blockNumber": 96308536,
- "transactionHash": "0xbe90d4066f62381a1a2c725364c3d35093e1ff685736f3fa0a7b75c3b0e82f93",
- "address": "0xd6E96b7c993763B5CDDa1139C7387B82A7c8B8B5",
+ "transactionIndex": 2,
+ "blockNumber": 193533776,
+ "transactionHash": "0xbc5117fa79c44f4304b16dfe26f072d80a71dce7cf9986f10f363c6e20457bd5",
+ "address": "0x82F2089442979A6b56c80274D144575980092F91",
"topics": [
"0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2"
],
"data": "0x0000000000000000000000000000000000000000000000000000000000000001",
- "logIndex": 0,
- "blockHash": "0x1e4647532736ec4a239971727f05a17b1bb50fc89c0ec7a8da6e34f4f5bfcc90"
+ "logIndex": 4,
+ "blockHash": "0x11a1f340150df5f9ad32caef5cb1157e97be0914fb56af4c3835a86a743a5184"
}
],
- "blockNumber": 96308536,
- "cumulativeGasUsed": "189732",
+ "blockNumber": 193533776,
+ "cumulativeGasUsed": "320063",
"status": 1,
"byzantium": true
},
"args": [
- "0x87e863b94d2CB79A8aB53bD87Dc4A10E11C0918B",
- "0x485cc955000000000000000000000000f1c7c037891525e360c59f708739ac09a7670c590000000000000000000000000000000000000000000000000000000000000000"
+ "0x602ADa1cE706404BFb5417e497cdDae934436081",
+ "0xcf756fdf000000000000000000000000f1c7c037891525e360c59f708739ac09a7670c5900000000000000000000000000000000000000000000000000000000000000000000000000000000000000003829a2486d53ee984a0ca2d76552715726b771380000000000000000000000000000000000000000000000000000000000000001"
],
"numDeployments": 1,
- "solcInputHash": "a5602534c00c2f67ca4b6a1cab8c717e",
- "metadata": "{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_implementation\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"stateMutability\":\"payable\",\"type\":\"fallback\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/proxy/KlerosProxies.sol\":\"DisputeKitClassicUniversityProxy\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":100},\"remappings\":[]},\"sources\":{\"src/proxy/KlerosProxies.sol\":{\"content\":\"//SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.24;\\n\\nimport \\\"./UUPSProxy.sol\\\";\\n\\n/// Workaround to get meaningful names for the proxy contracts\\n/// Otherwise all the contracts are called `UUPSProxy` on the chain explorers\\n\\ncontract DisputeKitClassicNeoProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract DisputeKitClassicUniversityProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract DisputeKitClassicProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract DisputeTemplateRegistryProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract EvidenceModuleProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract ForeignGatewayOnEthereumProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract HomeGatewayToEthereumProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract KlerosCoreNeoProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract KlerosCoreRulerProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract KlerosCoreUniversityProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract KlerosCoreProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract PolicyRegistryProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract RandomizerRNGProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract SortitionModuleNeoProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract SortitionModuleUniversityProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract SortitionModuleProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\",\"keccak256\":\"0x4393c05bbfda204b9992e1e546142a0fbf4c92a1c4061f5985463d02a71b84d4\",\"license\":\"MIT\"},\"src/proxy/UUPSProxy.sol\":{\"content\":\"//SPDX-License-Identifier: MIT\\n// Adapted from \\n\\n/**\\n * @authors: [@malatrax]\\n * @reviewers: []\\n * @auditors: []\\n * @bounties: []\\n * @deployments: []\\n */\\npragma solidity 0.8.24;\\n\\n/**\\n * @title UUPS Proxy\\n * @author Simon Malatrait \\n * @dev This contract implements a UUPS Proxy compliant with ERC-1967 & ERC-1822.\\n * @dev This contract delegates all calls to another contract (UUPS Proxiable) through a fallback function and the use of the `delegatecall` EVM instruction.\\n * @dev We refer to the Proxiable contract (as per ERC-1822) with `implementation`.\\n */\\ncontract UUPSProxy {\\n /**\\n * @dev Storage slot with the address of the current implementation.\\n * This is the keccak-256 hash of \\\"eip1967.proxy.implementation\\\" subtracted by 1, and is\\n * validated in the constructor.\\n * NOTE: bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1)\\n */\\n bytes32 private constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\\n\\n // ************************************* //\\n // * Constructor * //\\n // ************************************* //\\n\\n /**\\n * @dev Initializes the upgradeable proxy with an initial implementation specified by `_implementation`.\\n *\\n * If `_data` is nonempty, it's used as data in a delegate call to `_implementation`. This will typically be an encoded\\n * function call, and allows initializing the storage of the proxy like a Solidity constructor.\\n */\\n constructor(address _implementation, bytes memory _data) {\\n assembly {\\n sstore(IMPLEMENTATION_SLOT, _implementation)\\n }\\n\\n if (_data.length != 0) {\\n (bool success, ) = _implementation.delegatecall(_data);\\n require(success, \\\"Proxy Constructor failed\\\");\\n }\\n }\\n\\n // ************************************* //\\n // * State Modifiers * //\\n // ************************************* //\\n\\n /**\\n * @dev Delegates the current call to `implementation`.\\n *\\n * NOTE: This function does not return to its internal call site, it will return directly to the external caller.\\n */\\n function _delegate(address implementation) internal {\\n assembly {\\n // Copy msg.data. We take full control of memory in this inline assembly\\n // block because it will not return to Solidity code. We overwrite the\\n // Solidity scratch pad at memory position 0.\\n calldatacopy(0, 0, calldatasize())\\n\\n // Call the implementation.\\n // out and outsize are 0 because we don't know the size yet.\\n let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)\\n\\n // Copy the returned data.\\n returndatacopy(0, 0, returndatasize())\\n\\n switch result\\n // delegatecall returns 0 on error.\\n case 0 {\\n revert(0, returndatasize())\\n }\\n default {\\n return(0, returndatasize())\\n }\\n }\\n }\\n\\n // ************************************* //\\n // * Internal Views * //\\n // ************************************* //\\n\\n function _getImplementation() internal view returns (address implementation) {\\n assembly {\\n implementation := sload(IMPLEMENTATION_SLOT)\\n }\\n }\\n\\n // ************************************* //\\n // * Fallback * //\\n // ************************************* //\\n\\n /**\\n * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other\\n * function in the contract matches the call data.\\n */\\n fallback() external payable {\\n _delegate(_getImplementation());\\n }\\n\\n receive() external payable {\\n _delegate(_getImplementation());\\n }\\n}\\n\",\"keccak256\":\"0x7aa5f14ce351299722ac1a1afca9e65e1c795f32ea3e9702b0d5faaf7ca822a0\",\"license\":\"MIT\"}},\"version\":1}",
- "bytecode": "0x608060405234801561001057600080fd5b5060405161030238038061030283398101604081905261002f91610151565b8181817f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc55805160001461010e576000826001600160a01b031682604051610077919061021f565b600060405180830381855af49150503d80600081146100b2576040519150601f19603f3d011682016040523d82523d6000602084013e6100b7565b606091505b505090508061010c5760405162461bcd60e51b815260206004820152601860248201527f50726f787920436f6e7374727563746f72206661696c65640000000000000000604482015260640160405180910390fd5b505b5050505061023b565b634e487b7160e01b600052604160045260246000fd5b60005b83811015610148578181015183820152602001610130565b50506000910152565b6000806040838503121561016457600080fd5b82516001600160a01b038116811461017b57600080fd5b60208401519092506001600160401b038082111561019857600080fd5b818501915085601f8301126101ac57600080fd5b8151818111156101be576101be610117565b604051601f8201601f19908116603f011681019083821181831017156101e6576101e6610117565b816040528281528860208487010111156101ff57600080fd5b61021083602083016020880161012d565b80955050505050509250929050565b6000825161023181846020870161012d565b9190910192915050565b60b9806102496000396000f3fe608060405236603757603560317f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5490565b6060565b005b603560317f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5490565b3660008037600080366000845af43d6000803e808015607e573d6000f35b3d6000fdfea2646970667358221220a67e53546ab2c83f023c185d90506ad48d4e7af6339cf6db0c4ed97ec9ed376f64736f6c63430008180033",
- "deployedBytecode": "0x608060405236603757603560317f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5490565b6060565b005b603560317f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5490565b3660008037600080366000845af43d6000803e808015607e573d6000f35b3d6000fdfea2646970667358221220a67e53546ab2c83f023c185d90506ad48d4e7af6339cf6db0c4ed97ec9ed376f64736f6c63430008180033",
+ "solcInputHash": "d547d738900bce1310e91a5d1adfc179",
+ "metadata": "{\"compiler\":{\"version\":\"0.8.30+commit.73712a01\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_implementation\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"stateMutability\":\"payable\",\"type\":\"fallback\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"notice\":\"Workaround to get meaningful names for the proxy contracts Otherwise all the contracts are called `UUPSProxy` on the chain explorers\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/proxy/KlerosProxies.sol\":\"DisputeKitClassicUniversityProxy\"},\"evmVersion\":\"cancun\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000},\"remappings\":[],\"viaIR\":true},\"sources\":{\"src/proxy/KlerosProxies.sol\":{\"content\":\"//SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.24;\\n\\nimport \\\"./UUPSProxy.sol\\\";\\n\\n/// Workaround to get meaningful names for the proxy contracts\\n/// Otherwise all the contracts are called `UUPSProxy` on the chain explorers\\n\\ncontract DisputeKitClassicUniversityProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract DisputeKitClassicProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract DisputeKitGatedProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract DisputeKitGatedShutterProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract DisputeKitShutterProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract DisputeKitSybilResistantProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract DisputeTemplateRegistryProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract EvidenceModuleProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract ForeignGatewayOnEthereumProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract HomeGatewayToEthereumProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract KlerosCoreRulerProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract KlerosCoreUniversityProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract KlerosCoreProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract PolicyRegistryProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract RandomizerRNGProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract SortitionModuleUniversityProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract SortitionModuleProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\",\"keccak256\":\"0x3160bd320b23c6ec0c21862b455c3044a9b33654ae84a1b6cd76255626c9154b\",\"license\":\"MIT\"},\"src/proxy/UUPSProxy.sol\":{\"content\":\"//SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.24;\\n\\n/// @title UUPS Proxy\\n/// @author Simon Malatrait \\n/// @notice This contract implements a UUPS Proxy compliant with ERC-1967 & ERC-1822.\\n///\\n/// @dev This contract delegates all calls to another contract (UUPS Proxiable) through a fallback function and the use of the `delegatecall` EVM instruction.\\n/// We refer to the Proxiable contract (as per ERC-1822) with `implementation`.\\n/// Adapted from \\ncontract UUPSProxy {\\n /// @dev Storage slot with the address of the current implementation.\\n /// This is the keccak-256 hash of \\\"eip1967.proxy.implementation\\\" subtracted by 1, and is\\n /// validated in the constructor.\\n /// NOTE: bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1)\\n bytes32 private constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\\n\\n // ************************************* //\\n // * Constructor * //\\n // ************************************* //\\n\\n /// @notice Initializes the upgradeable proxy with an initial implementation specified by `_implementation`.\\n /// @dev If `_data` is nonempty, it's used as data in a delegate call to `_implementation`.\\n /// This will typically be an encoded function call, and allows initializing the storage of the proxy like a Solidity constructor.\\n constructor(address _implementation, bytes memory _data) {\\n assembly {\\n sstore(IMPLEMENTATION_SLOT, _implementation)\\n }\\n\\n if (_data.length != 0) {\\n (bool success, ) = _implementation.delegatecall(_data);\\n require(success, \\\"Proxy Constructor failed\\\");\\n }\\n }\\n\\n // ************************************* //\\n // * State Modifiers * //\\n // ************************************* //\\n\\n /// @dev Delegates the current call to `implementation`.\\n /// NOTE: This function does not return to its internal call site, it will return directly to the external caller.\\n function _delegate(address implementation) internal {\\n assembly {\\n // Copy msg.data. We take full control of memory in this inline assembly\\n // block because it will not return to Solidity code. We overwrite the\\n // Solidity scratch pad at memory position 0.\\n calldatacopy(0, 0, calldatasize())\\n\\n // Call the implementation.\\n // out and outsize are 0 because we don't know the size yet.\\n let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)\\n\\n // Copy the returned data.\\n returndatacopy(0, 0, returndatasize())\\n\\n switch result\\n // delegatecall returns 0 on error.\\n case 0 {\\n revert(0, returndatasize())\\n }\\n default {\\n return(0, returndatasize())\\n }\\n }\\n }\\n\\n // ************************************* //\\n // * Internal Views * //\\n // ************************************* //\\n\\n function _getImplementation() internal view returns (address implementation) {\\n assembly {\\n implementation := sload(IMPLEMENTATION_SLOT)\\n }\\n }\\n\\n // ************************************* //\\n // * Fallback * //\\n // ************************************* //\\n\\n /// @dev Fallback function that delegates calls to the address returned by `_implementation()`.\\n /// @dev Will run if no other function in the contract matches the call data.\\n fallback() external payable {\\n _delegate(_getImplementation());\\n }\\n\\n receive() external payable {\\n _delegate(_getImplementation());\\n }\\n}\\n\",\"keccak256\":\"0x2d7b1f81e525787f1b8b033ce381a81cb5f39e411ff31490e019113205a661cd\",\"license\":\"MIT\"}},\"version\":1}",
+ "bytecode": "0x608060405234610144576102148038038061001981610148565b928339810190604081830312610144578051906001600160a01b0382168203610144576020810151906001600160401b038211610144570182601f8201121561014457805161006f61006a82610181565b610148565b9181835260208301946020838301011161014457815f926020809301875e83010152817f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5551806100c9575b6040516077908161019d8239f35b5f9283925af43d1561013f573d6100e261006a82610181565b9081525f60203d92013e5b156100fa575f80806100bb565b60405162461bcd60e51b815260206004820152601860248201527f50726f787920436f6e7374727563746f72206661696c656400000000000000006044820152606490fd5b6100ed565b5f80fd5b6040519190601f01601f191682016001600160401b0381118382101761016d57604052565b634e487b7160e01b5f52604160045260245ffd5b6001600160401b03811161016d57601f01601f19166020019056fe60806040525f807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc54368280378136915af43d5f803e15603d573d5ff35b3d5ffdfea264697066735822122078e638e186ffb95282090eae06b37667016702ebe14876894d9cb231ea135b1264736f6c634300081e0033",
+ "deployedBytecode": "0x60806040525f807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc54368280378136915af43d5f803e15603d573d5ff35b3d5ffdfea264697066735822122078e638e186ffb95282090eae06b37667016702ebe14876894d9cb231ea135b1264736f6c634300081e0033",
"execute": {
"methodName": "initialize",
"args": [
"0xf1C7c037891525E360C59f708739Ac09A7670c59",
- "0x0000000000000000000000000000000000000000"
+ "0x0000000000000000000000000000000000000000",
+ "0x3829A2486d53ee984a0ca2D76552715726b77138",
+ 1
]
},
- "implementation": "0x87e863b94d2CB79A8aB53bD87Dc4A10E11C0918B",
+ "implementation": "0x602ADa1cE706404BFb5417e497cdDae934436081",
"devdoc": {
"kind": "dev",
"methods": {},
@@ -1000,6 +1374,7 @@
"userdoc": {
"kind": "user",
"methods": {},
+ "notice": "Workaround to get meaningful names for the proxy contracts Otherwise all the contracts are called `UUPSProxy` on the chain explorers",
"version": 1
},
"storageLayout": {
diff --git a/contracts/deployments/arbitrumSepoliaDevnet/DisputeKitClassicUniversity_Implementation.json b/contracts/deployments/arbitrumSepoliaDevnet/DisputeKitClassicUniversity_Implementation.json
index 3ac36edd4..dd3e3b270 100644
--- a/contracts/deployments/arbitrumSepoliaDevnet/DisputeKitClassicUniversity_Implementation.json
+++ b/contracts/deployments/arbitrumSepoliaDevnet/DisputeKitClassicUniversity_Implementation.json
@@ -1,5 +1,5 @@
{
- "address": "0x87e863b94d2CB79A8aB53bD87Dc4A10E11C0918B",
+ "address": "0x602ADa1cE706404BFb5417e497cdDae934436081",
"abi": [
{
"inputs": [],
@@ -11,11 +11,61 @@
"name": "AlreadyInitialized",
"type": "error"
},
+ {
+ "inputs": [],
+ "name": "AppealFeeIsAlreadyPaid",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "AppealPeriodIsOver",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "AppealPeriodIsOverForLoser",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "ChoiceOutOfBounds",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "CoreIsPaused",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "DisputeJumpedToParentDK",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "DisputeNotResolved",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "EmptyCommit",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "EmptyVoteIDs",
+ "type": "error"
+ },
{
"inputs": [],
"name": "FailedDelegateCall",
"type": "error"
},
+ {
+ "inputs": [],
+ "name": "HashDoesNotMatchHiddenVoteCommitment",
+ "type": "error"
+ },
{
"inputs": [
{
@@ -27,11 +77,41 @@
"name": "InvalidImplementation",
"type": "error"
},
+ {
+ "inputs": [],
+ "name": "JurorHasToOwnTheVote",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "KlerosCoreOnly",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "NotActiveForCoreDisputeID",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "NotCommitPeriod",
+ "type": "error"
+ },
{
"inputs": [],
"name": "NotInitializing",
"type": "error"
},
+ {
+ "inputs": [],
+ "name": "NotVotePeriod",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "OwnerOnly",
+ "type": "error"
+ },
{
"inputs": [],
"name": "UUPSUnauthorizedCallContext",
@@ -48,6 +128,16 @@
"name": "UUPSUnsupportedProxiableUUID",
"type": "error"
},
+ {
+ "inputs": [],
+ "name": "UnsuccessfulCall",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "VoteAlreadyCast",
+ "type": "error"
+ },
{
"anonymous": false,
"inputs": [
@@ -292,19 +382,6 @@
"stateMutability": "view",
"type": "function"
},
- {
- "inputs": [],
- "name": "ONE_BASIS_POINT",
- "outputs": [
- {
- "internalType": "uint256",
- "name": "",
- "type": "uint256"
- }
- ],
- "stateMutability": "view",
- "type": "function"
- },
{
"inputs": [],
"name": "WINNER_STAKE_MULTIPLIER",
@@ -425,15 +502,28 @@
"stateMutability": "nonpayable",
"type": "function"
},
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "_jumpDisputeKitID",
+ "type": "uint256"
+ }
+ ],
+ "name": "changeJumpDisputeKitID",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
{
"inputs": [
{
"internalType": "address payable",
- "name": "_governor",
+ "name": "_owner",
"type": "address"
}
],
- "name": "changeGovernor",
+ "name": "changeOwner",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
@@ -451,6 +541,25 @@
"stateMutability": "view",
"type": "function"
},
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "coreDisputeID",
+ "type": "uint256"
+ }
+ ],
+ "name": "coreDisputeIDToActive",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
{
"inputs": [
{
@@ -489,7 +598,7 @@
},
{
"internalType": "uint256",
- "name": "_nbVotes",
+ "name": "",
"type": "uint256"
}
],
@@ -575,11 +684,35 @@
"internalType": "address",
"name": "drawnAddress",
"type": "address"
+ },
+ {
+ "internalType": "uint96",
+ "name": "fromSubcourtID",
+ "type": "uint96"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "name": "earlyCourtJump",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "pure",
+ "type": "function"
+ },
{
"inputs": [
{
@@ -598,7 +731,7 @@
"type": "bytes"
}
],
- "name": "executeGovernorProposal",
+ "name": "executeOwnerProposal",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
@@ -673,14 +806,58 @@
"type": "uint256"
}
],
- "name": "getDegreeOfCoherence",
+ "name": "getDegreeOfCoherencePenalty",
"outputs": [
+ {
+ "internalType": "uint256",
+ "name": "pnkCoherence",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "_coreDisputeID",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "_coreRoundID",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "_voteID",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ },
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
+ "name": "getDegreeOfCoherenceReward",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "pnkCoherence",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "feeCoherence",
+ "type": "uint256"
+ }
+ ],
"stateMutability": "view",
"type": "function"
},
@@ -703,6 +880,91 @@
"stateMutability": "view",
"type": "function"
},
+ {
+ "inputs": [],
+ "name": "getJumpDisputeKitID",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "_coreDisputeID",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "_coreRoundID",
+ "type": "uint256"
+ }
+ ],
+ "name": "getLocalDisputeRoundID",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "localDisputeID",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "localRoundID",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "contract IDisputeKit",
+ "name": "",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "_currentNbVotes",
+ "type": "uint256"
+ }
+ ],
+ "name": "getNbVotesAfterAppeal",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "pure",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "_localDisputeID",
+ "type": "uint256"
+ }
+ ],
+ "name": "getNumberOfRounds",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
{
"inputs": [
{
@@ -740,7 +1002,7 @@
},
{
"internalType": "uint256",
- "name": "totalCommited",
+ "name": "totalCommitted",
"type": "uint256"
},
{
@@ -802,29 +1064,55 @@
"type": "function"
},
{
- "inputs": [],
- "name": "governor",
- "outputs": [
+ "inputs": [
{
- "internalType": "address",
- "name": "",
- "type": "address"
- }
- ],
- "stateMutability": "view",
+ "internalType": "uint256",
+ "name": "_choice",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "_salt",
+ "type": "uint256"
+ },
+ {
+ "internalType": "string",
+ "name": "",
+ "type": "string"
+ }
+ ],
+ "name": "hashVote",
+ "outputs": [
+ {
+ "internalType": "bytes32",
+ "name": "",
+ "type": "bytes32"
+ }
+ ],
+ "stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
- "name": "_governor",
+ "name": "_owner",
"type": "address"
},
{
"internalType": "contract KlerosCore",
"name": "_core",
"type": "address"
+ },
+ {
+ "internalType": "address",
+ "name": "_wNative",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "_jumpDisputeKitID",
+ "type": "uint256"
}
],
"name": "initialize",
@@ -832,6 +1120,25 @@
"stateMutability": "nonpayable",
"type": "function"
},
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "_coreDisputeID",
+ "type": "uint256"
+ }
+ ],
+ "name": "isAppealFunded",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
{
"inputs": [
{
@@ -861,6 +1168,32 @@
"stateMutability": "view",
"type": "function"
},
+ {
+ "inputs": [],
+ "name": "jumpDisputeKitID",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "owner",
+ "outputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
{
"inputs": [],
"name": "proxiableUUID",
@@ -874,6 +1207,19 @@
"stateMutability": "view",
"type": "function"
},
+ {
+ "inputs": [],
+ "name": "singleDrawPerJuror",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
{
"inputs": [
{
@@ -892,6 +1238,32 @@
"stateMutability": "payable",
"type": "function"
},
+ {
+ "inputs": [],
+ "name": "version",
+ "outputs": [
+ {
+ "internalType": "string",
+ "name": "",
+ "type": "string"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "wNative",
+ "outputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
{
"inputs": [
{
@@ -927,41 +1299,41 @@
"type": "function"
}
],
- "transactionHash": "0x89ac5a2ce88c22071edfaf2f092cb26862b52facde1274b9a495dccdd03a41d9",
+ "transactionHash": "0x140fcdeaa468903f80081c238adf55c9e98ed99dfccc7d9c3e5f1b0fe90cf644",
"receipt": {
"to": null,
"from": "0xf1C7c037891525E360C59f708739Ac09A7670c59",
- "contractAddress": "0x87e863b94d2CB79A8aB53bD87Dc4A10E11C0918B",
+ "contractAddress": "0x602ADa1cE706404BFb5417e497cdDae934436081",
"transactionIndex": 2,
- "gasUsed": "3665145",
- "logsBloom": "0x00000800000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000400000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
- "blockHash": "0x9c2007f9245166eb377461ad5c2dd50dfa7e21fc79284f7d7591fb8348960fe3",
- "transactionHash": "0x89ac5a2ce88c22071edfaf2f092cb26862b52facde1274b9a495dccdd03a41d9",
+ "gasUsed": "2891480",
+ "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000800000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ "blockHash": "0xa1d507b667521779bef446125f900ce13bca11861cf05645709556422aad0f04",
+ "transactionHash": "0x140fcdeaa468903f80081c238adf55c9e98ed99dfccc7d9c3e5f1b0fe90cf644",
"logs": [
{
"transactionIndex": 2,
- "blockNumber": 96308519,
- "transactionHash": "0x89ac5a2ce88c22071edfaf2f092cb26862b52facde1274b9a495dccdd03a41d9",
- "address": "0x87e863b94d2CB79A8aB53bD87Dc4A10E11C0918B",
+ "blockNumber": 193533768,
+ "transactionHash": "0x140fcdeaa468903f80081c238adf55c9e98ed99dfccc7d9c3e5f1b0fe90cf644",
+ "address": "0x602ADa1cE706404BFb5417e497cdDae934436081",
"topics": [
"0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2"
],
"data": "0x000000000000000000000000000000000000000000000000ffffffffffffffff",
- "logIndex": 6,
- "blockHash": "0x9c2007f9245166eb377461ad5c2dd50dfa7e21fc79284f7d7591fb8348960fe3"
+ "logIndex": 1,
+ "blockHash": "0xa1d507b667521779bef446125f900ce13bca11861cf05645709556422aad0f04"
}
],
- "blockNumber": 96308519,
- "cumulativeGasUsed": "3756092",
+ "blockNumber": 193533768,
+ "cumulativeGasUsed": "3568712",
"status": 1,
"byzantium": true
},
"args": [],
"numDeployments": 1,
- "solcInputHash": "a5602534c00c2f67ca4b6a1cab8c717e",
- "metadata": "{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"AlreadyInitialized\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedDelegateCall\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"implementation\",\"type\":\"address\"}],\"name\":\"InvalidImplementation\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotInitializing\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UUPSUnauthorizedCallContext\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"slot\",\"type\":\"bytes32\"}],\"name\":\"UUPSUnsupportedProxiableUUID\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_coreDisputeID\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_coreRoundID\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_choice\",\"type\":\"uint256\"}],\"name\":\"ChoiceFunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_coreDisputeID\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_juror\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"_voteIDs\",\"type\":\"uint256[]\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"_commit\",\"type\":\"bytes32\"}],\"name\":\"CommitCast\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_coreDisputeID\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_coreRoundID\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_choice\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_contributor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"Contribution\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_coreDisputeID\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_numberOfChoices\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"_extraData\",\"type\":\"bytes\"}],\"name\":\"DisputeCreation\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"version\",\"type\":\"uint64\"}],\"name\":\"Initialized\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newImplementation\",\"type\":\"address\"}],\"name\":\"Upgraded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_coreDisputeID\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_juror\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"_voteIDs\",\"type\":\"uint256[]\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_choice\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"_justification\",\"type\":\"string\"}],\"name\":\"VoteCast\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_coreDisputeID\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_coreRoundID\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_choice\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_contributor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"Withdrawal\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"LOSER_APPEAL_PERIOD_MULTIPLIER\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"LOSER_STAKE_MULTIPLIER\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"ONE_BASIS_POINT\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"WINNER_STAKE_MULTIPLIER\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_coreDisputeID\",\"type\":\"uint256\"}],\"name\":\"areCommitsAllCast\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_coreDisputeID\",\"type\":\"uint256\"}],\"name\":\"areVotesAllCast\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_coreDisputeID\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"_voteIDs\",\"type\":\"uint256[]\"},{\"internalType\":\"bytes32\",\"name\":\"_commit\",\"type\":\"bytes32\"}],\"name\":\"castCommit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_coreDisputeID\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"_voteIDs\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256\",\"name\":\"_choice\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_salt\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"_justification\",\"type\":\"string\"}],\"name\":\"castVote\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_core\",\"type\":\"address\"}],\"name\":\"changeCore\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address payable\",\"name\":\"_governor\",\"type\":\"address\"}],\"name\":\"changeGovernor\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"core\",\"outputs\":[{\"internalType\":\"contract KlerosCore\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"coreDisputeIDToLocal\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_coreDisputeID\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_numberOfChoices\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"_extraData\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"_nbVotes\",\"type\":\"uint256\"}],\"name\":\"createDispute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_coreDisputeID\",\"type\":\"uint256\"}],\"name\":\"currentRuling\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"ruling\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"tied\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"overridden\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"disputes\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"numberOfChoices\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"jumped\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_coreDisputeID\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_nonce\",\"type\":\"uint256\"}],\"name\":\"draw\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"drawnAddress\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_destination\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"executeGovernorProposal\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_coreDisputeID\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_choice\",\"type\":\"uint256\"}],\"name\":\"fundAppeal\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_coreDisputeID\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_coreRoundID\",\"type\":\"uint256\"}],\"name\":\"getCoherentCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_coreDisputeID\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_coreRoundID\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_voteID\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"getDegreeOfCoherence\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_coreDisputeID\",\"type\":\"uint256\"}],\"name\":\"getFundedChoices\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"fundedChoices\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_coreDisputeID\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_coreRoundID\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_choice\",\"type\":\"uint256\"}],\"name\":\"getRoundInfo\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"winningChoice\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"tied\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"totalVoted\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"totalCommited\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nbVoters\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"choiceCount\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_coreDisputeID\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_coreRoundID\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_voteID\",\"type\":\"uint256\"}],\"name\":\"getVoteInfo\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"commit\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"choice\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"voted\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"governor\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_governor\",\"type\":\"address\"},{\"internalType\":\"contract KlerosCore\",\"name\":\"_core\",\"type\":\"address\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_coreDisputeID\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_coreRoundID\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_voteID\",\"type\":\"uint256\"}],\"name\":\"isVoteActive\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"proxiableUUID\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newImplementation\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"upgradeToAndCall\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_coreDisputeID\",\"type\":\"uint256\"},{\"internalType\":\"address payable\",\"name\":\"_beneficiary\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_coreRoundID\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_choice\",\"type\":\"uint256\"}],\"name\":\"withdrawFeesAndRewards\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"errors\":{\"AlreadyInitialized()\":[{\"details\":\"The contract is already initialized.\"}],\"NotInitializing()\":[{\"details\":\"The contract is not initializing.\"}],\"UUPSUnauthorizedCallContext()\":[{\"details\":\"The call is from an unauthorized context.\"}],\"UUPSUnsupportedProxiableUUID(bytes32)\":[{\"details\":\"The storage `slot` is unsupported as a UUID.\"}]},\"events\":{\"ChoiceFunded(uint256,uint256,uint256)\":{\"details\":\"To be emitted when a choice is fully funded for an appeal.\",\"params\":{\"_choice\":\"The choice that is being funded.\",\"_coreDisputeID\":\"The identifier of the dispute in the Arbitrator contract.\",\"_coreRoundID\":\"The identifier of the round in the Arbitrator contract.\"}},\"CommitCast(uint256,address,uint256[],bytes32)\":{\"details\":\"To be emitted when a vote commitment is cast.\",\"params\":{\"_commit\":\"The commitment of the juror.\",\"_coreDisputeID\":\"The identifier of the dispute in the Arbitrator contract.\",\"_juror\":\"The address of the juror casting the vote commitment.\",\"_voteIDs\":\"The identifiers of the votes in the dispute.\"}},\"Contribution(uint256,uint256,uint256,address,uint256)\":{\"details\":\"To be emitted when a funding contribution is made.\",\"params\":{\"_amount\":\"The amount contributed.\",\"_choice\":\"The choice that is being funded.\",\"_contributor\":\"The address of the contributor.\",\"_coreDisputeID\":\"The identifier of the dispute in the Arbitrator contract.\",\"_coreRoundID\":\"The identifier of the round in the Arbitrator contract.\"}},\"DisputeCreation(uint256,uint256,bytes)\":{\"details\":\"To be emitted when a dispute is created.\",\"params\":{\"_coreDisputeID\":\"The identifier of the dispute in the Arbitrator contract.\",\"_extraData\":\"The extra data for the dispute.\",\"_numberOfChoices\":\"The number of choices available in the dispute.\"}},\"Initialized(uint64)\":{\"details\":\"Triggered when the contract has been initialized or reinitialized.\"},\"Upgraded(address)\":{\"params\":{\"newImplementation\":\"Address of the new implementation the proxy is now forwarding calls to.\"}},\"VoteCast(uint256,address,uint256[],uint256,string)\":{\"details\":\"Emitted when casting a vote to provide the justification of juror's choice.\",\"params\":{\"_choice\":\"The choice juror voted for.\",\"_coreDisputeID\":\"The identifier of the dispute in the Arbitrator contract.\",\"_juror\":\"Address of the juror.\",\"_justification\":\"Justification of the choice.\",\"_voteIDs\":\"The identifiers of the votes in the dispute.\"}},\"Withdrawal(uint256,uint256,uint256,address,uint256)\":{\"details\":\"To be emitted when the contributed funds are withdrawn.\",\"params\":{\"_amount\":\"The amount withdrawn.\",\"_choice\":\"The choice that is being funded.\",\"_contributor\":\"The address of the contributor.\",\"_coreDisputeID\":\"The identifier of the dispute in the Arbitrator contract.\",\"_coreRoundID\":\"The identifier of the round in the Arbitrator contract.\"}}},\"kind\":\"dev\",\"methods\":{\"areCommitsAllCast(uint256)\":{\"details\":\"Returns true if all of the jurors have cast their commits for the last round.\",\"params\":{\"_coreDisputeID\":\"The ID of the dispute in Kleros Core.\"},\"returns\":{\"_0\":\"Whether all of the jurors have cast their commits for the last round.\"}},\"areVotesAllCast(uint256)\":{\"details\":\"Returns true if all of the jurors have cast their votes for the last round.\",\"params\":{\"_coreDisputeID\":\"The ID of the dispute in Kleros Core.\"},\"returns\":{\"_0\":\"Whether all of the jurors have cast their votes for the last round.\"}},\"castCommit(uint256,uint256[],bytes32)\":{\"details\":\"Sets the caller's commit for the specified votes. It can be called multiple times during the commit period, each call overrides the commits of the previous one. `O(n)` where `n` is the number of votes.\",\"params\":{\"_commit\":\"The commit. Note that justification string is a part of the commit.\",\"_coreDisputeID\":\"The ID of the dispute in Kleros Core.\",\"_voteIDs\":\"The IDs of the votes.\"}},\"castVote(uint256,uint256[],uint256,uint256,string)\":{\"details\":\"Sets the caller's choices for the specified votes. `O(n)` where `n` is the number of votes.\",\"params\":{\"_choice\":\"The choice.\",\"_coreDisputeID\":\"The ID of the dispute in Kleros Core.\",\"_justification\":\"Justification of the choice.\",\"_salt\":\"The salt for the commit if the votes were hidden.\",\"_voteIDs\":\"The IDs of the votes.\"}},\"changeCore(address)\":{\"details\":\"Changes the `core` storage variable.\",\"params\":{\"_core\":\"The new value for the `core` storage variable.\"}},\"changeGovernor(address)\":{\"details\":\"Changes the `governor` storage variable.\",\"params\":{\"_governor\":\"The new value for the `governor` storage variable.\"}},\"constructor\":{\"details\":\"Constructor, initializing the implementation to reduce attack surface.\"},\"createDispute(uint256,uint256,bytes,uint256)\":{\"details\":\"Creates a local dispute and maps it to the dispute ID in the Core contract. Note: Access restricted to Kleros Core only.\",\"params\":{\"_coreDisputeID\":\"The ID of the dispute in Kleros Core.\",\"_extraData\":\"Additional info about the dispute, for possible use in future dispute kits.\",\"_nbVotes\":\"Number of votes for this dispute.\",\"_numberOfChoices\":\"Number of choices of the dispute\"}},\"currentRuling(uint256)\":{\"details\":\"Gets the current ruling of a specified dispute.\",\"params\":{\"_coreDisputeID\":\"The ID of the dispute in Kleros Core.\"},\"returns\":{\"overridden\":\"Whether the ruling was overridden by appeal funding or not.\",\"ruling\":\"The current ruling.\",\"tied\":\"Whether it's a tie or not.\"}},\"draw(uint256,uint256)\":{\"details\":\"Draws the juror from the sortition tree. The drawn address is picked up by Kleros Core. Note: Access restricted to Kleros Core only.\",\"params\":{\"_coreDisputeID\":\"The ID of the dispute in Kleros Core.\",\"_nonce\":\"Nonce of the drawing iteration.\"},\"returns\":{\"drawnAddress\":\"The drawn address.\"}},\"executeGovernorProposal(address,uint256,bytes)\":{\"details\":\"Allows the governor to call anything on behalf of the contract.\",\"params\":{\"_amount\":\"The value sent with the call.\",\"_data\":\"The data sent with the call.\",\"_destination\":\"The destination of the call.\"}},\"fundAppeal(uint256,uint256)\":{\"details\":\"Manages contributions, and appeals a dispute if at least two choices are fully funded. Note that the surplus deposit will be reimbursed.\",\"params\":{\"_choice\":\"A choice that receives funding.\",\"_coreDisputeID\":\"Index of the dispute in Kleros Core.\"}},\"getCoherentCount(uint256,uint256)\":{\"details\":\"Gets the number of jurors who are eligible to a reward in this round.\",\"params\":{\"_coreDisputeID\":\"The ID of the dispute in Kleros Core, not in the Dispute Kit.\",\"_coreRoundID\":\"The ID of the round in Kleros Core, not in the Dispute Kit.\"},\"returns\":{\"_0\":\"The number of coherent jurors.\"}},\"getDegreeOfCoherence(uint256,uint256,uint256,uint256,uint256)\":{\"details\":\"Gets the degree of coherence of a particular voter. This function is called by Kleros Core in order to determine the amount of the reward.\",\"params\":{\"_coreDisputeID\":\"The ID of the dispute in Kleros Core, not in the Dispute Kit.\",\"_coreRoundID\":\"The ID of the round in Kleros Core, not in the Dispute Kit.\",\"_voteID\":\"The ID of the vote.\"},\"returns\":{\"_0\":\"The degree of coherence in basis points.\"}},\"initialize(address,address)\":{\"details\":\"Initializer.\",\"params\":{\"_core\":\"The KlerosCore arbitrator.\",\"_governor\":\"The governor's address.\"}},\"isVoteActive(uint256,uint256,uint256)\":{\"details\":\"Returns true if the specified voter was active in this round.\",\"params\":{\"_coreDisputeID\":\"The ID of the dispute in Kleros Core, not in the Dispute Kit.\",\"_coreRoundID\":\"The ID of the round in Kleros Core, not in the Dispute Kit.\",\"_voteID\":\"The ID of the voter.\"},\"returns\":{\"_0\":\"Whether the voter was active or not.\"}},\"proxiableUUID()\":{\"details\":\"Implementation of the ERC1822 `proxiableUUID` function. This returns the storage slot used by the implementation. It is used to validate the implementation's compatibility when performing an upgrade. IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this function revert if invoked through a proxy. This is guaranteed by the if statement.\"},\"upgradeToAndCall(address,bytes)\":{\"details\":\"Upgrade mechanism including access control and UUPS-compliance.Reverts if the execution is not performed via delegatecall or the execution context is not of a proxy with an ERC1967-compliant implementation pointing to self.\",\"params\":{\"data\":\"Data used in a delegate call to `newImplementation` if non-empty. This will typically be an encoded function call, and allows initializing the storage of the proxy like a Solidity constructor.\",\"newImplementation\":\"Address of the new implementation contract.\"}},\"withdrawFeesAndRewards(uint256,address,uint256,uint256)\":{\"details\":\"Allows those contributors who attempted to fund an appeal round to withdraw any reimbursable fees or rewards after the dispute gets resolved. Note that withdrawals are not possible if the core contract is paused.\",\"params\":{\"_beneficiary\":\"The address whose rewards to withdraw.\",\"_choice\":\"The ruling option that the caller wants to withdraw from.\",\"_coreDisputeID\":\"Index of the dispute in Kleros Core contract.\",\"_coreRoundID\":\"The round in the Kleros Core contract the caller wants to withdraw from.\"},\"returns\":{\"amount\":\"The withdrawn amount.\"}}},\"title\":\"DisputeKitClassic Dispute kit implementation of the Kleros v1 features including: - a drawing system: proportional to staked PNK, - a vote aggregation system: plurality, - an incentive system: equal split between coherent votes, - an appeal system: fund 2 choices only, vote on any choice.\",\"version\":1},\"userdoc\":{\"errors\":{\"FailedDelegateCall()\":[{\"notice\":\"Failed Delegated call\"}],\"InvalidImplementation(address)\":[{\"notice\":\"The `implementation` is not UUPS-compliant\"}]},\"events\":{\"Upgraded(address)\":{\"notice\":\"Emitted when the `implementation` has been successfully upgraded.\"}},\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/arbitration/dispute-kits/DisputeKitClassic.sol\":\"DisputeKitClassic\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":100},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.20;\\n\\n/**\\n * @dev Interface of the ERC-20 standard as defined in the ERC.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n\\n /**\\n * @dev Returns the value of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the value of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 value) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\\n * caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 value) external returns (bool);\\n\\n /**\\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\\n * allowance mechanism. `value` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(address from, address to, uint256 value) external returns (bool);\\n}\\n\",\"keccak256\":\"0xe06a3f08a987af6ad2e1c1e774405d4fe08f1694b67517438b467cecf0da0ef7\",\"license\":\"MIT\"},\"src/arbitration/KlerosCore.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\n/// @custom:authors: [@unknownunknown1, @jaybuidl]\\n/// @custom:reviewers: []\\n/// @custom:auditors: []\\n/// @custom:bounties: []\\n/// @custom:deployments: []\\n\\npragma solidity 0.8.24;\\n\\nimport \\\"./KlerosCoreBase.sol\\\";\\nimport {UUPSProxiable} from \\\"../proxy/UUPSProxiable.sol\\\";\\nimport {Initializable} from \\\"../proxy/Initializable.sol\\\";\\n\\n/// @title KlerosCore\\n/// Core arbitrator contract for Kleros v2.\\n/// Note that this contract trusts the PNK token, the dispute kit and the sortition module contracts.\\ncontract KlerosCore is KlerosCoreBase, UUPSProxiable, Initializable {\\n // ************************************* //\\n // * Constructor * //\\n // ************************************* //\\n\\n /// @dev Constructor, initializing the implementation to reduce attack surface.\\n constructor() {\\n _disableInitializers();\\n }\\n\\n /// @dev Initializer (constructor equivalent for upgradable contracts).\\n /// @param _governor The governor's address.\\n /// @param _guardian The guardian's address.\\n /// @param _pinakion The address of the token contract.\\n /// @param _jurorProsecutionModule The address of the juror prosecution module.\\n /// @param _disputeKit The address of the default dispute kit.\\n /// @param _hiddenVotes The `hiddenVotes` property value of the general court.\\n /// @param _courtParameters Numeric parameters of General court (minStake, alpha, feeForJuror and jurorsForCourtJump respectively).\\n /// @param _timesPerPeriod The `timesPerPeriod` property value of the general court.\\n /// @param _sortitionExtraData The extra data for sortition module.\\n /// @param _sortitionModuleAddress The sortition module responsible for sortition of the jurors.\\n function initialize(\\n address _governor,\\n address _guardian,\\n IERC20 _pinakion,\\n address _jurorProsecutionModule,\\n IDisputeKit _disputeKit,\\n bool _hiddenVotes,\\n uint256[4] memory _courtParameters,\\n uint256[4] memory _timesPerPeriod,\\n bytes memory _sortitionExtraData,\\n ISortitionModule _sortitionModuleAddress\\n ) external reinitializer(1) {\\n _initialize(\\n _governor,\\n _guardian,\\n _pinakion,\\n _jurorProsecutionModule,\\n _disputeKit,\\n _hiddenVotes,\\n _courtParameters,\\n _timesPerPeriod,\\n _sortitionExtraData,\\n _sortitionModuleAddress\\n );\\n }\\n\\n // ************************************* //\\n // * Governance * //\\n // ************************************* //\\n\\n /// @dev Access Control to perform implementation upgrades (UUPS Proxiable)\\n /// Only the governor can perform upgrades (`onlyByGovernor`)\\n function _authorizeUpgrade(address) internal view override onlyByGovernor {\\n // NOP\\n }\\n}\\n\",\"keccak256\":\"0x1dc9311f4df8d5c707be5fc0f0e87574b2ca4a4957eb0ffecdf2153a8eace1d2\",\"license\":\"MIT\"},\"src/arbitration/KlerosCoreBase.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\n/// @custom:authors: [@unknownunknown1, @jaybuidl]\\n/// @custom:reviewers: []\\n/// @custom:auditors: []\\n/// @custom:bounties: []\\n/// @custom:deployments: []\\n\\npragma solidity 0.8.24;\\n\\nimport {IArbitrableV2, IArbitratorV2} from \\\"./interfaces/IArbitratorV2.sol\\\";\\nimport {IDisputeKit} from \\\"./interfaces/IDisputeKit.sol\\\";\\nimport {ISortitionModule} from \\\"./interfaces/ISortitionModule.sol\\\";\\nimport {SafeERC20, IERC20} from \\\"../libraries/SafeERC20.sol\\\";\\nimport \\\"../libraries/Constants.sol\\\";\\n\\n/// @title KlerosCoreBase\\n/// Core arbitrator contract for Kleros v2.\\n/// Note that this contract trusts the PNK token, the dispute kit and the sortition module contracts.\\nabstract contract KlerosCoreBase is IArbitratorV2 {\\n using SafeERC20 for IERC20;\\n\\n // ************************************* //\\n // * Enums / Structs * //\\n // ************************************* //\\n\\n enum Period {\\n evidence, // Evidence can be submitted. This is also when drawing has to take place.\\n commit, // Jurors commit a hashed vote. This is skipped for courts without hidden votes.\\n vote, // Jurors reveal/cast their vote depending on whether the court has hidden votes or not.\\n appeal, // The dispute can be appealed.\\n execution // Tokens are redistributed and the ruling is executed.\\n }\\n\\n struct Court {\\n uint96 parent; // The parent court.\\n bool hiddenVotes; // Whether to use commit and reveal or not.\\n uint256[] children; // List of child courts.\\n uint256 minStake; // Minimum PNKs needed to stake in the court.\\n uint256 alpha; // Basis point of PNKs that are lost when incoherent.\\n uint256 feeForJuror; // Arbitration fee paid per juror.\\n uint256 jurorsForCourtJump; // The appeal after the one that reaches this number of jurors will go to the parent court if any.\\n uint256[4] timesPerPeriod; // The time allotted to each dispute period in the form `timesPerPeriod[period]`.\\n mapping(uint256 disputeKitId => bool) supportedDisputeKits; // True if DK with this ID is supported by the court. Note that each court must support classic dispute kit.\\n bool disabled; // True if the court is disabled. Unused for now, will be implemented later.\\n }\\n\\n struct Dispute {\\n uint96 courtID; // The ID of the court the dispute is in.\\n IArbitrableV2 arbitrated; // The arbitrable contract.\\n Period period; // The current period of the dispute.\\n bool ruled; // True if the ruling has been executed, false otherwise.\\n uint256 lastPeriodChange; // The last time the period was changed.\\n Round[] rounds;\\n }\\n\\n struct Round {\\n uint256 disputeKitID; // Index of the dispute kit in the array.\\n uint256 pnkAtStakePerJuror; // The amount of PNKs at stake for each juror in this round.\\n uint256 totalFeesForJurors; // The total juror fees paid in this round.\\n uint256 nbVotes; // The total number of votes the dispute can possibly have in the current round. Former votes[_round].length.\\n uint256 repartitions; // A counter of reward repartitions made in this round.\\n uint256 pnkPenalties; // The amount of PNKs collected from penalties in this round.\\n address[] drawnJurors; // Addresses of the jurors that were drawn in this round.\\n uint256 sumFeeRewardPaid; // Total sum of arbitration fees paid to coherent jurors as a reward in this round.\\n uint256 sumPnkRewardPaid; // Total sum of PNK paid to coherent jurors as a reward in this round.\\n IERC20 feeToken; // The token used for paying fees in this round.\\n uint256 drawIterations; // The number of iterations passed drawing the jurors for this round.\\n }\\n\\n // Workaround \\\"stack too deep\\\" errors\\n struct ExecuteParams {\\n uint256 disputeID; // The ID of the dispute to execute.\\n uint256 round; // The round to execute.\\n uint256 coherentCount; // The number of coherent votes in the round.\\n uint256 numberOfVotesInRound; // The number of votes in the round.\\n uint256 feePerJurorInRound; // The fee per juror in the round.\\n uint256 pnkAtStakePerJurorInRound; // The amount of PNKs at stake for each juror in the round.\\n uint256 pnkPenaltiesInRound; // The amount of PNKs collected from penalties in the round.\\n uint256 repartition; // The index of the repartition to execute.\\n }\\n\\n struct CurrencyRate {\\n bool feePaymentAccepted;\\n uint64 rateInEth;\\n uint8 rateDecimals;\\n }\\n\\n // ************************************* //\\n // * Storage * //\\n // ************************************* //\\n\\n uint256 private constant ALPHA_DIVISOR = 1e4; // The number to divide `Court.alpha` by.\\n uint256 private constant NON_PAYABLE_AMOUNT = (2 ** 256 - 2) / 2; // An amount higher than the supply of ETH.\\n\\n address public governor; // The governor of the contract.\\n address public guardian; // The guardian able to pause asset withdrawals.\\n IERC20 public pinakion; // The Pinakion token contract.\\n address public jurorProsecutionModule; // The module for juror's prosecution.\\n ISortitionModule public sortitionModule; // Sortition module for drawing.\\n Court[] public courts; // The courts.\\n IDisputeKit[] public disputeKits; // Array of dispute kits.\\n Dispute[] public disputes; // The disputes.\\n mapping(IERC20 => CurrencyRate) public currencyRates; // The price of each token in ETH.\\n bool public paused; // Whether asset withdrawals are paused.\\n\\n // ************************************* //\\n // * Events * //\\n // ************************************* //\\n\\n event NewPeriod(uint256 indexed _disputeID, Period _period);\\n event AppealPossible(uint256 indexed _disputeID, IArbitrableV2 indexed _arbitrable);\\n event AppealDecision(uint256 indexed _disputeID, IArbitrableV2 indexed _arbitrable);\\n event Draw(address indexed _address, uint256 indexed _disputeID, uint256 _roundID, uint256 _voteID);\\n event CourtCreated(\\n uint256 indexed _courtID,\\n uint96 indexed _parent,\\n bool _hiddenVotes,\\n uint256 _minStake,\\n uint256 _alpha,\\n uint256 _feeForJuror,\\n uint256 _jurorsForCourtJump,\\n uint256[4] _timesPerPeriod,\\n uint256[] _supportedDisputeKits\\n );\\n event CourtModified(\\n uint96 indexed _courtID,\\n bool _hiddenVotes,\\n uint256 _minStake,\\n uint256 _alpha,\\n uint256 _feeForJuror,\\n uint256 _jurorsForCourtJump,\\n uint256[4] _timesPerPeriod\\n );\\n event DisputeKitCreated(uint256 indexed _disputeKitID, IDisputeKit indexed _disputeKitAddress);\\n event DisputeKitEnabled(uint96 indexed _courtID, uint256 indexed _disputeKitID, bool indexed _enable);\\n event CourtJump(\\n uint256 indexed _disputeID,\\n uint256 indexed _roundID,\\n uint96 indexed _fromCourtID,\\n uint96 _toCourtID\\n );\\n event DisputeKitJump(\\n uint256 indexed _disputeID,\\n uint256 indexed _roundID,\\n uint256 indexed _fromDisputeKitID,\\n uint256 _toDisputeKitID\\n );\\n event TokenAndETHShift(\\n address indexed _account,\\n uint256 indexed _disputeID,\\n uint256 indexed _roundID,\\n uint256 _degreeOfCoherency,\\n int256 _pnkAmount,\\n int256 _feeAmount,\\n IERC20 _feeToken\\n );\\n event LeftoverRewardSent(\\n uint256 indexed _disputeID,\\n uint256 indexed _roundID,\\n uint256 _pnkAmount,\\n uint256 _feeAmount,\\n IERC20 _feeToken\\n );\\n event Paused();\\n event Unpaused();\\n\\n // ************************************* //\\n // * Function Modifiers * //\\n // ************************************* //\\n\\n modifier onlyByGovernor() {\\n if (governor != msg.sender) revert GovernorOnly();\\n _;\\n }\\n\\n modifier onlyByGuardianOrGovernor() {\\n if (guardian != msg.sender && governor != msg.sender) revert GuardianOrGovernorOnly();\\n _;\\n }\\n\\n modifier whenPaused() {\\n if (!paused) revert WhenPausedOnly();\\n _;\\n }\\n\\n modifier whenNotPaused() {\\n if (paused) revert WhenNotPausedOnly();\\n _;\\n }\\n\\n // ************************************* //\\n // * Constructor * //\\n // ************************************* //\\n\\n function _initialize(\\n address _governor,\\n address _guardian,\\n IERC20 _pinakion,\\n address _jurorProsecutionModule,\\n IDisputeKit _disputeKit,\\n bool _hiddenVotes,\\n uint256[4] memory _courtParameters,\\n uint256[4] memory _timesPerPeriod,\\n bytes memory _sortitionExtraData,\\n ISortitionModule _sortitionModuleAddress\\n ) internal {\\n governor = _governor;\\n guardian = _guardian;\\n pinakion = _pinakion;\\n jurorProsecutionModule = _jurorProsecutionModule;\\n sortitionModule = _sortitionModuleAddress;\\n\\n // NULL_DISPUTE_KIT: an empty element at index 0 to indicate when a dispute kit is not supported.\\n disputeKits.push();\\n\\n // DISPUTE_KIT_CLASSIC\\n disputeKits.push(_disputeKit);\\n\\n emit DisputeKitCreated(DISPUTE_KIT_CLASSIC, _disputeKit);\\n\\n // FORKING_COURT\\n // TODO: Fill the properties for the Forking court, emit CourtCreated.\\n courts.push();\\n sortitionModule.createTree(bytes32(uint256(FORKING_COURT)), _sortitionExtraData);\\n\\n // GENERAL_COURT\\n Court storage court = courts.push();\\n court.parent = FORKING_COURT;\\n court.children = new uint256[](0);\\n court.hiddenVotes = _hiddenVotes;\\n court.minStake = _courtParameters[0];\\n court.alpha = _courtParameters[1];\\n court.feeForJuror = _courtParameters[2];\\n court.jurorsForCourtJump = _courtParameters[3];\\n court.timesPerPeriod = _timesPerPeriod;\\n\\n sortitionModule.createTree(bytes32(uint256(GENERAL_COURT)), _sortitionExtraData);\\n\\n emit CourtCreated(\\n 1,\\n court.parent,\\n _hiddenVotes,\\n _courtParameters[0],\\n _courtParameters[1],\\n _courtParameters[2],\\n _courtParameters[3],\\n _timesPerPeriod,\\n new uint256[](0)\\n );\\n _enableDisputeKit(GENERAL_COURT, DISPUTE_KIT_CLASSIC, true);\\n }\\n\\n // ************************************* //\\n // * Governance * //\\n // ************************************* //\\n\\n /// @dev Pause staking and reward execution. Can only be done by guardian or governor.\\n function pause() external onlyByGuardianOrGovernor whenNotPaused {\\n paused = true;\\n emit Paused();\\n }\\n\\n /// @dev Unpause staking and reward execution. Can only be done by governor.\\n function unpause() external onlyByGovernor whenPaused {\\n paused = false;\\n emit Unpaused();\\n }\\n\\n /// @dev Allows the governor to call anything on behalf of the contract.\\n /// @param _destination The destination of the call.\\n /// @param _amount The value sent with the call.\\n /// @param _data The data sent with the call.\\n function executeGovernorProposal(\\n address _destination,\\n uint256 _amount,\\n bytes memory _data\\n ) external onlyByGovernor {\\n (bool success, ) = _destination.call{value: _amount}(_data);\\n if (!success) revert UnsuccessfulCall();\\n }\\n\\n /// @dev Changes the `governor` storage variable.\\n /// @param _governor The new value for the `governor` storage variable.\\n function changeGovernor(address payable _governor) external onlyByGovernor {\\n governor = _governor;\\n }\\n\\n /// @dev Changes the `guardian` storage variable.\\n /// @param _guardian The new value for the `guardian` storage variable.\\n function changeGuardian(address _guardian) external onlyByGovernor {\\n guardian = _guardian;\\n }\\n\\n /// @dev Changes the `pinakion` storage variable.\\n /// @param _pinakion The new value for the `pinakion` storage variable.\\n function changePinakion(IERC20 _pinakion) external onlyByGovernor {\\n pinakion = _pinakion;\\n }\\n\\n /// @dev Changes the `jurorProsecutionModule` storage variable.\\n /// @param _jurorProsecutionModule The new value for the `jurorProsecutionModule` storage variable.\\n function changeJurorProsecutionModule(address _jurorProsecutionModule) external onlyByGovernor {\\n jurorProsecutionModule = _jurorProsecutionModule;\\n }\\n\\n /// @dev Changes the `_sortitionModule` storage variable.\\n /// Note that the new module should be initialized for all courts.\\n /// @param _sortitionModule The new value for the `sortitionModule` storage variable.\\n function changeSortitionModule(ISortitionModule _sortitionModule) external onlyByGovernor {\\n sortitionModule = _sortitionModule;\\n }\\n\\n /// @dev Add a new supported dispute kit module to the court.\\n /// @param _disputeKitAddress The address of the dispute kit contract.\\n function addNewDisputeKit(IDisputeKit _disputeKitAddress) external onlyByGovernor {\\n uint256 disputeKitID = disputeKits.length;\\n disputeKits.push(_disputeKitAddress);\\n emit DisputeKitCreated(disputeKitID, _disputeKitAddress);\\n }\\n\\n /// @dev Creates a court under a specified parent court.\\n /// @param _parent The `parent` property value of the court.\\n /// @param _hiddenVotes The `hiddenVotes` property value of the court.\\n /// @param _minStake The `minStake` property value of the court.\\n /// @param _alpha The `alpha` property value of the court.\\n /// @param _feeForJuror The `feeForJuror` property value of the court.\\n /// @param _jurorsForCourtJump The `jurorsForCourtJump` property value of the court.\\n /// @param _timesPerPeriod The `timesPerPeriod` property value of the court.\\n /// @param _sortitionExtraData Extra data for sortition module.\\n /// @param _supportedDisputeKits Indexes of dispute kits that this court will support.\\n function createCourt(\\n uint96 _parent,\\n bool _hiddenVotes,\\n uint256 _minStake,\\n uint256 _alpha,\\n uint256 _feeForJuror,\\n uint256 _jurorsForCourtJump,\\n uint256[4] memory _timesPerPeriod,\\n bytes memory _sortitionExtraData,\\n uint256[] memory _supportedDisputeKits\\n ) external onlyByGovernor {\\n if (courts[_parent].minStake > _minStake) revert MinStakeLowerThanParentCourt();\\n if (_supportedDisputeKits.length == 0) revert UnsupportedDisputeKit();\\n if (_parent == FORKING_COURT) revert InvalidForkingCourtAsParent();\\n\\n uint256 courtID = courts.length;\\n Court storage court = courts.push();\\n\\n for (uint256 i = 0; i < _supportedDisputeKits.length; i++) {\\n if (_supportedDisputeKits[i] == 0 || _supportedDisputeKits[i] >= disputeKits.length) {\\n revert WrongDisputeKitIndex();\\n }\\n court.supportedDisputeKits[_supportedDisputeKits[i]] = true;\\n }\\n // Check that Classic DK support was added.\\n if (!court.supportedDisputeKits[DISPUTE_KIT_CLASSIC]) revert MustSupportDisputeKitClassic();\\n\\n court.parent = _parent;\\n court.children = new uint256[](0);\\n court.hiddenVotes = _hiddenVotes;\\n court.minStake = _minStake;\\n court.alpha = _alpha;\\n court.feeForJuror = _feeForJuror;\\n court.jurorsForCourtJump = _jurorsForCourtJump;\\n court.timesPerPeriod = _timesPerPeriod;\\n\\n sortitionModule.createTree(bytes32(courtID), _sortitionExtraData);\\n\\n // Update the parent.\\n courts[_parent].children.push(courtID);\\n emit CourtCreated(\\n courtID,\\n _parent,\\n _hiddenVotes,\\n _minStake,\\n _alpha,\\n _feeForJuror,\\n _jurorsForCourtJump,\\n _timesPerPeriod,\\n _supportedDisputeKits\\n );\\n }\\n\\n function changeCourtParameters(\\n uint96 _courtID,\\n bool _hiddenVotes,\\n uint256 _minStake,\\n uint256 _alpha,\\n uint256 _feeForJuror,\\n uint256 _jurorsForCourtJump,\\n uint256[4] memory _timesPerPeriod\\n ) external onlyByGovernor {\\n Court storage court = courts[_courtID];\\n if (_courtID != GENERAL_COURT && courts[court.parent].minStake > _minStake) {\\n revert MinStakeLowerThanParentCourt();\\n }\\n for (uint256 i = 0; i < court.children.length; i++) {\\n if (courts[court.children[i]].minStake < _minStake) {\\n revert MinStakeLowerThanParentCourt();\\n }\\n }\\n court.minStake = _minStake;\\n court.hiddenVotes = _hiddenVotes;\\n court.alpha = _alpha;\\n court.feeForJuror = _feeForJuror;\\n court.jurorsForCourtJump = _jurorsForCourtJump;\\n court.timesPerPeriod = _timesPerPeriod;\\n emit CourtModified(\\n _courtID,\\n _hiddenVotes,\\n _minStake,\\n _alpha,\\n _feeForJuror,\\n _jurorsForCourtJump,\\n _timesPerPeriod\\n );\\n }\\n\\n /// @dev Adds/removes court's support for specified dispute kits.\\n /// @param _courtID The ID of the court.\\n /// @param _disputeKitIDs The IDs of dispute kits which support should be added/removed.\\n /// @param _enable Whether add or remove the dispute kits from the court.\\n function enableDisputeKits(uint96 _courtID, uint256[] memory _disputeKitIDs, bool _enable) external onlyByGovernor {\\n for (uint256 i = 0; i < _disputeKitIDs.length; i++) {\\n if (_enable) {\\n if (_disputeKitIDs[i] == 0 || _disputeKitIDs[i] >= disputeKits.length) {\\n revert WrongDisputeKitIndex();\\n }\\n _enableDisputeKit(_courtID, _disputeKitIDs[i], true);\\n } else {\\n // Classic dispute kit must be supported by all courts.\\n if (_disputeKitIDs[i] == DISPUTE_KIT_CLASSIC) {\\n revert CannotDisableClassicDK();\\n }\\n _enableDisputeKit(_courtID, _disputeKitIDs[i], false);\\n }\\n }\\n }\\n\\n /// @dev Changes the supported fee tokens.\\n /// @param _feeToken The fee token.\\n /// @param _accepted Whether the token is supported or not as a method of fee payment.\\n function changeAcceptedFeeTokens(IERC20 _feeToken, bool _accepted) external onlyByGovernor {\\n currencyRates[_feeToken].feePaymentAccepted = _accepted;\\n emit AcceptedFeeToken(_feeToken, _accepted);\\n }\\n\\n /// @dev Changes the currency rate of a fee token.\\n /// @param _feeToken The fee token.\\n /// @param _rateInEth The new rate of the fee token in ETH.\\n /// @param _rateDecimals The new decimals of the fee token rate.\\n function changeCurrencyRates(IERC20 _feeToken, uint64 _rateInEth, uint8 _rateDecimals) external onlyByGovernor {\\n currencyRates[_feeToken].rateInEth = _rateInEth;\\n currencyRates[_feeToken].rateDecimals = _rateDecimals;\\n emit NewCurrencyRate(_feeToken, _rateInEth, _rateDecimals);\\n }\\n\\n // ************************************* //\\n // * State Modifiers * //\\n // ************************************* //\\n\\n /// @dev Sets the caller's stake in a court.\\n /// @param _courtID The ID of the court.\\n /// @param _newStake The new stake.\\n /// Note that the existing delayed stake will be nullified as non-relevant.\\n function setStake(uint96 _courtID, uint256 _newStake) external virtual whenNotPaused {\\n _setStake(msg.sender, _courtID, _newStake, false, OnError.Revert);\\n }\\n\\n /// @dev Sets the stake of a specified account in a court, typically to apply a delayed stake or unstake inactive jurors.\\n /// @param _account The account whose stake is being set.\\n /// @param _courtID The ID of the court.\\n /// @param _newStake The new stake.\\n /// @param _alreadyTransferred Whether the PNKs have already been transferred to the contract.\\n function setStakeBySortitionModule(\\n address _account,\\n uint96 _courtID,\\n uint256 _newStake,\\n bool _alreadyTransferred\\n ) external {\\n if (msg.sender != address(sortitionModule)) revert SortitionModuleOnly();\\n _setStake(_account, _courtID, _newStake, _alreadyTransferred, OnError.Return);\\n }\\n\\n /// @inheritdoc IArbitratorV2\\n function createDispute(\\n uint256 _numberOfChoices,\\n bytes memory _extraData\\n ) external payable override returns (uint256 disputeID) {\\n if (msg.value < arbitrationCost(_extraData)) revert ArbitrationFeesNotEnough();\\n\\n return _createDispute(_numberOfChoices, _extraData, NATIVE_CURRENCY, msg.value);\\n }\\n\\n /// @inheritdoc IArbitratorV2\\n function createDispute(\\n uint256 _numberOfChoices,\\n bytes calldata _extraData,\\n IERC20 _feeToken,\\n uint256 _feeAmount\\n ) external override returns (uint256 disputeID) {\\n if (!currencyRates[_feeToken].feePaymentAccepted) revert TokenNotAccepted();\\n if (_feeAmount < arbitrationCost(_extraData, _feeToken)) revert ArbitrationFeesNotEnough();\\n\\n if (!_feeToken.safeTransferFrom(msg.sender, address(this), _feeAmount)) revert TransferFailed();\\n return _createDispute(_numberOfChoices, _extraData, _feeToken, _feeAmount);\\n }\\n\\n function _createDispute(\\n uint256 _numberOfChoices,\\n bytes memory _extraData,\\n IERC20 _feeToken,\\n uint256 _feeAmount\\n ) internal virtual returns (uint256 disputeID) {\\n (uint96 courtID, , uint256 disputeKitID) = _extraDataToCourtIDMinJurorsDisputeKit(_extraData);\\n if (!courts[courtID].supportedDisputeKits[disputeKitID]) revert DisputeKitNotSupportedByCourt();\\n\\n disputeID = disputes.length;\\n Dispute storage dispute = disputes.push();\\n dispute.courtID = courtID;\\n dispute.arbitrated = IArbitrableV2(msg.sender);\\n dispute.lastPeriodChange = block.timestamp;\\n\\n IDisputeKit disputeKit = disputeKits[disputeKitID];\\n Court storage court = courts[courtID];\\n Round storage round = dispute.rounds.push();\\n\\n // Obtain the feeForJuror in the same currency as the _feeAmount\\n uint256 feeForJuror = (_feeToken == NATIVE_CURRENCY)\\n ? court.feeForJuror\\n : convertEthToTokenAmount(_feeToken, court.feeForJuror);\\n round.nbVotes = _feeAmount / feeForJuror;\\n round.disputeKitID = disputeKitID;\\n round.pnkAtStakePerJuror = (court.minStake * court.alpha) / ALPHA_DIVISOR;\\n round.totalFeesForJurors = _feeAmount;\\n round.feeToken = IERC20(_feeToken);\\n\\n sortitionModule.createDisputeHook(disputeID, 0); // Default round ID.\\n\\n disputeKit.createDispute(disputeID, _numberOfChoices, _extraData, round.nbVotes);\\n emit DisputeCreation(disputeID, IArbitrableV2(msg.sender));\\n }\\n\\n /// @dev Passes the period of a specified dispute.\\n /// @param _disputeID The ID of the dispute.\\n function passPeriod(uint256 _disputeID) external {\\n Dispute storage dispute = disputes[_disputeID];\\n Court storage court = courts[dispute.courtID];\\n\\n uint256 currentRound = dispute.rounds.length - 1;\\n Round storage round = dispute.rounds[currentRound];\\n if (dispute.period == Period.evidence) {\\n if (\\n currentRound == 0 &&\\n block.timestamp - dispute.lastPeriodChange < court.timesPerPeriod[uint256(dispute.period)]\\n ) {\\n revert EvidenceNotPassedAndNotAppeal();\\n }\\n if (round.drawnJurors.length != round.nbVotes) revert DisputeStillDrawing();\\n dispute.period = court.hiddenVotes ? Period.commit : Period.vote;\\n } else if (dispute.period == Period.commit) {\\n if (\\n block.timestamp - dispute.lastPeriodChange < court.timesPerPeriod[uint256(dispute.period)] &&\\n !disputeKits[round.disputeKitID].areCommitsAllCast(_disputeID)\\n ) {\\n revert CommitPeriodNotPassed();\\n }\\n dispute.period = Period.vote;\\n } else if (dispute.period == Period.vote) {\\n if (\\n block.timestamp - dispute.lastPeriodChange < court.timesPerPeriod[uint256(dispute.period)] &&\\n !disputeKits[round.disputeKitID].areVotesAllCast(_disputeID)\\n ) {\\n revert VotePeriodNotPassed();\\n }\\n dispute.period = Period.appeal;\\n emit AppealPossible(_disputeID, dispute.arbitrated);\\n } else if (dispute.period == Period.appeal) {\\n if (block.timestamp - dispute.lastPeriodChange < court.timesPerPeriod[uint256(dispute.period)]) {\\n revert AppealPeriodNotPassed();\\n }\\n dispute.period = Period.execution;\\n } else if (dispute.period == Period.execution) {\\n revert DisputePeriodIsFinal();\\n }\\n\\n dispute.lastPeriodChange = block.timestamp;\\n emit NewPeriod(_disputeID, dispute.period);\\n }\\n\\n /// @dev Draws jurors for the dispute. Can be called in parts.\\n /// @param _disputeID The ID of the dispute.\\n /// @param _iterations The number of iterations to run.\\n function draw(uint256 _disputeID, uint256 _iterations) external {\\n Dispute storage dispute = disputes[_disputeID];\\n uint256 currentRound = dispute.rounds.length - 1;\\n Round storage round = dispute.rounds[currentRound];\\n if (dispute.period != Period.evidence) revert NotEvidencePeriod();\\n\\n IDisputeKit disputeKit = disputeKits[round.disputeKitID];\\n\\n uint256 startIndex = round.drawIterations; // for gas: less storage reads\\n uint256 i;\\n while (i < _iterations && round.drawnJurors.length < round.nbVotes) {\\n address drawnAddress = disputeKit.draw(_disputeID, startIndex + i++);\\n if (drawnAddress == address(0)) {\\n continue;\\n }\\n sortitionModule.lockStake(drawnAddress, round.pnkAtStakePerJuror);\\n emit Draw(drawnAddress, _disputeID, currentRound, round.drawnJurors.length);\\n round.drawnJurors.push(drawnAddress);\\n if (round.drawnJurors.length == round.nbVotes) {\\n sortitionModule.postDrawHook(_disputeID, currentRound);\\n }\\n }\\n round.drawIterations += i;\\n }\\n\\n /// @dev Appeals the ruling of a specified dispute.\\n /// Note: Access restricted to the Dispute Kit for this `disputeID`.\\n /// @param _disputeID The ID of the dispute.\\n /// @param _numberOfChoices Number of choices for the dispute. Can be required during court jump.\\n /// @param _extraData Extradata for the dispute. Can be required during court jump.\\n function appeal(uint256 _disputeID, uint256 _numberOfChoices, bytes memory _extraData) external payable {\\n if (msg.value < appealCost(_disputeID)) revert AppealFeesNotEnough();\\n\\n Dispute storage dispute = disputes[_disputeID];\\n if (dispute.period != Period.appeal) revert DisputeNotAppealable();\\n\\n Round storage round = dispute.rounds[dispute.rounds.length - 1];\\n if (msg.sender != address(disputeKits[round.disputeKitID])) revert DisputeKitOnly();\\n\\n uint96 newCourtID = dispute.courtID;\\n uint256 newDisputeKitID = round.disputeKitID;\\n\\n // Warning: the extra round must be created before calling disputeKit.createDispute()\\n Round storage extraRound = dispute.rounds.push();\\n\\n if (round.nbVotes >= courts[newCourtID].jurorsForCourtJump) {\\n // Jump to parent court.\\n newCourtID = courts[newCourtID].parent;\\n\\n if (!courts[newCourtID].supportedDisputeKits[newDisputeKitID]) {\\n // Switch to classic dispute kit if parent court doesn't support the current one.\\n newDisputeKitID = DISPUTE_KIT_CLASSIC;\\n }\\n\\n if (newCourtID != dispute.courtID) {\\n emit CourtJump(_disputeID, dispute.rounds.length - 1, dispute.courtID, newCourtID);\\n }\\n }\\n\\n dispute.courtID = newCourtID;\\n dispute.period = Period.evidence;\\n dispute.lastPeriodChange = block.timestamp;\\n\\n Court storage court = courts[newCourtID];\\n extraRound.nbVotes = msg.value / court.feeForJuror; // As many votes that can be afforded by the provided funds.\\n extraRound.pnkAtStakePerJuror = (court.minStake * court.alpha) / ALPHA_DIVISOR;\\n extraRound.totalFeesForJurors = msg.value;\\n extraRound.disputeKitID = newDisputeKitID;\\n\\n sortitionModule.createDisputeHook(_disputeID, dispute.rounds.length - 1);\\n\\n // Dispute kit was changed, so create a dispute in the new DK contract.\\n if (extraRound.disputeKitID != round.disputeKitID) {\\n emit DisputeKitJump(_disputeID, dispute.rounds.length - 1, round.disputeKitID, extraRound.disputeKitID);\\n disputeKits[extraRound.disputeKitID].createDispute(\\n _disputeID,\\n _numberOfChoices,\\n _extraData,\\n extraRound.nbVotes\\n );\\n }\\n\\n emit AppealDecision(_disputeID, dispute.arbitrated);\\n emit NewPeriod(_disputeID, Period.evidence);\\n }\\n\\n /// @dev Distribute the PNKs at stake and the dispute fees for the specific round of the dispute. Can be called in parts.\\n /// Note: Reward distributions are forbidden during pause.\\n /// @param _disputeID The ID of the dispute.\\n /// @param _round The appeal round.\\n /// @param _iterations The number of iterations to run.\\n function execute(uint256 _disputeID, uint256 _round, uint256 _iterations) external whenNotPaused {\\n Round storage round;\\n {\\n Dispute storage dispute = disputes[_disputeID];\\n if (dispute.period != Period.execution) revert NotExecutionPeriod();\\n\\n round = dispute.rounds[_round];\\n } // stack too deep workaround\\n\\n uint256 start = round.repartitions;\\n uint256 end = round.repartitions + _iterations;\\n\\n uint256 pnkPenaltiesInRound = round.pnkPenalties; // Keep in memory to save gas.\\n uint256 numberOfVotesInRound = round.drawnJurors.length;\\n uint256 feePerJurorInRound = round.totalFeesForJurors / numberOfVotesInRound;\\n uint256 pnkAtStakePerJurorInRound = round.pnkAtStakePerJuror;\\n uint256 coherentCount;\\n {\\n IDisputeKit disputeKit = disputeKits[round.disputeKitID];\\n coherentCount = disputeKit.getCoherentCount(_disputeID, _round); // Total number of jurors that are eligible to a reward in this round.\\n } // stack too deep workaround\\n\\n if (coherentCount == 0) {\\n // We loop over the votes once as there are no rewards because it is not a tie and no one in this round is coherent with the final outcome.\\n if (end > numberOfVotesInRound) end = numberOfVotesInRound;\\n } else {\\n // We loop over the votes twice, first to collect the PNK penalties, and second to distribute them as rewards along with arbitration fees.\\n if (end > numberOfVotesInRound * 2) end = numberOfVotesInRound * 2;\\n }\\n round.repartitions = end;\\n\\n for (uint256 i = start; i < end; i++) {\\n if (i < numberOfVotesInRound) {\\n pnkPenaltiesInRound = _executePenalties(\\n ExecuteParams({\\n disputeID: _disputeID,\\n round: _round,\\n coherentCount: coherentCount,\\n numberOfVotesInRound: numberOfVotesInRound,\\n feePerJurorInRound: feePerJurorInRound,\\n pnkAtStakePerJurorInRound: pnkAtStakePerJurorInRound,\\n pnkPenaltiesInRound: pnkPenaltiesInRound,\\n repartition: i\\n })\\n );\\n } else {\\n _executeRewards(\\n ExecuteParams({\\n disputeID: _disputeID,\\n round: _round,\\n coherentCount: coherentCount,\\n numberOfVotesInRound: numberOfVotesInRound,\\n feePerJurorInRound: feePerJurorInRound,\\n pnkAtStakePerJurorInRound: pnkAtStakePerJurorInRound,\\n pnkPenaltiesInRound: pnkPenaltiesInRound,\\n repartition: i\\n })\\n );\\n }\\n }\\n if (round.pnkPenalties != pnkPenaltiesInRound) {\\n round.pnkPenalties = pnkPenaltiesInRound; // Reentrancy risk: breaks Check-Effect-Interact\\n }\\n }\\n\\n /// @dev Distribute the PNKs at stake and the dispute fees for the specific round of the dispute, penalties only.\\n /// @param _params The parameters for the execution, see `ExecuteParams`.\\n /// @return pnkPenaltiesInRoundCache The updated penalties in round cache.\\n function _executePenalties(ExecuteParams memory _params) internal returns (uint256) {\\n Dispute storage dispute = disputes[_params.disputeID];\\n Round storage round = dispute.rounds[_params.round];\\n IDisputeKit disputeKit = disputeKits[round.disputeKitID];\\n\\n // [0, 1] value that determines how coherent the juror was in this round, in basis points.\\n uint256 degreeOfCoherence = disputeKit.getDegreeOfCoherence(\\n _params.disputeID,\\n _params.round,\\n _params.repartition,\\n _params.feePerJurorInRound,\\n _params.pnkAtStakePerJurorInRound\\n );\\n if (degreeOfCoherence > ALPHA_DIVISOR) {\\n // Make sure the degree doesn't exceed 1, though it should be ensured by the dispute kit.\\n degreeOfCoherence = ALPHA_DIVISOR;\\n }\\n\\n // Fully coherent jurors won't be penalized.\\n uint256 penalty = (round.pnkAtStakePerJuror * (ALPHA_DIVISOR - degreeOfCoherence)) / ALPHA_DIVISOR;\\n _params.pnkPenaltiesInRound += penalty;\\n\\n // Unlock the PNKs affected by the penalty\\n address account = round.drawnJurors[_params.repartition];\\n sortitionModule.unlockStake(account, penalty);\\n\\n // Apply the penalty to the staked PNKs.\\n sortitionModule.penalizeStake(account, penalty);\\n emit TokenAndETHShift(\\n account,\\n _params.disputeID,\\n _params.round,\\n degreeOfCoherence,\\n -int256(penalty),\\n 0,\\n round.feeToken\\n );\\n\\n if (!disputeKit.isVoteActive(_params.disputeID, _params.round, _params.repartition)) {\\n // The juror is inactive, unstake them.\\n sortitionModule.setJurorInactive(account);\\n }\\n if (_params.repartition == _params.numberOfVotesInRound - 1 && _params.coherentCount == 0) {\\n // No one was coherent, send the rewards to the governor.\\n if (round.feeToken == NATIVE_CURRENCY) {\\n // The dispute fees were paid in ETH\\n payable(governor).send(round.totalFeesForJurors);\\n } else {\\n // The dispute fees were paid in ERC20\\n round.feeToken.safeTransfer(governor, round.totalFeesForJurors);\\n }\\n pinakion.safeTransfer(governor, _params.pnkPenaltiesInRound);\\n emit LeftoverRewardSent(\\n _params.disputeID,\\n _params.round,\\n _params.pnkPenaltiesInRound,\\n round.totalFeesForJurors,\\n round.feeToken\\n );\\n }\\n return _params.pnkPenaltiesInRound;\\n }\\n\\n /// @dev Distribute the PNKs at stake and the dispute fees for the specific round of the dispute, rewards only.\\n /// @param _params The parameters for the execution, see `ExecuteParams`.\\n function _executeRewards(ExecuteParams memory _params) internal {\\n Dispute storage dispute = disputes[_params.disputeID];\\n Round storage round = dispute.rounds[_params.round];\\n IDisputeKit disputeKit = disputeKits[round.disputeKitID];\\n\\n // [0, 1] value that determines how coherent the juror was in this round, in basis points.\\n uint256 degreeOfCoherence = disputeKit.getDegreeOfCoherence(\\n _params.disputeID,\\n _params.round,\\n _params.repartition % _params.numberOfVotesInRound,\\n _params.feePerJurorInRound,\\n _params.pnkAtStakePerJurorInRound\\n );\\n\\n // Make sure the degree doesn't exceed 1, though it should be ensured by the dispute kit.\\n if (degreeOfCoherence > ALPHA_DIVISOR) {\\n degreeOfCoherence = ALPHA_DIVISOR;\\n }\\n\\n address account = round.drawnJurors[_params.repartition % _params.numberOfVotesInRound];\\n uint256 pnkLocked = (round.pnkAtStakePerJuror * degreeOfCoherence) / ALPHA_DIVISOR;\\n\\n // Release the rest of the PNKs of the juror for this round.\\n sortitionModule.unlockStake(account, pnkLocked);\\n\\n // Give back the locked PNKs in case the juror fully unstaked earlier.\\n if (!sortitionModule.isJurorStaked(account)) {\\n pinakion.safeTransfer(account, pnkLocked);\\n }\\n\\n // Transfer the rewards\\n uint256 pnkReward = ((_params.pnkPenaltiesInRound / _params.coherentCount) * degreeOfCoherence) / ALPHA_DIVISOR;\\n round.sumPnkRewardPaid += pnkReward;\\n uint256 feeReward = ((round.totalFeesForJurors / _params.coherentCount) * degreeOfCoherence) / ALPHA_DIVISOR;\\n round.sumFeeRewardPaid += feeReward;\\n pinakion.safeTransfer(account, pnkReward);\\n if (round.feeToken == NATIVE_CURRENCY) {\\n // The dispute fees were paid in ETH\\n payable(account).send(feeReward);\\n } else {\\n // The dispute fees were paid in ERC20\\n round.feeToken.safeTransfer(account, feeReward);\\n }\\n emit TokenAndETHShift(\\n account,\\n _params.disputeID,\\n _params.round,\\n degreeOfCoherence,\\n int256(pnkReward),\\n int256(feeReward),\\n round.feeToken\\n );\\n\\n // Transfer any residual rewards to the governor. It may happen due to partial coherence of the jurors.\\n if (_params.repartition == _params.numberOfVotesInRound * 2 - 1) {\\n uint256 leftoverPnkReward = _params.pnkPenaltiesInRound - round.sumPnkRewardPaid;\\n uint256 leftoverFeeReward = round.totalFeesForJurors - round.sumFeeRewardPaid;\\n if (leftoverPnkReward != 0 || leftoverFeeReward != 0) {\\n if (leftoverPnkReward != 0) {\\n pinakion.safeTransfer(governor, leftoverPnkReward);\\n }\\n if (leftoverFeeReward != 0) {\\n if (round.feeToken == NATIVE_CURRENCY) {\\n // The dispute fees were paid in ETH\\n payable(governor).send(leftoverFeeReward);\\n } else {\\n // The dispute fees were paid in ERC20\\n round.feeToken.safeTransfer(governor, leftoverFeeReward);\\n }\\n }\\n emit LeftoverRewardSent(\\n _params.disputeID,\\n _params.round,\\n leftoverPnkReward,\\n leftoverFeeReward,\\n round.feeToken\\n );\\n }\\n }\\n }\\n\\n /// @dev Executes a specified dispute's ruling.\\n /// @param _disputeID The ID of the dispute.\\n function executeRuling(uint256 _disputeID) external {\\n Dispute storage dispute = disputes[_disputeID];\\n if (dispute.period != Period.execution) revert NotExecutionPeriod();\\n if (dispute.ruled) revert RulingAlreadyExecuted();\\n\\n (uint256 winningChoice, , ) = currentRuling(_disputeID);\\n dispute.ruled = true;\\n emit Ruling(dispute.arbitrated, _disputeID, winningChoice);\\n dispute.arbitrated.rule(_disputeID, winningChoice);\\n }\\n\\n // ************************************* //\\n // * Public Views * //\\n // ************************************* //\\n\\n /// @dev Compute the cost of arbitration denominated in ETH.\\n /// It is recommended not to increase it often, as it can be highly time and gas consuming for the arbitrated contracts to cope with fee augmentation.\\n /// @param _extraData Additional info about the dispute. We use it to pass the ID of the dispute's court (first 32 bytes), the minimum number of jurors required (next 32 bytes) and the ID of the specific dispute kit (last 32 bytes).\\n /// @return cost The arbitration cost in ETH.\\n function arbitrationCost(bytes memory _extraData) public view override returns (uint256 cost) {\\n (uint96 courtID, uint256 minJurors, ) = _extraDataToCourtIDMinJurorsDisputeKit(_extraData);\\n cost = courts[courtID].feeForJuror * minJurors;\\n }\\n\\n /// @dev Compute the cost of arbitration denominated in `_feeToken`.\\n /// It is recommended not to increase it often, as it can be highly time and gas consuming for the arbitrated contracts to cope with fee augmentation.\\n /// @param _extraData Additional info about the dispute. We use it to pass the ID of the dispute's court (first 32 bytes), the minimum number of jurors required (next 32 bytes) and the ID of the specific dispute kit (last 32 bytes).\\n /// @param _feeToken The ERC20 token used to pay fees.\\n /// @return cost The arbitration cost in `_feeToken`.\\n function arbitrationCost(bytes calldata _extraData, IERC20 _feeToken) public view override returns (uint256 cost) {\\n cost = convertEthToTokenAmount(_feeToken, arbitrationCost(_extraData));\\n }\\n\\n /// @dev Gets the cost of appealing a specified dispute.\\n /// @param _disputeID The ID of the dispute.\\n /// @return cost The appeal cost.\\n function appealCost(uint256 _disputeID) public view returns (uint256 cost) {\\n Dispute storage dispute = disputes[_disputeID];\\n Round storage round = dispute.rounds[dispute.rounds.length - 1];\\n Court storage court = courts[dispute.courtID];\\n if (round.nbVotes >= court.jurorsForCourtJump) {\\n // Jump to parent court.\\n if (dispute.courtID == GENERAL_COURT) {\\n // TODO: Handle the forking when appealed in General court.\\n cost = NON_PAYABLE_AMOUNT; // Get the cost of the parent court.\\n } else {\\n cost = courts[court.parent].feeForJuror * ((round.nbVotes * 2) + 1);\\n }\\n } else {\\n // Stay in current court.\\n cost = court.feeForJuror * ((round.nbVotes * 2) + 1);\\n }\\n }\\n\\n /// @dev Gets the start and the end of a specified dispute's current appeal period.\\n /// @param _disputeID The ID of the dispute.\\n /// @return start The start of the appeal period.\\n /// @return end The end of the appeal period.\\n function appealPeriod(uint256 _disputeID) public view returns (uint256 start, uint256 end) {\\n Dispute storage dispute = disputes[_disputeID];\\n if (dispute.period == Period.appeal) {\\n start = dispute.lastPeriodChange;\\n end = dispute.lastPeriodChange + courts[dispute.courtID].timesPerPeriod[uint256(Period.appeal)];\\n } else {\\n start = 0;\\n end = 0;\\n }\\n }\\n\\n /// @dev Gets the current ruling of a specified dispute.\\n /// @param _disputeID The ID of the dispute.\\n /// @return ruling The current ruling.\\n /// @return tied Whether it's a tie or not.\\n /// @return overridden Whether the ruling was overridden by appeal funding or not.\\n function currentRuling(uint256 _disputeID) public view returns (uint256 ruling, bool tied, bool overridden) {\\n Dispute storage dispute = disputes[_disputeID];\\n Round storage round = dispute.rounds[dispute.rounds.length - 1];\\n IDisputeKit disputeKit = disputeKits[round.disputeKitID];\\n (ruling, tied, overridden) = disputeKit.currentRuling(_disputeID);\\n }\\n\\n function getRoundInfo(uint256 _disputeID, uint256 _round) external view returns (Round memory) {\\n return disputes[_disputeID].rounds[_round];\\n }\\n\\n function getNumberOfRounds(uint256 _disputeID) external view returns (uint256) {\\n return disputes[_disputeID].rounds.length;\\n }\\n\\n function isSupported(uint96 _courtID, uint256 _disputeKitID) external view returns (bool) {\\n return courts[_courtID].supportedDisputeKits[_disputeKitID];\\n }\\n\\n /// @dev Gets the timesPerPeriod array for a given court.\\n /// @param _courtID The ID of the court to get the times from.\\n /// @return timesPerPeriod The timesPerPeriod array for the given court.\\n function getTimesPerPeriod(uint96 _courtID) external view returns (uint256[4] memory timesPerPeriod) {\\n timesPerPeriod = courts[_courtID].timesPerPeriod;\\n }\\n\\n // ************************************* //\\n // * Public Views for Dispute Kits * //\\n // ************************************* //\\n\\n /// @dev Gets the number of votes permitted for the specified dispute in the latest round.\\n /// @param _disputeID The ID of the dispute.\\n function getNumberOfVotes(uint256 _disputeID) external view returns (uint256) {\\n Dispute storage dispute = disputes[_disputeID];\\n return dispute.rounds[dispute.rounds.length - 1].nbVotes;\\n }\\n\\n /// @dev Returns true if the dispute kit will be switched to a parent DK.\\n /// @param _disputeID The ID of the dispute.\\n /// @return Whether DK will be switched or not.\\n function isDisputeKitJumping(uint256 _disputeID) external view returns (bool) {\\n Dispute storage dispute = disputes[_disputeID];\\n Round storage round = dispute.rounds[dispute.rounds.length - 1];\\n Court storage court = courts[dispute.courtID];\\n\\n if (round.nbVotes < court.jurorsForCourtJump) {\\n return false;\\n }\\n\\n // Jump if the parent court doesn't support the current DK.\\n return !courts[court.parent].supportedDisputeKits[round.disputeKitID];\\n }\\n\\n function getDisputeKitsLength() external view returns (uint256) {\\n return disputeKits.length;\\n }\\n\\n function convertEthToTokenAmount(IERC20 _toToken, uint256 _amountInEth) public view returns (uint256) {\\n return (_amountInEth * 10 ** currencyRates[_toToken].rateDecimals) / currencyRates[_toToken].rateInEth;\\n }\\n\\n // ************************************* //\\n // * Internal * //\\n // ************************************* //\\n\\n /// @dev Toggles the dispute kit support for a given court.\\n /// @param _courtID The ID of the court to toggle the support for.\\n /// @param _disputeKitID The ID of the dispute kit to toggle the support for.\\n /// @param _enable Whether to enable or disable the support. Note that classic dispute kit should always be enabled.\\n function _enableDisputeKit(uint96 _courtID, uint256 _disputeKitID, bool _enable) internal {\\n courts[_courtID].supportedDisputeKits[_disputeKitID] = _enable;\\n emit DisputeKitEnabled(_courtID, _disputeKitID, _enable);\\n }\\n\\n /// @dev If called only once then set _onError to Revert, otherwise set it to Return\\n /// @param _account The account to set the stake for.\\n /// @param _courtID The ID of the court to set the stake for.\\n /// @param _newStake The new stake.\\n /// @param _alreadyTransferred Whether the PNKs were already transferred to/from the staking contract.\\n /// @param _onError Whether to revert or return false on error.\\n /// @return Whether the stake was successfully set or not.\\n function _setStake(\\n address _account,\\n uint96 _courtID,\\n uint256 _newStake,\\n bool _alreadyTransferred,\\n OnError _onError\\n ) internal returns (bool) {\\n if (_courtID == FORKING_COURT || _courtID > courts.length) {\\n _stakingFailed(_onError, StakingResult.CannotStakeInThisCourt); // Staking directly into the forking court is not allowed.\\n return false;\\n }\\n if (_newStake != 0 && _newStake < courts[_courtID].minStake) {\\n _stakingFailed(_onError, StakingResult.CannotStakeLessThanMinStake); // Staking less than the minimum stake is not allowed.\\n return false;\\n }\\n (uint256 pnkDeposit, uint256 pnkWithdrawal, StakingResult stakingResult) = sortitionModule.setStake(\\n _account,\\n _courtID,\\n _newStake,\\n _alreadyTransferred\\n );\\n if (stakingResult != StakingResult.Successful) {\\n _stakingFailed(_onError, stakingResult);\\n return false;\\n }\\n if (pnkDeposit > 0) {\\n if (!pinakion.safeTransferFrom(_account, address(this), pnkDeposit)) {\\n _stakingFailed(_onError, StakingResult.StakingTransferFailed);\\n return false;\\n }\\n }\\n if (pnkWithdrawal > 0) {\\n if (!pinakion.safeTransfer(_account, pnkWithdrawal)) {\\n _stakingFailed(_onError, StakingResult.UnstakingTransferFailed);\\n return false;\\n }\\n }\\n return true;\\n }\\n\\n /// @dev It may revert depending on the _onError parameter.\\n function _stakingFailed(OnError _onError, StakingResult _result) internal pure virtual {\\n if (_onError == OnError.Return) return;\\n if (_result == StakingResult.StakingTransferFailed) revert StakingTransferFailed();\\n if (_result == StakingResult.UnstakingTransferFailed) revert UnstakingTransferFailed();\\n if (_result == StakingResult.CannotStakeInMoreCourts) revert StakingInTooManyCourts();\\n if (_result == StakingResult.CannotStakeInThisCourt) revert StakingNotPossibeInThisCourt();\\n if (_result == StakingResult.CannotStakeLessThanMinStake) revert StakingLessThanCourtMinStake();\\n }\\n\\n /// @dev Gets a court ID, the minimum number of jurors and an ID of a dispute kit from a specified extra data bytes array.\\n /// Note that if extradata contains an incorrect value then this value will be switched to default.\\n /// @param _extraData The extra data bytes array. The first 32 bytes are the court ID, the next are the minimum number of jurors and the last are the dispute kit ID.\\n /// @return courtID The court ID.\\n /// @return minJurors The minimum number of jurors required.\\n /// @return disputeKitID The ID of the dispute kit.\\n function _extraDataToCourtIDMinJurorsDisputeKit(\\n bytes memory _extraData\\n ) internal view returns (uint96 courtID, uint256 minJurors, uint256 disputeKitID) {\\n // Note that if the extradata doesn't contain 32 bytes for the dispute kit ID it'll return the default 0 index.\\n if (_extraData.length >= 64) {\\n assembly {\\n // solium-disable-line security/no-inline-assembly\\n courtID := mload(add(_extraData, 0x20))\\n minJurors := mload(add(_extraData, 0x40))\\n disputeKitID := mload(add(_extraData, 0x60))\\n }\\n if (courtID == FORKING_COURT || courtID >= courts.length) {\\n courtID = GENERAL_COURT;\\n }\\n if (minJurors == 0) {\\n minJurors = DEFAULT_NB_OF_JURORS;\\n }\\n if (disputeKitID == NULL_DISPUTE_KIT || disputeKitID >= disputeKits.length) {\\n disputeKitID = DISPUTE_KIT_CLASSIC; // 0 index is not used.\\n }\\n } else {\\n courtID = GENERAL_COURT;\\n minJurors = DEFAULT_NB_OF_JURORS;\\n disputeKitID = DISPUTE_KIT_CLASSIC;\\n }\\n }\\n\\n // ************************************* //\\n // * Errors * //\\n // ************************************* //\\n\\n error GovernorOnly();\\n error GuardianOrGovernorOnly();\\n error DisputeKitOnly();\\n error SortitionModuleOnly();\\n error UnsuccessfulCall();\\n error InvalidDisputKitParent();\\n error DepthLevelMax();\\n error MinStakeLowerThanParentCourt();\\n error UnsupportedDisputeKit();\\n error InvalidForkingCourtAsParent();\\n error WrongDisputeKitIndex();\\n error CannotDisableClassicDK();\\n error ArraysLengthMismatch();\\n error StakingInTooManyCourts();\\n error StakingNotPossibeInThisCourt();\\n error StakingLessThanCourtMinStake();\\n error StakingTransferFailed();\\n error UnstakingTransferFailed();\\n error ArbitrationFeesNotEnough();\\n error DisputeKitNotSupportedByCourt();\\n error MustSupportDisputeKitClassic();\\n error TokenNotAccepted();\\n error EvidenceNotPassedAndNotAppeal();\\n error DisputeStillDrawing();\\n error CommitPeriodNotPassed();\\n error VotePeriodNotPassed();\\n error AppealPeriodNotPassed();\\n error NotEvidencePeriod();\\n error AppealFeesNotEnough();\\n error DisputeNotAppealable();\\n error NotExecutionPeriod();\\n error RulingAlreadyExecuted();\\n error DisputePeriodIsFinal();\\n error TransferFailed();\\n error WhenNotPausedOnly();\\n error WhenPausedOnly();\\n}\\n\",\"keccak256\":\"0x7435f0d24fde25165d4de404cbd4040339be136bac507196bfed0bb1f9f493f4\",\"license\":\"MIT\"},\"src/arbitration/dispute-kits/DisputeKitClassic.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\n/// @custom:authors: [@unknownunknown1, @jaybuidl]\\n/// @custom:reviewers: []\\n/// @custom:auditors: []\\n/// @custom:bounties: []\\n/// @custom:deployments: []\\n\\npragma solidity 0.8.24;\\n\\nimport \\\"../KlerosCore.sol\\\";\\nimport \\\"../interfaces/IDisputeKit.sol\\\";\\nimport \\\"../../proxy/UUPSProxiable.sol\\\";\\nimport \\\"../../proxy/Initializable.sol\\\";\\n\\n/// @title DisputeKitClassic\\n/// Dispute kit implementation of the Kleros v1 features including:\\n/// - a drawing system: proportional to staked PNK,\\n/// - a vote aggregation system: plurality,\\n/// - an incentive system: equal split between coherent votes,\\n/// - an appeal system: fund 2 choices only, vote on any choice.\\ncontract DisputeKitClassic is IDisputeKit, Initializable, UUPSProxiable {\\n // ************************************* //\\n // * Structs * //\\n // ************************************* //\\n\\n struct Dispute {\\n Round[] rounds; // Rounds of the dispute. 0 is the default round, and [1, ..n] are the appeal rounds.\\n uint256 numberOfChoices; // The number of choices jurors have when voting. This does not include choice `0` which is reserved for \\\"refuse to arbitrate\\\".\\n bool jumped; // True if dispute jumped to a parent dispute kit and won't be handled by this DK anymore.\\n mapping(uint256 => uint256) coreRoundIDToLocal; // Maps id of the round in the core contract to the index of the round of related local dispute.\\n bytes extraData; // Extradata for the dispute.\\n }\\n\\n struct Round {\\n Vote[] votes; // Former votes[_appeal][].\\n uint256 winningChoice; // The choice with the most votes. Note that in the case of a tie, it is the choice that reached the tied number of votes first.\\n mapping(uint256 => uint256) counts; // The sum of votes for each choice in the form `counts[choice]`.\\n bool tied; // True if there is a tie, false otherwise.\\n uint256 totalVoted; // Former uint[_appeal] votesInEachRound.\\n uint256 totalCommitted; // Former commitsInRound.\\n mapping(uint256 choiceId => uint256) paidFees; // Tracks the fees paid for each choice in this round.\\n mapping(uint256 choiceId => bool) hasPaid; // True if this choice was fully funded, false otherwise.\\n mapping(address account => mapping(uint256 choiceId => uint256)) contributions; // Maps contributors to their contributions for each choice.\\n uint256 feeRewards; // Sum of reimbursable appeal fees available to the parties that made contributions to the ruling that ultimately wins a dispute.\\n uint256[] fundedChoices; // Stores the choices that are fully funded.\\n uint256 nbVotes; // Maximal number of votes this dispute can get.\\n }\\n\\n struct Vote {\\n address account; // The address of the juror.\\n bytes32 commit; // The commit of the juror. For courts with hidden votes.\\n uint256 choice; // The choice of the juror.\\n bool voted; // True if the vote has been cast.\\n }\\n\\n // ************************************* //\\n // * Storage * //\\n // ************************************* //\\n\\n uint256 public constant WINNER_STAKE_MULTIPLIER = 10000; // Multiplier of the appeal cost that the winner has to pay as fee stake for a round in basis points. Default is 1x of appeal fee.\\n uint256 public constant LOSER_STAKE_MULTIPLIER = 20000; // Multiplier of the appeal cost that the loser has to pay as fee stake for a round in basis points. Default is 2x of appeal fee.\\n uint256 public constant LOSER_APPEAL_PERIOD_MULTIPLIER = 5000; // Multiplier of the appeal period for the choice that wasn't voted for in the previous round, in basis points. Default is 1/2 of original appeal period.\\n uint256 public constant ONE_BASIS_POINT = 10000; // One basis point, for scaling.\\n\\n address public governor; // The governor of the contract.\\n KlerosCore public core; // The Kleros Core arbitrator\\n Dispute[] public disputes; // Array of the locally created disputes.\\n mapping(uint256 => uint256) public coreDisputeIDToLocal; // Maps the dispute ID in Kleros Core to the local dispute ID.\\n\\n // ************************************* //\\n // * Events * //\\n // ************************************* //\\n\\n /// @dev To be emitted when a dispute is created.\\n /// @param _coreDisputeID The identifier of the dispute in the Arbitrator contract.\\n /// @param _numberOfChoices The number of choices available in the dispute.\\n /// @param _extraData The extra data for the dispute.\\n event DisputeCreation(uint256 indexed _coreDisputeID, uint256 _numberOfChoices, bytes _extraData);\\n\\n /// @dev To be emitted when a vote commitment is cast.\\n /// @param _coreDisputeID The identifier of the dispute in the Arbitrator contract.\\n /// @param _juror The address of the juror casting the vote commitment.\\n /// @param _voteIDs The identifiers of the votes in the dispute.\\n /// @param _commit The commitment of the juror.\\n event CommitCast(uint256 indexed _coreDisputeID, address indexed _juror, uint256[] _voteIDs, bytes32 _commit);\\n\\n /// @dev To be emitted when a funding contribution is made.\\n /// @param _coreDisputeID The identifier of the dispute in the Arbitrator contract.\\n /// @param _coreRoundID The identifier of the round in the Arbitrator contract.\\n /// @param _choice The choice that is being funded.\\n /// @param _contributor The address of the contributor.\\n /// @param _amount The amount contributed.\\n event Contribution(\\n uint256 indexed _coreDisputeID,\\n uint256 indexed _coreRoundID,\\n uint256 _choice,\\n address indexed _contributor,\\n uint256 _amount\\n );\\n\\n /// @dev To be emitted when the contributed funds are withdrawn.\\n /// @param _coreDisputeID The identifier of the dispute in the Arbitrator contract.\\n /// @param _coreRoundID The identifier of the round in the Arbitrator contract.\\n /// @param _choice The choice that is being funded.\\n /// @param _contributor The address of the contributor.\\n /// @param _amount The amount withdrawn.\\n event Withdrawal(\\n uint256 indexed _coreDisputeID,\\n uint256 indexed _coreRoundID,\\n uint256 _choice,\\n address indexed _contributor,\\n uint256 _amount\\n );\\n\\n /// @dev To be emitted when a choice is fully funded for an appeal.\\n /// @param _coreDisputeID The identifier of the dispute in the Arbitrator contract.\\n /// @param _coreRoundID The identifier of the round in the Arbitrator contract.\\n /// @param _choice The choice that is being funded.\\n event ChoiceFunded(uint256 indexed _coreDisputeID, uint256 indexed _coreRoundID, uint256 indexed _choice);\\n\\n // ************************************* //\\n // * Modifiers * //\\n // ************************************* //\\n\\n modifier onlyByGovernor() {\\n require(governor == msg.sender, \\\"Access not allowed: Governor only.\\\");\\n _;\\n }\\n\\n modifier onlyByCore() {\\n require(address(core) == msg.sender, \\\"Access not allowed: KlerosCore only.\\\");\\n _;\\n }\\n\\n modifier notJumped(uint256 _coreDisputeID) {\\n require(!disputes[coreDisputeIDToLocal[_coreDisputeID]].jumped, \\\"Dispute jumped to a parent DK!\\\");\\n _;\\n }\\n\\n // ************************************* //\\n // * Constructor * //\\n // ************************************* //\\n\\n /// @dev Constructor, initializing the implementation to reduce attack surface.\\n constructor() {\\n _disableInitializers();\\n }\\n\\n /// @dev Initializer.\\n /// @param _governor The governor's address.\\n /// @param _core The KlerosCore arbitrator.\\n function initialize(address _governor, KlerosCore _core) external reinitializer(1) {\\n governor = _governor;\\n core = _core;\\n }\\n\\n // ************************ //\\n // * Governance * //\\n // ************************ //\\n\\n /// @dev Access Control to perform implementation upgrades (UUPS Proxiable)\\n /// Only the governor can perform upgrades (`onlyByGovernor`)\\n function _authorizeUpgrade(address) internal view override onlyByGovernor {\\n // NOP\\n }\\n\\n /// @dev Allows the governor to call anything on behalf of the contract.\\n /// @param _destination The destination of the call.\\n /// @param _amount The value sent with the call.\\n /// @param _data The data sent with the call.\\n function executeGovernorProposal(\\n address _destination,\\n uint256 _amount,\\n bytes memory _data\\n ) external onlyByGovernor {\\n (bool success, ) = _destination.call{value: _amount}(_data);\\n require(success, \\\"Unsuccessful call\\\");\\n }\\n\\n /// @dev Changes the `governor` storage variable.\\n /// @param _governor The new value for the `governor` storage variable.\\n function changeGovernor(address payable _governor) external onlyByGovernor {\\n governor = _governor;\\n }\\n\\n /// @dev Changes the `core` storage variable.\\n /// @param _core The new value for the `core` storage variable.\\n function changeCore(address _core) external onlyByGovernor {\\n core = KlerosCore(_core);\\n }\\n\\n // ************************************* //\\n // * State Modifiers * //\\n // ************************************* //\\n\\n /// @dev Creates a local dispute and maps it to the dispute ID in the Core contract.\\n /// Note: Access restricted to Kleros Core only.\\n /// @param _coreDisputeID The ID of the dispute in Kleros Core.\\n /// @param _numberOfChoices Number of choices of the dispute\\n /// @param _extraData Additional info about the dispute, for possible use in future dispute kits.\\n /// @param _nbVotes Number of votes for this dispute.\\n function createDispute(\\n uint256 _coreDisputeID,\\n uint256 _numberOfChoices,\\n bytes calldata _extraData,\\n uint256 _nbVotes\\n ) external override onlyByCore {\\n uint256 localDisputeID = disputes.length;\\n Dispute storage dispute = disputes.push();\\n dispute.numberOfChoices = _numberOfChoices;\\n dispute.extraData = _extraData;\\n\\n // New round in the Core should be created before the dispute creation in DK.\\n dispute.coreRoundIDToLocal[core.getNumberOfRounds(_coreDisputeID) - 1] = dispute.rounds.length;\\n\\n Round storage round = dispute.rounds.push();\\n round.nbVotes = _nbVotes;\\n round.tied = true;\\n\\n coreDisputeIDToLocal[_coreDisputeID] = localDisputeID;\\n emit DisputeCreation(_coreDisputeID, _numberOfChoices, _extraData);\\n }\\n\\n /// @dev Draws the juror from the sortition tree. The drawn address is picked up by Kleros Core.\\n /// Note: Access restricted to Kleros Core only.\\n /// @param _coreDisputeID The ID of the dispute in Kleros Core.\\n /// @param _nonce Nonce of the drawing iteration.\\n /// @return drawnAddress The drawn address.\\n function draw(\\n uint256 _coreDisputeID,\\n uint256 _nonce\\n ) external override onlyByCore notJumped(_coreDisputeID) returns (address drawnAddress) {\\n Dispute storage dispute = disputes[coreDisputeIDToLocal[_coreDisputeID]];\\n Round storage round = dispute.rounds[dispute.rounds.length - 1];\\n\\n ISortitionModule sortitionModule = core.sortitionModule();\\n (uint96 courtID, , , , ) = core.disputes(_coreDisputeID);\\n bytes32 key = bytes32(uint256(courtID)); // Get the ID of the tree.\\n\\n // TODO: Handle the situation when no one has staked yet.\\n drawnAddress = sortitionModule.draw(key, _coreDisputeID, _nonce);\\n\\n if (_postDrawCheck(_coreDisputeID, drawnAddress)) {\\n round.votes.push(Vote({account: drawnAddress, commit: bytes32(0), choice: 0, voted: false}));\\n } else {\\n drawnAddress = address(0);\\n }\\n }\\n\\n /// @dev Sets the caller's commit for the specified votes. It can be called multiple times during the\\n /// commit period, each call overrides the commits of the previous one.\\n /// `O(n)` where\\n /// `n` is the number of votes.\\n /// @param _coreDisputeID The ID of the dispute in Kleros Core.\\n /// @param _voteIDs The IDs of the votes.\\n /// @param _commit The commit. Note that justification string is a part of the commit.\\n function castCommit(\\n uint256 _coreDisputeID,\\n uint256[] calldata _voteIDs,\\n bytes32 _commit\\n ) external notJumped(_coreDisputeID) {\\n (, , KlerosCore.Period period, , ) = core.disputes(_coreDisputeID);\\n require(period == KlerosCoreBase.Period.commit, \\\"The dispute should be in Commit period.\\\");\\n require(_commit != bytes32(0), \\\"Empty commit.\\\");\\n\\n Dispute storage dispute = disputes[coreDisputeIDToLocal[_coreDisputeID]];\\n Round storage round = dispute.rounds[dispute.rounds.length - 1];\\n for (uint256 i = 0; i < _voteIDs.length; i++) {\\n require(round.votes[_voteIDs[i]].account == msg.sender, \\\"The caller has to own the vote.\\\");\\n round.votes[_voteIDs[i]].commit = _commit;\\n }\\n round.totalCommitted += _voteIDs.length;\\n emit CommitCast(_coreDisputeID, msg.sender, _voteIDs, _commit);\\n }\\n\\n /// @dev Sets the caller's choices for the specified votes.\\n /// `O(n)` where\\n /// `n` is the number of votes.\\n /// @param _coreDisputeID The ID of the dispute in Kleros Core.\\n /// @param _voteIDs The IDs of the votes.\\n /// @param _choice The choice.\\n /// @param _salt The salt for the commit if the votes were hidden.\\n /// @param _justification Justification of the choice.\\n function castVote(\\n uint256 _coreDisputeID,\\n uint256[] calldata _voteIDs,\\n uint256 _choice,\\n uint256 _salt,\\n string memory _justification\\n ) external notJumped(_coreDisputeID) {\\n (, , KlerosCore.Period period, , ) = core.disputes(_coreDisputeID);\\n require(period == KlerosCoreBase.Period.vote, \\\"The dispute should be in Vote period.\\\");\\n require(_voteIDs.length > 0, \\\"No voteID provided\\\");\\n\\n Dispute storage dispute = disputes[coreDisputeIDToLocal[_coreDisputeID]];\\n require(_choice <= dispute.numberOfChoices, \\\"Choice out of bounds\\\");\\n\\n Round storage round = dispute.rounds[dispute.rounds.length - 1];\\n (uint96 courtID, , , , ) = core.disputes(_coreDisputeID);\\n (, bool hiddenVotes, , , , , ) = core.courts(courtID);\\n\\n // Save the votes.\\n for (uint256 i = 0; i < _voteIDs.length; i++) {\\n require(round.votes[_voteIDs[i]].account == msg.sender, \\\"The caller has to own the vote.\\\");\\n require(\\n !hiddenVotes || round.votes[_voteIDs[i]].commit == keccak256(abi.encodePacked(_choice, _salt)),\\n \\\"The commit must match the choice in courts with hidden votes.\\\"\\n );\\n require(!round.votes[_voteIDs[i]].voted, \\\"Vote already cast.\\\");\\n round.votes[_voteIDs[i]].choice = _choice;\\n round.votes[_voteIDs[i]].voted = true;\\n }\\n\\n round.totalVoted += _voteIDs.length;\\n\\n round.counts[_choice] += _voteIDs.length;\\n if (_choice == round.winningChoice) {\\n if (round.tied) round.tied = false;\\n } else {\\n // Voted for another choice.\\n if (round.counts[_choice] == round.counts[round.winningChoice]) {\\n // Tie.\\n if (!round.tied) round.tied = true;\\n } else if (round.counts[_choice] > round.counts[round.winningChoice]) {\\n // New winner.\\n round.winningChoice = _choice;\\n round.tied = false;\\n }\\n }\\n emit VoteCast(_coreDisputeID, msg.sender, _voteIDs, _choice, _justification);\\n }\\n\\n /// @dev Manages contributions, and appeals a dispute if at least two choices are fully funded.\\n /// Note that the surplus deposit will be reimbursed.\\n /// @param _coreDisputeID Index of the dispute in Kleros Core.\\n /// @param _choice A choice that receives funding.\\n function fundAppeal(uint256 _coreDisputeID, uint256 _choice) external payable notJumped(_coreDisputeID) {\\n Dispute storage dispute = disputes[coreDisputeIDToLocal[_coreDisputeID]];\\n require(_choice <= dispute.numberOfChoices, \\\"There is no such ruling to fund.\\\");\\n\\n (uint256 appealPeriodStart, uint256 appealPeriodEnd) = core.appealPeriod(_coreDisputeID);\\n require(block.timestamp >= appealPeriodStart && block.timestamp < appealPeriodEnd, \\\"Appeal period is over.\\\");\\n\\n uint256 multiplier;\\n (uint256 ruling, , ) = this.currentRuling(_coreDisputeID);\\n if (ruling == _choice) {\\n multiplier = WINNER_STAKE_MULTIPLIER;\\n } else {\\n require(\\n block.timestamp - appealPeriodStart <\\n ((appealPeriodEnd - appealPeriodStart) * LOSER_APPEAL_PERIOD_MULTIPLIER) / ONE_BASIS_POINT,\\n \\\"Appeal period is over for loser\\\"\\n );\\n multiplier = LOSER_STAKE_MULTIPLIER;\\n }\\n\\n Round storage round = dispute.rounds[dispute.rounds.length - 1];\\n uint256 coreRoundID = core.getNumberOfRounds(_coreDisputeID) - 1;\\n\\n require(!round.hasPaid[_choice], \\\"Appeal fee is already paid.\\\");\\n uint256 appealCost = core.appealCost(_coreDisputeID);\\n uint256 totalCost = appealCost + (appealCost * multiplier) / ONE_BASIS_POINT;\\n\\n // Take up to the amount necessary to fund the current round at the current costs.\\n uint256 contribution;\\n if (totalCost > round.paidFees[_choice]) {\\n contribution = totalCost - round.paidFees[_choice] > msg.value // Overflows and underflows will be managed on the compiler level.\\n ? msg.value\\n : totalCost - round.paidFees[_choice];\\n emit Contribution(_coreDisputeID, coreRoundID, _choice, msg.sender, contribution);\\n }\\n\\n round.contributions[msg.sender][_choice] += contribution;\\n round.paidFees[_choice] += contribution;\\n if (round.paidFees[_choice] >= totalCost) {\\n round.feeRewards += round.paidFees[_choice];\\n round.fundedChoices.push(_choice);\\n round.hasPaid[_choice] = true;\\n emit ChoiceFunded(_coreDisputeID, coreRoundID, _choice);\\n }\\n\\n if (round.fundedChoices.length > 1) {\\n // At least two sides are fully funded.\\n round.feeRewards = round.feeRewards - appealCost;\\n\\n if (core.isDisputeKitJumping(_coreDisputeID)) {\\n // Don't create a new round in case of a jump, and remove local dispute from the flow.\\n dispute.jumped = true;\\n } else {\\n // Don't subtract 1 from length since both round arrays haven't been updated yet.\\n dispute.coreRoundIDToLocal[coreRoundID + 1] = dispute.rounds.length;\\n\\n Round storage newRound = dispute.rounds.push();\\n newRound.nbVotes = core.getNumberOfVotes(_coreDisputeID);\\n newRound.tied = true;\\n }\\n core.appeal{value: appealCost}(_coreDisputeID, dispute.numberOfChoices, dispute.extraData);\\n }\\n\\n if (msg.value > contribution) payable(msg.sender).send(msg.value - contribution);\\n }\\n\\n /// @dev Allows those contributors who attempted to fund an appeal round to withdraw any reimbursable fees or rewards after the dispute gets resolved.\\n /// Note that withdrawals are not possible if the core contract is paused.\\n /// @param _coreDisputeID Index of the dispute in Kleros Core contract.\\n /// @param _beneficiary The address whose rewards to withdraw.\\n /// @param _coreRoundID The round in the Kleros Core contract the caller wants to withdraw from.\\n /// @param _choice The ruling option that the caller wants to withdraw from.\\n /// @return amount The withdrawn amount.\\n function withdrawFeesAndRewards(\\n uint256 _coreDisputeID,\\n address payable _beneficiary,\\n uint256 _coreRoundID,\\n uint256 _choice\\n ) external returns (uint256 amount) {\\n (, , , bool isRuled, ) = core.disputes(_coreDisputeID);\\n require(isRuled, \\\"Dispute should be resolved.\\\");\\n require(!core.paused(), \\\"Core is paused\\\");\\n\\n Dispute storage dispute = disputes[coreDisputeIDToLocal[_coreDisputeID]];\\n Round storage round = dispute.rounds[dispute.coreRoundIDToLocal[_coreRoundID]];\\n (uint256 finalRuling, , ) = core.currentRuling(_coreDisputeID);\\n\\n if (!round.hasPaid[_choice]) {\\n // Allow to reimburse if funding was unsuccessful for this ruling option.\\n amount = round.contributions[_beneficiary][_choice];\\n } else {\\n // Funding was successful for this ruling option.\\n if (_choice == finalRuling) {\\n // This ruling option is the ultimate winner.\\n amount = round.paidFees[_choice] > 0\\n ? (round.contributions[_beneficiary][_choice] * round.feeRewards) / round.paidFees[_choice]\\n : 0;\\n } else if (!round.hasPaid[finalRuling]) {\\n // The ultimate winner was not funded in this round. In this case funded ruling option(s) are reimbursed.\\n amount =\\n (round.contributions[_beneficiary][_choice] * round.feeRewards) /\\n (round.paidFees[round.fundedChoices[0]] + round.paidFees[round.fundedChoices[1]]);\\n }\\n }\\n round.contributions[_beneficiary][_choice] = 0;\\n\\n if (amount != 0) {\\n _beneficiary.send(amount); // Deliberate use of send to prevent reverting fallback. It's the user's responsibility to accept ETH.\\n emit Withdrawal(_coreDisputeID, _coreRoundID, _choice, _beneficiary, amount);\\n }\\n }\\n\\n // ************************************* //\\n // * Public Views * //\\n // ************************************* //\\n\\n function getFundedChoices(uint256 _coreDisputeID) public view returns (uint256[] memory fundedChoices) {\\n Dispute storage dispute = disputes[coreDisputeIDToLocal[_coreDisputeID]];\\n Round storage lastRound = dispute.rounds[dispute.rounds.length - 1];\\n return lastRound.fundedChoices;\\n }\\n\\n /// @dev Gets the current ruling of a specified dispute.\\n /// @param _coreDisputeID The ID of the dispute in Kleros Core.\\n /// @return ruling The current ruling.\\n /// @return tied Whether it's a tie or not.\\n /// @return overridden Whether the ruling was overridden by appeal funding or not.\\n function currentRuling(\\n uint256 _coreDisputeID\\n ) external view override returns (uint256 ruling, bool tied, bool overridden) {\\n Dispute storage dispute = disputes[coreDisputeIDToLocal[_coreDisputeID]];\\n Round storage round = dispute.rounds[dispute.rounds.length - 1];\\n tied = round.tied;\\n ruling = tied ? 0 : round.winningChoice;\\n (, , KlerosCore.Period period, , ) = core.disputes(_coreDisputeID);\\n // Override the final ruling if only one side funded the appeals.\\n if (period == KlerosCoreBase.Period.execution) {\\n uint256[] memory fundedChoices = getFundedChoices(_coreDisputeID);\\n if (fundedChoices.length == 1) {\\n ruling = fundedChoices[0];\\n tied = false;\\n overridden = true;\\n }\\n }\\n }\\n\\n /// @dev Gets the degree of coherence of a particular voter. This function is called by Kleros Core in order to determine the amount of the reward.\\n /// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.\\n /// @param _coreRoundID The ID of the round in Kleros Core, not in the Dispute Kit.\\n /// @param _voteID The ID of the vote.\\n /// @return The degree of coherence in basis points.\\n function getDegreeOfCoherence(\\n uint256 _coreDisputeID,\\n uint256 _coreRoundID,\\n uint256 _voteID,\\n uint256 /* _feePerJuror */,\\n uint256 /* _pnkAtStakePerJuror */\\n ) external view override returns (uint256) {\\n // In this contract this degree can be either 0 or 1, but in other dispute kits this value can be something in between.\\n Dispute storage dispute = disputes[coreDisputeIDToLocal[_coreDisputeID]];\\n Vote storage vote = dispute.rounds[dispute.coreRoundIDToLocal[_coreRoundID]].votes[_voteID];\\n (uint256 winningChoice, bool tied, ) = core.currentRuling(_coreDisputeID);\\n\\n if (vote.voted && (vote.choice == winningChoice || tied)) {\\n return ONE_BASIS_POINT;\\n } else {\\n return 0;\\n }\\n }\\n\\n /// @dev Gets the number of jurors who are eligible to a reward in this round.\\n /// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.\\n /// @param _coreRoundID The ID of the round in Kleros Core, not in the Dispute Kit.\\n /// @return The number of coherent jurors.\\n function getCoherentCount(uint256 _coreDisputeID, uint256 _coreRoundID) external view override returns (uint256) {\\n Dispute storage dispute = disputes[coreDisputeIDToLocal[_coreDisputeID]];\\n Round storage currentRound = dispute.rounds[dispute.coreRoundIDToLocal[_coreRoundID]];\\n (uint256 winningChoice, bool tied, ) = core.currentRuling(_coreDisputeID);\\n\\n if (currentRound.totalVoted == 0 || (!tied && currentRound.counts[winningChoice] == 0)) {\\n return 0;\\n } else if (tied) {\\n return currentRound.totalVoted;\\n } else {\\n return currentRound.counts[winningChoice];\\n }\\n }\\n\\n /// @dev Returns true if all of the jurors have cast their commits for the last round.\\n /// @param _coreDisputeID The ID of the dispute in Kleros Core.\\n /// @return Whether all of the jurors have cast their commits for the last round.\\n function areCommitsAllCast(uint256 _coreDisputeID) external view override returns (bool) {\\n Dispute storage dispute = disputes[coreDisputeIDToLocal[_coreDisputeID]];\\n Round storage round = dispute.rounds[dispute.rounds.length - 1];\\n return round.totalCommitted == round.votes.length;\\n }\\n\\n /// @dev Returns true if all of the jurors have cast their votes for the last round.\\n /// @param _coreDisputeID The ID of the dispute in Kleros Core.\\n /// @return Whether all of the jurors have cast their votes for the last round.\\n function areVotesAllCast(uint256 _coreDisputeID) external view override returns (bool) {\\n Dispute storage dispute = disputes[coreDisputeIDToLocal[_coreDisputeID]];\\n Round storage round = dispute.rounds[dispute.rounds.length - 1];\\n return round.totalVoted == round.votes.length;\\n }\\n\\n /// @dev Returns true if the specified voter was active in this round.\\n /// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.\\n /// @param _coreRoundID The ID of the round in Kleros Core, not in the Dispute Kit.\\n /// @param _voteID The ID of the voter.\\n /// @return Whether the voter was active or not.\\n function isVoteActive(\\n uint256 _coreDisputeID,\\n uint256 _coreRoundID,\\n uint256 _voteID\\n ) external view override returns (bool) {\\n Dispute storage dispute = disputes[coreDisputeIDToLocal[_coreDisputeID]];\\n Vote storage vote = dispute.rounds[dispute.coreRoundIDToLocal[_coreRoundID]].votes[_voteID];\\n return vote.voted;\\n }\\n\\n function getRoundInfo(\\n uint256 _coreDisputeID,\\n uint256 _coreRoundID,\\n uint256 _choice\\n )\\n external\\n view\\n override\\n returns (\\n uint256 winningChoice,\\n bool tied,\\n uint256 totalVoted,\\n uint256 totalCommited,\\n uint256 nbVoters,\\n uint256 choiceCount\\n )\\n {\\n Dispute storage dispute = disputes[coreDisputeIDToLocal[_coreDisputeID]];\\n Round storage round = dispute.rounds[dispute.coreRoundIDToLocal[_coreRoundID]];\\n return (\\n round.winningChoice,\\n round.tied,\\n round.totalVoted,\\n round.totalCommitted,\\n round.votes.length,\\n round.counts[_choice]\\n );\\n }\\n\\n function getVoteInfo(\\n uint256 _coreDisputeID,\\n uint256 _coreRoundID,\\n uint256 _voteID\\n ) external view override returns (address account, bytes32 commit, uint256 choice, bool voted) {\\n Dispute storage dispute = disputes[coreDisputeIDToLocal[_coreDisputeID]];\\n Vote storage vote = dispute.rounds[dispute.coreRoundIDToLocal[_coreRoundID]].votes[_voteID];\\n return (vote.account, vote.commit, vote.choice, vote.voted);\\n }\\n\\n // ************************************* //\\n // * Internal * //\\n // ************************************* //\\n\\n /// @dev Checks that the chosen address satisfies certain conditions for being drawn.\\n /// @param _coreDisputeID ID of the dispute in the core contract.\\n /// @param _juror Chosen address.\\n /// @return Whether the address can be drawn or not.\\n function _postDrawCheck(uint256 _coreDisputeID, address _juror) internal view returns (bool) {\\n (uint96 courtID, , , , ) = core.disputes(_coreDisputeID);\\n uint256 lockedAmountPerJuror = core\\n .getRoundInfo(_coreDisputeID, core.getNumberOfRounds(_coreDisputeID) - 1)\\n .pnkAtStakePerJuror;\\n (uint256 totalStaked, uint256 totalLocked, , ) = core.sortitionModule().getJurorBalance(_juror, courtID);\\n return totalStaked >= totalLocked + lockedAmountPerJuror;\\n }\\n}\\n\",\"keccak256\":\"0xde57a6569422626bf1ec215f3442ede6c13df57f6f5d27da3bc8cd8bc3d313cd\",\"license\":\"MIT\"},\"src/arbitration/interfaces/IArbitrableV2.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.24;\\n\\nimport \\\"./IArbitratorV2.sol\\\";\\n\\n/// @title IArbitrableV2\\n/// @notice Arbitrable interface.\\n/// @dev When developing arbitrable contracts, we need to:\\n/// - Define the action taken when a ruling is received by the contract.\\n/// - Allow dispute creation. For this a function must call arbitrator.createDispute{value: _fee}(_choices,_extraData);\\ninterface IArbitrableV2 {\\n /// @dev To be emitted when a dispute is created to link the correct meta-evidence to the disputeID.\\n /// @param _arbitrator The arbitrator of the contract.\\n /// @param _arbitratorDisputeID The identifier of the dispute in the Arbitrator contract.\\n /// @param _externalDisputeID An identifier created outside Kleros by the protocol requesting arbitration.\\n /// @param _templateId The identifier of the dispute template. Should not be used with _templateUri.\\n /// @param _templateUri The URI to the dispute template. For example on IPFS: starting with '/ipfs/'. Should not be used with _templateId.\\n event DisputeRequest(\\n IArbitratorV2 indexed _arbitrator,\\n uint256 indexed _arbitratorDisputeID,\\n uint256 _externalDisputeID,\\n uint256 _templateId,\\n string _templateUri\\n );\\n\\n /// @dev To be raised when a ruling is given.\\n /// @param _arbitrator The arbitrator giving the ruling.\\n /// @param _disputeID The identifier of the dispute in the Arbitrator contract.\\n /// @param _ruling The ruling which was given.\\n event Ruling(IArbitratorV2 indexed _arbitrator, uint256 indexed _disputeID, uint256 _ruling);\\n\\n /// @dev Give a ruling for a dispute.\\n /// Must be called by the arbitrator.\\n /// The purpose of this function is to ensure that the address calling it has the right to rule on the contract.\\n /// @param _disputeID The identifier of the dispute in the Arbitrator contract.\\n /// @param _ruling Ruling given by the arbitrator.\\n /// Note that 0 is reserved for \\\"Not able/wanting to make a decision\\\".\\n function rule(uint256 _disputeID, uint256 _ruling) external;\\n}\\n\",\"keccak256\":\"0xe841a4fe8ec109ce17dde4457bf1583c8b499109b05887c53a49a3207fc6e80b\",\"license\":\"MIT\"},\"src/arbitration/interfaces/IArbitratorV2.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"./IArbitrableV2.sol\\\";\\n\\n/// @title Arbitrator\\n/// Arbitrator interface that implements the new arbitration standard.\\n/// Unlike the ERC-792 this standard is not concerned with appeals, so each arbitrator can implement an appeal system that suits it the most.\\n/// When developing arbitrator contracts we need to:\\n/// - Define the functions for dispute creation (createDispute). Don't forget to store the arbitrated contract and the disputeID (which should be unique, may nbDisputes).\\n/// - Define the functions for cost display (arbitrationCost).\\n/// - Allow giving rulings. For this a function must call arbitrable.rule(disputeID, ruling).\\ninterface IArbitratorV2 {\\n /// @dev To be emitted when a dispute is created.\\n /// @param _disputeID The identifier of the dispute in the Arbitrator contract.\\n /// @param _arbitrable The contract which created the dispute.\\n event DisputeCreation(uint256 indexed _disputeID, IArbitrableV2 indexed _arbitrable);\\n\\n /// @dev To be raised when a ruling is given.\\n /// @param _arbitrable The arbitrable receiving the ruling.\\n /// @param _disputeID The identifier of the dispute in the Arbitrator contract.\\n /// @param _ruling The ruling which was given.\\n event Ruling(IArbitrableV2 indexed _arbitrable, uint256 indexed _disputeID, uint256 _ruling);\\n\\n /// @dev To be emitted when an ERC20 token is added or removed as a method to pay fees.\\n /// @param _token The ERC20 token.\\n /// @param _accepted Whether the token is accepted or not.\\n event AcceptedFeeToken(IERC20 indexed _token, bool indexed _accepted);\\n\\n /// @dev To be emitted when the fee for a particular ERC20 token is updated.\\n /// @param _feeToken The ERC20 token.\\n /// @param _rateInEth The new rate of the fee token in ETH.\\n /// @param _rateDecimals The new decimals of the fee token rate.\\n event NewCurrencyRate(IERC20 indexed _feeToken, uint64 _rateInEth, uint8 _rateDecimals);\\n\\n /// @dev Create a dispute and pay for the fees in the native currency, typically ETH.\\n /// Must be called by the arbitrable contract.\\n /// Must pay at least arbitrationCost(_extraData).\\n /// @param _numberOfChoices The number of choices the arbitrator can choose from in this dispute.\\n /// @param _extraData Additional info about the dispute. We use it to pass the ID of the dispute's court (first 32 bytes), the minimum number of jurors required (next 32 bytes) and the ID of the specific dispute kit (last 32 bytes).\\n /// @return disputeID The identifier of the dispute created.\\n function createDispute(\\n uint256 _numberOfChoices,\\n bytes calldata _extraData\\n ) external payable returns (uint256 disputeID);\\n\\n /// @dev Create a dispute and pay for the fees in a supported ERC20 token.\\n /// Must be called by the arbitrable contract.\\n /// Must pay at least arbitrationCost(_extraData).\\n /// @param _numberOfChoices The number of choices the arbitrator can choose from in this dispute.\\n /// @param _extraData Additional info about the dispute. We use it to pass the ID of the dispute's court (first 32 bytes), the minimum number of jurors required (next 32 bytes) and the ID of the specific dispute kit (last 32 bytes).\\n /// @param _feeToken The ERC20 token used to pay fees.\\n /// @param _feeAmount Amount of the ERC20 token used to pay fees.\\n /// @return disputeID The identifier of the dispute created.\\n function createDispute(\\n uint256 _numberOfChoices,\\n bytes calldata _extraData,\\n IERC20 _feeToken,\\n uint256 _feeAmount\\n ) external returns (uint256 disputeID);\\n\\n /// @dev Compute the cost of arbitration denominated in the native currency, typically ETH.\\n /// It is recommended not to increase it often, as it can be highly time and gas consuming for the arbitrated contracts to cope with fee augmentation.\\n /// @param _extraData Additional info about the dispute. We use it to pass the ID of the dispute's court (first 32 bytes), the minimum number of jurors required (next 32 bytes) and the ID of the specific dispute kit (last 32 bytes).\\n /// @return cost The arbitration cost in ETH.\\n function arbitrationCost(bytes calldata _extraData) external view returns (uint256 cost);\\n\\n /// @dev Compute the cost of arbitration denominated in `_feeToken`.\\n /// It is recommended not to increase it often, as it can be highly time and gas consuming for the arbitrated contracts to cope with fee augmentation.\\n /// @param _extraData Additional info about the dispute. We use it to pass the ID of the dispute's court (first 32 bytes), the minimum number of jurors required (next 32 bytes) and the ID of the specific dispute kit (last 32 bytes).\\n /// @param _feeToken The ERC20 token used to pay fees.\\n /// @return cost The arbitration cost in `_feeToken`.\\n function arbitrationCost(bytes calldata _extraData, IERC20 _feeToken) external view returns (uint256 cost);\\n\\n /// @dev Gets the current ruling of a specified dispute.\\n /// @param _disputeID The ID of the dispute.\\n /// @return ruling The current ruling.\\n /// @return tied Whether it's a tie or not.\\n /// @return overridden Whether the ruling was overridden by appeal funding or not.\\n function currentRuling(uint256 _disputeID) external view returns (uint256 ruling, bool tied, bool overridden);\\n}\\n\",\"keccak256\":\"0xa4dc6b958197adead238de4246cd04e7389c3dc1b9f968acd10985f8fc5b74cf\",\"license\":\"MIT\"},\"src/arbitration/interfaces/IDisputeKit.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\n/// @custom:authors: [@unknownunknown1, @jaybuidl]\\n/// @custom:reviewers: []\\n/// @custom:auditors: []\\n/// @custom:bounties: []\\n/// @custom:deployments: []\\n\\npragma solidity 0.8.24;\\n\\nimport \\\"./IArbitratorV2.sol\\\";\\n\\n/// @title IDisputeKit\\n/// An abstraction of the Dispute Kits intended for interfacing with KlerosCore.\\n/// It does not intend to abstract the interactions with the user (such as voting or appeal funding) to allow for implementation-specific parameters.\\ninterface IDisputeKit {\\n // ************************************ //\\n // * Events * //\\n // ************************************ //\\n\\n /// @dev Emitted when casting a vote to provide the justification of juror's choice.\\n /// @param _coreDisputeID The identifier of the dispute in the Arbitrator contract.\\n /// @param _juror Address of the juror.\\n /// @param _voteIDs The identifiers of the votes in the dispute.\\n /// @param _choice The choice juror voted for.\\n /// @param _justification Justification of the choice.\\n event VoteCast(\\n uint256 indexed _coreDisputeID,\\n address indexed _juror,\\n uint256[] _voteIDs,\\n uint256 indexed _choice,\\n string _justification\\n );\\n\\n // ************************************* //\\n // * State Modifiers * //\\n // ************************************* //\\n\\n /// @dev Creates a local dispute and maps it to the dispute ID in the Core contract.\\n /// Note: Access restricted to Kleros Core only.\\n /// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.\\n /// @param _numberOfChoices Number of choices of the dispute\\n /// @param _extraData Additional info about the dispute, for possible use in future dispute kits.\\n function createDispute(\\n uint256 _coreDisputeID,\\n uint256 _numberOfChoices,\\n bytes calldata _extraData,\\n uint256 _nbVotes\\n ) external;\\n\\n /// @dev Draws the juror from the sortition tree. The drawn address is picked up by Kleros Core.\\n /// Note: Access restricted to Kleros Core only.\\n /// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.\\n /// @param _nonce Nonce.\\n /// @return drawnAddress The drawn address.\\n function draw(uint256 _coreDisputeID, uint256 _nonce) external returns (address drawnAddress);\\n\\n // ************************************* //\\n // * Public Views * //\\n // ************************************* //\\n\\n /// @dev Gets the current ruling of a specified dispute.\\n /// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.\\n /// @return ruling The current ruling.\\n /// @return tied Whether it's a tie or not.\\n /// @return overridden Whether the ruling was overridden by appeal funding or not.\\n function currentRuling(uint256 _coreDisputeID) external view returns (uint256 ruling, bool tied, bool overridden);\\n\\n /// @dev Gets the degree of coherence of a particular voter. This function is called by Kleros Core in order to determine the amount of the reward.\\n /// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.\\n /// @param _coreRoundID The ID of the round in Kleros Core, not in the Dispute Kit.\\n /// @param _voteID The ID of the vote.\\n /// @param _feePerJuror The fee per juror.\\n /// @param _pnkAtStakePerJuror The PNK at stake per juror.\\n /// @return The degree of coherence in basis points.\\n function getDegreeOfCoherence(\\n uint256 _coreDisputeID,\\n uint256 _coreRoundID,\\n uint256 _voteID,\\n uint256 _feePerJuror,\\n uint256 _pnkAtStakePerJuror\\n ) external view returns (uint256);\\n\\n /// @dev Gets the number of jurors who are eligible to a reward in this round.\\n /// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.\\n /// @param _coreRoundID The ID of the round in Kleros Core, not in the Dispute Kit.\\n /// @return The number of coherent jurors.\\n function getCoherentCount(uint256 _coreDisputeID, uint256 _coreRoundID) external view returns (uint256);\\n\\n /// @dev Returns true if all of the jurors have cast their commits for the last round.\\n /// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.\\n /// @return Whether all of the jurors have cast their commits for the last round.\\n function areCommitsAllCast(uint256 _coreDisputeID) external view returns (bool);\\n\\n /// @dev Returns true if all of the jurors have cast their votes for the last round.\\n /// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.\\n /// @return Whether all of the jurors have cast their votes for the last round.\\n function areVotesAllCast(uint256 _coreDisputeID) external view returns (bool);\\n\\n /// @dev Returns true if the specified voter was active in this round.\\n /// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.\\n /// @param _coreRoundID The ID of the round in Kleros Core, not in the Dispute Kit.\\n /// @param _voteID The ID of the voter.\\n /// @return Whether the voter was active or not.\\n function isVoteActive(uint256 _coreDisputeID, uint256 _coreRoundID, uint256 _voteID) external view returns (bool);\\n\\n function getRoundInfo(\\n uint256 _coreDisputeID,\\n uint256 _coreRoundID,\\n uint256 _choice\\n )\\n external\\n view\\n returns (\\n uint256 winningChoice,\\n bool tied,\\n uint256 totalVoted,\\n uint256 totalCommited,\\n uint256 nbVoters,\\n uint256 choiceCount\\n );\\n\\n function getVoteInfo(\\n uint256 _coreDisputeID,\\n uint256 _coreRoundID,\\n uint256 _voteID\\n ) external view returns (address account, bytes32 commit, uint256 choice, bool voted);\\n}\\n\",\"keccak256\":\"0xb9590d05f9df08dd0ed027b2eb40c7b1885b7574a121b1b0b7da0920429bb4d5\",\"license\":\"MIT\"},\"src/arbitration/interfaces/ISortitionModule.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.24;\\n\\nimport \\\"../../libraries/Constants.sol\\\";\\n\\ninterface ISortitionModule {\\n enum Phase {\\n staking, // Stake sum trees can be updated. Pass after `minStakingTime` passes and there is at least one dispute without jurors.\\n generating, // Waiting for a random number. Pass as soon as it is ready.\\n drawing // Jurors can be drawn. Pass after all disputes have jurors or `maxDrawingTime` passes.\\n }\\n\\n event NewPhase(Phase _phase);\\n\\n function createTree(bytes32 _key, bytes memory _extraData) external;\\n\\n function setStake(\\n address _account,\\n uint96 _courtID,\\n uint256 _newStake,\\n bool _alreadyTransferred\\n ) external returns (uint256 pnkDeposit, uint256 pnkWithdrawal, StakingResult stakingResult);\\n\\n function setJurorInactive(address _account) external;\\n\\n function lockStake(address _account, uint256 _relativeAmount) external;\\n\\n function unlockStake(address _account, uint256 _relativeAmount) external;\\n\\n function penalizeStake(address _account, uint256 _relativeAmount) external;\\n\\n function notifyRandomNumber(uint256 _drawnNumber) external;\\n\\n function draw(bytes32 _court, uint256 _coreDisputeID, uint256 _nonce) external view returns (address);\\n\\n function getJurorBalance(\\n address _juror,\\n uint96 _courtID\\n ) external view returns (uint256 totalStaked, uint256 totalLocked, uint256 stakedInCourt, uint256 nbCourts);\\n\\n function getJurorCourtIDs(address _juror) external view returns (uint96[] memory);\\n\\n function isJurorStaked(address _juror) external view returns (bool);\\n\\n function createDisputeHook(uint256 _disputeID, uint256 _roundID) external;\\n\\n function postDrawHook(uint256 _disputeID, uint256 _roundID) external;\\n}\\n\",\"keccak256\":\"0x18a4ff126bb51e7b5b0e3fbff7cf0dbbcfff7195ad79307e69cdbc9226e63502\",\"license\":\"MIT\"},\"src/libraries/Constants.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n// Courts\\nuint96 constant FORKING_COURT = 0; // Index of the forking court.\\nuint96 constant GENERAL_COURT = 1; // Index of the default (general) court.\\n\\n// Dispute Kits\\nuint256 constant NULL_DISPUTE_KIT = 0; // Null pattern to indicate a top-level DK which has no parent.\\nuint256 constant DISPUTE_KIT_CLASSIC = 1; // Index of the default DK. 0 index is skipped.\\n\\n// Sortition Module\\nuint256 constant MAX_STAKE_PATHS = 4; // The maximum number of stake paths a juror can have.\\nuint256 constant DEFAULT_K = 6; // Default number of children per node.\\n\\n// Defaults\\nuint256 constant DEFAULT_NB_OF_JURORS = 3; // The default number of jurors in a dispute.\\nIERC20 constant NATIVE_CURRENCY = IERC20(address(0)); // The native currency, such as ETH on Arbitrum, Optimism and Ethereum L1.\\n\\nenum OnError {\\n Revert,\\n Return\\n}\\n\\nenum StakingResult {\\n Successful,\\n StakingTransferFailed,\\n UnstakingTransferFailed,\\n CannotStakeInMoreCourts,\\n CannotStakeInThisCourt,\\n CannotStakeLessThanMinStake,\\n CannotStakeMoreThanMaxStakePerJuror,\\n CannotStakeMoreThanMaxTotalStaked\\n}\\n\",\"keccak256\":\"0x486016fb74cc91439c2ec918e97a79190ab4eed223987d516986fff8eaeecfbf\",\"license\":\"MIT\"},\"src/libraries/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// Adapted from https://github.com/OpenZeppelin/openzeppelin-contracts/blob/a7a94c77463acea95d979aae1580fb0ddc3b6a1e/contracts/token/ERC20/utils/SafeERC20.sol\\n\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/// @title SafeERC20\\n/// @dev Wrappers around ERC20 operations that throw on failure (when the token\\n/// contract returns false). Tokens that return no value (and instead revert or\\n/// throw on failure) are also supported, non-reverting calls are assumed to be\\n/// successful.\\n/// To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n/// which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\nlibrary SafeERC20 {\\n /// @dev Increases the allowance granted to `spender` by the caller.\\n /// @param _token Token to transfer.\\n /// @param _spender The address which will spend the funds.\\n /// @param _addedValue The amount of tokens to increase the allowance by.\\n function increaseAllowance(IERC20 _token, address _spender, uint256 _addedValue) internal returns (bool) {\\n _token.approve(_spender, _token.allowance(address(this), _spender) + _addedValue);\\n return true;\\n }\\n\\n /// @dev Calls transfer() without reverting.\\n /// @param _token Token to transfer.\\n /// @param _to Recepient address.\\n /// @param _value Amount transferred.\\n /// @return Whether transfer succeeded or not.\\n function safeTransfer(IERC20 _token, address _to, uint256 _value) internal returns (bool) {\\n (bool success, bytes memory data) = address(_token).call(abi.encodeCall(IERC20.transfer, (_to, _value)));\\n return (success && (data.length == 0 || abi.decode(data, (bool))));\\n }\\n\\n /// @dev Calls transferFrom() without reverting.\\n /// @param _token Token to transfer.\\n /// @param _from Sender address.\\n /// @param _to Recepient address.\\n /// @param _value Amount transferred.\\n /// @return Whether transfer succeeded or not.\\n function safeTransferFrom(IERC20 _token, address _from, address _to, uint256 _value) internal returns (bool) {\\n (bool success, bytes memory data) = address(_token).call(\\n abi.encodeCall(IERC20.transferFrom, (_from, _to, _value))\\n );\\n return (success && (data.length == 0 || abi.decode(data, (bool))));\\n }\\n}\\n\",\"keccak256\":\"0x3e39adb9cdd9f86b0defc8f6e1223533d86f82c804e186193f729c32c10161b1\",\"license\":\"MIT\"},\"src/proxy/Initializable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol) \\n\\npragma solidity 0.8.24;\\n\\n/**\\n * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed\\n * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an\\n * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer\\n * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.\\n *\\n * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be\\n * reused. This mechanism prevents re-execution of each \\\"step\\\" but allows the creation of new initialization steps in\\n * case an upgrade adds a module that needs to be initialized.\\n *\\n * For example:\\n *\\n * ```solidity\\n * contract MyToken is ERC20Upgradeable {\\n * function initialize() initializer public {\\n * __ERC20_init(\\\"MyToken\\\", \\\"MTK\\\");\\n * }\\n * }\\n *\\n * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {\\n * function initializeV2() reinitializer(2) public {\\n * __ERC20Permit_init(\\\"MyToken\\\");\\n * }\\n * }\\n * ```\\n *\\n * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as\\n * possible by providing the encoded function call as the `_data` argument to the proxy constructor\\n *\\n * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure\\n * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.\\n *\\n * [CAUTION]\\n * ====\\n * Avoid leaving a contract uninitialized.\\n *\\n * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation\\n * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke\\n * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:\\n *\\n * ```\\n * /// @custom:oz-upgrades-unsafe-allow constructor\\n * constructor() {\\n * _disableInitializers();\\n * }\\n * ```\\n */\\nabstract contract Initializable {\\n /**\\n * @dev Storage of the initializable contract.\\n *\\n * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions\\n * when using with upgradeable contracts.\\n *\\n * @custom:storage-location erc7201:openzeppelin.storage.Initializable\\n */\\n struct InitializableStorage {\\n /**\\n * @dev Indicates that the contract has been initialized.\\n */\\n uint64 _initialized;\\n /**\\n * @dev Indicates that the contract is in the process of being initialized.\\n */\\n bool _initializing;\\n }\\n\\n // keccak256(abi.encode(uint256(keccak256(\\\"openzeppelin.storage.Initializable\\\")) - 1))\\n bytes32 private constant _INITIALIZABLE_STORAGE =\\n 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0e;\\n\\n /**\\n * @dev The contract is already initialized.\\n */\\n error AlreadyInitialized();\\n\\n /**\\n * @dev The contract is not initializing.\\n */\\n error NotInitializing();\\n\\n /**\\n * @dev Triggered when the contract has been initialized or reinitialized.\\n */\\n event Initialized(uint64 version);\\n\\n /**\\n * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,\\n * `onlyInitializing` functions can be used to initialize parent contracts.\\n *\\n * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a\\n * constructor.\\n *\\n * Emits an {Initialized} event.\\n */\\n modifier initializer() {\\n // solhint-disable-next-line var-name-mixedcase\\n InitializableStorage storage $ = _getInitializableStorage();\\n\\n bool isTopLevelCall = !$._initializing;\\n uint64 initialized = $._initialized;\\n if (!(isTopLevelCall && initialized < 1) && !(address(this).code.length == 0 && initialized == 1)) {\\n revert AlreadyInitialized();\\n }\\n $._initialized = 1;\\n if (isTopLevelCall) {\\n $._initializing = true;\\n }\\n _;\\n if (isTopLevelCall) {\\n $._initializing = false;\\n emit Initialized(1);\\n }\\n }\\n\\n /**\\n * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the\\n * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be\\n * used to initialize parent contracts.\\n *\\n * A reinitializer may be used after the original initialization step. This is essential to configure modules that\\n * are added through upgrades and that require initialization.\\n *\\n * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`\\n * cannot be nested. If one is invoked in the context of another, execution will revert.\\n *\\n * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in\\n * a contract, executing them in the right order is up to the developer or operator.\\n *\\n * WARNING: setting the version to 255 will prevent any future reinitialization.\\n *\\n * Emits an {Initialized} event.\\n */\\n modifier reinitializer(uint64 version) {\\n // solhint-disable-next-line var-name-mixedcase\\n InitializableStorage storage $ = _getInitializableStorage();\\n\\n if ($._initializing || $._initialized >= version) {\\n revert AlreadyInitialized();\\n }\\n $._initialized = version;\\n $._initializing = true;\\n _;\\n $._initializing = false;\\n emit Initialized(version);\\n }\\n\\n /**\\n * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the\\n * {initializer} and {reinitializer} modifiers, directly or indirectly.\\n */\\n modifier onlyInitializing() {\\n _checkInitializing();\\n _;\\n }\\n\\n /**\\n * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.\\n */\\n function _checkInitializing() internal view virtual {\\n if (!_isInitializing()) {\\n revert NotInitializing();\\n }\\n }\\n\\n /**\\n * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.\\n * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized\\n * to any version. It is recommended to use this to lock implementation contracts that are designed to be called\\n * through proxies.\\n *\\n * Emits an {Initialized} event the first time it is successfully executed.\\n */\\n function _disableInitializers() internal virtual {\\n // solhint-disable-next-line var-name-mixedcase\\n InitializableStorage storage $ = _getInitializableStorage();\\n\\n if ($._initializing) {\\n revert AlreadyInitialized();\\n }\\n if ($._initialized != type(uint64).max) {\\n $._initialized = type(uint64).max;\\n emit Initialized(type(uint64).max);\\n }\\n }\\n\\n /**\\n * @dev Returns the highest version that has been initialized. See {reinitializer}.\\n */\\n function _getInitializedVersion() internal view returns (uint64) {\\n return _getInitializableStorage()._initialized;\\n }\\n\\n /**\\n * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.\\n */\\n function _isInitializing() internal view returns (bool) {\\n return _getInitializableStorage()._initializing;\\n }\\n\\n /**\\n * @dev Returns a pointer to the storage namespace.\\n */\\n // solhint-disable-next-line var-name-mixedcase\\n function _getInitializableStorage() private pure returns (InitializableStorage storage $) {\\n assembly {\\n $.slot := _INITIALIZABLE_STORAGE\\n }\\n }\\n}\\n\",\"keccak256\":\"0x560ea64115636ecd6b3596248817125551c038ce1648019fde3cbe02d9759a30\",\"license\":\"MIT\"},\"src/proxy/UUPSProxiable.sol\":{\"content\":\"//SPDX-License-Identifier: MIT\\n// Adapted from \\n\\n/**\\n * @authors: [@malatrax]\\n * @reviewers: []\\n * @auditors: []\\n * @bounties: []\\n * @deployments: []\\n */\\npragma solidity 0.8.24;\\n\\n/**\\n * @title UUPS Proxiable\\n * @author Simon Malatrait \\n * @dev This contract implements an upgradeability mechanism designed for UUPS proxies.\\n * The functions included here can perform an upgrade of an UUPS Proxy, when this contract is set as the implementation behind such a proxy.\\n *\\n * IMPORTANT: A UUPS proxy requires its upgradeability functions to be in the implementation as opposed to the transparent proxy.\\n * This means that if the proxy is upgraded to an implementation that does not support this interface, it will no longer be upgradeable.\\n *\\n * A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is\\n * reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing\\n * `UUPSProxiable` with a custom implementation of upgrades.\\n *\\n * The `_authorizeUpgrade` function must be overridden to include access restriction to the upgrade mechanism.\\n */\\nabstract contract UUPSProxiable {\\n // ************************************* //\\n // * Event * //\\n // ************************************* //\\n\\n /**\\n * Emitted when the `implementation` has been successfully upgraded.\\n * @param newImplementation Address of the new implementation the proxy is now forwarding calls to.\\n */\\n event Upgraded(address indexed newImplementation);\\n\\n // ************************************* //\\n // * Error * //\\n // ************************************* //\\n\\n /**\\n * @dev The call is from an unauthorized context.\\n */\\n error UUPSUnauthorizedCallContext();\\n\\n /**\\n * @dev The storage `slot` is unsupported as a UUID.\\n */\\n error UUPSUnsupportedProxiableUUID(bytes32 slot);\\n\\n /// The `implementation` is not UUPS-compliant\\n error InvalidImplementation(address implementation);\\n\\n /// Failed Delegated call\\n error FailedDelegateCall();\\n\\n // ************************************* //\\n // * Storage * //\\n // ************************************* //\\n\\n /**\\n * @dev Storage slot with the address of the current implementation.\\n * This is the keccak-256 hash of \\\"eip1967.proxy.implementation\\\" subtracted by 1, and is\\n * validated in the constructor.\\n * NOTE: bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1)\\n */\\n bytes32 private constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\\n\\n /**\\n * @dev Storage variable of the proxiable contract address.\\n * It is used to check whether or not the current call is from the proxy.\\n */\\n address private immutable __self = address(this);\\n\\n // ************************************* //\\n // * Governance * //\\n // ************************************* //\\n\\n /**\\n * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract.\\n * @dev Called by {upgradeToAndCall}.\\n */\\n function _authorizeUpgrade(address newImplementation) internal virtual;\\n\\n // ************************************* //\\n // * State Modifiers * //\\n // ************************************* //\\n\\n /**\\n * @dev Upgrade mechanism including access control and UUPS-compliance.\\n * @param newImplementation Address of the new implementation contract.\\n * @param data Data used in a delegate call to `newImplementation` if non-empty. This will typically be an encoded\\n * function call, and allows initializing the storage of the proxy like a Solidity constructor.\\n *\\n * @dev Reverts if the execution is not performed via delegatecall or the execution\\n * context is not of a proxy with an ERC1967-compliant implementation pointing to self.\\n */\\n function upgradeToAndCall(address newImplementation, bytes memory data) public payable virtual {\\n _authorizeUpgrade(newImplementation);\\n\\n /* Check that the execution is being performed through a delegatecall call and that the execution context is\\n a proxy contract with an implementation (as defined in ERC1967) pointing to self. */\\n if (address(this) == __self || _getImplementation() != __self) {\\n revert UUPSUnauthorizedCallContext();\\n }\\n\\n try UUPSProxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {\\n if (slot != IMPLEMENTATION_SLOT) {\\n revert UUPSUnsupportedProxiableUUID(slot);\\n }\\n // Store the new implementation address to the implementation storage slot.\\n assembly {\\n sstore(IMPLEMENTATION_SLOT, newImplementation)\\n }\\n emit Upgraded(newImplementation);\\n\\n if (data.length != 0) {\\n // The return data is not checked (checking, in case of success, that the newImplementation code is non-empty if the return data is empty) because the authorized callee is trusted.\\n (bool success, ) = newImplementation.delegatecall(data);\\n if (!success) {\\n revert FailedDelegateCall();\\n }\\n }\\n } catch {\\n revert InvalidImplementation(newImplementation);\\n }\\n }\\n\\n // ************************************* //\\n // * Public Views * //\\n // ************************************* //\\n\\n /**\\n * @dev Implementation of the ERC1822 `proxiableUUID` function. This returns the storage slot used by the\\n * implementation. It is used to validate the implementation's compatibility when performing an upgrade.\\n *\\n * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks\\n * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this\\n * function revert if invoked through a proxy. This is guaranteed by the if statement.\\n */\\n function proxiableUUID() external view virtual returns (bytes32) {\\n if (address(this) != __self) {\\n // Must not be called through delegatecall\\n revert UUPSUnauthorizedCallContext();\\n }\\n return IMPLEMENTATION_SLOT;\\n }\\n\\n // ************************************* //\\n // * Internal Views * //\\n // ************************************* //\\n\\n function _getImplementation() internal view returns (address implementation) {\\n assembly {\\n implementation := sload(IMPLEMENTATION_SLOT)\\n }\\n }\\n}\\n\",\"keccak256\":\"0x5956855046cdda7aa45f44e379ef45323af7266c44c817d1266d8b32d52b0e22\",\"license\":\"MIT\"}},\"version\":1}",
- "bytecode": "0x60a0604052306080523480156200001557600080fd5b506200002062000026565b620000d9565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0e805468010000000000000000900460ff1615620000765760405162dc149f60e41b815260040160405180910390fd5b80546001600160401b0390811614620000d65780546001600160401b0319166001600160401b0390811782556040519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50565b608051613ec76200010360003960008181611588015281816115b101526117a90152613ec76000f3fe6080604052600436106101825760003560e01c80636d4cd8ea116100d7578063b6ede54011610085578063b6ede540146104ca578063ba66fde7146104ea578063be4676041461050a578063d2b8035a14610520578063da3beb8c14610540578063e349ad3014610412578063e4c0aaf414610560578063f2f4eb261461058057600080fd5b80636d4cd8ea146103d2578063751accd0146103f2578063796490f9146104125780637c04034e146104285780638e42646014610448578063a7cc08fe14610468578063b34bfaa8146104b457600080fd5b80634f1ef286116101345780634f1ef286146102c157806352d1902d146102d4578063564a565d146102e95780635c92e2f61461031857806365540b9614610338578063675926f61461036557806369f3f0411461038557600080fd5b80630baa64d1146101875780630c340a24146101bc5780631200aabc146101f45780631c3db16d1461022f578063362c34791461026c578063485cc9551461028c5780634b2f0ea0146102ae575b600080fd5b34801561019357600080fd5b506101a76101a2366004613174565b6105a0565b60405190151581526020015b60405180910390f35b3480156101c857600080fd5b506000546101dc906001600160a01b031681565b6040516001600160a01b0390911681526020016101b3565b34801561020057600080fd5b5061022161020f366004613174565b60036020526000908152604090205481565b6040519081526020016101b3565b34801561023b57600080fd5b5061024f61024a366004613174565b610617565b6040805193845291151560208401521515908201526060016101b3565b34801561027857600080fd5b506102216102873660046131a2565b610785565b34801561029857600080fd5b506102ac6102a73660046131df565b610c10565b005b6102ac6102bc366004613218565b610d0d565b6102ac6102cf366004613327565b611574565b3480156102e057600080fd5b5061022161179c565b3480156102f557600080fd5b50610309610304366004613174565b6117fa565b6040516101b3939291906133c6565b34801561032457600080fd5b506102ac610333366004613432565b6118c0565b34801561034457600080fd5b50610358610353366004613174565b611bc5565b6040516101b39190613484565b34801561037157600080fd5b506102216103803660046134c8565b611c89565b34801561039157600080fd5b506103a56103a0366004613503565b611dce565b604080519687529415156020870152938501929092526060840152608083015260a082015260c0016101b3565b3480156103de57600080fd5b506101a76103ed366004613174565b611e86565b3480156103fe57600080fd5b506102ac61040d36600461352f565b611efd565b34801561041e57600080fd5b5061022161271081565b34801561043457600080fd5b506102ac610443366004613587565b611fc9565b34801561045457600080fd5b506102ac61046336600461361f565b61269a565b34801561047457600080fd5b50610488610483366004613503565b6126e6565b604080516001600160a01b039095168552602085019390935291830152151560608201526080016101b3565b3480156104c057600080fd5b50610221614e2081565b3480156104d657600080fd5b506102ac6104e536600461363c565b6127ac565b3480156104f657600080fd5b506101a7610505366004613503565b612981565b34801561051657600080fd5b5061022161138881565b34801561052c57600080fd5b506101dc61053b366004613218565b612a1c565b34801561054c57600080fd5b5061022161055b366004613218565b612d25565b34801561056c57600080fd5b506102ac61057b36600461361f565b612e78565b34801561058c57600080fd5b506001546101dc906001600160a01b031681565b6000818152600360205260408120546002805483929081106105c4576105c46136c3565b600091825260208220600590910201805490925082906105e6906001906136ef565b815481106105f6576105f66136c3565b60009182526020909120600c90910201805460059091015414949350505050565b6000806000806002600360008781526020019081526020016000205481548110610643576106436136c3565b60009182526020822060059091020180549092508290610665906001906136ef565b81548110610675576106756136c3565b60009182526020909120600c90910201600381015460ff1694509050836106a05780600101546106a3565b60005b60015460405163564a565d60e01b8152600481018990529196506000916001600160a01b039091169063564a565d9060240160a060405180830381865afa1580156106f2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610716919061372e565b5090935060049250610726915050565b81600481111561073857610738613795565b0361077b57600061074888611bc5565b905080516001036107795780600081518110610766576107666136c3565b6020026020010151965060009550600194505b505b5050509193909250565b60015460405163564a565d60e01b81526004810186905260009182916001600160a01b039091169063564a565d9060240160a060405180830381865afa1580156107d3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107f7919061372e565b5093505050508061084f5760405162461bcd60e51b815260206004820152601b60248201527f446973707574652073686f756c64206265207265736f6c7665642e000000000060448201526064015b60405180910390fd5b600160009054906101000a90046001600160a01b03166001600160a01b0316635c975abb6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156108a2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108c691906137ab565b156109045760405162461bcd60e51b815260206004820152600e60248201526d10dbdc99481a5cc81c185d5cd95960921b6044820152606401610846565b600086815260036020526040812054600280549091908110610928576109286136c3565b6000918252602080832088845260036005909302019182019052604082205481549193508391811061095c5761095c6136c3565b600091825260208220600154604051631c3db16d60e01b8152600481018d9052600c9390930290910193506001600160a01b031690631c3db16d90602401606060405180830381865afa1580156109b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109db91906137c6565b5050600087815260078401602052604090205490915060ff16610a25576001600160a01b038816600090815260088301602090815260408083208984529091529020549450610b6a565b808603610a9a576000868152600683016020526040902054610a48576000610a93565b600086815260068301602090815260408083205460098601546001600160a01b038d1685526008870184528285208b8652909352922054610a899190613802565b610a939190613819565b9450610b6a565b600081815260078301602052604090205460ff16610b6a5781600601600083600a01600181548110610ace57610ace6136c3565b906000526020600020015481526020019081526020016000205482600601600084600a01600081548110610b0457610b046136c3565b9060005260206000200154815260200190815260200160002054610b28919061383b565b60098301546001600160a01b038a16600090815260088501602090815260408083208b8452909152902054610b5d9190613802565b610b679190613819565b94505b6001600160a01b038816600090815260088301602090815260408083208984529091528120558415610c04576040516001600160a01b0389169086156108fc029087906000818181858888f15050604080518a8152602081018a90526001600160a01b038d1694508b93508d92507f54b3cab3cb5c4aca3209db1151caff092e878011202e43a36782d4ebe0b963ae910160405180910390a45b50505050949350505050565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0e805460019190600160401b900460ff1680610c59575080546001600160401b03808416911610155b15610c765760405162dc149f60e41b815260040160405180910390fd5b805468ffffffffffffffffff19166001600160401b038316908117600160401b178255600080546001600160a01b038781166001600160a01b0319928316179092556001805492871692909116919091179055815460ff60401b191682556040519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a150505050565b600082815260036020526040902054600280548492908110610d3157610d316136c3565b600091825260209091206002600590920201015460ff1615610d655760405162461bcd60e51b81526004016108469061384e565b600083815260036020526040812054600280549091908110610d8957610d896136c3565b906000526020600020906005020190508060010154831115610ded5760405162461bcd60e51b815260206004820181905260248201527f5468657265206973206e6f20737563682072756c696e6720746f2066756e642e6044820152606401610846565b60015460405163afe15cfb60e01b81526004810186905260009182916001600160a01b039091169063afe15cfb906024016040805180830381865afa158015610e3a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e5e9190613885565b91509150814210158015610e7157508042105b610eb65760405162461bcd60e51b815260206004820152601660248201527520b83832b0b6103832b934b7b21034b99037bb32b91760511b6044820152606401610846565b604051631c3db16d60e01b81526004810187905260009081903090631c3db16d90602401606060405180830381865afa158015610ef7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f1b91906137c6565b50509050868103610f30576127109150610fb1565b612710611388610f4086866136ef565b610f4a9190613802565b610f549190613819565b610f5e85426136ef565b10610fab5760405162461bcd60e51b815260206004820152601f60248201527f41707065616c20706572696f64206973206f76657220666f72206c6f736572006044820152606401610846565b614e2091505b84546000908690610fc4906001906136ef565b81548110610fd457610fd46136c3565b60009182526020822060018054604051637e37c78b60e11b8152600481018f9052600c949094029092019450916001600160a01b039091169063fc6f8f1690602401602060405180830381865afa158015611033573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061105791906138a9565b61106191906136ef565b60008a815260078401602052604090205490915060ff16156110c55760405162461bcd60e51b815260206004820152601b60248201527f41707065616c2066656520697320616c726561647920706169642e00000000006044820152606401610846565b600154604051632cf6413f60e11b8152600481018c90526000916001600160a01b0316906359ec827e90602401602060405180830381865afa15801561110f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061113391906138a9565b905060006127106111448784613802565b61114e9190613819565b611158908361383b565b60008c8152600686016020526040812054919250908211156112095760008c8152600686016020526040902054349061119190846136ef565b116111b65760008c81526006860160205260409020546111b190836136ef565b6111b8565b345b9050336001600160a01b0316848e7fcae597f39a3ad75c2e10d46b031f023c5c2babcd58ca0491b122acda3968d4c08f85604051611200929190918252602082015260400190565b60405180910390a45b33600090815260088601602090815260408083208f84529091528120805483929061123590849061383b565b909155505060008c81526006860160205260408120805483929061125a90849061383b565b909155505060008c8152600686016020526040902054821161132c5760008c81526006860160205260408120546009870180549192909161129c90849061383b565b9250508190555084600a018c908060018154018082558091505060019003906000526020600020016000909190919091505560018560070160008e815260200190815260200160002060006101000a81548160ff0219169083151502179055508b848e7fed764996238e4c1c873ae3af7ae2f00f1f6f4f10b9ac7d4bbea4a764c5dea00960405160405180910390a45b600a850154600110156115375782856009015461134991906136ef565b60098601556001546040516319b8152960e01b8152600481018f90526001600160a01b03909116906319b8152990602401602060405180830381865afa158015611397573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113bb91906137ab565b156113d45760028a01805460ff191660011790556114b7565b895460038b0160006113e787600161383b565b81526020019081526020016000208190555060008a6000016001816001815401808255809150500390600052602060002090600c02019050600160009054906101000a90046001600160a01b03166001600160a01b031663c71f42538f6040518263ffffffff1660e01b815260040161146291815260200190565b602060405180830381865afa15801561147f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114a391906138a9565b600b820155600301805460ff191660011790555b600160009054906101000a90046001600160a01b03166001600160a01b031663c3569902848f8d600101548e6004016040518563ffffffff1660e01b8152600401611504939291906138fc565b6000604051808303818588803b15801561151d57600080fd5b505af1158015611531573d6000803e3d6000fd5b50505050505b8034111561156557336108fc61154d83346136ef565b6040518115909202916000818181858888f150505050505b50505050505050505050505050565b61157d82612ec4565b306001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614806115fb57507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166115ef600080516020613e728339815191525490565b6001600160a01b031614155b156116195760405163703e46dd60e11b815260040160405180910390fd5b816001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015611673575060408051601f3d908101601f19168201909252611670918101906138a9565b60015b61169b57604051630c76093760e01b81526001600160a01b0383166004820152602401610846565b600080516020613e7283398151915281146116cc57604051632a87526960e21b815260048101829052602401610846565b600080516020613e728339815191528390556040516001600160a01b038416907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a2815115611797576000836001600160a01b031683604051611733919061399b565b600060405180830381855af49150503d806000811461176e576040519150601f19603f3d011682016040523d82523d6000602084013e611773565b606091505b5050905080611795576040516339b21b5d60e11b815260040160405180910390fd5b505b505050565b6000306001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146117e75760405163703e46dd60e11b815260040160405180910390fd5b50600080516020613e7283398151915290565b6002818154811061180a57600080fd5b600091825260209091206005909102016001810154600282015460048301805492945060ff909116929161183d906138c2565b80601f0160208091040260200160405190810160405280929190818152602001828054611869906138c2565b80156118b65780601f1061188b576101008083540402835291602001916118b6565b820191906000526020600020905b81548152906001019060200180831161189957829003601f168201915b5050505050905083565b6000848152600360205260409020546002805486929081106118e4576118e46136c3565b600091825260209091206002600590920201015460ff16156119185760405162461bcd60e51b81526004016108469061384e565b60015460405163564a565d60e01b8152600481018790526000916001600160a01b03169063564a565d9060240160a060405180830381865afa158015611962573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611986919061372e565b5090935060019250611996915050565b8160048111156119a8576119a8613795565b14611a055760405162461bcd60e51b815260206004820152602760248201527f54686520646973707574652073686f756c6420626520696e20436f6d6d6974206044820152663832b934b7b21760c91b6064820152608401610846565b82611a425760405162461bcd60e51b815260206004820152600d60248201526c22b6b83a3c9031b7b6b6b4ba1760991b6044820152606401610846565b600086815260036020526040812054600280549091908110611a6657611a666136c3565b60009182526020822060059091020180549092508290611a88906001906136ef565b81548110611a9857611a986136c3565b90600052602060002090600c0201905060005b86811015611b5e573382898984818110611ac757611ac76136c3565b9050602002013581548110611ade57611ade6136c3565b60009182526020909120600490910201546001600160a01b031614611b155760405162461bcd60e51b8152600401610846906139b7565b8582898984818110611b2957611b296136c3565b9050602002013581548110611b4057611b406136c3565b60009182526020909120600160049092020181019190915501611aab565b5086869050816005016000828254611b76919061383b565b9091555050604051339089907f05cc2f1c94966f1c961b410a50f3d3ffb64501346753a258177097ea23707f0890611bb3908b908b908b90613a20565b60405180910390a35050505050505050565b6000818152600360205260408120546002805460609392908110611beb57611beb6136c3565b60009182526020822060059091020180549092508290611c0d906001906136ef565b81548110611c1d57611c1d6136c3565b90600052602060002090600c0201905080600a01805480602002602001604051908101604052809291908181526020018280548015611c7b57602002820191906000526020600020905b815481526020019060010190808311611c67575b505050505092505050919050565b600085815260036020526040812054600280548392908110611cad57611cad6136c3565b60009182526020808320898452600360059093020191820190526040822054815491935083918110611ce157611ce16136c3565b90600052602060002090600c02016000018681548110611d0357611d036136c3565b600091825260208220600154604051631c3db16d60e01b815260048082018e905293909302909101935082916001600160a01b0390911690631c3db16d90602401606060405180830381865afa158015611d61573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d8591906137c6565b506003850154919350915060ff168015611da957508183600201541480611da95750805b15611dbc57612710945050505050611dc5565b60009450505050505b95945050505050565b60008060008060008060006002600360008c81526020019081526020016000205481548110611dff57611dff6136c3565b600091825260208083208c8452600360059093020191820190526040822054815491935083918110611e3357611e336136c3565b600091825260208083206001600c909302019182015460038301546004840154600585015485549f87526002909501909352604090942054909f60ff9094169e50909c50909a9950975095505050505050565b600081815260036020526040812054600280548392908110611eaa57611eaa6136c3565b60009182526020822060059091020180549092508290611ecc906001906136ef565b81548110611edc57611edc6136c3565b60009182526020909120600c90910201805460049091015414949350505050565b6000546001600160a01b03163314611f275760405162461bcd60e51b815260040161084690613a44565b6000836001600160a01b03168383604051611f42919061399b565b60006040518083038185875af1925050503d8060008114611f7f576040519150601f19603f3d011682016040523d82523d6000602084013e611f84565b606091505b50509050806117955760405162461bcd60e51b8152602060048201526011602482015270155b9cdd58d8d95cdcd99d5b0818d85b1b607a1b6044820152606401610846565b600086815260036020526040902054600280548892908110611fed57611fed6136c3565b600091825260209091206002600590920201015460ff16156120215760405162461bcd60e51b81526004016108469061384e565b60015460405163564a565d60e01b8152600481018990526000916001600160a01b03169063564a565d9060240160a060405180830381865afa15801561206b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061208f919061372e565b509093506002925061209f915050565b8160048111156120b1576120b1613795565b1461210c5760405162461bcd60e51b815260206004820152602560248201527f54686520646973707574652073686f756c6420626520696e20566f74652070656044820152643934b7b21760d91b6064820152608401610846565b8561214e5760405162461bcd60e51b8152602060048201526012602482015271139bc81d9bdd195251081c1c9bdd9a59195960721b6044820152606401610846565b600088815260036020526040812054600280549091908110612172576121726136c3565b9060005260206000209060050201905080600101548611156121cd5760405162461bcd60e51b815260206004820152601460248201527343686f696365206f7574206f6620626f756e647360601b6044820152606401610846565b805460009082906121e0906001906136ef565b815481106121f0576121f06136c3565b60009182526020822060015460405163564a565d60e01b8152600481018f9052600c9390930290910193506001600160a01b03169063564a565d9060240160a060405180830381865afa15801561224b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061226f919061372e565b5050600154604051630fad06e960e11b81526001600160601b03851660048201529394506000936001600160a01b039091169250631f5a0dd2915060240160e060405180830381865afa1580156122ca573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122ee9190613a86565b505050505091505060005b8a8110156125605733848d8d84818110612315576123156136c3565b905060200201358154811061232c5761232c6136c3565b60009182526020909120600490910201546001600160a01b0316146123635760405162461bcd60e51b8152600401610846906139b7565b8115806123d6575060408051602081018c90529081018a905260600160405160208183030381529060405280519060200120846000018d8d848181106123ab576123ab6136c3565b90506020020135815481106123c2576123c26136c3565b906000526020600020906004020160010154145b6124485760405162461bcd60e51b815260206004820152603d60248201527f54686520636f6d6d6974206d757374206d61746368207468652063686f69636560448201527f20696e20636f7572747320776974682068696464656e20766f7465732e0000006064820152608401610846565b838c8c8381811061245b5761245b6136c3565b9050602002013581548110612472576124726136c3565b600091825260209091206003600490920201015460ff16156124cb5760405162461bcd60e51b81526020600482015260126024820152712b37ba329030b63932b0b23c9031b0b9ba1760711b6044820152606401610846565b89848d8d848181106124df576124df6136c3565b90506020020135815481106124f6576124f66136c3565b60009182526020909120600260049092020101556001848d8d8481811061251f5761251f6136c3565b9050602002013581548110612536576125366136c3565b60009182526020909120600490910201600301805460ff19169115159190911790556001016122f9565b508a8a9050836004016000828254612578919061383b565b90915550506000898152600284016020526040812080548c929061259d90849061383b565b9091555050600183015489036125cc57600383015460ff16156125c75760038301805460ff191690555b612645565b60018301546000908152600284016020526040808220548b83529120540361260e57600383015460ff166125c75760038301805460ff19166001179055612645565b60018301546000908152600284016020526040808220548b83529120541115612645576001830189905560038301805460ff191690555b88336001600160a01b03168d7fa000893c71384499023d2d7b21234f7b9e80c78e0330f357dcd667ff578bd3a48e8e8c60405161268493929190613af0565b60405180910390a4505050505050505050505050565b6000546001600160a01b031633146126c45760405162461bcd60e51b815260040161084690613a44565b600180546001600160a01b0319166001600160a01b0392909216919091179055565b60008060008060006002600360008a81526020019081526020016000205481548110612714576127146136c3565b600091825260208083208a8452600360059093020191820190526040822054815491935083918110612748576127486136c3565b90600052602060002090600c0201600001878154811061276a5761276a6136c3565b600091825260209091206004909102018054600182015460028301546003909301546001600160a01b039092169c909b5091995060ff16975095505050505050565b6001546001600160a01b031633146127d65760405162461bcd60e51b815260040161084690613b20565b60028054600181018255600091909152600581027f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5acf81018690557f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace8101907f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ad201612861858783613bb4565b50805460018054604051637e37c78b60e11b8152600481018b9052600385019260009290916001600160a01b039091169063fc6f8f1690602401602060405180830381865afa1580156128b8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128dc91906138a9565b6128e691906136ef565b81526020808201929092526040908101600090812093909355835460018181018655858552838520600b600c909302019182018890556003808301805460ff19169092179091558b855290925291829020849055905188907fd3106f74c2d30a4b9230e756a3e78bde53865d40f6af4c479bb010ebaab581089061296f908a908a908a90613c74565b60405180910390a25050505050505050565b6000838152600360205260408120546002805483929081106129a5576129a56136c3565b600091825260208083208784526003600590930201918201905260408220548154919350839181106129d9576129d96136c3565b90600052602060002090600c020160000184815481106129fb576129fb6136c3565b600091825260209091206004909102016003015460ff169695505050505050565b6001546000906001600160a01b03163314612a495760405162461bcd60e51b815260040161084690613b20565b600083815260036020526040902054600280548592908110612a6d57612a6d6136c3565b600091825260209091206002600590920201015460ff1615612aa15760405162461bcd60e51b81526004016108469061384e565b600084815260036020526040812054600280549091908110612ac557612ac56136c3565b60009182526020822060059091020180549092508290612ae7906001906136ef565b81548110612af757612af76136c3565b90600052602060002090600c020190506000600160009054906101000a90046001600160a01b03166001600160a01b0316632e1daf2f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612b5c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b809190613caa565b60015460405163564a565d60e01b8152600481018a90529192506000916001600160a01b039091169063564a565d9060240160a060405180830381865afa158015612bcf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612bf3919061372e565b5050604051632638506b60e11b81526001600160601b03841660048201819052602482018d9052604482018c90529394506001600160a01b0386169250634c70a0d69150606401602060405180830381865afa158015612c57573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c7b9190613caa565b9650612c878988612ef1565b15612d1457604080516080810182526001600160a01b03898116825260006020808401828152948401828152606085018381528a5460018082018d558c8652939094209551600490940290950180546001600160a01b0319169390941692909217835593519382019390935591516002830155516003909101805460ff1916911515919091179055612d19565b600096505b50505050505092915050565b600082815260036020526040812054600280548392908110612d4957612d496136c3565b60009182526020808320868452600360059093020191820190526040822054815491935083918110612d7d57612d7d6136c3565b600091825260208220600154604051631c3db16d60e01b8152600481018a9052600c93909302909101935082916001600160a01b0390911690631c3db16d90602401606060405180830381865afa158015612ddc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e0091906137c6565b5091509150826004015460001480612e2f575080158015612e2f57506000828152600284016020526040902054155b15612e41576000945050505050612e72565b8015612e56575050600401549150612e729050565b506000908152600290910160205260409020549150612e729050565b92915050565b6000546001600160a01b03163314612ea25760405162461bcd60e51b815260040161084690613a44565b600080546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b03163314612eee5760405162461bcd60e51b815260040161084690613a44565b50565b60015460405163564a565d60e01b81526004810184905260009182916001600160a01b039091169063564a565d9060240160a060405180830381865afa158015612f3f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f63919061372e565b505060018054604051637e37c78b60e11b8152600481018a90529495506000946001600160a01b039091169350638a9bb02a9250889190849063fc6f8f1690602401602060405180830381865afa158015612fc2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fe691906138a9565b612ff091906136ef565b6040516001600160e01b031960e085901b16815260048101929092526024820152604401600060405180830381865afa158015613031573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526130599190810190613d5a565b602001519050600080600160009054906101000a90046001600160a01b03166001600160a01b0316632e1daf2f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156130b5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130d99190613caa565b604051631a383be960e31b81526001600160a01b0388811660048301526001600160601b0387166024830152919091169063d1c1df4890604401608060405180830381865afa158015613130573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131549190613e3b565b5050915091508281613166919061383b565b909110159695505050505050565b60006020828403121561318657600080fd5b5035919050565b6001600160a01b0381168114612eee57600080fd5b600080600080608085870312156131b857600080fd5b8435935060208501356131ca8161318d565b93969395505050506040820135916060013590565b600080604083850312156131f257600080fd5b82356131fd8161318d565b9150602083013561320d8161318d565b809150509250929050565b6000806040838503121561322b57600080fd5b50508035926020909101359150565b634e487b7160e01b600052604160045260246000fd5b60405161016081016001600160401b03811182821017156132735761327361323a565b60405290565b604051601f8201601f191681016001600160401b03811182821017156132a1576132a161323a565b604052919050565b60006001600160401b038311156132c2576132c261323a565b6132d5601f8401601f1916602001613279565b90508281528383830111156132e957600080fd5b828260208301376000602084830101529392505050565b600082601f83011261331157600080fd5b613320838335602085016132a9565b9392505050565b6000806040838503121561333a57600080fd5b82356133458161318d565b915060208301356001600160401b0381111561336057600080fd5b61336c85828601613300565b9150509250929050565b60005b83811015613391578181015183820152602001613379565b50506000910152565b600081518084526133b2816020860160208601613376565b601f01601f19169290920160200192915050565b8381528215156020820152606060408201526000611dc5606083018461339a565b60008083601f8401126133f957600080fd5b5081356001600160401b0381111561341057600080fd5b6020830191508360208260051b850101111561342b57600080fd5b9250929050565b6000806000806060858703121561344857600080fd5b8435935060208501356001600160401b0381111561346557600080fd5b613471878288016133e7565b9598909750949560400135949350505050565b6020808252825182820181905260009190848201906040850190845b818110156134bc578351835292840192918401916001016134a0565b50909695505050505050565b600080600080600060a086880312156134e057600080fd5b505083359560208501359550604085013594606081013594506080013592509050565b60008060006060848603121561351857600080fd5b505081359360208301359350604090920135919050565b60008060006060848603121561354457600080fd5b833561354f8161318d565b92506020840135915060408401356001600160401b0381111561357157600080fd5b61357d86828701613300565b9150509250925092565b60008060008060008060a087890312156135a057600080fd5b8635955060208701356001600160401b03808211156135be57600080fd5b6135ca8a838b016133e7565b9097509550604089013594506060890135935060808901359150808211156135f157600080fd5b508701601f8101891361360357600080fd5b613612898235602084016132a9565b9150509295509295509295565b60006020828403121561363157600080fd5b81356133208161318d565b60008060008060006080868803121561365457600080fd5b853594506020860135935060408601356001600160401b038082111561367957600080fd5b818801915088601f83011261368d57600080fd5b81358181111561369c57600080fd5b8960208285010111156136ae57600080fd5b96999598505060200195606001359392505050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b81810381811115612e7257612e726136d9565b80516001600160601b038116811461371957600080fd5b919050565b8051801515811461371957600080fd5b600080600080600060a0868803121561374657600080fd5b61374f86613702565b9450602086015161375f8161318d565b60408701519094506005811061377457600080fd5b92506137826060870161371e565b9150608086015190509295509295909350565b634e487b7160e01b600052602160045260246000fd5b6000602082840312156137bd57600080fd5b6133208261371e565b6000806000606084860312156137db57600080fd5b835192506137eb6020850161371e565b91506137f96040850161371e565b90509250925092565b8082028115828204841417612e7257612e726136d9565b60008261383657634e487b7160e01b600052601260045260246000fd5b500490565b80820180821115612e7257612e726136d9565b6020808252601e908201527f44697370757465206a756d70656420746f206120706172656e7420444b210000604082015260600190565b6000806040838503121561389857600080fd5b505080516020909101519092909150565b6000602082840312156138bb57600080fd5b5051919050565b600181811c908216806138d657607f821691505b6020821081036138f657634e487b7160e01b600052602260045260246000fd5b50919050565b83815260006020846020840152606060408401526000845461391d816138c2565b806060870152608060018084166000811461393f576001811461395b5761398b565b60ff19851660808a0152608084151560051b8a0101955061398b565b89600052602060002060005b858110156139825781548b8201860152908301908801613967565b8a016080019650505b50939a9950505050505050505050565b600082516139ad818460208701613376565b9190910192915050565b6020808252601f908201527f5468652063616c6c65722068617320746f206f776e2074686520766f74652e00604082015260600190565b81835260006001600160fb1b03831115613a0757600080fd5b8260051b80836020870137939093016020019392505050565b604081526000613a346040830185876139ee565b9050826020830152949350505050565b60208082526022908201527f416363657373206e6f7420616c6c6f7765643a20476f7665726e6f72206f6e6c6040820152613c9760f11b606082015260800190565b600080600080600080600060e0888a031215613aa157600080fd5b613aaa88613702565b9650613ab86020890161371e565b955060408801519450606088015193506080880151925060a08801519150613ae260c0890161371e565b905092959891949750929550565b604081526000613b046040830185876139ee565b8281036020840152613b16818561339a565b9695505050505050565b60208082526024908201527f416363657373206e6f7420616c6c6f7765643a204b6c65726f73436f7265206f60408201526337363c9760e11b606082015260800190565b601f821115611797576000816000526020600020601f850160051c81016020861015613b8d5750805b601f850160051c820191505b81811015613bac57828155600101613b99565b505050505050565b6001600160401b03831115613bcb57613bcb61323a565b613bdf83613bd983546138c2565b83613b64565b6000601f841160018114613c135760008515613bfb5750838201355b600019600387901b1c1916600186901b178355613c6d565b600083815260209020601f19861690835b82811015613c445786850135825560209485019460019092019101613c24565b5086821015613c615760001960f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b83815260406020820152816040820152818360608301376000818301606090810191909152601f909201601f1916010192915050565b600060208284031215613cbc57600080fd5b81516133208161318d565b600082601f830112613cd857600080fd5b815160206001600160401b03821115613cf357613cf361323a565b8160051b613d02828201613279565b9283528481018201928281019087851115613d1c57600080fd5b83870192505b84831015613d44578251613d358161318d565b82529183019190830190613d22565b979650505050505050565b80516137198161318d565b600060208284031215613d6c57600080fd5b81516001600160401b0380821115613d8357600080fd5b908301906101608286031215613d9857600080fd5b613da0613250565b825181526020830151602082015260408301516040820152606083015160608201526080830151608082015260a083015160a082015260c083015182811115613de857600080fd5b613df487828601613cc7565b60c08301525060e0838101519082015261010080840151908201526101209150613e1f828401613d4f565b9181019190915261014091820151918101919091529392505050565b60008060008060808587031215613e5157600080fd5b50508251602084015160408501516060909501519196909550909250905056fe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbca2646970667358221220ece2f97e5f37049420403eea1739d27d704a432100da66c99ed49ffe1796440264736f6c63430008180033",
- "deployedBytecode": "0x6080604052600436106101825760003560e01c80636d4cd8ea116100d7578063b6ede54011610085578063b6ede540146104ca578063ba66fde7146104ea578063be4676041461050a578063d2b8035a14610520578063da3beb8c14610540578063e349ad3014610412578063e4c0aaf414610560578063f2f4eb261461058057600080fd5b80636d4cd8ea146103d2578063751accd0146103f2578063796490f9146104125780637c04034e146104285780638e42646014610448578063a7cc08fe14610468578063b34bfaa8146104b457600080fd5b80634f1ef286116101345780634f1ef286146102c157806352d1902d146102d4578063564a565d146102e95780635c92e2f61461031857806365540b9614610338578063675926f61461036557806369f3f0411461038557600080fd5b80630baa64d1146101875780630c340a24146101bc5780631200aabc146101f45780631c3db16d1461022f578063362c34791461026c578063485cc9551461028c5780634b2f0ea0146102ae575b600080fd5b34801561019357600080fd5b506101a76101a2366004613174565b6105a0565b60405190151581526020015b60405180910390f35b3480156101c857600080fd5b506000546101dc906001600160a01b031681565b6040516001600160a01b0390911681526020016101b3565b34801561020057600080fd5b5061022161020f366004613174565b60036020526000908152604090205481565b6040519081526020016101b3565b34801561023b57600080fd5b5061024f61024a366004613174565b610617565b6040805193845291151560208401521515908201526060016101b3565b34801561027857600080fd5b506102216102873660046131a2565b610785565b34801561029857600080fd5b506102ac6102a73660046131df565b610c10565b005b6102ac6102bc366004613218565b610d0d565b6102ac6102cf366004613327565b611574565b3480156102e057600080fd5b5061022161179c565b3480156102f557600080fd5b50610309610304366004613174565b6117fa565b6040516101b3939291906133c6565b34801561032457600080fd5b506102ac610333366004613432565b6118c0565b34801561034457600080fd5b50610358610353366004613174565b611bc5565b6040516101b39190613484565b34801561037157600080fd5b506102216103803660046134c8565b611c89565b34801561039157600080fd5b506103a56103a0366004613503565b611dce565b604080519687529415156020870152938501929092526060840152608083015260a082015260c0016101b3565b3480156103de57600080fd5b506101a76103ed366004613174565b611e86565b3480156103fe57600080fd5b506102ac61040d36600461352f565b611efd565b34801561041e57600080fd5b5061022161271081565b34801561043457600080fd5b506102ac610443366004613587565b611fc9565b34801561045457600080fd5b506102ac61046336600461361f565b61269a565b34801561047457600080fd5b50610488610483366004613503565b6126e6565b604080516001600160a01b039095168552602085019390935291830152151560608201526080016101b3565b3480156104c057600080fd5b50610221614e2081565b3480156104d657600080fd5b506102ac6104e536600461363c565b6127ac565b3480156104f657600080fd5b506101a7610505366004613503565b612981565b34801561051657600080fd5b5061022161138881565b34801561052c57600080fd5b506101dc61053b366004613218565b612a1c565b34801561054c57600080fd5b5061022161055b366004613218565b612d25565b34801561056c57600080fd5b506102ac61057b36600461361f565b612e78565b34801561058c57600080fd5b506001546101dc906001600160a01b031681565b6000818152600360205260408120546002805483929081106105c4576105c46136c3565b600091825260208220600590910201805490925082906105e6906001906136ef565b815481106105f6576105f66136c3565b60009182526020909120600c90910201805460059091015414949350505050565b6000806000806002600360008781526020019081526020016000205481548110610643576106436136c3565b60009182526020822060059091020180549092508290610665906001906136ef565b81548110610675576106756136c3565b60009182526020909120600c90910201600381015460ff1694509050836106a05780600101546106a3565b60005b60015460405163564a565d60e01b8152600481018990529196506000916001600160a01b039091169063564a565d9060240160a060405180830381865afa1580156106f2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610716919061372e565b5090935060049250610726915050565b81600481111561073857610738613795565b0361077b57600061074888611bc5565b905080516001036107795780600081518110610766576107666136c3565b6020026020010151965060009550600194505b505b5050509193909250565b60015460405163564a565d60e01b81526004810186905260009182916001600160a01b039091169063564a565d9060240160a060405180830381865afa1580156107d3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107f7919061372e565b5093505050508061084f5760405162461bcd60e51b815260206004820152601b60248201527f446973707574652073686f756c64206265207265736f6c7665642e000000000060448201526064015b60405180910390fd5b600160009054906101000a90046001600160a01b03166001600160a01b0316635c975abb6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156108a2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108c691906137ab565b156109045760405162461bcd60e51b815260206004820152600e60248201526d10dbdc99481a5cc81c185d5cd95960921b6044820152606401610846565b600086815260036020526040812054600280549091908110610928576109286136c3565b6000918252602080832088845260036005909302019182019052604082205481549193508391811061095c5761095c6136c3565b600091825260208220600154604051631c3db16d60e01b8152600481018d9052600c9390930290910193506001600160a01b031690631c3db16d90602401606060405180830381865afa1580156109b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109db91906137c6565b5050600087815260078401602052604090205490915060ff16610a25576001600160a01b038816600090815260088301602090815260408083208984529091529020549450610b6a565b808603610a9a576000868152600683016020526040902054610a48576000610a93565b600086815260068301602090815260408083205460098601546001600160a01b038d1685526008870184528285208b8652909352922054610a899190613802565b610a939190613819565b9450610b6a565b600081815260078301602052604090205460ff16610b6a5781600601600083600a01600181548110610ace57610ace6136c3565b906000526020600020015481526020019081526020016000205482600601600084600a01600081548110610b0457610b046136c3565b9060005260206000200154815260200190815260200160002054610b28919061383b565b60098301546001600160a01b038a16600090815260088501602090815260408083208b8452909152902054610b5d9190613802565b610b679190613819565b94505b6001600160a01b038816600090815260088301602090815260408083208984529091528120558415610c04576040516001600160a01b0389169086156108fc029087906000818181858888f15050604080518a8152602081018a90526001600160a01b038d1694508b93508d92507f54b3cab3cb5c4aca3209db1151caff092e878011202e43a36782d4ebe0b963ae910160405180910390a45b50505050949350505050565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0e805460019190600160401b900460ff1680610c59575080546001600160401b03808416911610155b15610c765760405162dc149f60e41b815260040160405180910390fd5b805468ffffffffffffffffff19166001600160401b038316908117600160401b178255600080546001600160a01b038781166001600160a01b0319928316179092556001805492871692909116919091179055815460ff60401b191682556040519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a150505050565b600082815260036020526040902054600280548492908110610d3157610d316136c3565b600091825260209091206002600590920201015460ff1615610d655760405162461bcd60e51b81526004016108469061384e565b600083815260036020526040812054600280549091908110610d8957610d896136c3565b906000526020600020906005020190508060010154831115610ded5760405162461bcd60e51b815260206004820181905260248201527f5468657265206973206e6f20737563682072756c696e6720746f2066756e642e6044820152606401610846565b60015460405163afe15cfb60e01b81526004810186905260009182916001600160a01b039091169063afe15cfb906024016040805180830381865afa158015610e3a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e5e9190613885565b91509150814210158015610e7157508042105b610eb65760405162461bcd60e51b815260206004820152601660248201527520b83832b0b6103832b934b7b21034b99037bb32b91760511b6044820152606401610846565b604051631c3db16d60e01b81526004810187905260009081903090631c3db16d90602401606060405180830381865afa158015610ef7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f1b91906137c6565b50509050868103610f30576127109150610fb1565b612710611388610f4086866136ef565b610f4a9190613802565b610f549190613819565b610f5e85426136ef565b10610fab5760405162461bcd60e51b815260206004820152601f60248201527f41707065616c20706572696f64206973206f76657220666f72206c6f736572006044820152606401610846565b614e2091505b84546000908690610fc4906001906136ef565b81548110610fd457610fd46136c3565b60009182526020822060018054604051637e37c78b60e11b8152600481018f9052600c949094029092019450916001600160a01b039091169063fc6f8f1690602401602060405180830381865afa158015611033573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061105791906138a9565b61106191906136ef565b60008a815260078401602052604090205490915060ff16156110c55760405162461bcd60e51b815260206004820152601b60248201527f41707065616c2066656520697320616c726561647920706169642e00000000006044820152606401610846565b600154604051632cf6413f60e11b8152600481018c90526000916001600160a01b0316906359ec827e90602401602060405180830381865afa15801561110f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061113391906138a9565b905060006127106111448784613802565b61114e9190613819565b611158908361383b565b60008c8152600686016020526040812054919250908211156112095760008c8152600686016020526040902054349061119190846136ef565b116111b65760008c81526006860160205260409020546111b190836136ef565b6111b8565b345b9050336001600160a01b0316848e7fcae597f39a3ad75c2e10d46b031f023c5c2babcd58ca0491b122acda3968d4c08f85604051611200929190918252602082015260400190565b60405180910390a45b33600090815260088601602090815260408083208f84529091528120805483929061123590849061383b565b909155505060008c81526006860160205260408120805483929061125a90849061383b565b909155505060008c8152600686016020526040902054821161132c5760008c81526006860160205260408120546009870180549192909161129c90849061383b565b9250508190555084600a018c908060018154018082558091505060019003906000526020600020016000909190919091505560018560070160008e815260200190815260200160002060006101000a81548160ff0219169083151502179055508b848e7fed764996238e4c1c873ae3af7ae2f00f1f6f4f10b9ac7d4bbea4a764c5dea00960405160405180910390a45b600a850154600110156115375782856009015461134991906136ef565b60098601556001546040516319b8152960e01b8152600481018f90526001600160a01b03909116906319b8152990602401602060405180830381865afa158015611397573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113bb91906137ab565b156113d45760028a01805460ff191660011790556114b7565b895460038b0160006113e787600161383b565b81526020019081526020016000208190555060008a6000016001816001815401808255809150500390600052602060002090600c02019050600160009054906101000a90046001600160a01b03166001600160a01b031663c71f42538f6040518263ffffffff1660e01b815260040161146291815260200190565b602060405180830381865afa15801561147f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114a391906138a9565b600b820155600301805460ff191660011790555b600160009054906101000a90046001600160a01b03166001600160a01b031663c3569902848f8d600101548e6004016040518563ffffffff1660e01b8152600401611504939291906138fc565b6000604051808303818588803b15801561151d57600080fd5b505af1158015611531573d6000803e3d6000fd5b50505050505b8034111561156557336108fc61154d83346136ef565b6040518115909202916000818181858888f150505050505b50505050505050505050505050565b61157d82612ec4565b306001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614806115fb57507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166115ef600080516020613e728339815191525490565b6001600160a01b031614155b156116195760405163703e46dd60e11b815260040160405180910390fd5b816001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015611673575060408051601f3d908101601f19168201909252611670918101906138a9565b60015b61169b57604051630c76093760e01b81526001600160a01b0383166004820152602401610846565b600080516020613e7283398151915281146116cc57604051632a87526960e21b815260048101829052602401610846565b600080516020613e728339815191528390556040516001600160a01b038416907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a2815115611797576000836001600160a01b031683604051611733919061399b565b600060405180830381855af49150503d806000811461176e576040519150601f19603f3d011682016040523d82523d6000602084013e611773565b606091505b5050905080611795576040516339b21b5d60e11b815260040160405180910390fd5b505b505050565b6000306001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146117e75760405163703e46dd60e11b815260040160405180910390fd5b50600080516020613e7283398151915290565b6002818154811061180a57600080fd5b600091825260209091206005909102016001810154600282015460048301805492945060ff909116929161183d906138c2565b80601f0160208091040260200160405190810160405280929190818152602001828054611869906138c2565b80156118b65780601f1061188b576101008083540402835291602001916118b6565b820191906000526020600020905b81548152906001019060200180831161189957829003601f168201915b5050505050905083565b6000848152600360205260409020546002805486929081106118e4576118e46136c3565b600091825260209091206002600590920201015460ff16156119185760405162461bcd60e51b81526004016108469061384e565b60015460405163564a565d60e01b8152600481018790526000916001600160a01b03169063564a565d9060240160a060405180830381865afa158015611962573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611986919061372e565b5090935060019250611996915050565b8160048111156119a8576119a8613795565b14611a055760405162461bcd60e51b815260206004820152602760248201527f54686520646973707574652073686f756c6420626520696e20436f6d6d6974206044820152663832b934b7b21760c91b6064820152608401610846565b82611a425760405162461bcd60e51b815260206004820152600d60248201526c22b6b83a3c9031b7b6b6b4ba1760991b6044820152606401610846565b600086815260036020526040812054600280549091908110611a6657611a666136c3565b60009182526020822060059091020180549092508290611a88906001906136ef565b81548110611a9857611a986136c3565b90600052602060002090600c0201905060005b86811015611b5e573382898984818110611ac757611ac76136c3565b9050602002013581548110611ade57611ade6136c3565b60009182526020909120600490910201546001600160a01b031614611b155760405162461bcd60e51b8152600401610846906139b7565b8582898984818110611b2957611b296136c3565b9050602002013581548110611b4057611b406136c3565b60009182526020909120600160049092020181019190915501611aab565b5086869050816005016000828254611b76919061383b565b9091555050604051339089907f05cc2f1c94966f1c961b410a50f3d3ffb64501346753a258177097ea23707f0890611bb3908b908b908b90613a20565b60405180910390a35050505050505050565b6000818152600360205260408120546002805460609392908110611beb57611beb6136c3565b60009182526020822060059091020180549092508290611c0d906001906136ef565b81548110611c1d57611c1d6136c3565b90600052602060002090600c0201905080600a01805480602002602001604051908101604052809291908181526020018280548015611c7b57602002820191906000526020600020905b815481526020019060010190808311611c67575b505050505092505050919050565b600085815260036020526040812054600280548392908110611cad57611cad6136c3565b60009182526020808320898452600360059093020191820190526040822054815491935083918110611ce157611ce16136c3565b90600052602060002090600c02016000018681548110611d0357611d036136c3565b600091825260208220600154604051631c3db16d60e01b815260048082018e905293909302909101935082916001600160a01b0390911690631c3db16d90602401606060405180830381865afa158015611d61573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d8591906137c6565b506003850154919350915060ff168015611da957508183600201541480611da95750805b15611dbc57612710945050505050611dc5565b60009450505050505b95945050505050565b60008060008060008060006002600360008c81526020019081526020016000205481548110611dff57611dff6136c3565b600091825260208083208c8452600360059093020191820190526040822054815491935083918110611e3357611e336136c3565b600091825260208083206001600c909302019182015460038301546004840154600585015485549f87526002909501909352604090942054909f60ff9094169e50909c50909a9950975095505050505050565b600081815260036020526040812054600280548392908110611eaa57611eaa6136c3565b60009182526020822060059091020180549092508290611ecc906001906136ef565b81548110611edc57611edc6136c3565b60009182526020909120600c90910201805460049091015414949350505050565b6000546001600160a01b03163314611f275760405162461bcd60e51b815260040161084690613a44565b6000836001600160a01b03168383604051611f42919061399b565b60006040518083038185875af1925050503d8060008114611f7f576040519150601f19603f3d011682016040523d82523d6000602084013e611f84565b606091505b50509050806117955760405162461bcd60e51b8152602060048201526011602482015270155b9cdd58d8d95cdcd99d5b0818d85b1b607a1b6044820152606401610846565b600086815260036020526040902054600280548892908110611fed57611fed6136c3565b600091825260209091206002600590920201015460ff16156120215760405162461bcd60e51b81526004016108469061384e565b60015460405163564a565d60e01b8152600481018990526000916001600160a01b03169063564a565d9060240160a060405180830381865afa15801561206b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061208f919061372e565b509093506002925061209f915050565b8160048111156120b1576120b1613795565b1461210c5760405162461bcd60e51b815260206004820152602560248201527f54686520646973707574652073686f756c6420626520696e20566f74652070656044820152643934b7b21760d91b6064820152608401610846565b8561214e5760405162461bcd60e51b8152602060048201526012602482015271139bc81d9bdd195251081c1c9bdd9a59195960721b6044820152606401610846565b600088815260036020526040812054600280549091908110612172576121726136c3565b9060005260206000209060050201905080600101548611156121cd5760405162461bcd60e51b815260206004820152601460248201527343686f696365206f7574206f6620626f756e647360601b6044820152606401610846565b805460009082906121e0906001906136ef565b815481106121f0576121f06136c3565b60009182526020822060015460405163564a565d60e01b8152600481018f9052600c9390930290910193506001600160a01b03169063564a565d9060240160a060405180830381865afa15801561224b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061226f919061372e565b5050600154604051630fad06e960e11b81526001600160601b03851660048201529394506000936001600160a01b039091169250631f5a0dd2915060240160e060405180830381865afa1580156122ca573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122ee9190613a86565b505050505091505060005b8a8110156125605733848d8d84818110612315576123156136c3565b905060200201358154811061232c5761232c6136c3565b60009182526020909120600490910201546001600160a01b0316146123635760405162461bcd60e51b8152600401610846906139b7565b8115806123d6575060408051602081018c90529081018a905260600160405160208183030381529060405280519060200120846000018d8d848181106123ab576123ab6136c3565b90506020020135815481106123c2576123c26136c3565b906000526020600020906004020160010154145b6124485760405162461bcd60e51b815260206004820152603d60248201527f54686520636f6d6d6974206d757374206d61746368207468652063686f69636560448201527f20696e20636f7572747320776974682068696464656e20766f7465732e0000006064820152608401610846565b838c8c8381811061245b5761245b6136c3565b9050602002013581548110612472576124726136c3565b600091825260209091206003600490920201015460ff16156124cb5760405162461bcd60e51b81526020600482015260126024820152712b37ba329030b63932b0b23c9031b0b9ba1760711b6044820152606401610846565b89848d8d848181106124df576124df6136c3565b90506020020135815481106124f6576124f66136c3565b60009182526020909120600260049092020101556001848d8d8481811061251f5761251f6136c3565b9050602002013581548110612536576125366136c3565b60009182526020909120600490910201600301805460ff19169115159190911790556001016122f9565b508a8a9050836004016000828254612578919061383b565b90915550506000898152600284016020526040812080548c929061259d90849061383b565b9091555050600183015489036125cc57600383015460ff16156125c75760038301805460ff191690555b612645565b60018301546000908152600284016020526040808220548b83529120540361260e57600383015460ff166125c75760038301805460ff19166001179055612645565b60018301546000908152600284016020526040808220548b83529120541115612645576001830189905560038301805460ff191690555b88336001600160a01b03168d7fa000893c71384499023d2d7b21234f7b9e80c78e0330f357dcd667ff578bd3a48e8e8c60405161268493929190613af0565b60405180910390a4505050505050505050505050565b6000546001600160a01b031633146126c45760405162461bcd60e51b815260040161084690613a44565b600180546001600160a01b0319166001600160a01b0392909216919091179055565b60008060008060006002600360008a81526020019081526020016000205481548110612714576127146136c3565b600091825260208083208a8452600360059093020191820190526040822054815491935083918110612748576127486136c3565b90600052602060002090600c0201600001878154811061276a5761276a6136c3565b600091825260209091206004909102018054600182015460028301546003909301546001600160a01b039092169c909b5091995060ff16975095505050505050565b6001546001600160a01b031633146127d65760405162461bcd60e51b815260040161084690613b20565b60028054600181018255600091909152600581027f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5acf81018690557f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace8101907f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ad201612861858783613bb4565b50805460018054604051637e37c78b60e11b8152600481018b9052600385019260009290916001600160a01b039091169063fc6f8f1690602401602060405180830381865afa1580156128b8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128dc91906138a9565b6128e691906136ef565b81526020808201929092526040908101600090812093909355835460018181018655858552838520600b600c909302019182018890556003808301805460ff19169092179091558b855290925291829020849055905188907fd3106f74c2d30a4b9230e756a3e78bde53865d40f6af4c479bb010ebaab581089061296f908a908a908a90613c74565b60405180910390a25050505050505050565b6000838152600360205260408120546002805483929081106129a5576129a56136c3565b600091825260208083208784526003600590930201918201905260408220548154919350839181106129d9576129d96136c3565b90600052602060002090600c020160000184815481106129fb576129fb6136c3565b600091825260209091206004909102016003015460ff169695505050505050565b6001546000906001600160a01b03163314612a495760405162461bcd60e51b815260040161084690613b20565b600083815260036020526040902054600280548592908110612a6d57612a6d6136c3565b600091825260209091206002600590920201015460ff1615612aa15760405162461bcd60e51b81526004016108469061384e565b600084815260036020526040812054600280549091908110612ac557612ac56136c3565b60009182526020822060059091020180549092508290612ae7906001906136ef565b81548110612af757612af76136c3565b90600052602060002090600c020190506000600160009054906101000a90046001600160a01b03166001600160a01b0316632e1daf2f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612b5c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b809190613caa565b60015460405163564a565d60e01b8152600481018a90529192506000916001600160a01b039091169063564a565d9060240160a060405180830381865afa158015612bcf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612bf3919061372e565b5050604051632638506b60e11b81526001600160601b03841660048201819052602482018d9052604482018c90529394506001600160a01b0386169250634c70a0d69150606401602060405180830381865afa158015612c57573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c7b9190613caa565b9650612c878988612ef1565b15612d1457604080516080810182526001600160a01b03898116825260006020808401828152948401828152606085018381528a5460018082018d558c8652939094209551600490940290950180546001600160a01b0319169390941692909217835593519382019390935591516002830155516003909101805460ff1916911515919091179055612d19565b600096505b50505050505092915050565b600082815260036020526040812054600280548392908110612d4957612d496136c3565b60009182526020808320868452600360059093020191820190526040822054815491935083918110612d7d57612d7d6136c3565b600091825260208220600154604051631c3db16d60e01b8152600481018a9052600c93909302909101935082916001600160a01b0390911690631c3db16d90602401606060405180830381865afa158015612ddc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e0091906137c6565b5091509150826004015460001480612e2f575080158015612e2f57506000828152600284016020526040902054155b15612e41576000945050505050612e72565b8015612e56575050600401549150612e729050565b506000908152600290910160205260409020549150612e729050565b92915050565b6000546001600160a01b03163314612ea25760405162461bcd60e51b815260040161084690613a44565b600080546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b03163314612eee5760405162461bcd60e51b815260040161084690613a44565b50565b60015460405163564a565d60e01b81526004810184905260009182916001600160a01b039091169063564a565d9060240160a060405180830381865afa158015612f3f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f63919061372e565b505060018054604051637e37c78b60e11b8152600481018a90529495506000946001600160a01b039091169350638a9bb02a9250889190849063fc6f8f1690602401602060405180830381865afa158015612fc2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fe691906138a9565b612ff091906136ef565b6040516001600160e01b031960e085901b16815260048101929092526024820152604401600060405180830381865afa158015613031573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526130599190810190613d5a565b602001519050600080600160009054906101000a90046001600160a01b03166001600160a01b0316632e1daf2f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156130b5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130d99190613caa565b604051631a383be960e31b81526001600160a01b0388811660048301526001600160601b0387166024830152919091169063d1c1df4890604401608060405180830381865afa158015613130573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131549190613e3b565b5050915091508281613166919061383b565b909110159695505050505050565b60006020828403121561318657600080fd5b5035919050565b6001600160a01b0381168114612eee57600080fd5b600080600080608085870312156131b857600080fd5b8435935060208501356131ca8161318d565b93969395505050506040820135916060013590565b600080604083850312156131f257600080fd5b82356131fd8161318d565b9150602083013561320d8161318d565b809150509250929050565b6000806040838503121561322b57600080fd5b50508035926020909101359150565b634e487b7160e01b600052604160045260246000fd5b60405161016081016001600160401b03811182821017156132735761327361323a565b60405290565b604051601f8201601f191681016001600160401b03811182821017156132a1576132a161323a565b604052919050565b60006001600160401b038311156132c2576132c261323a565b6132d5601f8401601f1916602001613279565b90508281528383830111156132e957600080fd5b828260208301376000602084830101529392505050565b600082601f83011261331157600080fd5b613320838335602085016132a9565b9392505050565b6000806040838503121561333a57600080fd5b82356133458161318d565b915060208301356001600160401b0381111561336057600080fd5b61336c85828601613300565b9150509250929050565b60005b83811015613391578181015183820152602001613379565b50506000910152565b600081518084526133b2816020860160208601613376565b601f01601f19169290920160200192915050565b8381528215156020820152606060408201526000611dc5606083018461339a565b60008083601f8401126133f957600080fd5b5081356001600160401b0381111561341057600080fd5b6020830191508360208260051b850101111561342b57600080fd5b9250929050565b6000806000806060858703121561344857600080fd5b8435935060208501356001600160401b0381111561346557600080fd5b613471878288016133e7565b9598909750949560400135949350505050565b6020808252825182820181905260009190848201906040850190845b818110156134bc578351835292840192918401916001016134a0565b50909695505050505050565b600080600080600060a086880312156134e057600080fd5b505083359560208501359550604085013594606081013594506080013592509050565b60008060006060848603121561351857600080fd5b505081359360208301359350604090920135919050565b60008060006060848603121561354457600080fd5b833561354f8161318d565b92506020840135915060408401356001600160401b0381111561357157600080fd5b61357d86828701613300565b9150509250925092565b60008060008060008060a087890312156135a057600080fd5b8635955060208701356001600160401b03808211156135be57600080fd5b6135ca8a838b016133e7565b9097509550604089013594506060890135935060808901359150808211156135f157600080fd5b508701601f8101891361360357600080fd5b613612898235602084016132a9565b9150509295509295509295565b60006020828403121561363157600080fd5b81356133208161318d565b60008060008060006080868803121561365457600080fd5b853594506020860135935060408601356001600160401b038082111561367957600080fd5b818801915088601f83011261368d57600080fd5b81358181111561369c57600080fd5b8960208285010111156136ae57600080fd5b96999598505060200195606001359392505050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b81810381811115612e7257612e726136d9565b80516001600160601b038116811461371957600080fd5b919050565b8051801515811461371957600080fd5b600080600080600060a0868803121561374657600080fd5b61374f86613702565b9450602086015161375f8161318d565b60408701519094506005811061377457600080fd5b92506137826060870161371e565b9150608086015190509295509295909350565b634e487b7160e01b600052602160045260246000fd5b6000602082840312156137bd57600080fd5b6133208261371e565b6000806000606084860312156137db57600080fd5b835192506137eb6020850161371e565b91506137f96040850161371e565b90509250925092565b8082028115828204841417612e7257612e726136d9565b60008261383657634e487b7160e01b600052601260045260246000fd5b500490565b80820180821115612e7257612e726136d9565b6020808252601e908201527f44697370757465206a756d70656420746f206120706172656e7420444b210000604082015260600190565b6000806040838503121561389857600080fd5b505080516020909101519092909150565b6000602082840312156138bb57600080fd5b5051919050565b600181811c908216806138d657607f821691505b6020821081036138f657634e487b7160e01b600052602260045260246000fd5b50919050565b83815260006020846020840152606060408401526000845461391d816138c2565b806060870152608060018084166000811461393f576001811461395b5761398b565b60ff19851660808a0152608084151560051b8a0101955061398b565b89600052602060002060005b858110156139825781548b8201860152908301908801613967565b8a016080019650505b50939a9950505050505050505050565b600082516139ad818460208701613376565b9190910192915050565b6020808252601f908201527f5468652063616c6c65722068617320746f206f776e2074686520766f74652e00604082015260600190565b81835260006001600160fb1b03831115613a0757600080fd5b8260051b80836020870137939093016020019392505050565b604081526000613a346040830185876139ee565b9050826020830152949350505050565b60208082526022908201527f416363657373206e6f7420616c6c6f7765643a20476f7665726e6f72206f6e6c6040820152613c9760f11b606082015260800190565b600080600080600080600060e0888a031215613aa157600080fd5b613aaa88613702565b9650613ab86020890161371e565b955060408801519450606088015193506080880151925060a08801519150613ae260c0890161371e565b905092959891949750929550565b604081526000613b046040830185876139ee565b8281036020840152613b16818561339a565b9695505050505050565b60208082526024908201527f416363657373206e6f7420616c6c6f7765643a204b6c65726f73436f7265206f60408201526337363c9760e11b606082015260800190565b601f821115611797576000816000526020600020601f850160051c81016020861015613b8d5750805b601f850160051c820191505b81811015613bac57828155600101613b99565b505050505050565b6001600160401b03831115613bcb57613bcb61323a565b613bdf83613bd983546138c2565b83613b64565b6000601f841160018114613c135760008515613bfb5750838201355b600019600387901b1c1916600186901b178355613c6d565b600083815260209020601f19861690835b82811015613c445786850135825560209485019460019092019101613c24565b5086821015613c615760001960f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b83815260406020820152816040820152818360608301376000818301606090810191909152601f909201601f1916010192915050565b600060208284031215613cbc57600080fd5b81516133208161318d565b600082601f830112613cd857600080fd5b815160206001600160401b03821115613cf357613cf361323a565b8160051b613d02828201613279565b9283528481018201928281019087851115613d1c57600080fd5b83870192505b84831015613d44578251613d358161318d565b82529183019190830190613d22565b979650505050505050565b80516137198161318d565b600060208284031215613d6c57600080fd5b81516001600160401b0380821115613d8357600080fd5b908301906101608286031215613d9857600080fd5b613da0613250565b825181526020830151602082015260408301516040820152606083015160608201526080830151608082015260a083015160a082015260c083015182811115613de857600080fd5b613df487828601613cc7565b60c08301525060e0838101519082015261010080840151908201526101209150613e1f828401613d4f565b9181019190915261014091820151918101919091529392505050565b60008060008060808587031215613e5157600080fd5b50508251602084015160408501516060909501519196909550909250905056fe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbca2646970667358221220ece2f97e5f37049420403eea1739d27d704a432100da66c99ed49ffe1796440264736f6c63430008180033",
+ "solcInputHash": "d547d738900bce1310e91a5d1adfc179",
+ "metadata": "{\"compiler\":{\"version\":\"0.8.30+commit.73712a01\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"AlreadyInitialized\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"AppealFeeIsAlreadyPaid\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"AppealPeriodIsOver\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"AppealPeriodIsOverForLoser\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ChoiceOutOfBounds\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CoreIsPaused\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputeJumpedToParentDK\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputeNotResolved\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"EmptyCommit\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"EmptyVoteIDs\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedDelegateCall\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"HashDoesNotMatchHiddenVoteCommitment\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"implementation\",\"type\":\"address\"}],\"name\":\"InvalidImplementation\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"JurorHasToOwnTheVote\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"KlerosCoreOnly\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotActiveForCoreDisputeID\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotCommitPeriod\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotInitializing\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotVotePeriod\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OwnerOnly\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UUPSUnauthorizedCallContext\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"slot\",\"type\":\"bytes32\"}],\"name\":\"UUPSUnsupportedProxiableUUID\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnsuccessfulCall\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"VoteAlreadyCast\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_coreDisputeID\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_coreRoundID\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_choice\",\"type\":\"uint256\"}],\"name\":\"ChoiceFunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_coreDisputeID\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_juror\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"_voteIDs\",\"type\":\"uint256[]\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"_commit\",\"type\":\"bytes32\"}],\"name\":\"CommitCast\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_coreDisputeID\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_coreRoundID\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_choice\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_contributor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"Contribution\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_coreDisputeID\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_numberOfChoices\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"_extraData\",\"type\":\"bytes\"}],\"name\":\"DisputeCreation\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"version\",\"type\":\"uint64\"}],\"name\":\"Initialized\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newImplementation\",\"type\":\"address\"}],\"name\":\"Upgraded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_coreDisputeID\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_juror\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"_voteIDs\",\"type\":\"uint256[]\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_choice\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"_justification\",\"type\":\"string\"}],\"name\":\"VoteCast\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_coreDisputeID\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_coreRoundID\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_choice\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_contributor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"Withdrawal\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"LOSER_APPEAL_PERIOD_MULTIPLIER\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"LOSER_STAKE_MULTIPLIER\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"WINNER_STAKE_MULTIPLIER\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_coreDisputeID\",\"type\":\"uint256\"}],\"name\":\"areCommitsAllCast\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_coreDisputeID\",\"type\":\"uint256\"}],\"name\":\"areVotesAllCast\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_coreDisputeID\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"_voteIDs\",\"type\":\"uint256[]\"},{\"internalType\":\"bytes32\",\"name\":\"_commit\",\"type\":\"bytes32\"}],\"name\":\"castCommit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_coreDisputeID\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"_voteIDs\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256\",\"name\":\"_choice\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_salt\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"_justification\",\"type\":\"string\"}],\"name\":\"castVote\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_core\",\"type\":\"address\"}],\"name\":\"changeCore\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_jumpDisputeKitID\",\"type\":\"uint256\"}],\"name\":\"changeJumpDisputeKitID\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address payable\",\"name\":\"_owner\",\"type\":\"address\"}],\"name\":\"changeOwner\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"core\",\"outputs\":[{\"internalType\":\"contract KlerosCore\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"coreDisputeID\",\"type\":\"uint256\"}],\"name\":\"coreDisputeIDToActive\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"coreDisputeIDToLocal\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_coreDisputeID\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_numberOfChoices\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"_extraData\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"createDispute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_coreDisputeID\",\"type\":\"uint256\"}],\"name\":\"currentRuling\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"ruling\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"tied\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"overridden\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"disputes\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"numberOfChoices\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"jumped\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_coreDisputeID\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_nonce\",\"type\":\"uint256\"}],\"name\":\"draw\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"drawnAddress\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"fromSubcourtID\",\"type\":\"uint96\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"earlyCourtJump\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_destination\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"executeOwnerProposal\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_coreDisputeID\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_choice\",\"type\":\"uint256\"}],\"name\":\"fundAppeal\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_coreDisputeID\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_coreRoundID\",\"type\":\"uint256\"}],\"name\":\"getCoherentCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_coreDisputeID\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_coreRoundID\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_voteID\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"getDegreeOfCoherencePenalty\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"pnkCoherence\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_coreDisputeID\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_coreRoundID\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_voteID\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"getDegreeOfCoherenceReward\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"pnkCoherence\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"feeCoherence\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_coreDisputeID\",\"type\":\"uint256\"}],\"name\":\"getFundedChoices\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"fundedChoices\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getJumpDisputeKitID\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_coreDisputeID\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_coreRoundID\",\"type\":\"uint256\"}],\"name\":\"getLocalDisputeRoundID\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"localDisputeID\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"localRoundID\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract IDisputeKit\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_currentNbVotes\",\"type\":\"uint256\"}],\"name\":\"getNbVotesAfterAppeal\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_localDisputeID\",\"type\":\"uint256\"}],\"name\":\"getNumberOfRounds\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_coreDisputeID\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_coreRoundID\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_choice\",\"type\":\"uint256\"}],\"name\":\"getRoundInfo\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"winningChoice\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"tied\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"totalVoted\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"totalCommitted\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nbVoters\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"choiceCount\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_coreDisputeID\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_coreRoundID\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_voteID\",\"type\":\"uint256\"}],\"name\":\"getVoteInfo\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"commit\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"choice\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"voted\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_choice\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_salt\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"hashVote\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"},{\"internalType\":\"contract KlerosCore\",\"name\":\"_core\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_wNative\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_jumpDisputeKitID\",\"type\":\"uint256\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_coreDisputeID\",\"type\":\"uint256\"}],\"name\":\"isAppealFunded\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_coreDisputeID\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_coreRoundID\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_voteID\",\"type\":\"uint256\"}],\"name\":\"isVoteActive\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"jumpDisputeKitID\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"proxiableUUID\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"singleDrawPerJuror\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newImplementation\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"upgradeToAndCall\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"version\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"wNative\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_coreDisputeID\",\"type\":\"uint256\"},{\"internalType\":\"address payable\",\"name\":\"_beneficiary\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_coreRoundID\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_choice\",\"type\":\"uint256\"}],\"name\":\"withdrawFeesAndRewards\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"errors\":{\"AlreadyInitialized()\":[{\"details\":\"The contract is already initialized.\"}],\"NotInitializing()\":[{\"details\":\"The contract is not initializing.\"}]},\"events\":{\"ChoiceFunded(uint256,uint256,uint256)\":{\"params\":{\"_choice\":\"The choice that is being funded.\",\"_coreDisputeID\":\"The identifier of the dispute in the Arbitrator contract.\",\"_coreRoundID\":\"The identifier of the round in the Arbitrator contract.\"}},\"CommitCast(uint256,address,uint256[],bytes32)\":{\"params\":{\"_commit\":\"The commitment of the juror.\",\"_coreDisputeID\":\"The identifier of the dispute in the Arbitrator contract.\",\"_juror\":\"The address of the juror casting the vote commitment.\",\"_voteIDs\":\"The identifiers of the votes in the dispute.\"}},\"Contribution(uint256,uint256,uint256,address,uint256)\":{\"params\":{\"_amount\":\"The amount contributed.\",\"_choice\":\"The choice that is being funded.\",\"_contributor\":\"The address of the contributor.\",\"_coreDisputeID\":\"The identifier of the dispute in the Arbitrator contract.\",\"_coreRoundID\":\"The identifier of the round in the Arbitrator contract.\"}},\"DisputeCreation(uint256,uint256,bytes)\":{\"params\":{\"_coreDisputeID\":\"The identifier of the dispute in the Arbitrator contract.\",\"_extraData\":\"The extra data for the dispute.\",\"_numberOfChoices\":\"The number of choices available in the dispute.\"}},\"Initialized(uint64)\":{\"details\":\"Triggered when the contract has been initialized or reinitialized.\"},\"Upgraded(address)\":{\"params\":{\"newImplementation\":\"Address of the new implementation the proxy is now forwarding calls to.\"}},\"VoteCast(uint256,address,uint256[],uint256,string)\":{\"params\":{\"_choice\":\"The choice juror voted for.\",\"_coreDisputeID\":\"The identifier of the dispute in the Arbitrator contract.\",\"_juror\":\"Address of the juror.\",\"_justification\":\"Justification of the choice.\",\"_voteIDs\":\"The identifiers of the votes in the dispute.\"}},\"Withdrawal(uint256,uint256,uint256,address,uint256)\":{\"params\":{\"_amount\":\"The amount withdrawn.\",\"_choice\":\"The choice that is being funded.\",\"_contributor\":\"The address of the contributor.\",\"_coreDisputeID\":\"The identifier of the dispute in the Arbitrator contract.\",\"_coreRoundID\":\"The identifier of the round in the Arbitrator contract.\"}}},\"kind\":\"dev\",\"methods\":{\"areCommitsAllCast(uint256)\":{\"params\":{\"_coreDisputeID\":\"The ID of the dispute in Kleros Core, not in the Dispute Kit.\"},\"returns\":{\"_0\":\"Whether all of the jurors have cast their commits for the last round.\"}},\"areVotesAllCast(uint256)\":{\"details\":\"This function is to be called directly by the core contract and is not for off-chain usage.\",\"params\":{\"_coreDisputeID\":\"The ID of the dispute in Kleros Core, not in the Dispute Kit.\"},\"returns\":{\"_0\":\"Whether all of the jurors have cast their votes for the last round.\"}},\"castCommit(uint256,uint256[],bytes32)\":{\"details\":\"It can be called multiple times during the commit period, each call overrides the commits of the previous one. `O(n)` where `n` is the number of votes.\",\"params\":{\"_commit\":\"The commitment hash.\",\"_coreDisputeID\":\"The ID of the dispute in Kleros Core.\",\"_voteIDs\":\"The IDs of the votes.\"}},\"castVote(uint256,uint256[],uint256,uint256,string)\":{\"details\":\"`O(n)` where `n` is the number of votes.\",\"params\":{\"_choice\":\"The choice.\",\"_coreDisputeID\":\"The ID of the dispute in Kleros Core.\",\"_justification\":\"Justification of the choice.\",\"_salt\":\"The salt for the commit if the votes were hidden.\",\"_voteIDs\":\"The IDs of the votes.\"}},\"changeCore(address)\":{\"params\":{\"_core\":\"The new value for the `core` storage variable.\"}},\"changeJumpDisputeKitID(uint256)\":{\"params\":{\"_jumpDisputeKitID\":\"The new value for the `jumpDisputeKitID` storage variable.\"}},\"changeOwner(address)\":{\"params\":{\"_owner\":\"The new value for the `owner` storage variable.\"}},\"constructor\":{\"custom:oz-upgrades-unsafe-allow\":\"constructor\"},\"createDispute(uint256,uint256,bytes,uint256)\":{\"details\":\"Access restricted to Kleros Core only.\",\"params\":{\"_coreDisputeID\":\"The ID of the dispute in Kleros Core, not in the Dispute Kit.\",\"_extraData\":\"Additional info about the dispute, for possible use in future dispute kits.\",\"_nbVotes\":\"Maximal number of votes this dispute can get. Added for future-proofing.\",\"_numberOfChoices\":\"Number of choices of the dispute\"}},\"currentRuling(uint256)\":{\"params\":{\"_coreDisputeID\":\"The ID of the dispute in Kleros Core, not in the Dispute Kit.\"},\"returns\":{\"overridden\":\"Whether the ruling was overridden by appeal funding or not.\",\"ruling\":\"The current ruling.\",\"tied\":\"Whether it's a tie or not.\"}},\"draw(uint256,uint256)\":{\"details\":\"Access restricted to Kleros Core only.\",\"params\":{\"_coreDisputeID\":\"The ID of the dispute in Kleros Core, not in the Dispute Kit.\",\"_nonce\":\"Nonce.\"},\"returns\":{\"drawnAddress\":\"The drawn address.\"}},\"earlyCourtJump(uint256)\":{\"details\":\"Returns true if the dispute is jumping to a parent court.\",\"params\":{\"_coreDisputeID\":\"The ID of the dispute in Kleros Core, not in the Dispute Kit.\"},\"returns\":{\"_0\":\"Whether the dispute is jumping to a parent court or not.\"}},\"executeOwnerProposal(address,uint256,bytes)\":{\"params\":{\"_amount\":\"The value sent with the call.\",\"_data\":\"The data sent with the call.\",\"_destination\":\"The destination of the call.\"}},\"fundAppeal(uint256,uint256)\":{\"params\":{\"_choice\":\"A choice that receives funding.\",\"_coreDisputeID\":\"Index of the dispute in Kleros Core.\"}},\"getCoherentCount(uint256,uint256)\":{\"params\":{\"_coreDisputeID\":\"The ID of the dispute in Kleros Core, not in the Dispute Kit.\",\"_coreRoundID\":\"The ID of the round in Kleros Core, not in the Dispute Kit.\"},\"returns\":{\"_0\":\"The number of coherent jurors.\"}},\"getDegreeOfCoherencePenalty(uint256,uint256,uint256,uint256,uint256)\":{\"details\":\"This function is called by Kleros Core in order to determine the amount of the penalty.\",\"params\":{\"_coreDisputeID\":\"The ID of the dispute in Kleros Core, not in the Dispute Kit.\",\"_coreRoundID\":\"The ID of the round in Kleros Core, not in the Dispute Kit.\",\"_feePerJuror\":\"The fee per juror.\",\"_pnkAtStakePerJuror\":\"The PNK at stake per juror.\",\"_voteID\":\"The ID of the vote.\"},\"returns\":{\"pnkCoherence\":\"The degree of coherence in basis points for the dispute PNK reward.\"}},\"getDegreeOfCoherenceReward(uint256,uint256,uint256,uint256,uint256)\":{\"details\":\"This function is called by Kleros Core in order to determine the amount of the reward.\",\"params\":{\"_coreDisputeID\":\"The ID of the dispute in Kleros Core, not in the Dispute Kit.\",\"_coreRoundID\":\"The ID of the round in Kleros Core, not in the Dispute Kit.\",\"_feePerJuror\":\"The fee per juror.\",\"_pnkAtStakePerJuror\":\"The PNK at stake per juror.\",\"_voteID\":\"The ID of the vote.\"},\"returns\":{\"feeCoherence\":\"The degree of coherence in basis points for the dispute fee reward.\",\"pnkCoherence\":\"The degree of coherence in basis points for the dispute PNK reward.\"}},\"getFundedChoices(uint256)\":{\"params\":{\"_coreDisputeID\":\"The ID of the dispute in Kleros Core.\"},\"returns\":{\"fundedChoices\":\"Fully funded rulings.\"}},\"getJumpDisputeKitID()\":{\"returns\":{\"_0\":\"The ID of the dispute kit in Kleros Core disputeKits array.\"}},\"getLocalDisputeRoundID(uint256,uint256)\":{\"params\":{\"_coreDisputeID\":\"The ID of the dispute in Kleros Core.\",\"_coreRoundID\":\"The ID of the round in Kleros Core.\"},\"returns\":{\"localDisputeID\":\"The ID of the dispute in the Dispute Kit.\",\"localRoundID\":\"The ID of the round in the Dispute Kit.\"}},\"getNbVotesAfterAppeal(address,uint256)\":{\"params\":{\"_currentNbVotes\":\"The number of votes before the appeal.\",\"_previousDisputeKit\":\"The previous Dispute Kit.\"},\"returns\":{\"_0\":\"The number of votes after the appeal.\"}},\"getNumberOfRounds(uint256)\":{\"params\":{\"_localDisputeID\":\"The ID of the dispute in the Dispute Kit.\"},\"returns\":{\"_0\":\"The number of rounds in the dispute.\"}},\"getRoundInfo(uint256,uint256,uint256)\":{\"params\":{\"_choice\":\"The choice to query.\",\"_coreDisputeID\":\"The ID of the dispute in Kleros Core, not in the Dispute Kit.\",\"_coreRoundID\":\"The ID of the round in Kleros Core, not in the Dispute Kit.\"},\"returns\":{\"choiceCount\":\"Number of votes cast for the queried choice.\",\"nbVoters\":\"Total number of voters in this round.\",\"tied\":\"Whether it's a tie or not.\",\"totalCommitted\":\"Number of jurors who cast the commit already (only relevant for hidden votes).\",\"totalVoted\":\"Number of jurors who cast the vote already.\",\"winningChoice\":\"The winning choice of this round.\"}},\"getVoteInfo(uint256,uint256,uint256)\":{\"params\":{\"_coreDisputeID\":\"The ID of the dispute in Kleros Core.\",\"_coreRoundID\":\"The ID of the round in Kleros Core.\",\"_voteID\":\"The ID of the vote.\"},\"returns\":{\"account\":\"The address of the juror who cast the vote.\",\"choice\":\"The choice that got the vote.\",\"commit\":\"The commit of the vote.\",\"voted\":\"Whether the vote was cast or not.\"}},\"hashVote(uint256,uint256,string)\":{\"details\":\"The unused parameters may be used by overriding contracts.\",\"params\":{\"_choice\":\"The choice being voted for\",\"_salt\":\"A random salt for commitment\"},\"returns\":{\"_0\":\"bytes32 The hash of the encoded vote parameters\"}},\"initialize(address,address,address,uint256)\":{\"params\":{\"_core\":\"The KlerosCore arbitrator.\",\"_jumpDisputeKitID\":\"The ID of the dispute kit to switch to after the court jump.\",\"_owner\":\"The owner's address.\",\"_wNative\":\"The wrapped native token address, typically wETH.\"}},\"isAppealFunded(uint256)\":{\"details\":\"This function is to be called directly by the core contract and is not for off-chain usage.\",\"params\":{\"_coreDisputeID\":\"The ID of the dispute in Kleros Core, not in the Dispute Kit.\"},\"returns\":{\"_0\":\"Whether the appeal funding is finished.\"}},\"isVoteActive(uint256,uint256,uint256)\":{\"params\":{\"_coreDisputeID\":\"The ID of the dispute in Kleros Core, not in the Dispute Kit.\",\"_coreRoundID\":\"The ID of the round in Kleros Core, not in the Dispute Kit.\",\"_voteID\":\"The ID of the voter.\"},\"returns\":{\"_0\":\"Whether the voter was active or not.\"}},\"proxiableUUID()\":{\"details\":\"IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this function revert if invoked through a proxy. This is guaranteed by the if statement.\"},\"upgradeToAndCall(address,bytes)\":{\"details\":\"Reverts if the execution is not performed via delegatecall or the execution context is not of a proxy with an ERC1967-compliant implementation pointing to self.\",\"params\":{\"data\":\"Data used in a delegate call to `newImplementation` if non-empty. This will typically be an encoded function call, and allows initializing the storage of the proxy like a Solidity constructor.\",\"newImplementation\":\"Address of the new implementation contract.\"}},\"withdrawFeesAndRewards(uint256,address,uint256,uint256)\":{\"details\":\"Withdrawals are not possible if the core contract is paused.\",\"params\":{\"_beneficiary\":\"The address whose rewards to withdraw.\",\"_choice\":\"The ruling option that the caller wants to withdraw from.\",\"_coreDisputeID\":\"Index of the dispute in Kleros Core contract.\",\"_coreRoundID\":\"The round in the Kleros Core contract the caller wants to withdraw from.\"},\"returns\":{\"amount\":\"The withdrawn amount.\"}}},\"stateVariables\":{\"version\":{\"return\":\"Version string.\",\"returns\":{\"_0\":\"Version string.\"}}},\"title\":\"DisputeKitClassic\",\"version\":1},\"userdoc\":{\"errors\":{\"FailedDelegateCall()\":[{\"notice\":\"Failed Delegated call\"}],\"InvalidImplementation(address)\":[{\"notice\":\"The `implementation` is not UUPS-compliant\"}],\"UUPSUnauthorizedCallContext()\":[{\"notice\":\"The call is from an unauthorized context.\"}],\"UUPSUnsupportedProxiableUUID(bytes32)\":[{\"notice\":\"The storage `slot` is unsupported as a UUID.\"}]},\"events\":{\"ChoiceFunded(uint256,uint256,uint256)\":{\"notice\":\"To be emitted when a choice is fully funded for an appeal.\"},\"CommitCast(uint256,address,uint256[],bytes32)\":{\"notice\":\"To be emitted when a vote commitment is cast.\"},\"Contribution(uint256,uint256,uint256,address,uint256)\":{\"notice\":\"To be emitted when a funding contribution is made.\"},\"DisputeCreation(uint256,uint256,bytes)\":{\"notice\":\"To be emitted when a dispute is created.\"},\"Upgraded(address)\":{\"notice\":\"Emitted when the `implementation` has been successfully upgraded.\"},\"VoteCast(uint256,address,uint256[],uint256,string)\":{\"notice\":\"Emitted when casting a vote to provide the justification of juror's choice.\"},\"Withdrawal(uint256,uint256,uint256,address,uint256)\":{\"notice\":\"To be emitted when the contributed funds are withdrawn.\"}},\"kind\":\"user\",\"methods\":{\"areCommitsAllCast(uint256)\":{\"notice\":\"Returns true if all of the jurors have cast their commits for the last round.\"},\"areVotesAllCast(uint256)\":{\"notice\":\"Returns true if all of the jurors have cast their votes for the last round.\"},\"castCommit(uint256,uint256[],bytes32)\":{\"notice\":\"Sets the caller's commit for the specified votes.\"},\"castVote(uint256,uint256[],uint256,uint256,string)\":{\"notice\":\"Sets the caller's choices for the specified votes.\"},\"changeCore(address)\":{\"notice\":\"Changes the `core` storage variable.\"},\"changeJumpDisputeKitID(uint256)\":{\"notice\":\"Changes the dispute kit ID used for the jump.\"},\"changeOwner(address)\":{\"notice\":\"Changes the `owner` storage variable.\"},\"createDispute(uint256,uint256,bytes,uint256)\":{\"notice\":\"Creates a local dispute and maps it to the dispute ID in the Core contract.\"},\"currentRuling(uint256)\":{\"notice\":\"Gets the current ruling of a specified dispute.\"},\"draw(uint256,uint256)\":{\"notice\":\"Draws the juror from the sortition tree. The drawn address is picked up by Kleros Core.\"},\"executeOwnerProposal(address,uint256,bytes)\":{\"notice\":\"Allows the owner to call anything on behalf of the contract.\"},\"fundAppeal(uint256,uint256)\":{\"notice\":\"Manages contributions, and appeals a dispute if at least two choices are fully funded. Note that the surplus deposit will be reimbursed.\"},\"getCoherentCount(uint256,uint256)\":{\"notice\":\"Gets the number of jurors who are eligible to a reward in this round.\"},\"getDegreeOfCoherencePenalty(uint256,uint256,uint256,uint256,uint256)\":{\"notice\":\"Gets the degree of coherence of a particular voter.\"},\"getDegreeOfCoherenceReward(uint256,uint256,uint256,uint256,uint256)\":{\"notice\":\"Gets the degree of coherence of a particular voter.\"},\"getFundedChoices(uint256)\":{\"notice\":\"Returns the rulings that were fully funded in the latest appeal round.\"},\"getJumpDisputeKitID()\":{\"notice\":\"Returns the dispute kit ID to be used after court jump by Kleros Core.\"},\"getLocalDisputeRoundID(uint256,uint256)\":{\"notice\":\"Returns the local dispute ID and round ID for a given core dispute ID and core round ID.\"},\"getNbVotesAfterAppeal(address,uint256)\":{\"notice\":\"Returns the number of votes after the appeal.\"},\"getNumberOfRounds(uint256)\":{\"notice\":\"Returns the number of rounds in a dispute.\"},\"getRoundInfo(uint256,uint256,uint256)\":{\"notice\":\"Returns the info of the specified round in the core contract.\"},\"getVoteInfo(uint256,uint256,uint256)\":{\"notice\":\"Returns the vote information for a given vote ID.\"},\"hashVote(uint256,uint256,string)\":{\"notice\":\"Computes the hash of a vote using ABI encoding\"},\"initialize(address,address,address,uint256)\":{\"notice\":\"Initializer.\"},\"isAppealFunded(uint256)\":{\"notice\":\"Returns true if the appeal funding is finished prematurely (e.g. when losing side didn't fund).\"},\"isVoteActive(uint256,uint256,uint256)\":{\"notice\":\"Returns true if the specified voter was active in this round.\"},\"proxiableUUID()\":{\"notice\":\"Implementation of the ERC1822 `proxiableUUID` function. This returns the storage slot used by the implementation. It is used to validate the implementation's compatibility when performing an upgrade.\"},\"upgradeToAndCall(address,bytes)\":{\"notice\":\"Upgrade mechanism including access control and UUPS-compliance.\"},\"version()\":{\"notice\":\"Returns the version of the implementation.\"},\"withdrawFeesAndRewards(uint256,address,uint256,uint256)\":{\"notice\":\"Allows those contributors who attempted to fund an appeal round to withdraw any reimbursable fees or rewards after the dispute gets resolved.\"}},\"notice\":\"Dispute kit implementation of the Kleros v1 features including: - a drawing system: proportional to staked PNK, - a vote aggregation system: plurality, - an incentive system: equal split between coherent votes, - an appeal system: fund 2 choices only, vote on any choice.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/arbitration/dispute-kits/DisputeKitClassic.sol\":\"DisputeKitClassic\"},\"evmVersion\":\"cancun\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000},\"remappings\":[],\"viaIR\":true},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity >=0.4.16;\\n\\n/**\\n * @dev Interface of the ERC-20 standard as defined in the ERC.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n\\n /**\\n * @dev Returns the value of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the value of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 value) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\\n * caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 value) external returns (bool);\\n\\n /**\\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\\n * allowance mechanism. `value` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(address from, address to, uint256 value) external returns (bool);\\n}\\n\",\"keccak256\":\"0x74ed01eb66b923d0d0cfe3be84604ac04b76482a55f9dd655e1ef4d367f95bc2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC721/IERC721.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC721/IERC721.sol)\\n\\npragma solidity >=0.6.2;\\n\\nimport {IERC165} from \\\"../../utils/introspection/IERC165.sol\\\";\\n\\n/**\\n * @dev Required interface of an ERC-721 compliant contract.\\n */\\ninterface IERC721 is IERC165 {\\n /**\\n * @dev Emitted when `tokenId` token is transferred from `from` to `to`.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);\\n\\n /**\\n * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.\\n */\\n event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);\\n\\n /**\\n * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.\\n */\\n event ApprovalForAll(address indexed owner, address indexed operator, bool approved);\\n\\n /**\\n * @dev Returns the number of tokens in ``owner``'s account.\\n */\\n function balanceOf(address owner) external view returns (uint256 balance);\\n\\n /**\\n * @dev Returns the owner of the `tokenId` token.\\n *\\n * Requirements:\\n *\\n * - `tokenId` must exist.\\n */\\n function ownerOf(uint256 tokenId) external view returns (address owner);\\n\\n /**\\n * @dev Safely transfers `tokenId` token from `from` to `to`.\\n *\\n * Requirements:\\n *\\n * - `from` cannot be the zero address.\\n * - `to` cannot be the zero address.\\n * - `tokenId` token must exist and be owned by `from`.\\n * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\\n * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon\\n * a safe transfer.\\n *\\n * Emits a {Transfer} event.\\n */\\n function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;\\n\\n /**\\n * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients\\n * are aware of the ERC-721 protocol to prevent tokens from being forever locked.\\n *\\n * Requirements:\\n *\\n * - `from` cannot be the zero address.\\n * - `to` cannot be the zero address.\\n * - `tokenId` token must exist and be owned by `from`.\\n * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or\\n * {setApprovalForAll}.\\n * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon\\n * a safe transfer.\\n *\\n * Emits a {Transfer} event.\\n */\\n function safeTransferFrom(address from, address to, uint256 tokenId) external;\\n\\n /**\\n * @dev Transfers `tokenId` token from `from` to `to`.\\n *\\n * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC-721\\n * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must\\n * understand this adds an external call which potentially creates a reentrancy vulnerability.\\n *\\n * Requirements:\\n *\\n * - `from` cannot be the zero address.\\n * - `to` cannot be the zero address.\\n * - `tokenId` token must be owned by `from`.\\n * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(address from, address to, uint256 tokenId) external;\\n\\n /**\\n * @dev Gives permission to `to` to transfer `tokenId` token to another account.\\n * The approval is cleared when the token is transferred.\\n *\\n * Only a single account can be approved at a time, so approving the zero address clears previous approvals.\\n *\\n * Requirements:\\n *\\n * - The caller must own the token or be an approved operator.\\n * - `tokenId` must exist.\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address to, uint256 tokenId) external;\\n\\n /**\\n * @dev Approve or remove `operator` as an operator for the caller.\\n * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.\\n *\\n * Requirements:\\n *\\n * - The `operator` cannot be the address zero.\\n *\\n * Emits an {ApprovalForAll} event.\\n */\\n function setApprovalForAll(address operator, bool approved) external;\\n\\n /**\\n * @dev Returns the account approved for `tokenId` token.\\n *\\n * Requirements:\\n *\\n * - `tokenId` must exist.\\n */\\n function getApproved(uint256 tokenId) external view returns (address operator);\\n\\n /**\\n * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.\\n *\\n * See {setApprovalForAll}\\n */\\n function isApprovedForAll(address owner, address operator) external view returns (bool);\\n}\\n\",\"keccak256\":\"0xf78f05f3b8c9f75570e85300d7b4600d7f6f6a198449273f31d44c1641adb46f\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/introspection/IERC165.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v5.4.0) (utils/introspection/IERC165.sol)\\n\\npragma solidity >=0.4.16;\\n\\n/**\\n * @dev Interface of the ERC-165 standard, as defined in the\\n * https://eips.ethereum.org/EIPS/eip-165[ERC].\\n *\\n * Implementers can declare support of contract interfaces, which can then be\\n * queried by others ({ERC165Checker}).\\n *\\n * For an implementation, see {ERC165}.\\n */\\ninterface IERC165 {\\n /**\\n * @dev Returns true if this contract implements the interface defined by\\n * `interfaceId`. See the corresponding\\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]\\n * to learn more about how these ids are created.\\n *\\n * This function call must use less than 30 000 gas.\\n */\\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\\n}\\n\",\"keccak256\":\"0x8891738ffe910f0cf2da09566928589bf5d63f4524dd734fd9cedbac3274dd5c\",\"license\":\"MIT\"},\"src/arbitration/KlerosCore.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.24;\\n\\nimport {IArbitrableV2, IArbitratorV2} from \\\"./interfaces/IArbitratorV2.sol\\\";\\nimport {IDisputeKit} from \\\"./interfaces/IDisputeKit.sol\\\";\\nimport {ISortitionModule} from \\\"./interfaces/ISortitionModule.sol\\\";\\nimport {Initializable} from \\\"../proxy/Initializable.sol\\\";\\nimport {UUPSProxiable} from \\\"../proxy/UUPSProxiable.sol\\\";\\nimport {SafeERC20, IERC20} from \\\"../libraries/SafeERC20.sol\\\";\\nimport {SafeSend} from \\\"../libraries/SafeSend.sol\\\";\\nimport {IERC721} from \\\"@openzeppelin/contracts/token/ERC721/IERC721.sol\\\";\\nimport \\\"../libraries/Constants.sol\\\";\\n\\n/// @title KlerosCore\\n/// @notice Core arbitrator contract for Kleros v2.\\n/// @dev This contract trusts the PNK token, the dispute kits and the sortition module contracts.\\ncontract KlerosCore is IArbitratorV2, Initializable, UUPSProxiable {\\n using SafeERC20 for IERC20;\\n using SafeSend for address payable;\\n\\n string public constant override version = \\\"2.0.0\\\";\\n\\n // ************************************* //\\n // * Enums / Structs * //\\n // ************************************* //\\n\\n enum Period {\\n evidence, // Evidence can be submitted. This is also when drawing has to take place.\\n commit, // Jurors commit a hashed vote. This is skipped for courts without hidden votes.\\n vote, // Jurors reveal/cast their vote depending on whether the court has hidden votes or not.\\n appeal, // The dispute can be appealed.\\n execution // Tokens are redistributed and the ruling is executed.\\n }\\n\\n struct Court {\\n uint96 parent; // The parent court.\\n bool hiddenVotes; // Whether to use commit and reveal or not.\\n uint256[] children; // List of child courts.\\n uint256 minStake; // Minimum PNKs needed to stake in the court.\\n uint256 alpha; // Basis point of PNKs that are lost when incoherent.\\n uint256 feeForJuror; // Arbitration fee paid per juror.\\n uint256 jurorsForCourtJump; // The appeal after the one that reaches this number of jurors will go to the parent court if any.\\n uint256[4] timesPerPeriod; // The time allotted to each dispute period in the form `timesPerPeriod[period]`.\\n mapping(uint256 disputeKitId => bool) supportedDisputeKits; // True if DK with this ID is supported by the court. Note that each court must support classic dispute kit.\\n uint256[10] __gap; // Reserved slots for future upgrades.\\n }\\n\\n struct Dispute {\\n uint96 courtID; // The ID of the court the dispute is in.\\n IArbitrableV2 arbitrated; // The arbitrable contract.\\n Period period; // The current period of the dispute.\\n bool ruled; // True if the ruling has been executed, false otherwise.\\n uint256 lastPeriodChange; // The last time the period was changed.\\n Round[] rounds; // Rounds of the dispute.\\n uint256[10] __gap; // Reserved slots for future upgrades.\\n }\\n\\n struct Round {\\n uint256 disputeKitID; // Index of the dispute kit in the array.\\n uint256 pnkAtStakePerJuror; // The amount of PNKs at stake for each juror in this round.\\n uint256 totalFeesForJurors; // The total juror fees paid in this round.\\n uint256 nbVotes; // The total number of votes the dispute can possibly have in the current round. Former votes[_round].length.\\n uint256 repartitions; // A counter of reward repartitions made in this round.\\n uint256 pnkPenalties; // The amount of PNKs collected from penalties in this round.\\n address[] drawnJurors; // Addresses of the jurors that were drawn in this round.\\n uint96[] drawnJurorFromCourtIDs; // The courtIDs where the juror was drawn from, possibly their stake in a subcourt.\\n uint256 sumFeeRewardPaid; // Total sum of arbitration fees paid to coherent jurors as a reward in this round.\\n uint256 sumPnkRewardPaid; // Total sum of PNK paid to coherent jurors as a reward in this round.\\n IERC20 feeToken; // The token used for paying fees in this round.\\n uint256 drawIterations; // The number of iterations passed drawing the jurors for this round.\\n uint256[10] __gap; // Reserved slots for future upgrades.\\n }\\n\\n // Workaround \\\"stack too deep\\\" errors\\n struct ExecuteParams {\\n uint256 disputeID; // The ID of the dispute to execute.\\n uint256 round; // The round to execute.\\n uint256 coherentCount; // The number of coherent votes in the round.\\n uint256 numberOfVotesInRound; // The number of votes in the round.\\n uint256 feePerJurorInRound; // The fee per juror in the round.\\n uint256 pnkAtStakePerJurorInRound; // The amount of PNKs at stake for each juror in the round.\\n uint256 pnkPenaltiesInRound; // The amount of PNKs collected from penalties in the round.\\n uint256 repartition; // The index of the repartition to execute.\\n }\\n\\n struct CurrencyRate {\\n bool feePaymentAccepted; // True if this token is supported as payment method.\\n uint64 rateInEth; // Rate of the fee token in ETH.\\n uint8 rateDecimals; // Decimals of the fee token rate.\\n }\\n\\n // ************************************* //\\n // * Storage * //\\n // ************************************* //\\n\\n uint256 private constant NON_PAYABLE_AMOUNT = (2 ** 256 - 2) / 2; // An amount higher than the supply of ETH.\\n\\n address public owner; // The owner of the contract.\\n address public guardian; // The guardian able to pause asset withdrawals.\\n IERC20 public pinakion; // The Pinakion token contract.\\n address public jurorProsecutionModule; // The module for juror's prosecution.\\n ISortitionModule public sortitionModule; // Sortition module for drawing.\\n Court[] public courts; // The courts.\\n IDisputeKit[] public disputeKits; // Array of dispute kits.\\n Dispute[] public disputes; // The disputes.\\n mapping(IERC20 => CurrencyRate) public currencyRates; // The price of each token in ETH.\\n bool public paused; // Whether asset withdrawals are paused.\\n address public wNative; // The wrapped native token for safeSend().\\n mapping(address => bool) public arbitrableWhitelist; // Arbitrable whitelist.\\n bool public arbitrableWhitelistEnabled; // Whether the arbitrable whitelist is enabled.\\n IERC721 public jurorNft; // Eligible jurors NFT.\\n\\n // ************************************* //\\n // * Events * //\\n // ************************************* //\\n\\n /// @notice Emitted when period is passed.\\n /// @param _disputeID ID of the related dispute.\\n /// @param _period The new period.\\n event NewPeriod(uint256 indexed _disputeID, Period _period);\\n\\n /// @notice Emitted when appeal period starts.\\n /// @param _disputeID ID of the related dispute.\\n /// @param _arbitrable The arbitrable contract.\\n event AppealPossible(uint256 indexed _disputeID, IArbitrableV2 indexed _arbitrable);\\n\\n /// @notice Emitted when the dispute is successfully appealed.\\n /// @param _disputeID ID of the related dispute.\\n /// @param _arbitrable The arbitrable contract.\\n event AppealDecision(uint256 indexed _disputeID, IArbitrableV2 indexed _arbitrable);\\n\\n /// @notice Emitted when an address is successfully drawn.\\n /// @param _address The drawn address.\\n /// @param _disputeID ID of the related dispute.\\n /// @param _roundID ID of the related round.\\n /// @param _voteID ID of the vote given to the drawn juror.\\n event Draw(address indexed _address, uint256 indexed _disputeID, uint256 _roundID, uint256 _voteID);\\n\\n /// @notice Emitted when a new court is created.\\n /// @param _courtID ID of the new court.\\n /// @param _parent ID of the parent court.\\n /// @param _hiddenVotes Whether the court has hidden votes or not.\\n /// @param _minStake The `minStake` property value of the court.\\n /// @param _alpha The `alpha` property value of the court.\\n /// @param _feeForJuror The `feeForJuror` property value of the court.\\n /// @param _jurorsForCourtJump The `jurorsForCourtJump` property value of the court.\\n /// @param _timesPerPeriod The `timesPerPeriod` property value of the court.\\n /// @param _supportedDisputeKits Indexes of dispute kits that this court will support.\\n event CourtCreated(\\n uint96 indexed _courtID,\\n uint96 indexed _parent,\\n bool _hiddenVotes,\\n uint256 _minStake,\\n uint256 _alpha,\\n uint256 _feeForJuror,\\n uint256 _jurorsForCourtJump,\\n uint256[4] _timesPerPeriod,\\n uint256[] _supportedDisputeKits\\n );\\n\\n /// @notice Emitted when court's parameters are changed.\\n /// @param _courtID ID of the court.\\n /// @param _hiddenVotes Whether the court has hidden votes or not.\\n /// @param _minStake The `minStake` property value of the court.\\n /// @param _alpha The `alpha` property value of the court.\\n /// @param _feeForJuror The `feeForJuror` property value of the court.\\n /// @param _jurorsForCourtJump The `jurorsForCourtJump` property value of the court.\\n /// @param _timesPerPeriod The `timesPerPeriod` property value of the court.\\n event CourtModified(\\n uint96 indexed _courtID,\\n bool _hiddenVotes,\\n uint256 _minStake,\\n uint256 _alpha,\\n uint256 _feeForJuror,\\n uint256 _jurorsForCourtJump,\\n uint256[4] _timesPerPeriod\\n );\\n\\n /// @notice Emitted when a dispute kit is created.\\n /// @param _disputeKitID ID of the new dispute kit.\\n /// @param _disputeKitAddress Address of the new dispute kit.\\n event DisputeKitCreated(uint256 indexed _disputeKitID, IDisputeKit indexed _disputeKitAddress);\\n\\n /// @notice Emitted when a dispute kit is enabled/disabled in a court.\\n /// @param _courtID ID of the related court.\\n /// @param _disputeKitID ID of the dispute kit.\\n /// @param _enable Whether the dispute kit has been enabled or disabled.\\n event DisputeKitEnabled(uint96 indexed _courtID, uint256 indexed _disputeKitID, bool indexed _enable);\\n\\n /// @notice Emitted when a dispute jumps to a new court.\\n /// @param _disputeID ID of the dispute.\\n /// @param _roundID ID of the round.\\n /// @param _fromCourtID ID of the previous court.\\n /// @param _toCourtID ID of the new court.\\n event CourtJump(\\n uint256 indexed _disputeID,\\n uint256 indexed _roundID,\\n uint96 indexed _fromCourtID,\\n uint96 _toCourtID\\n );\\n\\n /// @notice Emitted when a dispute jumps to a new dispute kit.\\n /// @param _disputeID ID of the dispute.\\n /// @param _roundID ID of the round.\\n /// @param _fromDisputeKitID ID of the previous dispute kit.\\n /// @param _toDisputeKitID ID of the new dispute kit.\\n event DisputeKitJump(\\n uint256 indexed _disputeID,\\n uint256 indexed _roundID,\\n uint256 indexed _fromDisputeKitID,\\n uint256 _toDisputeKitID\\n );\\n\\n /// @notice Emitted when juror's balance shifts after penalties/rewards has been processed.\\n /// @param _account Juror's address.\\n /// @param _disputeID ID of the dispute.\\n /// @param _roundID ID of the round.\\n /// @param _degreeOfCoherencyPnk Juror's degree of coherency in this round applied to PNK.\\n /// @param _degreeOfCoherencyFee Juror's degree of coherency in this round applied to the dispute fee.\\n /// @param _amountPnk Amount of PNK shifted.\\n /// @param _amountFee Amount of fee shifted.\\n /// @param _feeToken Address of the fee token.\\n event JurorRewardPenalty(\\n address indexed _account,\\n uint256 indexed _disputeID,\\n uint256 indexed _roundID,\\n uint256 _degreeOfCoherencyPnk,\\n uint256 _degreeOfCoherencyFee,\\n int256 _amountPnk,\\n int256 _amountFee,\\n IERC20 _feeToken\\n );\\n\\n /// @notice Emitted when leftover reward sent to owner.\\n /// @param _disputeID ID of the dispute.\\n /// @param _roundID ID of the round.\\n /// @param _amountPnk Amount of PNK sent.\\n /// @param _amountFee Amount of fee sent.\\n /// @param _feeToken Address of the fee token.\\n event LeftoverRewardSent(\\n uint256 indexed _disputeID,\\n uint256 indexed _roundID,\\n uint256 _amountPnk,\\n uint256 _amountFee,\\n IERC20 _feeToken\\n );\\n\\n /// @notice Emitted when this contract is paused.\\n event Paused();\\n\\n /// @notice Emitted when this contract is unpaused.\\n event Unpaused();\\n\\n // ************************************* //\\n // * Function Modifiers * //\\n // ************************************* //\\n\\n modifier onlyByOwner() {\\n if (owner != msg.sender) revert OwnerOnly();\\n _;\\n }\\n\\n modifier onlyByGuardianOrOwner() {\\n if (guardian != msg.sender && owner != msg.sender) revert GuardianOrOwnerOnly();\\n _;\\n }\\n\\n modifier whenPaused() {\\n if (!paused) revert WhenPausedOnly();\\n _;\\n }\\n\\n modifier whenNotPaused() {\\n if (paused) revert WhenNotPausedOnly();\\n _;\\n }\\n\\n // ************************************* //\\n // * Constructor * //\\n // ************************************* //\\n\\n /// @custom:oz-upgrades-unsafe-allow constructor\\n constructor() {\\n _disableInitializers();\\n }\\n\\n /// @notice Initializer (constructor equivalent for upgradable contracts).\\n /// @param _owner The owner's address.\\n /// @param _guardian The guardian's address.\\n /// @param _pinakion The address of the token contract.\\n /// @param _jurorProsecutionModule The address of the juror prosecution module.\\n /// @param _disputeKit The address of the default dispute kit.\\n /// @param _hiddenVotes The `hiddenVotes` property value of the general court.\\n /// @param _courtParameters Numeric parameters of General court (minStake, alpha, feeForJuror and jurorsForCourtJump respectively).\\n /// @param _timesPerPeriod The `timesPerPeriod` property value of the general court.\\n /// @param _sortitionExtraData The extra data for sortition module.\\n /// @param _sortitionModuleAddress The sortition module responsible for sortition of the jurors.\\n /// @param _wNative The wrapped native token address, typically wETH.\\n /// @param _jurorNft NFT contract to vet the jurors.\\n function initialize(\\n address _owner,\\n address _guardian,\\n IERC20 _pinakion,\\n address _jurorProsecutionModule,\\n IDisputeKit _disputeKit,\\n bool _hiddenVotes,\\n uint256[4] memory _courtParameters,\\n uint256[4] memory _timesPerPeriod,\\n bytes memory _sortitionExtraData,\\n ISortitionModule _sortitionModuleAddress,\\n address _wNative,\\n IERC721 _jurorNft\\n ) external initializer {\\n owner = _owner;\\n guardian = _guardian;\\n pinakion = _pinakion;\\n jurorProsecutionModule = _jurorProsecutionModule;\\n sortitionModule = _sortitionModuleAddress;\\n wNative = _wNative;\\n jurorNft = _jurorNft;\\n\\n // NULL_DISPUTE_KIT: an empty element at index 0 to indicate when a dispute kit is not supported.\\n disputeKits.push();\\n\\n // DISPUTE_KIT_CLASSIC\\n disputeKits.push(_disputeKit);\\n\\n emit DisputeKitCreated(DISPUTE_KIT_CLASSIC, _disputeKit);\\n\\n // FORKING_COURT\\n // TODO: Fill the properties for the Forking court, emit CourtCreated.\\n courts.push();\\n sortitionModule.createTree(FORKING_COURT, _sortitionExtraData);\\n\\n // GENERAL_COURT\\n Court storage court = courts.push();\\n court.parent = FORKING_COURT;\\n court.children = new uint256[](0);\\n court.hiddenVotes = _hiddenVotes;\\n court.minStake = _courtParameters[0];\\n court.alpha = _courtParameters[1];\\n court.feeForJuror = _courtParameters[2];\\n court.jurorsForCourtJump = _courtParameters[3];\\n court.timesPerPeriod = _timesPerPeriod;\\n\\n sortitionModule.createTree(GENERAL_COURT, _sortitionExtraData);\\n\\n uint256[] memory supportedDisputeKits = new uint256[](1);\\n supportedDisputeKits[0] = DISPUTE_KIT_CLASSIC;\\n emit CourtCreated(\\n GENERAL_COURT,\\n court.parent,\\n _hiddenVotes,\\n _courtParameters[0],\\n _courtParameters[1],\\n _courtParameters[2],\\n _courtParameters[3],\\n _timesPerPeriod,\\n supportedDisputeKits\\n );\\n _enableDisputeKit(GENERAL_COURT, DISPUTE_KIT_CLASSIC, true);\\n }\\n\\n // ************************************* //\\n // * Governance * //\\n // ************************************* //\\n\\n /// @dev Access Control to perform implementation upgrades (UUPS Proxiable)\\n /// Only the owner can perform upgrades (`onlyByOwner`)\\n function _authorizeUpgrade(address) internal view override onlyByOwner {\\n // NOP\\n }\\n\\n /// @notice Pause staking and reward execution. Can only be done by guardian or owner.\\n function pause() external onlyByGuardianOrOwner whenNotPaused {\\n paused = true;\\n emit Paused();\\n }\\n\\n /// @notice Unpause staking and reward execution. Can only be done by owner.\\n function unpause() external onlyByOwner whenPaused {\\n paused = false;\\n emit Unpaused();\\n }\\n\\n /// @notice Allows the owner to call anything on behalf of the contract.\\n /// @param _destination The destination of the call.\\n /// @param _amount The value sent with the call.\\n /// @param _data The data sent with the call.\\n function executeOwnerProposal(address _destination, uint256 _amount, bytes memory _data) external onlyByOwner {\\n (bool success, ) = _destination.call{value: _amount}(_data);\\n if (!success) revert UnsuccessfulCall();\\n }\\n\\n /// @notice Changes the `owner` storage variable.\\n /// @param _owner The new value for the `owner` storage variable.\\n function changeOwner(address payable _owner) external onlyByOwner {\\n owner = _owner;\\n }\\n\\n /// @notice Changes the `guardian` storage variable.\\n /// @param _guardian The new value for the `guardian` storage variable.\\n function changeGuardian(address _guardian) external onlyByOwner {\\n guardian = _guardian;\\n }\\n\\n /// @notice Changes the `pinakion` storage variable.\\n /// @param _pinakion The new value for the `pinakion` storage variable.\\n function changePinakion(IERC20 _pinakion) external onlyByOwner {\\n pinakion = _pinakion;\\n }\\n\\n /// @notice Changes the `jurorProsecutionModule` storage variable.\\n /// @param _jurorProsecutionModule The new value for the `jurorProsecutionModule` storage variable.\\n function changeJurorProsecutionModule(address _jurorProsecutionModule) external onlyByOwner {\\n jurorProsecutionModule = _jurorProsecutionModule;\\n }\\n\\n /// @notice Changes the `_sortitionModule` storage variable.\\n /// Note that the new module should be initialized for all courts.\\n /// @param _sortitionModule The new value for the `sortitionModule` storage variable.\\n function changeSortitionModule(ISortitionModule _sortitionModule) external onlyByOwner {\\n sortitionModule = _sortitionModule;\\n }\\n\\n /// @notice Add a new supported dispute kit module to the court.\\n /// @param _disputeKitAddress The address of the dispute kit contract.\\n function addNewDisputeKit(IDisputeKit _disputeKitAddress) external onlyByOwner {\\n uint256 disputeKitID = disputeKits.length;\\n disputeKits.push(_disputeKitAddress);\\n emit DisputeKitCreated(disputeKitID, _disputeKitAddress);\\n }\\n\\n /// @notice Creates a court under a specified parent court.\\n /// @param _parent The `parent` property value of the court.\\n /// @param _hiddenVotes The `hiddenVotes` property value of the court.\\n /// @param _minStake The `minStake` property value of the court.\\n /// @param _alpha The `alpha` property value of the court.\\n /// @param _feeForJuror The `feeForJuror` property value of the court.\\n /// @param _jurorsForCourtJump The `jurorsForCourtJump` property value of the court.\\n /// @param _timesPerPeriod The `timesPerPeriod` property value of the court.\\n /// @param _sortitionExtraData Extra data for sortition module.\\n /// @param _supportedDisputeKits Indexes of dispute kits that this court will support.\\n function createCourt(\\n uint96 _parent,\\n bool _hiddenVotes,\\n uint256 _minStake,\\n uint256 _alpha,\\n uint256 _feeForJuror,\\n uint256 _jurorsForCourtJump,\\n uint256[4] memory _timesPerPeriod,\\n bytes memory _sortitionExtraData,\\n uint256[] memory _supportedDisputeKits\\n ) external onlyByOwner {\\n if (courts[_parent].minStake > _minStake) revert MinStakeLowerThanParentCourt();\\n if (_supportedDisputeKits.length == 0) revert UnsupportedDisputeKit();\\n if (_parent == FORKING_COURT) revert InvalidForkingCourtAsParent();\\n\\n uint96 courtID = uint96(courts.length);\\n Court storage court = courts.push();\\n\\n for (uint256 i = 0; i < _supportedDisputeKits.length; i++) {\\n if (_supportedDisputeKits[i] == 0 || _supportedDisputeKits[i] >= disputeKits.length) {\\n revert WrongDisputeKitIndex();\\n }\\n _enableDisputeKit(uint96(courtID), _supportedDisputeKits[i], true);\\n }\\n // Check that Classic DK support was added.\\n if (!court.supportedDisputeKits[DISPUTE_KIT_CLASSIC]) revert MustSupportDisputeKitClassic();\\n\\n court.parent = _parent;\\n court.children = new uint256[](0);\\n court.hiddenVotes = _hiddenVotes;\\n court.minStake = _minStake;\\n court.alpha = _alpha;\\n court.feeForJuror = _feeForJuror;\\n court.jurorsForCourtJump = _jurorsForCourtJump;\\n court.timesPerPeriod = _timesPerPeriod;\\n\\n sortitionModule.createTree(courtID, _sortitionExtraData);\\n\\n // Update the parent.\\n courts[_parent].children.push(courtID);\\n emit CourtCreated(\\n uint96(courtID),\\n _parent,\\n _hiddenVotes,\\n _minStake,\\n _alpha,\\n _feeForJuror,\\n _jurorsForCourtJump,\\n _timesPerPeriod,\\n _supportedDisputeKits\\n );\\n }\\n\\n /// @notice Changes the parameters of the court.\\n /// @param _courtID ID of the court.\\n /// @param _hiddenVotes The `hiddenVotes` property value of the court.\\n /// @param _minStake The `minStake` property value of the court.\\n /// @param _alpha The `alpha` property value of the court.\\n /// @param _feeForJuror The `feeForJuror` property value of the court.\\n /// @param _jurorsForCourtJump The `jurorsForCourtJump` property value of the court.\\n /// @param _timesPerPeriod The `timesPerPeriod` property value of the court.\\n function changeCourtParameters(\\n uint96 _courtID,\\n bool _hiddenVotes,\\n uint256 _minStake,\\n uint256 _alpha,\\n uint256 _feeForJuror,\\n uint256 _jurorsForCourtJump,\\n uint256[4] memory _timesPerPeriod\\n ) external onlyByOwner {\\n Court storage court = courts[_courtID];\\n if (_courtID != GENERAL_COURT && courts[court.parent].minStake > _minStake) {\\n revert MinStakeLowerThanParentCourt();\\n }\\n for (uint256 i = 0; i < court.children.length; i++) {\\n if (courts[court.children[i]].minStake < _minStake) {\\n revert MinStakeLowerThanParentCourt();\\n }\\n }\\n court.minStake = _minStake;\\n court.hiddenVotes = _hiddenVotes;\\n court.alpha = _alpha;\\n court.feeForJuror = _feeForJuror;\\n court.jurorsForCourtJump = _jurorsForCourtJump;\\n court.timesPerPeriod = _timesPerPeriod;\\n emit CourtModified(\\n _courtID,\\n _hiddenVotes,\\n _minStake,\\n _alpha,\\n _feeForJuror,\\n _jurorsForCourtJump,\\n _timesPerPeriod\\n );\\n }\\n\\n /// @notice Adds/removes court's support for specified dispute kits.\\n /// @param _courtID The ID of the court.\\n /// @param _disputeKitIDs The IDs of dispute kits which support should be added/removed.\\n /// @param _enable Whether add or remove the dispute kits from the court.\\n function enableDisputeKits(uint96 _courtID, uint256[] memory _disputeKitIDs, bool _enable) external onlyByOwner {\\n for (uint256 i = 0; i < _disputeKitIDs.length; i++) {\\n if (_enable) {\\n if (_disputeKitIDs[i] == 0 || _disputeKitIDs[i] >= disputeKits.length) {\\n revert WrongDisputeKitIndex();\\n }\\n _enableDisputeKit(_courtID, _disputeKitIDs[i], true);\\n } else {\\n // Classic dispute kit must be supported by all courts.\\n if (_disputeKitIDs[i] == DISPUTE_KIT_CLASSIC) {\\n revert CannotDisableClassicDK();\\n }\\n _enableDisputeKit(_courtID, _disputeKitIDs[i], false);\\n }\\n }\\n }\\n\\n /// @notice Changes the supported fee tokens.\\n /// @param _feeToken The fee token.\\n /// @param _accepted Whether the token is supported or not as a method of fee payment.\\n function changeAcceptedFeeTokens(IERC20 _feeToken, bool _accepted) external onlyByOwner {\\n currencyRates[_feeToken].feePaymentAccepted = _accepted;\\n emit AcceptedFeeToken(_feeToken, _accepted);\\n }\\n\\n /// @notice Changes the currency rate of a fee token.\\n /// @param _feeToken The fee token.\\n /// @param _rateInEth The new rate of the fee token in ETH.\\n /// @param _rateDecimals The new decimals of the fee token rate.\\n function changeCurrencyRates(IERC20 _feeToken, uint64 _rateInEth, uint8 _rateDecimals) external onlyByOwner {\\n currencyRates[_feeToken].rateInEth = _rateInEth;\\n currencyRates[_feeToken].rateDecimals = _rateDecimals;\\n emit NewCurrencyRate(_feeToken, _rateInEth, _rateDecimals);\\n }\\n\\n /// @notice Changes the `jurorNft` storage variable.\\n /// @param _jurorNft The new value for the `jurorNft` storage variable.\\n function changeJurorNft(IERC721 _jurorNft) external onlyByOwner {\\n jurorNft = _jurorNft;\\n }\\n\\n /// @notice Adds or removes an arbitrable from whitelist.\\n /// @param _arbitrable Arbitrable address.\\n /// @param _allowed Whether add or remove permission.\\n function changeArbitrableWhitelist(address _arbitrable, bool _allowed) external onlyByOwner {\\n arbitrableWhitelist[_arbitrable] = _allowed;\\n }\\n\\n /// @notice Enables or disables the arbitrable whitelist.\\n function changeArbitrableWhitelistEnabled(bool _enabled) external onlyByOwner {\\n arbitrableWhitelistEnabled = _enabled;\\n }\\n\\n // ************************************* //\\n // * State Modifiers * //\\n // ************************************* //\\n\\n /// @notice Sets the caller's stake in a court.\\n /// @param _courtID The ID of the court.\\n /// @param _newStake The new stake.\\n /// Note that the existing delayed stake will be nullified as non-relevant.\\n function setStake(uint96 _courtID, uint256 _newStake) external whenNotPaused {\\n if (address(jurorNft) != address(0) && jurorNft.balanceOf(msg.sender) == 0) revert NotEligibleForStaking();\\n _setStake(msg.sender, _courtID, _newStake, false, OnError.Revert);\\n }\\n\\n /// @notice Sets the stake of a specified account in a court without delaying stake changes, typically to apply a delayed stake or unstake inactive jurors.\\n /// @param _account The account whose stake is being set.\\n /// @param _courtID The ID of the court.\\n /// @param _newStake The new stake.\\n function setStakeBySortitionModule(address _account, uint96 _courtID, uint256 _newStake) external {\\n if (msg.sender != address(sortitionModule)) revert SortitionModuleOnly();\\n _setStake(_account, _courtID, _newStake, true, OnError.Return);\\n }\\n\\n /// @notice Transfers PNK to the juror by SortitionModule.\\n /// @param _account The account of the juror whose PNK to transfer.\\n /// @param _amount The amount to transfer.\\n function transferBySortitionModule(address _account, uint256 _amount) external {\\n if (msg.sender != address(sortitionModule)) revert SortitionModuleOnly();\\n // Note eligibility is checked in SortitionModule.\\n pinakion.safeTransfer(_account, _amount);\\n }\\n\\n /// @inheritdoc IArbitratorV2\\n function createDispute(\\n uint256 _numberOfChoices,\\n bytes memory _extraData\\n ) external payable override returns (uint256 disputeID) {\\n if (msg.value < arbitrationCost(_extraData)) revert ArbitrationFeesNotEnough();\\n\\n return _createDispute(_numberOfChoices, _extraData, NATIVE_CURRENCY, msg.value);\\n }\\n\\n /// @inheritdoc IArbitratorV2\\n function createDispute(\\n uint256 _numberOfChoices,\\n bytes calldata _extraData,\\n IERC20 _feeToken,\\n uint256 _feeAmount\\n ) external override returns (uint256 disputeID) {\\n if (!currencyRates[_feeToken].feePaymentAccepted) revert TokenNotAccepted();\\n if (_feeAmount < arbitrationCost(_extraData, _feeToken)) revert ArbitrationFeesNotEnough();\\n\\n if (!_feeToken.safeTransferFrom(msg.sender, address(this), _feeAmount)) revert TransferFailed();\\n return _createDispute(_numberOfChoices, _extraData, _feeToken, _feeAmount);\\n }\\n\\n function _createDispute(\\n uint256 _numberOfChoices,\\n bytes memory _extraData,\\n IERC20 _feeToken,\\n uint256 _feeAmount\\n ) internal returns (uint256 disputeID) {\\n if (arbitrableWhitelistEnabled && !arbitrableWhitelist[msg.sender]) revert ArbitrableNotWhitelisted();\\n (uint96 courtID, , uint256 disputeKitID) = _extraDataToCourtIDMinJurorsDisputeKit(_extraData);\\n if (!courts[courtID].supportedDisputeKits[disputeKitID]) revert DisputeKitNotSupportedByCourt();\\n\\n disputeID = disputes.length;\\n Dispute storage dispute = disputes.push();\\n dispute.courtID = courtID;\\n dispute.arbitrated = IArbitrableV2(msg.sender);\\n dispute.lastPeriodChange = block.timestamp;\\n\\n IDisputeKit disputeKit = disputeKits[disputeKitID];\\n Court storage court = courts[courtID];\\n Round storage round = dispute.rounds.push();\\n\\n // Obtain the feeForJuror in the same currency as the _feeAmount\\n uint256 feeForJuror = (_feeToken == NATIVE_CURRENCY)\\n ? court.feeForJuror\\n : convertEthToTokenAmount(_feeToken, court.feeForJuror);\\n round.nbVotes = _feeAmount / feeForJuror;\\n round.disputeKitID = disputeKitID;\\n round.pnkAtStakePerJuror = _calculatePnkAtStake(court.minStake, court.alpha);\\n round.totalFeesForJurors = _feeAmount;\\n round.feeToken = IERC20(_feeToken);\\n\\n sortitionModule.createDisputeHook(disputeID, 0); // Default round ID.\\n\\n disputeKit.createDispute(disputeID, _numberOfChoices, _extraData, round.nbVotes);\\n emit DisputeCreation(disputeID, IArbitrableV2(msg.sender));\\n }\\n\\n /// @notice Passes the period of a specified dispute.\\n /// @param _disputeID The ID of the dispute.\\n function passPeriod(uint256 _disputeID) external {\\n Dispute storage dispute = disputes[_disputeID];\\n Court storage court = courts[dispute.courtID];\\n\\n uint256 currentRound = dispute.rounds.length - 1;\\n Round storage round = dispute.rounds[currentRound];\\n if (dispute.period == Period.evidence) {\\n if (\\n currentRound == 0 &&\\n block.timestamp - dispute.lastPeriodChange < court.timesPerPeriod[uint256(dispute.period)]\\n ) {\\n revert EvidenceNotPassedAndNotAppeal();\\n }\\n if (round.drawnJurors.length != round.nbVotes) revert DisputeStillDrawing();\\n dispute.period = court.hiddenVotes ? Period.commit : Period.vote;\\n } else if (dispute.period == Period.commit) {\\n // Note that we do not want to pass to Voting period if all the commits are cast because it breaks the Shutter auto-reveal currently.\\n if (block.timestamp - dispute.lastPeriodChange < court.timesPerPeriod[uint256(dispute.period)]) {\\n revert CommitPeriodNotPassed();\\n }\\n dispute.period = Period.vote;\\n } else if (dispute.period == Period.vote) {\\n if (\\n block.timestamp - dispute.lastPeriodChange < court.timesPerPeriod[uint256(dispute.period)] &&\\n !disputeKits[round.disputeKitID].areVotesAllCast(_disputeID)\\n ) {\\n revert VotePeriodNotPassed();\\n }\\n dispute.period = Period.appeal;\\n emit AppealPossible(_disputeID, dispute.arbitrated);\\n } else if (dispute.period == Period.appeal) {\\n if (\\n block.timestamp - dispute.lastPeriodChange < court.timesPerPeriod[uint256(dispute.period)] &&\\n !disputeKits[round.disputeKitID].isAppealFunded(_disputeID)\\n ) {\\n revert AppealPeriodNotPassed();\\n }\\n dispute.period = Period.execution;\\n } else if (dispute.period == Period.execution) {\\n revert DisputePeriodIsFinal();\\n }\\n\\n dispute.lastPeriodChange = block.timestamp;\\n emit NewPeriod(_disputeID, dispute.period);\\n }\\n\\n /// @notice Draws jurors for the dispute. Can be called in parts.\\n /// @param _disputeID The ID of the dispute.\\n /// @param _iterations The number of iterations to run.\\n /// @return nbDrawnJurors The total number of jurors drawn in the round.\\n function draw(uint256 _disputeID, uint256 _iterations) external returns (uint256 nbDrawnJurors) {\\n Dispute storage dispute = disputes[_disputeID];\\n uint256 currentRound = dispute.rounds.length - 1;\\n Round storage round = dispute.rounds[currentRound];\\n if (dispute.period != Period.evidence) revert NotEvidencePeriod();\\n\\n IDisputeKit disputeKit = disputeKits[round.disputeKitID];\\n\\n uint256 startIndex = round.drawIterations; // for gas: less storage reads\\n uint256 i;\\n while (i < _iterations && round.drawnJurors.length < round.nbVotes) {\\n (address drawnAddress, uint96 fromSubcourtID) = disputeKit.draw(_disputeID, startIndex + i++);\\n if (drawnAddress == address(0)) {\\n continue;\\n }\\n sortitionModule.lockStake(drawnAddress, round.pnkAtStakePerJuror);\\n emit Draw(drawnAddress, _disputeID, currentRound, round.drawnJurors.length);\\n round.drawnJurors.push(drawnAddress);\\n round.drawnJurorFromCourtIDs.push(fromSubcourtID != 0 ? fromSubcourtID : dispute.courtID);\\n if (round.drawnJurors.length == round.nbVotes) {\\n sortitionModule.postDrawHook(_disputeID, currentRound);\\n }\\n }\\n round.drawIterations += i;\\n return round.drawnJurors.length;\\n }\\n\\n /// @notice Appeals the ruling of a specified dispute.\\n /// @dev Access restricted to the Dispute Kit for this `_disputeID`.\\n /// @param _disputeID The ID of the dispute.\\n /// @param _numberOfChoices Number of choices for the dispute. Can be required during court jump.\\n /// @param _extraData Extradata for the dispute. Can be required during court jump.\\n function appeal(uint256 _disputeID, uint256 _numberOfChoices, bytes memory _extraData) external payable {\\n if (msg.value < appealCost(_disputeID)) revert AppealFeesNotEnough();\\n\\n Dispute storage dispute = disputes[_disputeID];\\n if (dispute.period != Period.appeal) revert DisputeNotAppealable();\\n\\n Round storage round = dispute.rounds[dispute.rounds.length - 1];\\n if (msg.sender != address(disputeKits[round.disputeKitID])) revert DisputeKitOnly();\\n\\n // Warning: the extra round must be created before calling disputeKit.createDispute()\\n Round storage extraRound = dispute.rounds.push();\\n\\n (uint96 newCourtID, uint256 newDisputeKitID, bool courtJump, ) = _getCourtAndDisputeKitJumps(\\n dispute,\\n round,\\n courts[dispute.courtID],\\n _disputeID\\n );\\n if (courtJump) {\\n emit CourtJump(_disputeID, dispute.rounds.length - 1, dispute.courtID, newCourtID);\\n }\\n\\n dispute.courtID = newCourtID;\\n dispute.period = Period.evidence;\\n dispute.lastPeriodChange = block.timestamp;\\n\\n Court storage court = courts[newCourtID];\\n extraRound.nbVotes = msg.value / court.feeForJuror; // As many votes that can be afforded by the provided funds.\\n extraRound.pnkAtStakePerJuror = _calculatePnkAtStake(court.minStake, court.alpha);\\n extraRound.totalFeesForJurors = msg.value;\\n extraRound.disputeKitID = newDisputeKitID;\\n\\n sortitionModule.createDisputeHook(_disputeID, dispute.rounds.length - 1);\\n\\n // Dispute kit was changed, so create a dispute in the new DK contract.\\n if (extraRound.disputeKitID != round.disputeKitID) {\\n emit DisputeKitJump(_disputeID, dispute.rounds.length - 1, round.disputeKitID, extraRound.disputeKitID);\\n disputeKits[extraRound.disputeKitID].createDispute(\\n _disputeID,\\n _numberOfChoices,\\n _extraData,\\n extraRound.nbVotes\\n );\\n }\\n\\n emit AppealDecision(_disputeID, dispute.arbitrated);\\n emit NewPeriod(_disputeID, Period.evidence);\\n }\\n\\n /// @notice Distribute the PNKs at stake and the dispute fees for the specific round of the dispute. Can be called in parts.\\n /// @dev Reward distributions are forbidden during pause.\\n /// @param _disputeID The ID of the dispute.\\n /// @param _round The appeal round.\\n /// @param _iterations The number of iterations to run.\\n function execute(uint256 _disputeID, uint256 _round, uint256 _iterations) external whenNotPaused {\\n Round storage round;\\n {\\n Dispute storage dispute = disputes[_disputeID];\\n if (dispute.period != Period.execution) revert NotExecutionPeriod();\\n\\n round = dispute.rounds[_round];\\n } // stack too deep workaround\\n\\n uint256 start = round.repartitions;\\n uint256 end = round.repartitions + _iterations;\\n\\n uint256 pnkPenaltiesInRound = round.pnkPenalties; // Keep in memory to save gas.\\n uint256 numberOfVotesInRound = round.drawnJurors.length;\\n uint256 feePerJurorInRound = round.totalFeesForJurors / numberOfVotesInRound;\\n uint256 pnkAtStakePerJurorInRound = round.pnkAtStakePerJuror;\\n uint256 coherentCount;\\n {\\n IDisputeKit disputeKit = disputeKits[round.disputeKitID];\\n coherentCount = disputeKit.getCoherentCount(_disputeID, _round); // Total number of jurors that are eligible to a reward in this round.\\n } // stack too deep workaround\\n\\n if (coherentCount == 0) {\\n // We loop over the votes once as there are no rewards because it is not a tie and no one in this round is coherent with the final outcome.\\n if (end > numberOfVotesInRound) end = numberOfVotesInRound;\\n } else {\\n // We loop over the votes twice, first to collect the PNK penalties, and second to distribute them as rewards along with arbitration fees.\\n if (end > numberOfVotesInRound * 2) end = numberOfVotesInRound * 2;\\n }\\n round.repartitions = end;\\n\\n for (uint256 i = start; i < end; i++) {\\n if (i < numberOfVotesInRound) {\\n pnkPenaltiesInRound = _executePenalties(\\n ExecuteParams({\\n disputeID: _disputeID,\\n round: _round,\\n coherentCount: coherentCount,\\n numberOfVotesInRound: numberOfVotesInRound,\\n feePerJurorInRound: feePerJurorInRound,\\n pnkAtStakePerJurorInRound: pnkAtStakePerJurorInRound,\\n pnkPenaltiesInRound: pnkPenaltiesInRound,\\n repartition: i\\n })\\n );\\n } else {\\n _executeRewards(\\n ExecuteParams({\\n disputeID: _disputeID,\\n round: _round,\\n coherentCount: coherentCount,\\n numberOfVotesInRound: numberOfVotesInRound,\\n feePerJurorInRound: feePerJurorInRound,\\n pnkAtStakePerJurorInRound: pnkAtStakePerJurorInRound,\\n pnkPenaltiesInRound: pnkPenaltiesInRound,\\n repartition: i\\n })\\n );\\n }\\n }\\n if (round.pnkPenalties != pnkPenaltiesInRound) {\\n round.pnkPenalties = pnkPenaltiesInRound; // Note: Check-Effect-Interaction pattern is compromised here, but in the current state it doesn't cause any issues.\\n }\\n }\\n\\n /// @notice Distribute the PNKs at stake and the dispute fees for the specific round of the dispute, penalties only.\\n /// @param _params The parameters for the execution, see `ExecuteParams`.\\n /// @return pnkPenaltiesInRoundCache The updated penalties in round cache.\\n function _executePenalties(ExecuteParams memory _params) internal returns (uint256) {\\n Dispute storage dispute = disputes[_params.disputeID];\\n Round storage round = dispute.rounds[_params.round];\\n IDisputeKit disputeKit = disputeKits[round.disputeKitID];\\n\\n // [0, 1] value that determines how coherent the juror was in this round, in basis points.\\n uint256 coherence = disputeKit.getDegreeOfCoherencePenalty(\\n _params.disputeID,\\n _params.round,\\n _params.repartition,\\n _params.feePerJurorInRound,\\n _params.pnkAtStakePerJurorInRound\\n );\\n\\n // Extra check to guard against degree exceeding 1, though it should be ensured by the dispute kit.\\n if (coherence > ONE_BASIS_POINT) {\\n coherence = ONE_BASIS_POINT;\\n }\\n\\n // Fully coherent jurors won't be penalized.\\n uint256 penalty = (round.pnkAtStakePerJuror * (ONE_BASIS_POINT - coherence)) / ONE_BASIS_POINT;\\n\\n // Unlock the PNKs affected by the penalty\\n address account = round.drawnJurors[_params.repartition];\\n sortitionModule.unlockStake(account, penalty);\\n\\n // Apply the penalty to the staked PNKs.\\n uint96 penalizedInCourtID = round.drawnJurorFromCourtIDs[_params.repartition];\\n (uint256 pnkBalance, uint256 newCourtStake, uint256 availablePenalty) = sortitionModule.setStakePenalty(\\n account,\\n penalizedInCourtID,\\n penalty\\n );\\n if (availablePenalty != 0) {\\n _params.pnkPenaltiesInRound += availablePenalty;\\n emit JurorRewardPenalty(\\n account,\\n _params.disputeID,\\n _params.round,\\n coherence,\\n 0,\\n -int256(availablePenalty),\\n 0,\\n round.feeToken\\n );\\n }\\n\\n if (pnkBalance == 0 || !disputeKit.isVoteActive(_params.disputeID, _params.round, _params.repartition)) {\\n // The juror is inactive or their balance is can't cover penalties anymore, unstake them from all courts.\\n sortitionModule.forcedUnstakeAllCourts(account);\\n } else if (newCourtStake < courts[penalizedInCourtID].minStake) {\\n // The juror's balance fell below the court minStake, unstake them from the court.\\n sortitionModule.forcedUnstake(account, penalizedInCourtID);\\n }\\n\\n if (_params.repartition == _params.numberOfVotesInRound - 1 && _params.coherentCount == 0) {\\n // No one was coherent, send the rewards to the owner.\\n _transferFeeToken(round.feeToken, payable(owner), round.totalFeesForJurors);\\n pinakion.safeTransfer(owner, _params.pnkPenaltiesInRound);\\n emit LeftoverRewardSent(\\n _params.disputeID,\\n _params.round,\\n _params.pnkPenaltiesInRound,\\n round.totalFeesForJurors,\\n round.feeToken\\n );\\n }\\n return _params.pnkPenaltiesInRound;\\n }\\n\\n /// @notice Distribute the PNKs at stake and the dispute fees for the specific round of the dispute, rewards only.\\n /// @param _params The parameters for the execution, see `ExecuteParams`.\\n function _executeRewards(ExecuteParams memory _params) internal {\\n Dispute storage dispute = disputes[_params.disputeID];\\n Round storage round = dispute.rounds[_params.round];\\n IDisputeKit disputeKit = disputeKits[round.disputeKitID];\\n\\n // [0, 1] value that determines how coherent the juror was in this round, in basis points.\\n (uint256 pnkCoherence, uint256 feeCoherence) = disputeKit.getDegreeOfCoherenceReward(\\n _params.disputeID,\\n _params.round,\\n _params.repartition % _params.numberOfVotesInRound,\\n _params.feePerJurorInRound,\\n _params.pnkAtStakePerJurorInRound\\n );\\n\\n // Extra check to guard against degree exceeding 1, though it should be ensured by the dispute kit.\\n if (pnkCoherence > ONE_BASIS_POINT) {\\n pnkCoherence = ONE_BASIS_POINT;\\n }\\n if (feeCoherence > ONE_BASIS_POINT) {\\n feeCoherence = ONE_BASIS_POINT;\\n }\\n\\n address account = round.drawnJurors[_params.repartition % _params.numberOfVotesInRound];\\n uint256 pnkLocked = _applyCoherence(round.pnkAtStakePerJuror, pnkCoherence);\\n\\n // Release the rest of the PNKs of the juror for this round.\\n sortitionModule.unlockStake(account, pnkLocked);\\n\\n // Compute the rewards\\n uint256 pnkReward = _applyCoherence(_params.pnkPenaltiesInRound / _params.coherentCount, pnkCoherence);\\n round.sumPnkRewardPaid += pnkReward;\\n uint256 feeReward = _applyCoherence(round.totalFeesForJurors / _params.coherentCount, feeCoherence);\\n round.sumFeeRewardPaid += feeReward;\\n\\n if (feeReward != 0) {\\n // Transfer the fee reward\\n _transferFeeToken(round.feeToken, payable(account), feeReward);\\n }\\n if (pnkReward != 0) {\\n // Stake the PNK reward if possible, bypasses delayed stakes and other checks done by validateStake()\\n if (!sortitionModule.setStakeReward(account, dispute.courtID, pnkReward)) {\\n pinakion.safeTransfer(account, pnkReward);\\n }\\n }\\n if (pnkReward != 0 || feeReward != 0) {\\n emit JurorRewardPenalty(\\n account,\\n _params.disputeID,\\n _params.round,\\n pnkCoherence,\\n feeCoherence,\\n int256(pnkReward),\\n int256(feeReward),\\n round.feeToken\\n );\\n }\\n\\n // Transfer any residual rewards to the owner. It may happen due to partial coherence of the jurors.\\n if (_params.repartition == _params.numberOfVotesInRound * 2 - 1) {\\n uint256 leftoverPnkReward = _params.pnkPenaltiesInRound - round.sumPnkRewardPaid;\\n uint256 leftoverFeeReward = round.totalFeesForJurors - round.sumFeeRewardPaid;\\n if (leftoverPnkReward != 0 || leftoverFeeReward != 0) {\\n if (leftoverPnkReward != 0) {\\n pinakion.safeTransfer(owner, leftoverPnkReward);\\n }\\n if (leftoverFeeReward != 0) {\\n _transferFeeToken(round.feeToken, payable(owner), leftoverFeeReward);\\n }\\n emit LeftoverRewardSent(\\n _params.disputeID,\\n _params.round,\\n leftoverPnkReward,\\n leftoverFeeReward,\\n round.feeToken\\n );\\n }\\n }\\n }\\n\\n /// @notice Executes a specified dispute's ruling.\\n /// @param _disputeID The ID of the dispute.\\n function executeRuling(uint256 _disputeID) external {\\n Dispute storage dispute = disputes[_disputeID];\\n if (dispute.period != Period.execution) revert NotExecutionPeriod();\\n if (dispute.ruled) revert RulingAlreadyExecuted();\\n\\n (uint256 winningChoice, , ) = currentRuling(_disputeID);\\n dispute.ruled = true;\\n emit Ruling(dispute.arbitrated, _disputeID, winningChoice);\\n dispute.arbitrated.rule(_disputeID, winningChoice);\\n }\\n\\n // ************************************* //\\n // * Public Views * //\\n // ************************************* //\\n\\n /// @inheritdoc IArbitratorV2\\n function arbitrationCost(bytes memory _extraData) public view override returns (uint256 cost) {\\n (uint96 courtID, uint256 minJurors, ) = _extraDataToCourtIDMinJurorsDisputeKit(_extraData);\\n cost = courts[courtID].feeForJuror * minJurors;\\n }\\n\\n /// @inheritdoc IArbitratorV2\\n function arbitrationCost(bytes calldata _extraData, IERC20 _feeToken) public view override returns (uint256 cost) {\\n cost = convertEthToTokenAmount(_feeToken, arbitrationCost(_extraData));\\n }\\n\\n /// @notice Gets the cost of appealing a specified dispute.\\n /// @param _disputeID The ID of the dispute.\\n /// @return cost The appeal cost.\\n function appealCost(uint256 _disputeID) public view returns (uint256 cost) {\\n Dispute storage dispute = disputes[_disputeID];\\n Round storage round = dispute.rounds[dispute.rounds.length - 1];\\n Court storage court = courts[dispute.courtID];\\n\\n (, uint256 newDisputeKitID, bool courtJump, ) = _getCourtAndDisputeKitJumps(dispute, round, court, _disputeID);\\n\\n uint256 nbVotesAfterAppeal = disputeKits[newDisputeKitID].getNbVotesAfterAppeal(\\n disputeKits[round.disputeKitID],\\n round.nbVotes\\n );\\n\\n if (courtJump) {\\n // Jump to parent court.\\n if (dispute.courtID == GENERAL_COURT) {\\n // TODO: Handle the forking when appealed in General court.\\n cost = NON_PAYABLE_AMOUNT; // Get the cost of the parent court.\\n } else {\\n cost = courts[court.parent].feeForJuror * nbVotesAfterAppeal;\\n }\\n } else {\\n // Stay in current court.\\n cost = court.feeForJuror * nbVotesAfterAppeal;\\n }\\n }\\n\\n /// @notice Gets the start and the end of a specified dispute's current appeal period.\\n /// @param _disputeID The ID of the dispute.\\n /// @return start The start of the appeal period.\\n /// @return end The end of the appeal period.\\n function appealPeriod(uint256 _disputeID) external view returns (uint256 start, uint256 end) {\\n Dispute storage dispute = disputes[_disputeID];\\n if (dispute.period == Period.appeal) {\\n start = dispute.lastPeriodChange;\\n end = dispute.lastPeriodChange + courts[dispute.courtID].timesPerPeriod[uint256(Period.appeal)];\\n } else {\\n start = 0;\\n end = 0;\\n }\\n }\\n\\n /// @inheritdoc IArbitratorV2\\n function currentRuling(uint256 _disputeID) public view returns (uint256 ruling, bool tied, bool overridden) {\\n Dispute storage dispute = disputes[_disputeID];\\n Round storage round = dispute.rounds[dispute.rounds.length - 1];\\n IDisputeKit disputeKit = disputeKits[round.disputeKitID];\\n (ruling, tied, overridden) = disputeKit.currentRuling(_disputeID);\\n }\\n\\n /// @notice Gets the round info for a specified dispute and round.\\n /// @dev This function must not be called from a non-view function because it returns a dynamic array which might be very large, theoretically exceeding the block gas limit.\\n /// @param _disputeID The ID of the dispute.\\n /// @param _round The round to get the info for.\\n /// @return round The round info.\\n function getRoundInfo(uint256 _disputeID, uint256 _round) external view returns (Round memory) {\\n return disputes[_disputeID].rounds[_round];\\n }\\n\\n /// @notice Gets the PNK at stake per juror for a specified dispute and round.\\n /// @param _disputeID The ID of the dispute.\\n /// @param _round The round to get the info for.\\n /// @return pnkAtStakePerJuror The PNK at stake per juror.\\n function getPnkAtStakePerJuror(uint256 _disputeID, uint256 _round) external view returns (uint256) {\\n return disputes[_disputeID].rounds[_round].pnkAtStakePerJuror;\\n }\\n\\n /// @notice Gets the number of rounds for a specified dispute.\\n /// @param _disputeID The ID of the dispute.\\n /// @return The number of rounds.\\n function getNumberOfRounds(uint256 _disputeID) external view returns (uint256) {\\n return disputes[_disputeID].rounds.length;\\n }\\n\\n /// @notice Checks if a given dispute kit is supported by a given court.\\n /// @param _courtID The ID of the court to check the support for.\\n /// @param _disputeKitID The ID of the dispute kit to check the support for.\\n /// @return Whether the dispute kit is supported or not.\\n function isSupported(uint96 _courtID, uint256 _disputeKitID) external view returns (bool) {\\n return courts[_courtID].supportedDisputeKits[_disputeKitID];\\n }\\n\\n /// @notice Gets the timesPerPeriod array for a given court.\\n /// @param _courtID The ID of the court to get the times from.\\n /// @return timesPerPeriod The timesPerPeriod array for the given court.\\n function getTimesPerPeriod(uint96 _courtID) external view returns (uint256[4] memory timesPerPeriod) {\\n timesPerPeriod = courts[_courtID].timesPerPeriod;\\n }\\n\\n // ************************************* //\\n // * Public Views for Dispute Kits * //\\n // ************************************* //\\n\\n /// @notice Gets the number of votes permitted for the specified dispute in the latest round.\\n /// @param _disputeID The ID of the dispute.\\n function getNumberOfVotes(uint256 _disputeID) external view returns (uint256) {\\n Dispute storage dispute = disputes[_disputeID];\\n return dispute.rounds[dispute.rounds.length - 1].nbVotes;\\n }\\n\\n /// @notice Returns true if the dispute kit will be switched to a parent DK.\\n /// @param _disputeID The ID of the dispute.\\n /// @return Whether DK will be switched or not.\\n function isDisputeKitJumping(uint256 _disputeID) external view returns (bool) {\\n Dispute storage dispute = disputes[_disputeID];\\n Round storage round = dispute.rounds[dispute.rounds.length - 1];\\n Court storage court = courts[dispute.courtID];\\n\\n if (!_isCourtJumping(round, court, _disputeID)) {\\n return false;\\n }\\n\\n // Jump if the parent court doesn't support the current DK.\\n return !courts[court.parent].supportedDisputeKits[round.disputeKitID];\\n }\\n\\n /// @notice Returns the length of disputeKits array.\\n /// @return disputeKits length.\\n function getDisputeKitsLength() external view returns (uint256) {\\n return disputeKits.length;\\n }\\n\\n /// @notice Converts ETH into tokens.\\n /// @param _toToken The token to convert ETH into.\\n /// @param _amountInEth ETH amount.\\n /// @return Amount of tokens.\\n function convertEthToTokenAmount(IERC20 _toToken, uint256 _amountInEth) public view returns (uint256) {\\n return (_amountInEth * 10 ** currencyRates[_toToken].rateDecimals) / currencyRates[_toToken].rateInEth;\\n }\\n\\n // ************************************* //\\n // * Internal * //\\n // ************************************* //\\n\\n /// @notice Returns true if the round is jumping to a parent court.\\n /// @param _round The round to check.\\n /// @param _court The court to check.\\n /// @return Whether the round is jumping to a parent court or not.\\n function _isCourtJumping(\\n Round storage _round,\\n Court storage _court,\\n uint256 _disputeID\\n ) internal view returns (bool) {\\n return\\n disputeKits[_round.disputeKitID].earlyCourtJump(_disputeID) || _round.nbVotes >= _court.jurorsForCourtJump;\\n }\\n\\n /// @notice Checks whether a dispute will jump to new court/DK, and returns new court and DK.\\n /// @param _dispute Dispute data.\\n /// @param _round Round ID.\\n /// @param _court Current court ID.\\n /// @param _disputeID Dispute ID.\\n /// @return newCourtID Court ID after jump.\\n /// @return newDisputeKitID Dispute kit ID after jump.\\n /// @return courtJump Whether the dispute jumps to a new court or not.\\n /// @return disputeKitJump Whether the dispute jumps to a new dispute kit or not.\\n function _getCourtAndDisputeKitJumps(\\n Dispute storage _dispute,\\n Round storage _round,\\n Court storage _court,\\n uint256 _disputeID\\n ) internal view returns (uint96 newCourtID, uint256 newDisputeKitID, bool courtJump, bool disputeKitJump) {\\n newCourtID = _dispute.courtID;\\n newDisputeKitID = _round.disputeKitID;\\n\\n if (!_isCourtJumping(_round, _court, _disputeID)) return (newCourtID, newDisputeKitID, false, false);\\n\\n // Jump to parent court.\\n newCourtID = courts[newCourtID].parent;\\n courtJump = true;\\n\\n if (!courts[newCourtID].supportedDisputeKits[newDisputeKitID]) {\\n // The current Dispute Kit is not compatible with the new court, jump to another Dispute Kit.\\n newDisputeKitID = disputeKits[_round.disputeKitID].getJumpDisputeKitID();\\n if (newDisputeKitID == NULL_DISPUTE_KIT || !courts[newCourtID].supportedDisputeKits[newDisputeKitID]) {\\n // The new Dispute Kit is not defined or still not compatible, fall back to `DisputeKitClassic` which is always supported.\\n newDisputeKitID = DISPUTE_KIT_CLASSIC;\\n }\\n disputeKitJump = true;\\n }\\n }\\n\\n /// @notice Internal function to transfer fee tokens (ETH or ERC20)\\n /// @param _feeToken The token to transfer (NATIVE_CURRENCY for ETH).\\n /// @param _recipient The recipient address.\\n /// @param _amount The amount to transfer.\\n function _transferFeeToken(IERC20 _feeToken, address payable _recipient, uint256 _amount) internal {\\n if (_feeToken == NATIVE_CURRENCY) {\\n _recipient.safeSend(_amount, wNative);\\n } else {\\n _feeToken.safeTransfer(_recipient, _amount);\\n }\\n }\\n\\n /// @notice Applies degree of coherence to an amount\\n /// @param _amount The base amount to apply coherence to.\\n /// @param _coherence The degree of coherence in basis points.\\n /// @return The amount after applying the degree of coherence.\\n function _applyCoherence(uint256 _amount, uint256 _coherence) internal pure returns (uint256) {\\n return (_amount * _coherence) / ONE_BASIS_POINT;\\n }\\n\\n /// @notice Calculates PNK at stake per juror based on court parameters\\n /// @param _minStake The minimum stake for the court.\\n /// @param _alpha The alpha parameter for the court in basis points.\\n /// @return The amount of PNK at stake per juror.\\n function _calculatePnkAtStake(uint256 _minStake, uint256 _alpha) internal pure returns (uint256) {\\n return (_minStake * _alpha) / ONE_BASIS_POINT;\\n }\\n\\n /// @notice Toggles the dispute kit support for a given court.\\n /// @param _courtID The ID of the court to toggle the support for.\\n /// @param _disputeKitID The ID of the dispute kit to toggle the support for.\\n /// @param _enable Whether to enable or disable the support. Note that classic dispute kit should always be enabled.\\n function _enableDisputeKit(uint96 _courtID, uint256 _disputeKitID, bool _enable) internal {\\n courts[_courtID].supportedDisputeKits[_disputeKitID] = _enable;\\n emit DisputeKitEnabled(_courtID, _disputeKitID, _enable);\\n }\\n\\n /// @notice If called only once then set _onError to Revert, otherwise set it to Return\\n /// @param _account The account to set the stake for.\\n /// @param _courtID The ID of the court to set the stake for.\\n /// @param _newStake The new stake.\\n /// @param _noDelay True if the stake change should not be delayed.\\n /// @param _onError Whether to revert or return false on error.\\n /// @return Whether the stake was successfully set or not.\\n function _setStake(\\n address _account,\\n uint96 _courtID,\\n uint256 _newStake,\\n bool _noDelay,\\n OnError _onError\\n ) internal returns (bool) {\\n if (_courtID == FORKING_COURT || _courtID >= courts.length) {\\n _stakingFailed(_onError, StakingResult.CannotStakeInThisCourt); // Staking directly into the forking court is not allowed.\\n return false;\\n }\\n if (_newStake != 0 && _newStake < courts[_courtID].minStake) {\\n _stakingFailed(_onError, StakingResult.CannotStakeLessThanMinStake); // Staking less than the minimum stake is not allowed.\\n return false;\\n }\\n (uint256 pnkDeposit, uint256 pnkWithdrawal, StakingResult stakingResult) = sortitionModule.validateStake(\\n _account,\\n _courtID,\\n _newStake,\\n _noDelay\\n );\\n if (stakingResult != StakingResult.Successful && stakingResult != StakingResult.Delayed) {\\n _stakingFailed(_onError, stakingResult);\\n return false;\\n } else if (stakingResult == StakingResult.Delayed) {\\n return true;\\n }\\n if (pnkDeposit > 0) {\\n if (!pinakion.safeTransferFrom(_account, address(this), pnkDeposit)) {\\n _stakingFailed(_onError, StakingResult.StakingTransferFailed);\\n return false;\\n }\\n }\\n if (pnkWithdrawal > 0) {\\n if (!pinakion.safeTransfer(_account, pnkWithdrawal)) {\\n _stakingFailed(_onError, StakingResult.UnstakingTransferFailed);\\n return false;\\n }\\n }\\n sortitionModule.setStake(_account, _courtID, pnkDeposit, pnkWithdrawal, _newStake);\\n\\n return true;\\n }\\n\\n /// @notice It may revert depending on the _onError parameter.\\n function _stakingFailed(OnError _onError, StakingResult _result) internal pure {\\n if (_onError == OnError.Return) return;\\n if (_result == StakingResult.StakingTransferFailed) revert StakingTransferFailed();\\n if (_result == StakingResult.UnstakingTransferFailed) revert UnstakingTransferFailed();\\n if (_result == StakingResult.CannotStakeInMoreCourts) revert StakingInTooManyCourts();\\n if (_result == StakingResult.CannotStakeInThisCourt) revert StakingNotPossibleInThisCourt();\\n if (_result == StakingResult.CannotStakeLessThanMinStake) revert StakingLessThanCourtMinStake();\\n if (_result == StakingResult.CannotStakeZeroWhenNoStake) revert StakingZeroWhenNoStake();\\n if (_result == StakingResult.CannotStakeMoreThanMaxStakePerJuror) revert StakingMoreThanMaxStakePerJuror();\\n if (_result == StakingResult.CannotStakeMoreThanMaxTotalStaked) revert StakingMoreThanMaxTotalStaked();\\n }\\n\\n /// @notice Gets a court ID, the minimum number of jurors and an ID of a dispute kit from a specified extra data bytes array.\\n /// @dev If `_extraData` contains an incorrect value then this value will be switched to default.\\n /// @param _extraData The extra data bytes array. The first 32 bytes are the court ID, the next are the minimum number of jurors and the last are the dispute kit ID.\\n /// @return courtID The court ID.\\n /// @return minJurors The minimum number of jurors required.\\n /// @return disputeKitID The ID of the dispute kit.\\n function _extraDataToCourtIDMinJurorsDisputeKit(\\n bytes memory _extraData\\n ) internal view returns (uint96 courtID, uint256 minJurors, uint256 disputeKitID) {\\n // Note that if the extradata doesn't contain 32 bytes for the dispute kit ID it'll return the default 0 index.\\n if (_extraData.length >= 64) {\\n assembly {\\n // solium-disable-line security/no-inline-assembly\\n courtID := mload(add(_extraData, 0x20))\\n minJurors := mload(add(_extraData, 0x40))\\n disputeKitID := mload(add(_extraData, 0x60))\\n }\\n if (courtID == FORKING_COURT || courtID >= courts.length) {\\n courtID = GENERAL_COURT;\\n }\\n if (minJurors == 0) {\\n minJurors = DEFAULT_NB_OF_JURORS;\\n }\\n if (disputeKitID == NULL_DISPUTE_KIT || disputeKitID >= disputeKits.length) {\\n disputeKitID = DISPUTE_KIT_CLASSIC; // 0 index is not used.\\n }\\n } else {\\n courtID = GENERAL_COURT;\\n minJurors = DEFAULT_NB_OF_JURORS;\\n disputeKitID = DISPUTE_KIT_CLASSIC;\\n }\\n }\\n\\n // ************************************* //\\n // * Errors * //\\n // ************************************* //\\n\\n error OwnerOnly();\\n error GuardianOrOwnerOnly();\\n error DisputeKitOnly();\\n error SortitionModuleOnly();\\n error UnsuccessfulCall();\\n error InvalidDisputKitParent();\\n error MinStakeLowerThanParentCourt();\\n error UnsupportedDisputeKit();\\n error InvalidForkingCourtAsParent();\\n error WrongDisputeKitIndex();\\n error CannotDisableClassicDK();\\n error NotEligibleForStaking();\\n error StakingMoreThanMaxStakePerJuror();\\n error StakingMoreThanMaxTotalStaked();\\n error StakingInTooManyCourts();\\n error StakingNotPossibleInThisCourt();\\n error StakingLessThanCourtMinStake();\\n error StakingTransferFailed();\\n error UnstakingTransferFailed();\\n error ArbitrableNotWhitelisted();\\n error ArbitrationFeesNotEnough();\\n error DisputeKitNotSupportedByCourt();\\n error MustSupportDisputeKitClassic();\\n error TokenNotAccepted();\\n error EvidenceNotPassedAndNotAppeal();\\n error DisputeStillDrawing();\\n error CommitPeriodNotPassed();\\n error VotePeriodNotPassed();\\n error AppealPeriodNotPassed();\\n error NotEvidencePeriod();\\n error AppealFeesNotEnough();\\n error DisputeNotAppealable();\\n error NotExecutionPeriod();\\n error RulingAlreadyExecuted();\\n error DisputePeriodIsFinal();\\n error TransferFailed();\\n error WhenNotPausedOnly();\\n error WhenPausedOnly();\\n error StakingZeroWhenNoStake();\\n}\\n\",\"keccak256\":\"0xcb6d1b26b8a595effc86f8d19a42aef42a20c23c28d361b084c62e0a332e3cf3\",\"license\":\"MIT\"},\"src/arbitration/dispute-kits/DisputeKitClassic.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.24;\\n\\nimport {DisputeKitClassicBase, KlerosCore} from \\\"./DisputeKitClassicBase.sol\\\";\\n\\n/// @title DisputeKitClassic\\n/// @notice Dispute kit implementation of the Kleros v1 features including:\\n/// - a drawing system: proportional to staked PNK,\\n/// - a vote aggregation system: plurality,\\n/// - an incentive system: equal split between coherent votes,\\n/// - an appeal system: fund 2 choices only, vote on any choice.\\ncontract DisputeKitClassic is DisputeKitClassicBase {\\n string public constant override version = \\\"2.0.0\\\";\\n\\n // ************************************* //\\n // * Constructor * //\\n // ************************************* //\\n\\n /// @custom:oz-upgrades-unsafe-allow constructor\\n constructor() {\\n _disableInitializers();\\n }\\n\\n /// @notice Initializer.\\n /// @param _owner The owner's address.\\n /// @param _core The KlerosCore arbitrator.\\n /// @param _wNative The wrapped native token address, typically wETH.\\n /// @param _jumpDisputeKitID The ID of the dispute kit to switch to after the court jump.\\n function initialize(\\n address _owner,\\n KlerosCore _core,\\n address _wNative,\\n uint256 _jumpDisputeKitID\\n ) external initializer {\\n __DisputeKitClassicBase_initialize(_owner, _core, _wNative, _jumpDisputeKitID);\\n }\\n\\n // ************************ //\\n // * Governance * //\\n // ************************ //\\n\\n /// @dev Access Control to perform implementation upgrades (UUPS Proxiable)\\n /// Only the owner can perform upgrades (`onlyByOwner`)\\n function _authorizeUpgrade(address) internal view override onlyByOwner {\\n // NOP\\n }\\n}\\n\",\"keccak256\":\"0xf87fdd5b448a31b915bd881760a7c1ac1ad697d051d1357b5831476125256237\",\"license\":\"MIT\"},\"src/arbitration/dispute-kits/DisputeKitClassicBase.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.24;\\n\\nimport {KlerosCore, IDisputeKit, ISortitionModule} from \\\"../KlerosCore.sol\\\";\\nimport {Initializable} from \\\"../../proxy/Initializable.sol\\\";\\nimport {UUPSProxiable} from \\\"../../proxy/UUPSProxiable.sol\\\";\\nimport {SafeSend} from \\\"../../libraries/SafeSend.sol\\\";\\nimport {ONE_BASIS_POINT, DISPUTE_KIT_CLASSIC} from \\\"../../libraries/Constants.sol\\\";\\n\\n/// @title DisputeKitClassicBase\\n/// @notice Abstract Dispute kit classic implementation of the Kleros v1 features including:\\n/// - a drawing system: proportional to staked PNK,\\n/// - a vote aggregation system: plurality,\\n/// - an incentive system: equal split between coherent votes,\\n/// - an appeal system: fund 2 choices only, vote on any choice.\\nabstract contract DisputeKitClassicBase is IDisputeKit, Initializable, UUPSProxiable {\\n using SafeSend for address payable;\\n\\n // ************************************* //\\n // * Structs * //\\n // ************************************* //\\n\\n struct Dispute {\\n Round[] rounds; // Rounds of the dispute. 0 is the default round, and [1, ..n] are the appeal rounds.\\n uint256 numberOfChoices; // The number of choices jurors have when voting. This does not include choice `0` which is reserved for \\\"refuse to arbitrate\\\".\\n bool jumped; // True if dispute jumped to a parent dispute kit and won't be handled by this DK anymore.\\n mapping(uint256 => uint256) coreRoundIDToLocal; // Maps id of the round in the core contract to the index of the round of related local dispute.\\n bytes extraData; // Extradata for the dispute.\\n uint256[10] __gap; // Reserved slots for future upgrades.\\n }\\n\\n struct Round {\\n Vote[] votes; // Former votes[_appeal][].\\n uint256 winningChoice; // The choice with the most votes. Note that in the case of a tie, it is the choice that reached the tied number of votes first.\\n mapping(uint256 => uint256) counts; // The sum of votes for each choice in the form `counts[choice]`.\\n bool tied; // True if there is a tie, false otherwise.\\n uint256 totalVoted; // Former uint[_appeal] votesInEachRound.\\n uint256 totalCommitted; // Former commitsInRound.\\n mapping(uint256 choiceId => uint256) paidFees; // Tracks the fees paid for each choice in this round.\\n mapping(uint256 choiceId => bool) hasPaid; // True if this choice was fully funded, false otherwise.\\n mapping(address account => mapping(uint256 choiceId => uint256)) contributions; // Maps contributors to their contributions for each choice.\\n uint256 feeRewards; // Sum of reimbursable appeal fees available to the parties that made contributions to the ruling that ultimately wins a dispute.\\n uint256[] fundedChoices; // Stores the choices that are fully funded.\\n mapping(address drawnAddress => bool) alreadyDrawn; // True if the address has already been drawn, false by default.\\n uint256[10] __gap; // Reserved slots for future upgrades.\\n }\\n\\n struct Vote {\\n bool voted; // True if the vote has been cast.\\n address account; // The address of the juror.\\n bytes32 commit; // The commit of the juror. For courts with hidden votes.\\n uint256 choice; // The choice of the juror.\\n uint256[10] __gap; // Reserved slots for future upgrades.\\n }\\n\\n // ************************************* //\\n // * Storage * //\\n // ************************************* //\\n\\n uint256 public constant WINNER_STAKE_MULTIPLIER = 10000; // Multiplier of the appeal cost that the winner has to pay as fee stake for a round in basis points. Default is 1x of appeal fee.\\n uint256 public constant LOSER_STAKE_MULTIPLIER = 20000; // Multiplier of the appeal cost that the loser has to pay as fee stake for a round in basis points. Default is 2x of appeal fee.\\n uint256 public constant LOSER_APPEAL_PERIOD_MULTIPLIER = 5000; // Multiplier of the appeal period for the choice that wasn't voted for in the previous round, in basis points. Default is 1/2 of original appeal period.\\n\\n address public owner; // The owner of the contract.\\n KlerosCore public core; // The Kleros Core arbitrator\\n Dispute[] public disputes; // Array of the locally created disputes.\\n mapping(uint256 => uint256) public coreDisputeIDToLocal; // Maps the dispute ID in Kleros Core to the local dispute ID.\\n bool public singleDrawPerJuror; // Whether each juror can only draw once per dispute, false by default.\\n mapping(uint256 coreDisputeID => bool) public coreDisputeIDToActive; // True if this dispute kit is active for this core dispute ID.\\n address public wNative; // The wrapped native token for safeSend().\\n uint256 public jumpDisputeKitID; // The ID of the dispute kit in Kleros Core disputeKits array that the dispute should switch to after the court jump, in case the new court doesn't support this dispute kit.\\n\\n uint256[50] private __gap; // Reserved slots for future upgrades.\\n\\n // ************************************* //\\n // * Events * //\\n // ************************************* //\\n\\n /// @notice To be emitted when a dispute is created.\\n /// @param _coreDisputeID The identifier of the dispute in the Arbitrator contract.\\n /// @param _numberOfChoices The number of choices available in the dispute.\\n /// @param _extraData The extra data for the dispute.\\n event DisputeCreation(uint256 indexed _coreDisputeID, uint256 _numberOfChoices, bytes _extraData);\\n\\n /// @notice To be emitted when a vote commitment is cast.\\n /// @param _coreDisputeID The identifier of the dispute in the Arbitrator contract.\\n /// @param _juror The address of the juror casting the vote commitment.\\n /// @param _voteIDs The identifiers of the votes in the dispute.\\n /// @param _commit The commitment of the juror.\\n event CommitCast(uint256 indexed _coreDisputeID, address indexed _juror, uint256[] _voteIDs, bytes32 _commit);\\n\\n /// @notice To be emitted when a funding contribution is made.\\n /// @param _coreDisputeID The identifier of the dispute in the Arbitrator contract.\\n /// @param _coreRoundID The identifier of the round in the Arbitrator contract.\\n /// @param _choice The choice that is being funded.\\n /// @param _contributor The address of the contributor.\\n /// @param _amount The amount contributed.\\n event Contribution(\\n uint256 indexed _coreDisputeID,\\n uint256 indexed _coreRoundID,\\n uint256 _choice,\\n address indexed _contributor,\\n uint256 _amount\\n );\\n\\n /// @notice To be emitted when the contributed funds are withdrawn.\\n /// @param _coreDisputeID The identifier of the dispute in the Arbitrator contract.\\n /// @param _coreRoundID The identifier of the round in the Arbitrator contract.\\n /// @param _choice The choice that is being funded.\\n /// @param _contributor The address of the contributor.\\n /// @param _amount The amount withdrawn.\\n event Withdrawal(\\n uint256 indexed _coreDisputeID,\\n uint256 indexed _coreRoundID,\\n uint256 _choice,\\n address indexed _contributor,\\n uint256 _amount\\n );\\n\\n /// @notice To be emitted when a choice is fully funded for an appeal.\\n /// @param _coreDisputeID The identifier of the dispute in the Arbitrator contract.\\n /// @param _coreRoundID The identifier of the round in the Arbitrator contract.\\n /// @param _choice The choice that is being funded.\\n event ChoiceFunded(uint256 indexed _coreDisputeID, uint256 indexed _coreRoundID, uint256 indexed _choice);\\n\\n // ************************************* //\\n // * Modifiers * //\\n // ************************************* //\\n\\n modifier onlyByOwner() {\\n if (owner != msg.sender) revert OwnerOnly();\\n _;\\n }\\n\\n modifier onlyByCore() {\\n if (address(core) != msg.sender) revert KlerosCoreOnly();\\n _;\\n }\\n\\n modifier notJumped(uint256 _coreDisputeID) {\\n if (disputes[coreDisputeIDToLocal[_coreDisputeID]].jumped) revert DisputeJumpedToParentDK();\\n _;\\n }\\n\\n // ************************************* //\\n // * Constructor * //\\n // ************************************* //\\n\\n /// @notice Initializer.\\n /// @param _owner The owner's address.\\n /// @param _core The KlerosCore arbitrator.\\n /// @param _wNative The wrapped native token address, typically wETH.\\n /// @param _jumpDisputeKitID The ID of the dispute kit to switch to after the court jump.\\n function __DisputeKitClassicBase_initialize(\\n address _owner,\\n KlerosCore _core,\\n address _wNative,\\n uint256 _jumpDisputeKitID\\n ) internal onlyInitializing {\\n owner = _owner;\\n core = _core;\\n wNative = _wNative;\\n jumpDisputeKitID = _jumpDisputeKitID;\\n }\\n\\n // ************************ //\\n // * Governance * //\\n // ************************ //\\n\\n /// @notice Allows the owner to call anything on behalf of the contract.\\n /// @param _destination The destination of the call.\\n /// @param _amount The value sent with the call.\\n /// @param _data The data sent with the call.\\n function executeOwnerProposal(address _destination, uint256 _amount, bytes memory _data) external onlyByOwner {\\n (bool success, ) = _destination.call{value: _amount}(_data);\\n if (!success) revert UnsuccessfulCall();\\n }\\n\\n /// @notice Changes the `owner` storage variable.\\n /// @param _owner The new value for the `owner` storage variable.\\n function changeOwner(address payable _owner) external onlyByOwner {\\n owner = _owner;\\n }\\n\\n /// @notice Changes the `core` storage variable.\\n /// @param _core The new value for the `core` storage variable.\\n function changeCore(address _core) external onlyByOwner {\\n core = KlerosCore(_core);\\n }\\n\\n /// @notice Changes the dispute kit ID used for the jump.\\n /// @param _jumpDisputeKitID The new value for the `jumpDisputeKitID` storage variable.\\n function changeJumpDisputeKitID(uint256 _jumpDisputeKitID) external onlyByOwner {\\n jumpDisputeKitID = _jumpDisputeKitID;\\n }\\n\\n // ************************************* //\\n // * State Modifiers * //\\n // ************************************* //\\n\\n /// @inheritdoc IDisputeKit\\n function createDispute(\\n uint256 _coreDisputeID,\\n uint256 _numberOfChoices,\\n bytes calldata _extraData,\\n uint256 /*_nbVotes*/\\n ) external override onlyByCore {\\n uint256 localDisputeID = disputes.length;\\n Dispute storage dispute = disputes.push();\\n dispute.numberOfChoices = _numberOfChoices;\\n dispute.extraData = _extraData;\\n dispute.jumped = false; // Possibly true if this DK has jumped in a previous round.\\n\\n // New round in the Core should be created before the dispute creation in DK.\\n dispute.coreRoundIDToLocal[core.getNumberOfRounds(_coreDisputeID) - 1] = dispute.rounds.length;\\n\\n Round storage round = dispute.rounds.push();\\n round.tied = true;\\n\\n coreDisputeIDToLocal[_coreDisputeID] = localDisputeID;\\n coreDisputeIDToActive[_coreDisputeID] = true;\\n emit DisputeCreation(_coreDisputeID, _numberOfChoices, _extraData);\\n }\\n\\n /// @inheritdoc IDisputeKit\\n function draw(\\n uint256 _coreDisputeID,\\n uint256 _nonce\\n ) external override onlyByCore notJumped(_coreDisputeID) returns (address drawnAddress, uint96 fromSubcourtID) {\\n uint256 localDisputeID = coreDisputeIDToLocal[_coreDisputeID];\\n Dispute storage dispute = disputes[localDisputeID];\\n uint256 localRoundID = dispute.rounds.length - 1;\\n Round storage round = dispute.rounds[localRoundID];\\n\\n ISortitionModule sortitionModule = core.sortitionModule();\\n (uint96 courtID, , , , ) = core.disputes(_coreDisputeID);\\n (drawnAddress, fromSubcourtID) = sortitionModule.draw(courtID, _coreDisputeID, _nonce);\\n if (drawnAddress == address(0)) {\\n // Sortition can return 0 address if no one has staked yet.\\n return (drawnAddress, fromSubcourtID);\\n }\\n\\n if (_postDrawCheck(round, _coreDisputeID, drawnAddress)) {\\n Vote storage vote = round.votes.push();\\n vote.account = drawnAddress;\\n round.alreadyDrawn[drawnAddress] = true;\\n } else {\\n drawnAddress = address(0);\\n }\\n }\\n\\n /// @notice Sets the caller's commit for the specified votes.\\n ///\\n /// @dev It can be called multiple times during the commit period, each call overrides the commits of the previous one.\\n /// `O(n)` where `n` is the number of votes.\\n ///\\n /// @param _coreDisputeID The ID of the dispute in Kleros Core.\\n /// @param _voteIDs The IDs of the votes.\\n /// @param _commit The commitment hash.\\n function castCommit(uint256 _coreDisputeID, uint256[] calldata _voteIDs, bytes32 _commit) external {\\n _castCommit(_coreDisputeID, _voteIDs, _commit);\\n }\\n\\n function _castCommit(\\n uint256 _coreDisputeID,\\n uint256[] calldata _voteIDs,\\n bytes32 _commit\\n ) internal notJumped(_coreDisputeID) {\\n (, , KlerosCore.Period period, , ) = core.disputes(_coreDisputeID);\\n if (period != KlerosCore.Period.commit) revert NotCommitPeriod();\\n if (_commit == bytes32(0)) revert EmptyCommit();\\n if (!coreDisputeIDToActive[_coreDisputeID]) revert NotActiveForCoreDisputeID();\\n\\n Dispute storage dispute = disputes[coreDisputeIDToLocal[_coreDisputeID]];\\n Round storage round = dispute.rounds[dispute.rounds.length - 1];\\n for (uint256 i = 0; i < _voteIDs.length; i++) {\\n if (round.votes[_voteIDs[i]].account != msg.sender) revert JurorHasToOwnTheVote();\\n round.votes[_voteIDs[i]].commit = _commit;\\n }\\n round.totalCommitted += _voteIDs.length;\\n emit CommitCast(_coreDisputeID, msg.sender, _voteIDs, _commit);\\n }\\n\\n /// @notice Sets the caller's choices for the specified votes.\\n ///\\n /// @dev `O(n)` where `n` is the number of votes.\\n ///\\n /// @param _coreDisputeID The ID of the dispute in Kleros Core.\\n /// @param _voteIDs The IDs of the votes.\\n /// @param _choice The choice.\\n /// @param _salt The salt for the commit if the votes were hidden.\\n /// @param _justification Justification of the choice.\\n function castVote(\\n uint256 _coreDisputeID,\\n uint256[] calldata _voteIDs,\\n uint256 _choice,\\n uint256 _salt,\\n string memory _justification\\n ) external {\\n _castVote(_coreDisputeID, _voteIDs, _choice, _salt, _justification, msg.sender);\\n }\\n\\n function _castVote(\\n uint256 _coreDisputeID,\\n uint256[] calldata _voteIDs,\\n uint256 _choice,\\n uint256 _salt,\\n string memory _justification,\\n address _juror\\n ) internal notJumped(_coreDisputeID) {\\n (, , KlerosCore.Period period, , ) = core.disputes(_coreDisputeID);\\n if (period != KlerosCore.Period.vote) revert NotVotePeriod();\\n if (_voteIDs.length == 0) revert EmptyVoteIDs();\\n if (!coreDisputeIDToActive[_coreDisputeID]) revert NotActiveForCoreDisputeID();\\n\\n uint256 localDisputeID = coreDisputeIDToLocal[_coreDisputeID];\\n Dispute storage dispute = disputes[localDisputeID];\\n if (_choice > dispute.numberOfChoices) revert ChoiceOutOfBounds();\\n\\n uint256 localRoundID = dispute.rounds.length - 1;\\n Round storage round = dispute.rounds[localRoundID];\\n {\\n (uint96 courtID, , , , ) = core.disputes(_coreDisputeID);\\n (, bool hiddenVotes, , , , ) = core.courts(courtID);\\n bytes32 actualVoteHash = hashVote(_choice, _salt, _justification);\\n\\n // Save the votes.\\n for (uint256 i = 0; i < _voteIDs.length; i++) {\\n if (round.votes[_voteIDs[i]].account != _juror) revert JurorHasToOwnTheVote();\\n if (hiddenVotes && _getExpectedVoteHash(localDisputeID, localRoundID, _voteIDs[i]) != actualVoteHash)\\n revert HashDoesNotMatchHiddenVoteCommitment();\\n if (round.votes[_voteIDs[i]].voted) revert VoteAlreadyCast();\\n round.votes[_voteIDs[i]].choice = _choice;\\n round.votes[_voteIDs[i]].voted = true;\\n }\\n } // Workaround stack too deep\\n\\n round.totalVoted += _voteIDs.length;\\n\\n round.counts[_choice] += _voteIDs.length;\\n if (_choice == round.winningChoice) {\\n if (round.tied) round.tied = false;\\n } else {\\n // Voted for another choice.\\n if (round.counts[_choice] == round.counts[round.winningChoice]) {\\n // Tie.\\n if (!round.tied) round.tied = true;\\n } else if (round.counts[_choice] > round.counts[round.winningChoice]) {\\n // New winner.\\n round.winningChoice = _choice;\\n round.tied = false;\\n }\\n }\\n emit VoteCast(_coreDisputeID, _juror, _voteIDs, _choice, _justification);\\n }\\n\\n /// @notice Manages contributions, and appeals a dispute if at least two choices are fully funded.\\n /// Note that the surplus deposit will be reimbursed.\\n /// @param _coreDisputeID Index of the dispute in Kleros Core.\\n /// @param _choice A choice that receives funding.\\n function fundAppeal(uint256 _coreDisputeID, uint256 _choice) external payable notJumped(_coreDisputeID) {\\n Dispute storage dispute = disputes[coreDisputeIDToLocal[_coreDisputeID]];\\n if (_choice > dispute.numberOfChoices) revert ChoiceOutOfBounds();\\n if (!coreDisputeIDToActive[_coreDisputeID]) revert NotActiveForCoreDisputeID();\\n\\n (uint256 appealPeriodStart, uint256 appealPeriodEnd) = core.appealPeriod(_coreDisputeID);\\n if (block.timestamp < appealPeriodStart || block.timestamp >= appealPeriodEnd) revert AppealPeriodIsOver();\\n\\n uint256 multiplier;\\n (uint256 ruling, , ) = this.currentRuling(_coreDisputeID);\\n if (ruling == _choice) {\\n multiplier = WINNER_STAKE_MULTIPLIER;\\n } else {\\n if (\\n block.timestamp - appealPeriodStart >=\\n ((appealPeriodEnd - appealPeriodStart) * LOSER_APPEAL_PERIOD_MULTIPLIER) / ONE_BASIS_POINT\\n ) {\\n revert AppealPeriodIsOverForLoser();\\n }\\n multiplier = LOSER_STAKE_MULTIPLIER;\\n }\\n\\n Round storage round = dispute.rounds[dispute.rounds.length - 1];\\n uint256 coreRoundID = core.getNumberOfRounds(_coreDisputeID) - 1;\\n\\n if (round.hasPaid[_choice]) revert AppealFeeIsAlreadyPaid();\\n uint256 appealCost = core.appealCost(_coreDisputeID);\\n uint256 totalCost = appealCost + (appealCost * multiplier) / ONE_BASIS_POINT;\\n\\n // Take up to the amount necessary to fund the current round at the current costs.\\n uint256 contribution;\\n if (totalCost > round.paidFees[_choice]) {\\n contribution = totalCost - round.paidFees[_choice] > msg.value // Overflows and underflows will be managed on the compiler level.\\n ? msg.value\\n : totalCost - round.paidFees[_choice];\\n emit Contribution(_coreDisputeID, coreRoundID, _choice, msg.sender, contribution);\\n }\\n\\n round.contributions[msg.sender][_choice] += contribution;\\n round.paidFees[_choice] += contribution;\\n if (round.paidFees[_choice] >= totalCost) {\\n round.feeRewards += round.paidFees[_choice];\\n round.fundedChoices.push(_choice);\\n round.hasPaid[_choice] = true;\\n emit ChoiceFunded(_coreDisputeID, coreRoundID, _choice);\\n }\\n\\n if (round.fundedChoices.length > 1) {\\n // At least two sides are fully funded.\\n round.feeRewards = round.feeRewards - appealCost;\\n\\n if (core.isDisputeKitJumping(_coreDisputeID)) {\\n // Don't create a new round in case of a jump, and remove local dispute from the flow.\\n dispute.jumped = true;\\n } else {\\n // Don't subtract 1 from length since both round arrays haven't been updated yet.\\n dispute.coreRoundIDToLocal[coreRoundID + 1] = dispute.rounds.length;\\n\\n Round storage newRound = dispute.rounds.push();\\n newRound.tied = true;\\n }\\n core.appeal{value: appealCost}(_coreDisputeID, dispute.numberOfChoices, dispute.extraData);\\n }\\n\\n if (msg.value > contribution) payable(msg.sender).safeSend(msg.value - contribution, wNative);\\n }\\n\\n /// @notice Allows those contributors who attempted to fund an appeal round to withdraw any reimbursable fees or rewards after the dispute gets resolved.\\n /// @dev Withdrawals are not possible if the core contract is paused.\\n /// @param _coreDisputeID Index of the dispute in Kleros Core contract.\\n /// @param _beneficiary The address whose rewards to withdraw.\\n /// @param _coreRoundID The round in the Kleros Core contract the caller wants to withdraw from.\\n /// @param _choice The ruling option that the caller wants to withdraw from.\\n /// @return amount The withdrawn amount.\\n function withdrawFeesAndRewards(\\n uint256 _coreDisputeID,\\n address payable _beneficiary,\\n uint256 _coreRoundID,\\n uint256 _choice\\n ) external returns (uint256 amount) {\\n (, , , bool isRuled, ) = core.disputes(_coreDisputeID);\\n if (!isRuled) revert DisputeNotResolved();\\n if (core.paused()) revert CoreIsPaused();\\n if (!coreDisputeIDToActive[_coreDisputeID]) revert NotActiveForCoreDisputeID();\\n\\n Dispute storage dispute = disputes[coreDisputeIDToLocal[_coreDisputeID]];\\n Round storage round = dispute.rounds[dispute.coreRoundIDToLocal[_coreRoundID]];\\n (uint256 finalRuling, , ) = core.currentRuling(_coreDisputeID);\\n\\n if (!round.hasPaid[_choice]) {\\n // Allow to reimburse if funding was unsuccessful for this ruling option.\\n amount = round.contributions[_beneficiary][_choice];\\n } else {\\n // Funding was successful for this ruling option.\\n if (_choice == finalRuling) {\\n // This ruling option is the ultimate winner.\\n amount = round.paidFees[_choice] > 0\\n ? (round.contributions[_beneficiary][_choice] * round.feeRewards) / round.paidFees[_choice]\\n : 0;\\n } else if (!round.hasPaid[finalRuling]) {\\n // The ultimate winner was not funded in this round. In this case funded ruling option(s) are reimbursed.\\n amount =\\n (round.contributions[_beneficiary][_choice] * round.feeRewards) /\\n (round.paidFees[round.fundedChoices[0]] + round.paidFees[round.fundedChoices[1]]);\\n }\\n }\\n round.contributions[_beneficiary][_choice] = 0;\\n\\n if (amount != 0) {\\n _beneficiary.safeSend(amount, wNative);\\n emit Withdrawal(_coreDisputeID, _coreRoundID, _choice, _beneficiary, amount);\\n }\\n }\\n\\n // ************************************* //\\n // * Public Views * //\\n // ************************************* //\\n\\n /// @notice Computes the hash of a vote using ABI encoding\\n /// @dev The unused parameters may be used by overriding contracts.\\n /// @param _choice The choice being voted for\\n /// @param _salt A random salt for commitment\\n /// @return bytes32 The hash of the encoded vote parameters\\n function hashVote(\\n uint256 _choice,\\n uint256 _salt,\\n string memory /*_justification*/\\n ) public view virtual returns (bytes32) {\\n return keccak256(abi.encodePacked(_choice, _salt));\\n }\\n\\n /// @notice Returns the rulings that were fully funded in the latest appeal round.\\n /// @param _coreDisputeID The ID of the dispute in Kleros Core.\\n /// @return fundedChoices Fully funded rulings.\\n function getFundedChoices(uint256 _coreDisputeID) public view returns (uint256[] memory fundedChoices) {\\n Dispute storage dispute = disputes[coreDisputeIDToLocal[_coreDisputeID]];\\n Round storage lastRound = dispute.rounds[dispute.rounds.length - 1];\\n return lastRound.fundedChoices;\\n }\\n\\n /// @inheritdoc IDisputeKit\\n function currentRuling(\\n uint256 _coreDisputeID\\n ) external view override returns (uint256 ruling, bool tied, bool overridden) {\\n Dispute storage dispute = disputes[coreDisputeIDToLocal[_coreDisputeID]];\\n Round storage round = dispute.rounds[dispute.rounds.length - 1];\\n tied = round.tied;\\n ruling = tied ? 0 : round.winningChoice;\\n (, , KlerosCore.Period period, , ) = core.disputes(_coreDisputeID);\\n // Override the final ruling if only one side funded the appeals.\\n if (period == KlerosCore.Period.execution) {\\n uint256[] memory fundedChoices = getFundedChoices(_coreDisputeID);\\n if (fundedChoices.length == 1) {\\n ruling = fundedChoices[0];\\n tied = false;\\n overridden = true;\\n }\\n }\\n }\\n\\n /// @inheritdoc IDisputeKit\\n function getDegreeOfCoherenceReward(\\n uint256 _coreDisputeID,\\n uint256 _coreRoundID,\\n uint256 _voteID,\\n uint256 /* _feePerJuror */,\\n uint256 /* _pnkAtStakePerJuror */\\n ) external view override returns (uint256 pnkCoherence, uint256 feeCoherence) {\\n uint256 coherence = _getDegreeOfCoherence(_coreDisputeID, _coreRoundID, _voteID);\\n return (coherence, coherence);\\n }\\n\\n /// @inheritdoc IDisputeKit\\n function getDegreeOfCoherencePenalty(\\n uint256 _coreDisputeID,\\n uint256 _coreRoundID,\\n uint256 _voteID,\\n uint256 /* _feePerJuror */,\\n uint256 /* _pnkAtStakePerJuror */\\n ) external view override returns (uint256 pnkCoherence) {\\n return _getDegreeOfCoherence(_coreDisputeID, _coreRoundID, _voteID);\\n }\\n\\n function _getDegreeOfCoherence(\\n uint256 _coreDisputeID,\\n uint256 _coreRoundID,\\n uint256 _voteID\\n ) internal view returns (uint256 coherence) {\\n // In this contract this degree can be either 0 or 1, but in other dispute kits this value can be something in between.\\n Dispute storage dispute = disputes[coreDisputeIDToLocal[_coreDisputeID]];\\n Vote storage vote = dispute.rounds[dispute.coreRoundIDToLocal[_coreRoundID]].votes[_voteID];\\n (uint256 winningChoice, bool tied, ) = core.currentRuling(_coreDisputeID);\\n\\n if (vote.voted && (vote.choice == winningChoice || tied)) {\\n return ONE_BASIS_POINT;\\n } else {\\n return 0;\\n }\\n }\\n\\n /// @inheritdoc IDisputeKit\\n function getCoherentCount(uint256 _coreDisputeID, uint256 _coreRoundID) external view override returns (uint256) {\\n Dispute storage dispute = disputes[coreDisputeIDToLocal[_coreDisputeID]];\\n Round storage currentRound = dispute.rounds[dispute.coreRoundIDToLocal[_coreRoundID]];\\n (uint256 winningChoice, bool tied, ) = core.currentRuling(_coreDisputeID);\\n\\n if (currentRound.totalVoted == 0 || (!tied && currentRound.counts[winningChoice] == 0)) {\\n return 0;\\n } else if (tied) {\\n return currentRound.totalVoted;\\n } else {\\n return currentRound.counts[winningChoice];\\n }\\n }\\n\\n /// @inheritdoc IDisputeKit\\n function areCommitsAllCast(uint256 _coreDisputeID) external view override returns (bool) {\\n Dispute storage dispute = disputes[coreDisputeIDToLocal[_coreDisputeID]];\\n Round storage round = dispute.rounds[dispute.rounds.length - 1];\\n return round.totalCommitted == round.votes.length;\\n }\\n\\n /// @inheritdoc IDisputeKit\\n function areVotesAllCast(uint256 _coreDisputeID) external view override returns (bool) {\\n Dispute storage dispute = disputes[coreDisputeIDToLocal[_coreDisputeID]];\\n Round storage round = dispute.rounds[dispute.rounds.length - 1];\\n\\n (uint96 courtID, , , , ) = core.disputes(_coreDisputeID);\\n (, bool hiddenVotes, , , , ) = core.courts(courtID);\\n uint256 expectedTotalVoted = hiddenVotes ? round.totalCommitted : round.votes.length;\\n\\n return round.totalVoted == expectedTotalVoted;\\n }\\n\\n /// @inheritdoc IDisputeKit\\n function isAppealFunded(uint256 _coreDisputeID) external view override returns (bool) {\\n (uint256 appealPeriodStart, uint256 appealPeriodEnd) = core.appealPeriod(_coreDisputeID);\\n\\n uint256[] memory fundedChoices = getFundedChoices(_coreDisputeID);\\n // Uses block.timestamp from the current tx when called by the core contract.\\n return (fundedChoices.length == 0 &&\\n block.timestamp - appealPeriodStart >=\\n ((appealPeriodEnd - appealPeriodStart) * LOSER_APPEAL_PERIOD_MULTIPLIER) / ONE_BASIS_POINT);\\n }\\n\\n /// @inheritdoc IDisputeKit\\n function earlyCourtJump(uint256 /* _coreDisputeID */) external pure override returns (bool) {\\n return false;\\n }\\n\\n /// @inheritdoc IDisputeKit\\n function getNbVotesAfterAppeal(\\n IDisputeKit /* _previousDisputeKit */,\\n uint256 _currentNbVotes\\n ) external pure override returns (uint256) {\\n return (_currentNbVotes * 2) + 1;\\n }\\n\\n /// @inheritdoc IDisputeKit\\n function getJumpDisputeKitID() external view override returns (uint256) {\\n // Fall back to classic DK in case the jump ID is not defined.\\n return jumpDisputeKitID == 0 ? DISPUTE_KIT_CLASSIC : jumpDisputeKitID;\\n }\\n\\n /// @inheritdoc IDisputeKit\\n function isVoteActive(\\n uint256 _coreDisputeID,\\n uint256 _coreRoundID,\\n uint256 _voteID\\n ) external view override returns (bool) {\\n Dispute storage dispute = disputes[coreDisputeIDToLocal[_coreDisputeID]];\\n Vote storage vote = dispute.rounds[dispute.coreRoundIDToLocal[_coreRoundID]].votes[_voteID];\\n return vote.voted;\\n }\\n\\n /// @inheritdoc IDisputeKit\\n function getRoundInfo(\\n uint256 _coreDisputeID,\\n uint256 _coreRoundID,\\n uint256 _choice\\n )\\n external\\n view\\n override\\n returns (\\n uint256 winningChoice,\\n bool tied,\\n uint256 totalVoted,\\n uint256 totalCommitted,\\n uint256 nbVoters,\\n uint256 choiceCount\\n )\\n {\\n Dispute storage dispute = disputes[coreDisputeIDToLocal[_coreDisputeID]];\\n Round storage round = dispute.rounds[dispute.coreRoundIDToLocal[_coreRoundID]];\\n return (\\n round.winningChoice,\\n round.tied,\\n round.totalVoted,\\n round.totalCommitted,\\n round.votes.length,\\n round.counts[_choice]\\n );\\n }\\n\\n /// @notice Returns the number of rounds in a dispute.\\n /// @param _localDisputeID The ID of the dispute in the Dispute Kit.\\n /// @return The number of rounds in the dispute.\\n function getNumberOfRounds(uint256 _localDisputeID) external view returns (uint256) {\\n return disputes[_localDisputeID].rounds.length;\\n }\\n\\n /// @notice Returns the local dispute ID and round ID for a given core dispute ID and core round ID.\\n /// @param _coreDisputeID The ID of the dispute in Kleros Core.\\n /// @param _coreRoundID The ID of the round in Kleros Core.\\n /// @return localDisputeID The ID of the dispute in the Dispute Kit.\\n /// @return localRoundID The ID of the round in the Dispute Kit.\\n function getLocalDisputeRoundID(\\n uint256 _coreDisputeID,\\n uint256 _coreRoundID\\n ) external view returns (uint256 localDisputeID, uint256 localRoundID) {\\n localDisputeID = coreDisputeIDToLocal[_coreDisputeID];\\n localRoundID = disputes[localDisputeID].coreRoundIDToLocal[_coreRoundID];\\n }\\n\\n /// @inheritdoc IDisputeKit\\n function getVoteInfo(\\n uint256 _coreDisputeID,\\n uint256 _coreRoundID,\\n uint256 _voteID\\n ) external view override returns (address account, bytes32 commit, uint256 choice, bool voted) {\\n Dispute storage dispute = disputes[coreDisputeIDToLocal[_coreDisputeID]];\\n Vote storage vote = dispute.rounds[dispute.coreRoundIDToLocal[_coreRoundID]].votes[_voteID];\\n return (vote.account, vote.commit, vote.choice, vote.voted);\\n }\\n\\n // ************************************* //\\n // * Internal * //\\n // ************************************* //\\n\\n /// @notice Returns the expected vote hash for a given vote.\\n /// @param _localDisputeID The ID of the dispute in the Dispute Kit.\\n /// @param _localRoundID The ID of the round in the Dispute Kit.\\n /// @param _voteID The ID of the vote.\\n /// @return The expected vote hash.\\n function _getExpectedVoteHash(\\n uint256 _localDisputeID,\\n uint256 _localRoundID,\\n uint256 _voteID\\n ) internal view virtual returns (bytes32) {\\n return disputes[_localDisputeID].rounds[_localRoundID].votes[_voteID].commit;\\n }\\n\\n /// @notice Checks that the chosen address satisfies certain conditions for being drawn.\\n ///\\n /// @dev No need to check the minStake requirement here because of the implicit staking in parent courts.\\n /// minStake is checked directly during staking process however it's possible for the juror to get drawn\\n /// while having < minStake if it is later increased by governance.\\n /// This issue is expected and harmless.\\n ///\\n /// @param _coreDisputeID ID of the dispute in the core contract.\\n /// @param _juror Chosen address.\\n /// @return result Whether the address passes the check or not.\\n function _postDrawCheck(\\n Round storage /*_round*/,\\n uint256 _coreDisputeID,\\n address _juror\\n ) internal view virtual returns (bool result) {\\n if (singleDrawPerJuror) {\\n uint256 localDisputeID = coreDisputeIDToLocal[_coreDisputeID];\\n Dispute storage dispute = disputes[localDisputeID];\\n Round storage round = dispute.rounds[dispute.rounds.length - 1];\\n result = !round.alreadyDrawn[_juror];\\n } else {\\n result = true;\\n }\\n }\\n\\n // ************************************* //\\n // * Errors * //\\n // ************************************* //\\n\\n error OwnerOnly();\\n error KlerosCoreOnly();\\n error DisputeJumpedToParentDK();\\n error UnsuccessfulCall();\\n error NotCommitPeriod();\\n error EmptyCommit();\\n error NotActiveForCoreDisputeID();\\n error JurorHasToOwnTheVote();\\n error NotVotePeriod();\\n error EmptyVoteIDs();\\n error ChoiceOutOfBounds();\\n error HashDoesNotMatchHiddenVoteCommitment();\\n error VoteAlreadyCast();\\n error AppealPeriodIsOver();\\n error AppealPeriodIsOverForLoser();\\n error AppealFeeIsAlreadyPaid();\\n error DisputeNotResolved();\\n error CoreIsPaused();\\n}\\n\",\"keccak256\":\"0x15d38f814fc59844571eddbfddad77730cc541f8b86cd094139f4c8771dde011\",\"license\":\"MIT\"},\"src/arbitration/interfaces/IArbitrableV2.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity >=0.8.0 <0.9.0;\\n\\nimport \\\"./IArbitratorV2.sol\\\";\\n\\n/// @title IArbitrableV2\\n/// @notice Arbitrable interface.\\n/// @dev When developing arbitrable contracts, we need to:\\n/// - Define the action taken when a ruling is received by the contract.\\n/// - Allow dispute creation which calls `arbitrator.createDispute{value: _fee}(_choices,_extraData)`.\\ninterface IArbitrableV2 {\\n // ************************************* //\\n // * Events * //\\n // ************************************* //\\n\\n /// @notice To be emitted when a dispute is created to link the correct template to the disputeID.\\n /// @param _arbitrator The arbitrator of the contract.\\n /// @param _arbitratorDisputeID The identifier of the dispute in the Arbitrator contract.\\n /// @param _externalDisputeID An identifier created outside Kleros by the protocol requesting arbitration.\\n /// @param _templateId The identifier of the dispute template.\\n event DisputeRequest(\\n IArbitratorV2 indexed _arbitrator,\\n uint256 indexed _arbitratorDisputeID,\\n uint256 _externalDisputeID,\\n uint256 _templateId\\n );\\n\\n /// @notice To be raised when a ruling is given.\\n /// @param _arbitrator The arbitrator giving the ruling.\\n /// @param _disputeID The identifier of the dispute in the Arbitrator contract.\\n /// @param _ruling The ruling which was given.\\n event Ruling(IArbitratorV2 indexed _arbitrator, uint256 indexed _disputeID, uint256 _ruling);\\n\\n // ************************************* //\\n // * State Modifiers * //\\n // ************************************* //\\n\\n /// @notice Give a ruling for a dispute.\\n ///\\n /// @dev This is a callback function for the arbitrator to provide the ruling to this contract.\\n /// Only the arbitrator must be allowed to call this function.\\n /// Ruling 0 is reserved for \\\"Not able/wanting to make a decision\\\".\\n ///\\n /// @param _disputeID The identifier of the dispute in the Arbitrator contract.\\n /// @param _ruling Ruling given by the arbitrator.\\n function rule(uint256 _disputeID, uint256 _ruling) external;\\n}\\n\",\"keccak256\":\"0x3afa29a93847399c8705103350b69bb70706b2075ca41b39d523b007e69e23db\",\"license\":\"MIT\"},\"src/arbitration/interfaces/IArbitratorV2.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity >=0.8.0 <0.9.0;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"./IArbitrableV2.sol\\\";\\n\\n/// @title Arbitrator\\n/// @notice Arbitrator interface for the Kleros V2 protocol.\\n/// @dev Unlike the ERC-792 this standard is not concerned with appeals, so each arbitrator can implement an appeal system that suits it the most.\\ninterface IArbitratorV2 {\\n // ************************************* //\\n // * Events * //\\n // ************************************* //\\n\\n /// @notice To be emitted when a dispute is created.\\n /// @param _disputeID The identifier of the dispute in the Arbitrator contract.\\n /// @param _arbitrable The contract which created the dispute.\\n event DisputeCreation(uint256 indexed _disputeID, IArbitrableV2 indexed _arbitrable);\\n\\n /// @notice To be raised when a ruling is given.\\n /// @param _arbitrable The arbitrable receiving the ruling.\\n /// @param _disputeID The identifier of the dispute in the Arbitrator contract.\\n /// @param _ruling The ruling which was given.\\n event Ruling(IArbitrableV2 indexed _arbitrable, uint256 indexed _disputeID, uint256 _ruling);\\n\\n /// @notice To be emitted when an ERC20 token is added or removed as a method to pay fees.\\n /// @param _token The ERC20 token.\\n /// @param _accepted Whether the token is accepted or not.\\n event AcceptedFeeToken(IERC20 indexed _token, bool indexed _accepted);\\n\\n /// @notice To be emitted when the fee for a particular ERC20 token is updated.\\n /// @param _feeToken The ERC20 token.\\n /// @param _rateInEth The new rate of the fee token in ETH.\\n /// @param _rateDecimals The new decimals of the fee token rate.\\n event NewCurrencyRate(IERC20 indexed _feeToken, uint64 _rateInEth, uint8 _rateDecimals);\\n\\n // ************************************* //\\n // * State Modifiers * //\\n // ************************************* //\\n\\n /// @notice Create a dispute and pay for the fees in the native currency, typically ETH.\\n /// @dev Must be called by the arbitrable contract and pay at least `arbitrationCost(_extraData)` in ETH.\\n /// @param _numberOfChoices The number of choices the arbitrator can choose from in this dispute.\\n /// @param _extraData Additional info about the dispute. We use it to pass the ID of the dispute's court (first 32 bytes), the minimum number of jurors required (next 32 bytes) and the ID of the specific dispute kit (last 32 bytes).\\n /// @return disputeID The identifier of the dispute created.\\n function createDispute(\\n uint256 _numberOfChoices,\\n bytes calldata _extraData\\n ) external payable returns (uint256 disputeID);\\n\\n /// @notice Create a dispute and pay for the fees in a supported ERC20 token.\\n /// @dev Must be called by the arbitrable contract and pay at least `arbitrationCost(_extraData)` in the supported ERC20 token.\\n /// @param _numberOfChoices The number of choices the arbitrator can choose from in this dispute.\\n /// @param _extraData Additional info about the dispute. We use it to pass the ID of the dispute's court (first 32 bytes), the minimum number of jurors required (next 32 bytes) and the ID of the specific dispute kit (last 32 bytes).\\n /// @param _feeToken The ERC20 token used to pay fees.\\n /// @param _feeAmount Amount of the ERC20 token used to pay fees.\\n /// @return disputeID The identifier of the dispute created.\\n function createDispute(\\n uint256 _numberOfChoices,\\n bytes calldata _extraData,\\n IERC20 _feeToken,\\n uint256 _feeAmount\\n ) external returns (uint256 disputeID);\\n\\n // ************************************* //\\n // * Public Views * //\\n // ************************************* //\\n\\n /// @notice Compute the cost of arbitration denominated in the native currency, typically ETH.\\n /// @dev It is recommended not to increase it often, as it can be highly time and gas consuming for the arbitrated contracts to cope with fee augmentation.\\n /// @param _extraData Additional info about the dispute. We use it to pass the ID of the dispute's court (first 32 bytes), the minimum number of jurors required (next 32 bytes) and the ID of the specific dispute kit (last 32 bytes).\\n /// @return cost The arbitration cost in ETH.\\n function arbitrationCost(bytes calldata _extraData) external view returns (uint256 cost);\\n\\n /// @notice Compute the cost of arbitration denominated in `_feeToken`.\\n /// @dev It is recommended not to increase it often, as it can be highly time and gas consuming for the arbitrated contracts to cope with fee augmentation.\\n /// @param _extraData Additional info about the dispute. We use it to pass the ID of the dispute's court (first 32 bytes), the minimum number of jurors required (next 32 bytes) and the ID of the specific dispute kit (last 32 bytes).\\n /// @param _feeToken The ERC20 token used to pay fees.\\n /// @return cost The arbitration cost in `_feeToken`.\\n function arbitrationCost(bytes calldata _extraData, IERC20 _feeToken) external view returns (uint256 cost);\\n\\n /// @notice Gets the current ruling of a specified dispute.\\n /// @param _disputeID The ID of the dispute.\\n /// @return ruling The current ruling.\\n /// @return tied Whether it's a tie or not.\\n /// @return overridden Whether the ruling was overridden by appeal funding or not.\\n function currentRuling(uint256 _disputeID) external view returns (uint256 ruling, bool tied, bool overridden);\\n}\\n\",\"keccak256\":\"0x65ba87c5309cd6e6562e569f79778ca423c9be7b0a44b9407e5bd2bdf8fdc3b0\",\"license\":\"MIT\"},\"src/arbitration/interfaces/IDisputeKit.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity >=0.8.0 <0.9.0;\\n\\nimport \\\"./IArbitratorV2.sol\\\";\\n\\n/// @title IDisputeKit\\n/// @notice An abstraction of the Dispute Kits intended for interfacing with KlerosCore.\\n/// @dev It does not intend to abstract the interactions with the user (such as voting or appeal funding) to allow for implementation-specific parameters.\\ninterface IDisputeKit {\\n // ************************************ //\\n // * Events * //\\n // ************************************ //\\n\\n /// @notice Emitted when casting a vote to provide the justification of juror's choice.\\n /// @param _coreDisputeID The identifier of the dispute in the Arbitrator contract.\\n /// @param _juror Address of the juror.\\n /// @param _voteIDs The identifiers of the votes in the dispute.\\n /// @param _choice The choice juror voted for.\\n /// @param _justification Justification of the choice.\\n event VoteCast(\\n uint256 indexed _coreDisputeID,\\n address indexed _juror,\\n uint256[] _voteIDs,\\n uint256 indexed _choice,\\n string _justification\\n );\\n\\n // ************************************* //\\n // * State Modifiers * //\\n // ************************************* //\\n\\n /// @notice Creates a local dispute and maps it to the dispute ID in the Core contract.\\n /// @dev Access restricted to Kleros Core only.\\n /// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.\\n /// @param _numberOfChoices Number of choices of the dispute\\n /// @param _extraData Additional info about the dispute, for possible use in future dispute kits.\\n /// @param _nbVotes Maximal number of votes this dispute can get. Added for future-proofing.\\n function createDispute(\\n uint256 _coreDisputeID,\\n uint256 _numberOfChoices,\\n bytes calldata _extraData,\\n uint256 _nbVotes\\n ) external;\\n\\n /// @notice Draws the juror from the sortition tree. The drawn address is picked up by Kleros Core.\\n /// @dev Access restricted to Kleros Core only.\\n /// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.\\n /// @param _nonce Nonce.\\n /// @return drawnAddress The drawn address.\\n function draw(\\n uint256 _coreDisputeID,\\n uint256 _nonce\\n ) external returns (address drawnAddress, uint96 fromSubcourtID);\\n\\n // ************************************* //\\n // * Public Views * //\\n // ************************************* //\\n\\n /// @notice Gets the current ruling of a specified dispute.\\n /// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.\\n /// @return ruling The current ruling.\\n /// @return tied Whether it's a tie or not.\\n /// @return overridden Whether the ruling was overridden by appeal funding or not.\\n function currentRuling(uint256 _coreDisputeID) external view returns (uint256 ruling, bool tied, bool overridden);\\n\\n /// @notice Gets the degree of coherence of a particular voter.\\n /// @dev This function is called by Kleros Core in order to determine the amount of the reward.\\n /// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.\\n /// @param _coreRoundID The ID of the round in Kleros Core, not in the Dispute Kit.\\n /// @param _voteID The ID of the vote.\\n /// @param _feePerJuror The fee per juror.\\n /// @param _pnkAtStakePerJuror The PNK at stake per juror.\\n /// @return pnkCoherence The degree of coherence in basis points for the dispute PNK reward.\\n /// @return feeCoherence The degree of coherence in basis points for the dispute fee reward.\\n function getDegreeOfCoherenceReward(\\n uint256 _coreDisputeID,\\n uint256 _coreRoundID,\\n uint256 _voteID,\\n uint256 _feePerJuror,\\n uint256 _pnkAtStakePerJuror\\n ) external view returns (uint256 pnkCoherence, uint256 feeCoherence);\\n\\n /// @notice Gets the degree of coherence of a particular voter.\\n /// @dev This function is called by Kleros Core in order to determine the amount of the penalty.\\n /// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.\\n /// @param _coreRoundID The ID of the round in Kleros Core, not in the Dispute Kit.\\n /// @param _voteID The ID of the vote.\\n /// @param _feePerJuror The fee per juror.\\n /// @param _pnkAtStakePerJuror The PNK at stake per juror.\\n /// @return pnkCoherence The degree of coherence in basis points for the dispute PNK reward.\\n function getDegreeOfCoherencePenalty(\\n uint256 _coreDisputeID,\\n uint256 _coreRoundID,\\n uint256 _voteID,\\n uint256 _feePerJuror,\\n uint256 _pnkAtStakePerJuror\\n ) external view returns (uint256 pnkCoherence);\\n\\n /// @notice Gets the number of jurors who are eligible to a reward in this round.\\n /// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.\\n /// @param _coreRoundID The ID of the round in Kleros Core, not in the Dispute Kit.\\n /// @return The number of coherent jurors.\\n function getCoherentCount(uint256 _coreDisputeID, uint256 _coreRoundID) external view returns (uint256);\\n\\n /// @notice Returns true if all of the jurors have cast their commits for the last round.\\n /// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.\\n /// @return Whether all of the jurors have cast their commits for the last round.\\n function areCommitsAllCast(uint256 _coreDisputeID) external view returns (bool);\\n\\n /// @notice Returns true if all of the jurors have cast their votes for the last round.\\n /// @dev This function is to be called directly by the core contract and is not for off-chain usage.\\n /// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.\\n /// @return Whether all of the jurors have cast their votes for the last round.\\n function areVotesAllCast(uint256 _coreDisputeID) external view returns (bool);\\n\\n /// @notice Returns true if the appeal funding is finished prematurely (e.g. when losing side didn't fund).\\n /// @dev This function is to be called directly by the core contract and is not for off-chain usage.\\n /// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.\\n /// @return Whether the appeal funding is finished.\\n function isAppealFunded(uint256 _coreDisputeID) external view returns (bool);\\n\\n /// @dev Returns true if the dispute is jumping to a parent court.\\n /// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.\\n /// @return Whether the dispute is jumping to a parent court or not.\\n function earlyCourtJump(uint256 _coreDisputeID) external view returns (bool);\\n\\n /// @notice Returns the number of votes after the appeal.\\n /// @param _previousDisputeKit The previous Dispute Kit.\\n /// @param _currentNbVotes The number of votes before the appeal.\\n /// @return The number of votes after the appeal.\\n function getNbVotesAfterAppeal(\\n IDisputeKit _previousDisputeKit,\\n uint256 _currentNbVotes\\n ) external view returns (uint256);\\n\\n /// @notice Returns the dispute kit ID to be used after court jump by Kleros Core.\\n /// @return The ID of the dispute kit in Kleros Core disputeKits array.\\n function getJumpDisputeKitID() external view returns (uint256);\\n\\n /// @notice Returns true if the specified voter was active in this round.\\n /// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.\\n /// @param _coreRoundID The ID of the round in Kleros Core, not in the Dispute Kit.\\n /// @param _voteID The ID of the voter.\\n /// @return Whether the voter was active or not.\\n function isVoteActive(uint256 _coreDisputeID, uint256 _coreRoundID, uint256 _voteID) external view returns (bool);\\n\\n /// @notice Returns the info of the specified round in the core contract.\\n /// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.\\n /// @param _coreRoundID The ID of the round in Kleros Core, not in the Dispute Kit.\\n /// @param _choice The choice to query.\\n /// @return winningChoice The winning choice of this round.\\n /// @return tied Whether it's a tie or not.\\n /// @return totalVoted Number of jurors who cast the vote already.\\n /// @return totalCommited Number of jurors who cast the commit already (only relevant for hidden votes).\\n /// @return nbVoters Total number of voters in this round.\\n /// @return choiceCount Number of votes cast for the queried choice.\\n function getRoundInfo(\\n uint256 _coreDisputeID,\\n uint256 _coreRoundID,\\n uint256 _choice\\n )\\n external\\n view\\n returns (\\n uint256 winningChoice,\\n bool tied,\\n uint256 totalVoted,\\n uint256 totalCommited,\\n uint256 nbVoters,\\n uint256 choiceCount\\n );\\n\\n /// @notice Returns the vote information for a given vote ID.\\n /// @param _coreDisputeID The ID of the dispute in Kleros Core.\\n /// @param _coreRoundID The ID of the round in Kleros Core.\\n /// @param _voteID The ID of the vote.\\n /// @return account The address of the juror who cast the vote.\\n /// @return commit The commit of the vote.\\n /// @return choice The choice that got the vote.\\n /// @return voted Whether the vote was cast or not.\\n function getVoteInfo(\\n uint256 _coreDisputeID,\\n uint256 _coreRoundID,\\n uint256 _voteID\\n ) external view returns (address account, bytes32 commit, uint256 choice, bool voted);\\n}\\n\",\"keccak256\":\"0x1f12d2574dffd9bf83cf33a54aa4abbbfa4203251a0f962edd8e5c3b370408bc\",\"license\":\"MIT\"},\"src/arbitration/interfaces/ISortitionModule.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity >=0.8.0 <0.9.0;\\n\\nimport \\\"../../libraries/Constants.sol\\\";\\n\\n/// @title ISortitionModule\\n/// @notice Interface for the SortitionModule contract.\\ninterface ISortitionModule {\\n // ************************************* //\\n // * Enums * //\\n // ************************************* //\\n\\n enum Phase {\\n staking, // Stake sum trees can be updated. Pass after `minStakingTime` passes and there is at least one dispute without jurors.\\n generating, // Waiting for a random number. Pass as soon as it is ready.\\n drawing // Jurors can be drawn. Pass after all disputes have jurors or `maxDrawingTime` passes.\\n }\\n\\n // ************************************* //\\n // * Events * //\\n // ************************************* //\\n\\n /// @notice Emitted when the phase is changed.\\n /// @param _phase The new phase.\\n event NewPhase(Phase _phase);\\n\\n // ************************************* //\\n // * State Modifiers * //\\n // ************************************* //\\n\\n /// @notice Passes the phase.\\n function passPhase() external;\\n\\n /// @notice Executes the next delayed stakes.\\n /// @param _iterations The number of delayed stakes to execute.\\n function executeDelayedStakes(uint256 _iterations) external;\\n\\n /// @notice Create a sortition sum tree at the specified key.\\n /// @param _courtID The ID of the court.\\n /// @param _extraData Extra data that contains the number of children each node in the tree should have.\\n function createTree(uint96 _courtID, bytes memory _extraData) external;\\n\\n /// @notice Validate the specified juror's new stake for a court.\\n /// @dev No state changes should be made when returning stakingResult != Successful, otherwise delayed stakes might break invariants.\\n /// @param _account The address of the juror.\\n /// @param _courtID The ID of the court.\\n /// @param _newStake The new stake.\\n /// @param _noDelay True if the stake change should not be delayed.\\n /// @return pnkDeposit The amount of PNK to be deposited.\\n /// @return pnkWithdrawal The amount of PNK to be withdrawn.\\n /// @return stakingResult The result of the staking operation.\\n function validateStake(\\n address _account,\\n uint96 _courtID,\\n uint256 _newStake,\\n bool _noDelay\\n ) external returns (uint256 pnkDeposit, uint256 pnkWithdrawal, StakingResult stakingResult);\\n\\n /// @notice Update the state of the stakes, called by KC at the end of setStake flow.\\n ///\\n /// @dev `O(n + p * log_k(j))` where\\n /// `n` is the number of courts the juror has staked in,\\n /// `p` is the depth of the court tree,\\n /// `k` is the minimum number of children per node of one of these courts' sortition sum tree,\\n /// and `j` is the maximum number of jurors that ever staked in one of these courts simultaneously.\\n ///\\n /// @param _account The address of the juror.\\n /// @param _courtID The ID of the court.\\n /// @param _pnkDeposit The amount of PNK to be deposited.\\n /// @param _pnkWithdrawal The amount of PNK to be withdrawn.\\n /// @param _newStake The new stake.\\n function setStake(\\n address _account,\\n uint96 _courtID,\\n uint256 _pnkDeposit,\\n uint256 _pnkWithdrawal,\\n uint256 _newStake\\n ) external;\\n\\n /// @notice Update the state of the stakes with a PNK reward deposit, called by KC during rewards execution.\\n ///\\n /// @dev `O(n + p * log_k(j))` where\\n /// `n` is the number of courts the juror has staked in,\\n /// `p` is the depth of the court tree,\\n /// `k` is the minimum number of children per node of one of these courts' sortition sum tree,\\n /// and `j` is the maximum number of jurors that ever staked in one of these courts simultaneously.\\n ///\\n /// @param _account The address of the juror.\\n /// @param _courtID The ID of the court.\\n /// @param _penalty The amount of PNK to be deducted.\\n /// @return pnkBalance The updated total PNK balance of the juror, including the penalty.\\n /// @return newCourtStake The updated stake of the juror in the court.\\n /// @return availablePenalty The amount of PNK that was actually deducted.\\n function setStakePenalty(\\n address _account,\\n uint96 _courtID,\\n uint256 _penalty\\n ) external returns (uint256 pnkBalance, uint256 newCourtStake, uint256 availablePenalty);\\n\\n /// @notice Update the state of the stakes with a PNK reward deposit, called by KC during rewards execution.\\n ///\\n /// @dev `O(n + p * log_k(j))` where\\n /// `O(n + p * log_k(j))` where\\n /// `n` is the number of courts the juror has staked in,\\n /// `p` is the depth of the court tree,\\n /// `k` is the minimum number of children per node of one of these courts' sortition sum tree,\\n /// and `j` is the maximum number of jurors that ever staked in one of these courts simultaneously.\\n ///\\n /// @param _account The address of the juror.\\n /// @param _courtID The ID of the court.\\n /// @param _reward The amount of PNK to be deposited as a reward.\\n /// @return success True if the reward was added successfully.\\n function setStakeReward(address _account, uint96 _courtID, uint256 _reward) external returns (bool success);\\n\\n /// @notice Unstakes the inactive juror from all courts.\\n ///\\n /// @dev `O(n * (p * log_k(j)) )` where\\n /// `O(n * (p * log_k(j)) )` where\\n /// `n` is the number of courts the juror has staked in,\\n /// `p` is the depth of the court tree,\\n /// `k` is the minimum number of children per node of one of these courts' sortition sum tree,\\n /// and `j` is the maximum number of jurors that ever staked in one of these courts simultaneously.\\n ///\\n /// @param _account The juror to unstake.\\n function forcedUnstakeAllCourts(address _account) external;\\n\\n /// @notice Unstakes the inactive juror from a specific court.\\n ///\\n /// @dev `O(n * (p * log_k(j)) )` where\\n /// `n` is the number of courts the juror has staked in,\\n /// `p` is the depth of the court tree,\\n /// `k` is the minimum number of children per node of one of these courts' sortition sum tree,\\n /// and `j` is the maximum number of jurors that ever staked in one of these courts simultaneously.\\n ///\\n /// @param _account The juror to unstake.\\n /// @param _courtID The ID of the court.\\n function forcedUnstake(address _account, uint96 _courtID) external;\\n\\n /// @notice Locks the tokens of the drawn juror.\\n /// @param _account The address of the juror.\\n /// @param _relativeAmount The amount to lock.\\n function lockStake(address _account, uint256 _relativeAmount) external;\\n\\n /// @notice Unlocks the tokens of the drawn juror.\\n /// @param _account The address of the juror.\\n /// @param _relativeAmount The amount to unlock.\\n function unlockStake(address _account, uint256 _relativeAmount) external;\\n\\n /// @notice Triggers the state changes after dispute creation.\\n /// @param _disputeID The ID of the dispute.\\n /// @param _roundID The ID of the round.\\n function createDisputeHook(uint256 _disputeID, uint256 _roundID) external;\\n\\n /// @notice Triggers the state changes after drawing.\\n /// @param _disputeID The ID of the dispute.\\n /// @param _roundID The ID of the round.\\n function postDrawHook(uint256 _disputeID, uint256 _roundID) external;\\n\\n /// @notice Gives back the locked PNKs in case the juror fully unstaked earlier.\\n ///\\n /// @dev that since locked and staked PNK are async it is possible for the juror to have positive staked PNK balance\\n /// while having 0 stake in courts and 0 locked tokens (eg. when the juror fully unstaked during dispute and later got his tokens unlocked).\\n /// In this case the juror can use this function to withdraw the leftover tokens.\\n /// Also note that if the juror has some leftover PNK while not fully unstaked he'll have to manually unstake from all courts to trigger this function.\\n ///\\n /// @param _account The juror whose PNK to withdraw.\\n function withdrawLeftoverPNK(address _account) external;\\n\\n // ************************************* //\\n // * Public Views * //\\n // ************************************* //\\n\\n /// @notice Draw an ID from a tree using a number.\\n ///\\n /// @dev that this function reverts if the sum of all values in the tree is 0.\\n /// `O(k * log_k(n))` where\\n /// `k` is the maximum number of children per node in the tree,\\n /// and `n` is the maximum number of nodes ever appended.\\n ///\\n /// @param _courtID The ID of the court.\\n /// @param _coreDisputeID Index of the dispute in Kleros Core.\\n /// @param _nonce Nonce to hash with random number.\\n /// @return drawnAddress The drawn address.\\n function draw(\\n uint96 _courtID,\\n uint256 _coreDisputeID,\\n uint256 _nonce\\n ) external view returns (address drawnAddress, uint96 fromSubcourtID);\\n\\n /// @notice Gets the balance of a juror in a court.\\n /// @param _juror The address of the juror.\\n /// @param _courtID The ID of the court.\\n /// @return totalStakedPnk The total amount of tokens staked including locked tokens and penalty deductions. Equivalent to the effective stake in the General court.\\n /// @return totalLocked The total amount of tokens locked in disputes.\\n /// @return stakedInCourt The amount of tokens staked in the specified court including locked tokens and penalty deductions.\\n /// @return nbCourts The number of courts the juror has directly staked in.\\n function getJurorBalance(\\n address _juror,\\n uint96 _courtID\\n ) external view returns (uint256 totalStakedPnk, uint256 totalLocked, uint256 stakedInCourt, uint256 nbCourts);\\n\\n /// @notice Gets the court identifiers where a specific `_juror` has staked.\\n /// @param _juror The address of the juror.\\n function getJurorCourtIDs(address _juror) external view returns (uint96[] memory);\\n\\n /// @notice Checks if the juror is staked in any court.\\n /// @param _juror The address of the juror.\\n /// @return Whether the juror is staked or not.\\n function isJurorStaked(address _juror) external view returns (bool);\\n\\n /// @notice Checks if the juror has any leftover PNK in the contract.\\n /// @param _juror The address of the juror.\\n /// @return Whether the juror has leftover PNK.\\n function getJurorLeftoverPNK(address _juror) external view returns (uint256);\\n}\\n\",\"keccak256\":\"0x3eeff4281ddf3c731c6503094bbbcc80d8015e3a60a27c8cadadfffdf1bf5437\",\"license\":\"MIT\"},\"src/libraries/Constants.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n// Courts\\nuint96 constant FORKING_COURT = 0; // Index of the forking court.\\nuint96 constant GENERAL_COURT = 1; // Index of the default (general) court.\\n\\n// Dispute Kits\\nuint256 constant NULL_DISPUTE_KIT = 0; // Null pattern to indicate a top-level DK which has no parent.\\nuint256 constant DISPUTE_KIT_CLASSIC = 1; // Index of the default DK. 0 index is skipped.\\n\\n// Sortition Module\\nuint256 constant MAX_STAKE_PATHS = 4; // The maximum number of stake paths a juror can have.\\nuint256 constant DEFAULT_K = 6; // Default number of children per node.\\n\\n// Defaults\\nuint256 constant DEFAULT_NB_OF_JURORS = 3; // The default number of jurors in a dispute.\\nIERC20 constant NATIVE_CURRENCY = IERC20(address(0)); // The native currency, such as ETH on Arbitrum, Optimism and Ethereum L1.\\n\\n// Units\\nuint256 constant ONE_BASIS_POINT = 10000;\\n\\nenum OnError {\\n Revert,\\n Return\\n}\\n\\nenum StakingResult {\\n Successful,\\n Delayed,\\n StakingTransferFailed,\\n UnstakingTransferFailed,\\n CannotStakeInMoreCourts,\\n CannotStakeInThisCourt,\\n CannotStakeLessThanMinStake,\\n CannotStakeMoreThanMaxStakePerJuror,\\n CannotStakeMoreThanMaxTotalStaked,\\n CannotStakeZeroWhenNoStake\\n}\\n\",\"keccak256\":\"0xb8c96c842259ca1384e8450dfb214f0fcd604829c84293dd3f8981f3421b66c9\",\"license\":\"MIT\"},\"src/libraries/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// Adapted from https://github.com/OpenZeppelin/openzeppelin-contracts/blob/a7a94c77463acea95d979aae1580fb0ddc3b6a1e/contracts/token/ERC20/utils/SafeERC20.sol\\n\\npragma solidity ^0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/// @title SafeERC20\\n///\\n/// @notice Wrappers around ERC20 operations\\n///\\n/// @dev Throws on failure (when the token contract returns false).\\n/// Tokens that return no value (and instead revert or throw on failure) are also supported.\\n/// Non-reverting calls are assumed to be successful.\\n/// To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n/// which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\nlibrary SafeERC20 {\\n /// @notice Increases the allowance granted to `spender` by the caller.\\n /// @param _token Token to transfer.\\n /// @param _spender The address which will spend the funds.\\n /// @param _addedValue The amount of tokens to increase the allowance by.\\n function increaseAllowance(IERC20 _token, address _spender, uint256 _addedValue) internal returns (bool) {\\n _token.approve(_spender, _token.allowance(address(this), _spender) + _addedValue);\\n return true;\\n }\\n\\n /// @notice Calls transfer() without reverting.\\n /// @param _token Token to transfer.\\n /// @param _to Recipient address.\\n /// @param _value Amount transferred.\\n /// @return Whether transfer succeeded or not.\\n function safeTransfer(IERC20 _token, address _to, uint256 _value) internal returns (bool) {\\n (bool success, bytes memory data) = address(_token).call(abi.encodeCall(IERC20.transfer, (_to, _value)));\\n return (success && (data.length == 0 || abi.decode(data, (bool))));\\n }\\n\\n /// @notice Calls transferFrom() without reverting.\\n /// @param _token Token to transfer.\\n /// @param _from Sender address.\\n /// @param _to Recipient address.\\n /// @param _value Amount transferred.\\n /// @return Whether transfer succeeded or not.\\n function safeTransferFrom(IERC20 _token, address _from, address _to, uint256 _value) internal returns (bool) {\\n (bool success, bytes memory data) = address(_token).call(\\n abi.encodeCall(IERC20.transferFrom, (_from, _to, _value))\\n );\\n return (success && (data.length == 0 || abi.decode(data, (bool))));\\n }\\n}\\n\",\"keccak256\":\"0x36b92f984484f9dfd63a40ccb1c1e23cde0085db36ec8adb7afe7e98ef667bd7\",\"license\":\"MIT\"},\"src/libraries/SafeSend.sol\":{\"content\":\"/**\\n * @authors: [@andreimvp]\\n * @reviewers: [@divyangchauhan, @wadader, @fcanela, @unknownunknown1]\\n * @auditors: []\\n * @bounties: []\\n * SPDX-License-Identifier: MIT\\n */\\n\\npragma solidity ^0.8.24;\\n\\ninterface WethLike {\\n function deposit() external payable;\\n\\n function transfer(address dst, uint256 wad) external;\\n}\\n\\nlibrary SafeSend {\\n function safeSend(address payable _to, uint256 _value, address _wethLike) internal {\\n if (_to.send(_value)) return;\\n\\n WethLike(_wethLike).deposit{value: _value}();\\n WethLike(_wethLike).transfer(_to, _value); /// forge-lint: disable-line(erc20-unchecked-transfer)\\n }\\n}\\n\",\"keccak256\":\"0xd4d5b25d0eb7f7965ea7a9e3d3d6bc13368de9aaf882543a75dc9c57c85e9283\",\"license\":\"MIT\"},\"src/proxy/Initializable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol) \\n\\npragma solidity ^0.8.24;\\n\\n/**\\n * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed\\n * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an\\n * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer\\n * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.\\n *\\n * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be\\n * reused. This mechanism prevents re-execution of each \\\"step\\\" but allows the creation of new initialization steps in\\n * case an upgrade adds a module that needs to be initialized.\\n *\\n * For example:\\n *\\n * ```solidity\\n * contract MyToken is ERC20Upgradeable {\\n * function initialize() initializer public {\\n * __ERC20_init(\\\"MyToken\\\", \\\"MTK\\\");\\n * }\\n * }\\n *\\n * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {\\n * function initializeV2() reinitializer(2) public {\\n * __ERC20Permit_init(\\\"MyToken\\\");\\n * }\\n * }\\n * ```\\n *\\n * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as\\n * possible by providing the encoded function call as the `_data` argument to the proxy constructor\\n *\\n * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure\\n * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.\\n *\\n * [CAUTION]\\n * ====\\n * Avoid leaving a contract uninitialized.\\n *\\n * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation\\n * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke\\n * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:\\n *\\n * ```\\n * /// @custom:oz-upgrades-unsafe-allow constructor\\n * constructor() {\\n * _disableInitializers();\\n * }\\n * ```\\n */\\nabstract contract Initializable {\\n /**\\n * @dev Storage of the initializable contract.\\n *\\n * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions\\n * when using with upgradeable contracts.\\n *\\n * @custom:storage-location erc7201:openzeppelin.storage.Initializable\\n */\\n struct InitializableStorage {\\n /**\\n * @dev Indicates that the contract has been initialized.\\n */\\n uint64 _initialized;\\n /**\\n * @dev Indicates that the contract is in the process of being initialized.\\n */\\n bool _initializing;\\n }\\n\\n // keccak256(abi.encode(uint256(keccak256(\\\"openzeppelin.storage.Initializable\\\")) - 1))\\n bytes32 private constant _INITIALIZABLE_STORAGE =\\n 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0e;\\n\\n /**\\n * @dev The contract is already initialized.\\n */\\n error AlreadyInitialized();\\n\\n /**\\n * @dev The contract is not initializing.\\n */\\n error NotInitializing();\\n\\n /**\\n * @dev Triggered when the contract has been initialized or reinitialized.\\n */\\n event Initialized(uint64 version);\\n\\n /**\\n * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,\\n * `onlyInitializing` functions can be used to initialize parent contracts.\\n *\\n * Similar to `initializer()`, except that functions marked with `initializer` can be nested in the context of a\\n * constructor.\\n *\\n * Emits an {Initialized} event.\\n */\\n modifier initializer() {\\n // solhint-disable-next-line var-name-mixedcase\\n InitializableStorage storage $ = _getInitializableStorage();\\n\\n bool isTopLevelCall = !$._initializing;\\n uint64 initialized = $._initialized;\\n if (!(isTopLevelCall && initialized < 1) && !(address(this).code.length == 0 && initialized == 1)) {\\n revert AlreadyInitialized();\\n }\\n $._initialized = 1;\\n if (isTopLevelCall) {\\n $._initializing = true;\\n }\\n _;\\n if (isTopLevelCall) {\\n $._initializing = false;\\n emit Initialized(1);\\n }\\n }\\n\\n /**\\n * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the\\n * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be\\n * used to initialize parent contracts.\\n *\\n * A reinitializer may be used after the original initialization step. This is essential to configure modules that\\n * are added through upgrades and that require initialization.\\n *\\n * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`\\n * cannot be nested. If one is invoked in the context of another, execution will revert.\\n *\\n * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in\\n * a contract, executing them in the right order is up to the developer or operator.\\n *\\n * WARNING: setting the version to 255 will prevent any future reinitialization.\\n *\\n * Emits an {Initialized} event.\\n */\\n modifier reinitializer(uint64 version) {\\n // solhint-disable-next-line var-name-mixedcase\\n InitializableStorage storage $ = _getInitializableStorage();\\n\\n if ($._initializing || $._initialized >= version) {\\n revert AlreadyInitialized();\\n }\\n $._initialized = version;\\n $._initializing = true;\\n _;\\n $._initializing = false;\\n emit Initialized(version);\\n }\\n\\n /**\\n * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the\\n * {initializer} and {reinitializer} modifiers, directly or indirectly.\\n */\\n modifier onlyInitializing() {\\n _checkInitializing();\\n _;\\n }\\n\\n /**\\n * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.\\n */\\n function _checkInitializing() internal view virtual {\\n if (!_isInitializing()) {\\n revert NotInitializing();\\n }\\n }\\n\\n /**\\n * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.\\n * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized\\n * to any version. It is recommended to use this to lock implementation contracts that are designed to be called\\n * through proxies.\\n *\\n * Emits an {Initialized} event the first time it is successfully executed.\\n */\\n function _disableInitializers() internal virtual {\\n // solhint-disable-next-line var-name-mixedcase\\n InitializableStorage storage $ = _getInitializableStorage();\\n\\n if ($._initializing) {\\n revert AlreadyInitialized();\\n }\\n if ($._initialized != type(uint64).max) {\\n $._initialized = type(uint64).max;\\n emit Initialized(type(uint64).max);\\n }\\n }\\n\\n /**\\n * @dev Returns the highest version that has been initialized. See {reinitializer}.\\n */\\n function _getInitializedVersion() internal view returns (uint64) {\\n return _getInitializableStorage()._initialized;\\n }\\n\\n /**\\n * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.\\n */\\n function _isInitializing() internal view returns (bool) {\\n return _getInitializableStorage()._initializing;\\n }\\n\\n /**\\n * @dev Returns a pointer to the storage namespace.\\n */\\n // solhint-disable-next-line var-name-mixedcase\\n function _getInitializableStorage() private pure returns (InitializableStorage storage $) {\\n assembly {\\n $.slot := _INITIALIZABLE_STORAGE\\n }\\n }\\n}\\n\",\"keccak256\":\"0xdad09e5f773fa6940dbd8c28480f602a7eaa3c70d3da9d06df140187cbf5dad4\",\"license\":\"MIT\"},\"src/proxy/UUPSProxiable.sol\":{\"content\":\"//SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.24;\\n\\n/// @title UUPS Proxiable\\n/// @author Simon Malatrait \\n/// @notice This contract implements an upgradeability mechanism designed for UUPS proxies.\\n///\\n/// @dev Adapted from \\n/// The functions included here can perform an upgrade of an UUPS Proxy, when this contract is set as the implementation behind such a proxy.\\n///\\n/// IMPORTANT: A UUPS proxy requires its upgradeability functions to be in the implementation as opposed to the transparent proxy.\\n/// This means that if the proxy is upgraded to an implementation that does not support this interface, it will no longer be upgradeable.\\n///\\n/// A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is\\n/// reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing\\n/// `UUPSProxiable` with a custom implementation of upgrades.\\n///\\n/// The `_authorizeUpgrade` function must be overridden to include access restriction to the upgrade mechanism.\\nabstract contract UUPSProxiable {\\n // ************************************* //\\n // * Event * //\\n // ************************************* //\\n\\n /// @notice Emitted when the `implementation` has been successfully upgraded.\\n /// @param newImplementation Address of the new implementation the proxy is now forwarding calls to.\\n event Upgraded(address indexed newImplementation);\\n\\n // ************************************* //\\n // * Error * //\\n // ************************************* //\\n\\n /// @notice The call is from an unauthorized context.\\n error UUPSUnauthorizedCallContext();\\n\\n /// @notice The storage `slot` is unsupported as a UUID.\\n error UUPSUnsupportedProxiableUUID(bytes32 slot);\\n\\n /// @notice The `implementation` is not UUPS-compliant\\n error InvalidImplementation(address implementation);\\n\\n /// Failed Delegated call\\n error FailedDelegateCall();\\n\\n // ************************************* //\\n // * Storage * //\\n // ************************************* //\\n\\n /// @dev Storage slot with the address of the current implementation.\\n /// @dev This is the keccak-256 hash of \\\"eip1967.proxy.implementation\\\" subtracted by 1, and is\\n /// @dev validated in the constructor.\\n /// @dev NOTE: bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1)\\n bytes32 private constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\\n\\n /// @dev Storage variable of the proxiable contract address.\\n /// @dev It is used to check whether or not the current call is from the proxy.\\n /// @custom:oz-upgrades-unsafe-allow state-variable-immutable\\n address private immutable __self = address(this);\\n\\n // ************************************* //\\n // * Governance * //\\n // ************************************* //\\n\\n /// @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract.\\n /// @dev Called by {upgradeToAndCall}.\\n function _authorizeUpgrade(address newImplementation) internal virtual;\\n\\n // ************************************* //\\n // * State Modifiers * //\\n // ************************************* //\\n\\n /// @notice Upgrade mechanism including access control and UUPS-compliance.\\n /// @param newImplementation Address of the new implementation contract.\\n /// @param data Data used in a delegate call to `newImplementation` if non-empty. This will typically be an encoded\\n /// function call, and allows initializing the storage of the proxy like a Solidity constructor.\\n /// @dev Reverts if the execution is not performed via delegatecall or the execution\\n /// context is not of a proxy with an ERC1967-compliant implementation pointing to self.\\n function upgradeToAndCall(address newImplementation, bytes memory data) public payable virtual {\\n _authorizeUpgrade(newImplementation);\\n\\n // Check that the execution is being performed through a delegatecall call and that the execution context is\\n // a proxy contract with an implementation (as defined in ERC1967) pointing to self.\\n if (address(this) == __self || _getImplementation() != __self) {\\n revert UUPSUnauthorizedCallContext();\\n }\\n\\n try UUPSProxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {\\n if (slot != IMPLEMENTATION_SLOT) {\\n revert UUPSUnsupportedProxiableUUID(slot);\\n }\\n // Store the new implementation address to the implementation storage slot.\\n assembly {\\n sstore(IMPLEMENTATION_SLOT, newImplementation)\\n }\\n emit Upgraded(newImplementation);\\n\\n if (data.length != 0) {\\n // The return data is not checked (checking, in case of success, that the newImplementation code is non-empty if the return data is empty) because the authorized callee is trusted.\\n /// @custom:oz-upgrades-unsafe-allow delegatecall\\n (bool success, ) = newImplementation.delegatecall(data);\\n if (!success) {\\n revert FailedDelegateCall();\\n }\\n }\\n } catch {\\n revert InvalidImplementation(newImplementation);\\n }\\n }\\n\\n // ************************************* //\\n // * Public Views * //\\n // ************************************* //\\n\\n /// @notice Implementation of the ERC1822 `proxiableUUID` function. This returns the storage slot used by the\\n /// implementation. It is used to validate the implementation's compatibility when performing an upgrade.\\n ///\\n /// @dev IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks\\n /// bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this\\n /// function revert if invoked through a proxy. This is guaranteed by the if statement.\\n function proxiableUUID() external view virtual returns (bytes32) {\\n if (address(this) != __self) {\\n // Must not be called through delegatecall\\n revert UUPSUnauthorizedCallContext();\\n }\\n return IMPLEMENTATION_SLOT;\\n }\\n\\n /// @notice Returns the version of the implementation.\\n /// @return Version string.\\n function version() external view virtual returns (string memory);\\n\\n // ************************************* //\\n // * Internal Views * //\\n // ************************************* //\\n\\n function _getImplementation() internal view returns (address implementation) {\\n assembly {\\n implementation := sload(IMPLEMENTATION_SLOT)\\n }\\n }\\n}\\n\",\"keccak256\":\"0xa369061748e8a7b02873d597d4c78a2a09328111f04a97428b1c209e82cf5414\",\"license\":\"MIT\"}},\"version\":1}",
+ "bytecode": "0x60a080604052346100c157306080525f5160206133bf5f395f51905f525460ff8160401c166100b3576002600160401b03196001600160401b03821601610060575b6040516132f990816100c682396080518181816117f601526118a60152f35b6001600160401b0319166001600160401b039081175f5160206133bf5f395f51905f525581527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a15f80610041565b62dc149f60e41b5f5260045ffd5b5f80fdfe6080806040526004361015610012575f80fd5b5f905f3560e01c9081630855bbe914612836575080630baa64d1146127e25780631200aabc146127b8578063149a5dc0146127a55780631c3db16d146126755780631cc3423a146126335780632621b9a2146126115780632d68efc9146125eb578063362c34791461222d5780634b2f0ea014611ad65780634e514a1b14611ab95780634f1ef2861461185557806352d1902d146117db57806354fd4d501461177a578063564a565d1461166e5780635c92e2f6146113fc57806365540b961461139a57806369f3f041146113095780636a8c9194146112725780636d4cd8ea1461111e57806372d610d9146110e35780637c04034e14610b915780638da5cb5b14610b6b5780638e42646014610b145780639146cd4714610aaf5780639d61ab6e14610a86578063a0d216d114610a68578063a6f9dae114610a11578063a7cc08fe14610997578063b34bfaa81461097a578063b6ede5401461067a578063b70020d61461064b578063ba66fde7146105f4578063be467604146105d7578063cf756fdf14610380578063d2b8035a146102ee578063da3beb8c146102cc578063e349ad30146102af578063f2f4eb2614610288578063f32ab92714610246578063f8abee10146102175763fc6f8f16146101ec575f80fd5b3461021457602036600319011261021457602061020a6004356129ee565b5054604051908152f35b80fd5b50346102145760203660031901126102145760ff60406020926004358152600584522054166040519015158152f35b50346102145760409081610259366129b4565b92908152600360205260038282205493610272856129ee565b5090835201602052205482519182526020820152f35b503461021457806003193601126102145760206001600160a01b0360015416604051908152f35b503461021457806003193601126102145760206040516127108152f35b50346102145760206102e66102e0366129b4565b90612fd2565b604051908152f35b5034610214576102fd366129b4565b916001600160a01b0360015416330361037257818152600360205260ff600261032960408420546129ee565b500154166103635760406bffffffffffffffffffffffff61034a8585612cec565b6001600160a01b03849392935193168352166020820152f35b8063070f7fa560e51b60049252fd5b80628448c760e31b60049252fd5b50346102145760803660031901126102145761039a61299e565b6024356001600160a01b0381168091036105d3576044356001600160a01b0381168091036105cf577ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0e549160ff8360401c16159267ffffffffffffffff811684806105c5575b1590816105a7575b5061057f5767ffffffffffffffff1981166001177ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0e5583610540575b507ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0e549360ff8560401c1615610518576001600160a01b03166001600160a01b03198654161785556001600160a01b031960015416176001556001600160a01b031960065416176006556064356007556104bc575080f35b68ff000000000000000019167ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0e557fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2602060405160018152a180f35b6004867fd7e6bcf8000000000000000000000000000000000000000000000000000000008152fd5b68ffffffffffffffffff191668010000000000000001177ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0e555f610444565b6004867f0dc149f0000000000000000000000000000000000000000000000000000000008152fd5b303b159150816105ba575b50155f610408565b60019150145f6105b2565b5060018110610400565b8380fd5b8280fd5b503461021457806003193601126102145760206040516113888152f35b50346102145760ff61063e604061063860209461061036612a73565b94918391935260038852610626828220546129ee565b50928152600383018852205490612ae1565b50612cd3565b5054166040519015158152f35b50346102145780600319360112610214575060075480610672575060206001604051908152f35b6020906102e6565b50346102145760803660031901126102145760043560443560243567ffffffffffffffff82116105cf57366023830112156105cf57816004013567ffffffffffffffff8111610976573660248285010111610976576001600160a01b0360015416330361096857600254680100000000000000008110156109545760018101600255610705816129ee565b508360018201556004810161071a8154612a0a565b601f811161090f575b508388601f82116001146108a6578991610898575b508460011b905f198660031b1c19161790555b6002810160ff1981541690558054602460206001600160a01b036001541660405192838092637e37c78b60e11b82528c60048301525afa90811561088d578991610857575b505f198101908111610843576107dd606095937fd3106f74c2d30a4b9230e756a3e78bde53865d40f6af4c479bb010ebaab58108989795936003938c5283820160205260408c2055612bca565b5001600160ff1982541617905586885260036020526040882055858752600560205260408720600160ff1982541617905580602460405195869485526040602086015282604086015201848401378181018301879052601f01601f19168101030190a280f35b602489634e487b7160e01b81526011600452fd5b90506020813d602011610885575b816108726020938361291c565b8101031261088157515f610790565b5f80fd5b3d9150610865565b6040513d8b823e3d90fd5b60249150870101355f610738565b828a5260208a20915085601f1981168b5b8a8282106108f2575050106108d6575b5050600184811b01905561074b565b8701602401355f19600387901b60f8161c191690555f806108c7565b8401602401358555600190940193602093840193899350016108b7565b81895260208920601f860160051c8101916020871061094a575b601f0160051c01905b81811061093f5750610723565b898155600101610932565b9091508190610929565b602486634e487b7160e01b81526041600452fd5b600485628448c760e31b8152fd5b8480fd5b50346102145780600319360112610214576020604051614e208152f35b5034610214576109db60406106386080936109b136612a73565b94918391935260036020526109c8828220546129ee565b5092815260038301602052205490612ae1565b5060ff815460026001840154930154604051936001600160a01b038360081c168552602085015260408401521615156060820152f35b503461021457602036600319011261021457610a2b61299e565b815490336001600160a01b03831603610a59576001600160a01b036001600160a01b03199116911617815580f35b600483630b2db9b760e31b8152fd5b50346102145780600319360112610214576020600754604051908152f35b5034610214576040610aa2610a9a366128fa565b5050916130b9565b8151908082526020820152f35b5034610214576040366003190112610214576004356001600160a01b0381160361021457602435908160011b9180830460021490151715610b005760018201809211610b0057602082604051908152f35b80634e487b7160e01b602492526011600452fd5b503461021457602036600319011261021457610b2e61299e565b6001600160a01b038254163303610b5c576001600160a01b03166001600160a01b0319600154161760015580f35b600482630b2db9b760e31b8152fd5b50346102145780600319360112610214576001600160a01b036020915416604051908152f35b50346102145760a03660031901126102145760043560243567ffffffffffffffff81116105d357610bc6903690600401612a42565b90916044359260843567ffffffffffffffff81116110df57610bec90369060040161295a565b92828652600360205260ff6002610c0660408920546129ee565b500154166110d0576001600160a01b036001541660405163564a565d60e01b815284600482015260a081602481855afa9081156110c55788916110a1575b50600581101561108d5760020361106557811561103d57838752600560205260ff6040882054161561102e578387526003602052604087205490610c87826129ee565b50906001820154881161101f5781545f1981019290831161100b5782610cac91612ae1565b509260405163564a565d60e01b815287600482015260a081602481865afa908b8215610fff5760c0926bffffffffffffffffffffffff9260249291610fcc575b506040519586938492630fad06e960e11b84521660048301525afa918215610fc1578a92610f8a575b50610d226064358a612b6e565b908a5b868110610e6b575050505050908160047fa000893c71384499023d2d7b21234f7b9e80c78e0330f357dcd667ff578bd3a4949301610d64838254612bbd565b905560028101908789528160205260408920610d81848254612bbd565b90558760018201928354908183145f14610de7575050506003915001805460ff8116610dda575b50505b610dd4610dc5604051938493604085526040850191613286565b828103602084015233966129ca565b0390a480f35b60ff191690555f80610da8565b828c528060205260408c2054828d528160205260408d2054145f14610e31575050506003915001805460ff811615610e21575b5050610dab565b60ff191660011790555f80610e1a565b828c528060205260408c2054918c5260205260408b205410610e56575b505050610dab565b600392550160ff1981541690555f8087610e4e565b610e80610e7982898b613276565b3587612cd3565b506001600160a01b0333915460081c1603610f7b578380610f4b575b610f235760ff610eb7610eb0838a8c613276565b3588612cd3565b505416610efb57808b6002610ed9610ed26001958c8e613276565b358a612cd3565b500155610eea610eb0828a8c613276565b50805460ff19168317905501610d25565b60048c7fb3808bab000000000000000000000000000000000000000000000000000000008152fd5b60048c7f953075a3000000000000000000000000000000000000000000000000000000008152fd5b50826001610f71610f5d848b8d613276565b3561063889610f6b886129ee565b50612ae1565b5001541415610e9c565b60048c638016bef760e01b8152fd5b610fad91925060c03d60c011610fba575b610fa5818361291c565b810190612c97565b505050509050905f610d15565b503d610f9b565b6040513d8c823e3d90fd5b610fee915060a03d60a011610ff8575b610fe6818361291c565b810190612b20565b505050505f610cec565b503d610fdc565b604051903d90823e3d90fd5b60248a634e487b7160e01b81526011600452fd5b600489637cd5012560e11b8152fd5b6004876333f97f8960e01b8152fd5b6004877fb7a08e6e000000000000000000000000000000000000000000000000000000008152fd5b6004877febd6a5e7000000000000000000000000000000000000000000000000000000008152fd5b602488634e487b7160e01b81526021600452fd5b6110ba915060a03d60a011610ff857610fe6818361291c565b50509150505f610c44565b6040513d8a823e3d90fd5b60048663070f7fa560e51b8152fd5b8580fd5b5034610214576020366003190112610214576001600160a01b03815416330361110f5760043560075580f35b80630b2db9b760e31b60049252fd5b503461021457602036600319011261021457600435808252600360205261114860408320546129ee565b5080545f1981019190821161125e579061116191612ae1565b50906001600160a01b0360015416906040519063564a565d60e01b8252600482015260a081602481855afa80156112535760246bffffffffffffffffffffffff9160c0938791611230575b506040519485938492630fad06e960e11b84521660048301525afa908115611225579260209381926111fe575b5050156111f45760046005820154915b015414604051908152f35b60048154916111e9565b61121891925060c03d60c011610fba57610fa5818361291c565b505050509050905f6111d9565b6040513d85823e3d90fd5b611249915060a03d60a011610ff857610fe6818361291c565b505050505f6111ac565b6040513d86823e3d90fd5b602484634e487b7160e01b81526011600452fd5b50346102145760603660031901126102145761128c61299e565b60443567ffffffffffffffff81116105d3576112ac90369060040161295a565b906001600160a01b038354163303610a5957818392916020849351920190602435905af16112d8612bf0565b50156112e15780f35b807f44125e5e0000000000000000000000000000000000000000000000000000000060049252fd5b50346102145761134a60c09161131e36612a73565b93918352600360205261133460408420546129ee565b5090835260038101602052604083205490612ae1565b509160018301549260ff60038201541692604060048301549160026005850154948054968352016020522054936040519586521515602086015260408501526060840152608083015260a0820152f35b5034610214576020366003190112610214576113b7600435612c1f565b90604051918291602083016020845282518091526020604085019301915b8181106113e3575050500390f35b82518452859450602093840193909201916001016113d5565b50346102145760603660031901126102145760043560243567ffffffffffffffff81116105d357611431903690600401612a42565b60449291923592828552600360205260ff600261145160408820546129ee565b5001541661165f57602460a06001600160a01b03600154166040519283809263564a565d60e01b82528860048301525afa908115611654578691611630575b50600581101561161c576001036115f45783156115cc57828552600560205260ff604086205416156115bd5782855260036020526114d160408620546129ee565b5080545f198101919082116115a957906114ea91612ae1565b50855b83811061154d57507f05cc2f1c94966f1c961b410a50f3d3ffb64501346753a258177097ea23707f089291600561153e920161152a848254612bbd565b905560405192604084526040840191613286565b9360208201528033940390a380f35b61156261155b828686613276565b3583612cd3565b506001600160a01b0333915460081c160361159a578086600161159161158a82958989613276565b3586612cd3565b500155016114ed565b600487638016bef760e01b8152fd5b602487634e487b7160e01b81526011600452fd5b6004856333f97f8960e01b8152fd5b6004857f37b5b73d000000000000000000000000000000000000000000000000000000008152fd5b6004857f97ab7f79000000000000000000000000000000000000000000000000000000008152fd5b602486634e487b7160e01b81526021600452fd5b611649915060a03d60a011610ff857610fe6818361291c565b50509150505f611490565b6040513d88823e3d90fd5b60048563070f7fa560e51b8152fd5b50346102145760203660031901126102145760043560025481101561177657611696906129ee565b5090600182015490600460ff60028501541693019060405191818154916116bc83612a0a565b808652926001811690811561174c575060011461170b575b505050906116e78161170793038261291c565b6040519384938452151560208401526060604084015260608301906129ca565b0390f35b815260208120939250905b808210611732575090915081016020016116e7826117076116d4565b919260018160209254838588010152019101909291611716565b869550611707969350602092506116e794915060ff191682840152151560051b82010192936116d4565b5080fd5b50346102145780600319360112610214575061170760405161179d60408261291c565b600581527f322e302e3000000000000000000000000000000000000000000000000000000060208201526040519182916020835260208301906129ca565b50346102145780600319360112610214576001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001630036118465760206040517f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8152f35b8063703e46dd60e11b60049252fd5b5060403660031901126102145761186a61299e565b9060243567ffffffffffffffff81116117765761188b90369060040161295a565b6001600160a01b038254163303610b5c576001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016803014908115611a84575b50611a75576001600160a01b03831690604051937f52d1902d000000000000000000000000000000000000000000000000000000008552602085600481865afa80958596611a41575b5061194b57602484847f0c760937000000000000000000000000000000000000000000000000000000008252600452fd5b90917f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8503611a1557839450817f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b8480a2815190816119ce575b5050505080f35b6020849301905af46119de612bf0565b50156119ed57805f80806119c7565b807f736436ba0000000000000000000000000000000000000000000000000000000060049252fd5b602484867faa1d49a4000000000000000000000000000000000000000000000000000000008252600452fd5b9095506020813d602011611a6d575b81611a5d6020938361291c565b810103126109765751945f61191a565b3d9150611a50565b60048263703e46dd60e11b8152fd5b90506001600160a01b037f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc541614155f6118d1565b503461021457602036600319011261021457602090604051908152f35b50611ae0366129b4565b90805f52600360205260ff6002611afa60405f20546129ee565b5001541661221e57805f526003602052611b1760405f20546129ee565b509060018201908154841161220f57805f52600560205260ff60405f20541615612200576001600160a01b036001541660405163afe15cfb60e01b8152826004820152604081602481855afa908115611e61575f905f926121ce575b5080421080156121c4575b61219c57604051631c3db16d60e01b8152846004820152606081602481305afa8015611e615788915f9161216b575b5003612106575050612710945b84545f1981019081116120be57611bd19086612ae1565b5060405191637e37c78b60e11b8352846004840152602083602481875afa928315611e61575f936120d2575b505f1983018381116120be576007830198825f528960205260ff60405f205416612096576020602496604051978880927f59ec827e0000000000000000000000000000000000000000000000000000000082528b60048301525afa958615611e61575f96612060575b50612710611c77611c7e9288612ab0565b0486612bbd565b985f996006850190845f528160205260405f20548111611fea575b6001600160a01b0333165f526008860160205260405f20855f5260205260405f20611cc58d8254612bbd565b9055845f528160205260405f20611cdd8d8254612bbd565b9055845f528160205260405f20541015611f34575b505050506001600a82015411611d37575b505050505050803411611d14575080f35b611d21611d349134612aa3565b6001600160a01b03600654169033613173565b80f35b600901611d45838254612aa3565b9055602460206001600160a01b0360015416604051928380927f19b815290000000000000000000000000000000000000000000000000000000082528860048301525afa908115611e61575f91611efa575b5015611ecc575060028401805460ff191660011790555b60046001600160a01b036001541693549401833b15610881576040519485937fc356990200000000000000000000000000000000000000000000000000000000855260048501526024840152606060448401525f90805490611e0f82612a0a565b918260648701526001811690815f14611ea75750600114611e6c575b50505f939183809203925af18015611e6157611e4c575b8080808080611d03565b611e599192505f9061291c565b5f905f611e42565b6040513d5f823e3d90fd5b5f908152602081209092505b818310611e8d57505082016084018183611e2b565b805460848489010152869450602090920191600101611e78565b60ff191660848088019190915292151560051b86019092019250839150849050611e2b565b8454905f526003850160205260405f20556003611ee885612bca565b5001805460ff19166001179055611dae565b90506020813d602011611f2c575b81611f156020938361291c565b8101031261088157611f2690612b13565b5f611d97565b3d9150611f08565b835f5260205260405f2054611f4e60098601918254612bbd565b9055600a8401805468010000000000000000811015611fd65760018101808355811015611fc25784915f5260205f200155825f5260205260405f20600160ff19825416179055857fed764996238e4c1c873ae3af7ae2f00f1f6f4f10b9ac7d4bbea4a764c5dea0095f80a45f808080611cf2565b634e487b7160e01b5f52603260045260245ffd5b634e487b7160e01b5f52604160045260245ffd5b9a50835f528060205261200160405f20548c612aa3565b34101561204557349a5b8b604051908682526020820152848a7fcae597f39a3ad75c2e10d46b031f023c5c2babcd58ca0491b122acda3968d4c060403394a4611c99565b835f528060205261205a60405f20548c612aa3565b9a61200b565b9095506020813d60201161208e575b8161207c6020938361291c565b81010312610881575194612710611c66565b3d915061206f565b7fbcdf54db000000000000000000000000000000000000000000000000000000005f5260045ffd5b634e487b7160e01b5f52601160045260245ffd5b9092506020813d6020116120fe575b816120ee6020938361291c565b810103126108815751915f611bfd565b3d91506120e1565b8061211461211a9242612aa3565b92612aa3565b61138881029080820461138814901517156120be576127109004111561214357614e2094611bba565b7f508aa06c000000000000000000000000000000000000000000000000000000005f5260045ffd5b61218d915060603d606011612195575b612185818361291c565b810190612b94565b50505f611bad565b503d61217b565b7f13e72a50000000000000000000000000000000000000000000000000000000005f5260045ffd5b5081421015611b7e565b90506121f2915060403d6040116121f9575b6121ea818361291c565b810190612a8d565b905f611b73565b503d6121e0565b6333f97f8960e01b5f5260045ffd5b637cd5012560e11b5f5260045ffd5b63070f7fa560e51b5f5260045ffd5b34610881576080366003190112610881576024356004356001600160a01b03821680830361088157604435606435925f936001600160a01b03600154169460405163564a565d60e01b815283600482015260a0816024818a5afa908115611e61575f916125c7575b501561259f576040517f5c975abb0000000000000000000000000000000000000000000000000000000081526020816004818a5afa908115611e61575f91612565575b5061253d57825f52600560205260ff60405f2054161561220057825f5260036020526024606061232461230e60405f20546129ee565b50875f526003810160205260405f205490612ae1565b509760405192838092631c3db16d60e01b82528860048301525afa908115611e61575f9161251c575b506007870190835f528160205260ff60405f205416155f146123ff57505050602095845f5260088601875260405f20825f528752600860405f2054965b865f5201875260405f20825f5287525f6040812055856123af575b8686604051908152f35b7f54b3cab3cb5c4aca3209db1151caff092e878011202e43a36782d4ebe0b963ae916123ea604092886001600160a01b036006541691613173565b81519081528688820152a482808080806123a5565b83810361246d5750505060209560068601825f5280885260405f205415155f146124645761245e600891875f528289018a5260405f20855f528a5261244d60405f205460098b015490612ab0565b90855f528a5260405f205490612ac3565b9661238a565b5060085f61245e565b5f9792975260205260ff60405f2054161561248e575b95600860209761238a565b9450835f526008850160205260405f20815f526020526124b760405f2054600987015490612ab0565b956006860196600a870197885415611fc257885f5260205f20545f528060205260405f205491895460011015611fc25761250c6008936125129360209c5f5260018d5f2001545f528c5260405f205490612bbd565b90612ac3565b9691975050612483565b612535915060603d60601161219557612185818361291c565b50508861234d565b7f88226c22000000000000000000000000000000000000000000000000000000005f5260045ffd5b90506020813d602011612597575b816125806020938361291c565b810103126108815761259190612b13565b886122d8565b3d9150612573565b7f8a7dc9ee000000000000000000000000000000000000000000000000000000005f5260045ffd5b6125e0915060a03d60a011610ff857610fe6818361291c565b509250505088612295565b34610881575f3660031901126108815760206001600160a01b0360065416604051908152f35b34610881575f36600319011261088157602060ff600454166040519015158152f35b346108815760603660031901126108815760443567ffffffffffffffff81116108815761266490369060040161295a565b5060206102e6602435600435612b6e565b34610881576020366003190112610881576004355f90805f5260036020526126a060405f20546129ee565b5080545f1981019081116120be576126b791612ae1565b50600381015460ff169290831561279c57505f5b91602460a06001600160a01b03600154166040519283809263564a565d60e01b82528660048301525afa908115611e61575f91612778575b5060058110156127645760041461272f575b506060926040519283521515602083015215156040820152f35b61273890612c1f565b9283516001811461274b575b5092612715565b9250505015611fc2576020015160609060015f84612744565b634e487b7160e01b5f52602160045260245ffd5b612791915060a03d60a011610ff857610fe6818361291c565b505091505085612703565b600101546126cb565b346108815760206102e6610a9a366128fa565b34610881576020366003190112610881576004355f526003602052602060405f2054604051908152f35b34610881576020366003190112610881576004355f52600360205261280a60405f20546129ee565b5080545f198101919082116120be5760209161282591612ae1565b506005810154905414604051908152f35b3461088157602036600319011261088157600435906040816024816001600160a01b036001541663afe15cfb60e01b82528660048301525afa918215611e61575f915f936128d3575b5061288990612c1f565b5115908161289f575b6020826040519015158152f35b6128ae91506121148142612aa3565b9061138882029180830461138814901517156120be5761271060209204111582612892565b6128f2919350612889925060403d6040116121f9576121ea818361291c565b92909161287f565b60a0906003190112610881576004359060243590604435906064359060843590565b90601f8019910116810190811067ffffffffffffffff821117611fd657604052565b67ffffffffffffffff8111611fd657601f01601f191660200190565b81601f82011215610881576020813591016129748261293e565b92612982604051948561291c565b8284528282011161088157815f92602092838601378301015290565b600435906001600160a01b038216820361088157565b6040906003190112610881576004359060243590565b805180835260209291819084018484015e5f828201840152601f01601f1916010190565b600254811015611fc25760025f52600f60205f20910201905f90565b90600182811c92168015612a38575b6020831014612a2457565b634e487b7160e01b5f52602260045260245ffd5b91607f1691612a19565b9181601f840112156108815782359167ffffffffffffffff8311610881576020808501948460051b01011161088157565b606090600319011261088157600435906024359060443590565b9190826040910312610881576020825192015190565b919082039182116120be57565b818102929181159184041417156120be57565b8115612acd570490565b634e487b7160e01b5f52601260045260245ffd5b8054821015611fc2575f52601660205f20910201905f90565b51906bffffffffffffffffffffffff8216820361088157565b5190811515820361088157565b908160a091031261088157612b3481612afa565b9160208201516001600160a01b038116810361088157916040810151600581101561088157916080612b6860608401612b13565b92015190565b906040519060208201928352604082015260408152612b8e60608261291c565b51902090565b9081606091031261088157805191612bba6040612bb360208501612b13565b9301612b13565b90565b919082018092116120be57565b805468010000000000000000811015611fd657612bec91600182018155612ae1565b9091565b3d15612c1a573d90612c018261293e565b91612c0f604051938461291c565b82523d5f602084013e565b606090565b5f526003602052612c3360405f20546129ee565b5080545f198101919082116120be57600a91612c4e91612ae1565b5001604051808260208294549384815201905f5260205f20925f5b818110612c7e575050612bba9250038261291c565b8454835260019485019486945060209093019201612c69565b91908260c091031261088157612cac82612afa565b91612cb960208201612b13565b9160408201519160608101519160a0608083015192015190565b8054821015611fc2575f52600d60205f20910201905f90565b9091815f526003602052612d0360405f20546129ee565b5080545f1981019081116120be57612d1a91612ae1565b506001600160a01b03600154166040517f2e1daf2f000000000000000000000000000000000000000000000000000000008152602081600481855afa908115611e61575f91612f8d575b5060a06024926040519384809263564a565d60e01b82528960048301525afa918215611e61576040926bffffffffffffffffffffffff926064925f92612f5f575b506001600160a01b03908551998a9586947fd045e0020000000000000000000000000000000000000000000000000000000086521660048501528960248501526044840152165afa928315611e61575f945f94612f0c575b5083856001600160a01b03811615612f0457505060045460ff1615612efc575f526003602052612e3060405f20546129ee565b5080545f198101919082116120be57600b91612e4b91612ae1565b506001600160a01b0386165f520160205260ff60405f205416155b15612ef65780549068010000000000000000821015611fd657612e91826001600b9401835582612cd3565b5080547fffffffffffffffffffffff0000000000000000000000000000000000000000ff74ffffffffffffffffffffffffffffffffffffffff008860081b1691161790556001600160a01b0385165f520160205260405f20600160ff19825416179055565b505f9250565b506001612e66565b955093505050565b945092506040843d604011612f57575b81612f296040938361291c565b81010312610881578351936001600160a01b0385168503610881576020612f509101612afa565b925f612dfd565b3d9150612f1c565b6001600160a01b03919250612f829060a03d60a011610ff857610fe6818361291c565b505050509190612da5565b90506020813d602011612fca575b81612fa86020938361291c565b810103126108815751906001600160a01b0382168203610881579060a0612d64565b3d9150612f9b565b9061300290825f526003602052612fec60405f20546129ee565b50905f526003810160205260405f205490612ae1565b5060606001600160a01b036001541692602460405180958193631c3db16d60e01b835260048301525afa918215611e61575f905f93613094575b5060048201549283158015613075575b1561305957505050505f90565b1561306357505090565b600292505f520160205260405f205490565b508015801561304c5750815f526002830160205260405f20541561304c565b90506130b091925060603d60601161219557612185818361291c565b5091905f61303c565b916106386130d692845f526003602052612fec60405f20546129ee565b509060606001600160a01b036001541691602460405180948193631c3db16d60e01b835260048301525afa908115611e61575f905f92613150575b5060ff8354169283613131575b5050505f1461312d5761271090565b5f90565b600201541491508115613148575b505f808061311e565b90505f61313f565b905061316b915060603d60601161219557612185818361291c565b50905f613111565b6001600160a01b0316905f925f8284811561326c575b5f92839283928392f1613266576001600160a01b031691823b15610881576040517fd0e30db00000000000000000000000000000000000000000000000000000000081525f8160048186885af18015611e6157613251575b50823b156105cf5790604484928360405195869485937fa9059cbb000000000000000000000000000000000000000000000000000000008552600485015260248401525af1801561324657613234575050565b61323f82809261291c565b6102145750565b6040513d84823e3d90fd5b61325e9194505f9061291c565b5f925f6131e1565b50505050565b6108fc9250613189565b9190811015611fc25760051b0190565b90918281527f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83116108815760209260051b80928483013701019056fea2646970667358221220b5aaba208006c2770b2a559bb6595fe7390db7c206ee67f59edf25055757c98c64736f6c634300081e0033f0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0e",
+ "deployedBytecode": "0x6080806040526004361015610012575f80fd5b5f905f3560e01c9081630855bbe914612836575080630baa64d1146127e25780631200aabc146127b8578063149a5dc0146127a55780631c3db16d146126755780631cc3423a146126335780632621b9a2146126115780632d68efc9146125eb578063362c34791461222d5780634b2f0ea014611ad65780634e514a1b14611ab95780634f1ef2861461185557806352d1902d146117db57806354fd4d501461177a578063564a565d1461166e5780635c92e2f6146113fc57806365540b961461139a57806369f3f041146113095780636a8c9194146112725780636d4cd8ea1461111e57806372d610d9146110e35780637c04034e14610b915780638da5cb5b14610b6b5780638e42646014610b145780639146cd4714610aaf5780639d61ab6e14610a86578063a0d216d114610a68578063a6f9dae114610a11578063a7cc08fe14610997578063b34bfaa81461097a578063b6ede5401461067a578063b70020d61461064b578063ba66fde7146105f4578063be467604146105d7578063cf756fdf14610380578063d2b8035a146102ee578063da3beb8c146102cc578063e349ad30146102af578063f2f4eb2614610288578063f32ab92714610246578063f8abee10146102175763fc6f8f16146101ec575f80fd5b3461021457602036600319011261021457602061020a6004356129ee565b5054604051908152f35b80fd5b50346102145760203660031901126102145760ff60406020926004358152600584522054166040519015158152f35b50346102145760409081610259366129b4565b92908152600360205260038282205493610272856129ee565b5090835201602052205482519182526020820152f35b503461021457806003193601126102145760206001600160a01b0360015416604051908152f35b503461021457806003193601126102145760206040516127108152f35b50346102145760206102e66102e0366129b4565b90612fd2565b604051908152f35b5034610214576102fd366129b4565b916001600160a01b0360015416330361037257818152600360205260ff600261032960408420546129ee565b500154166103635760406bffffffffffffffffffffffff61034a8585612cec565b6001600160a01b03849392935193168352166020820152f35b8063070f7fa560e51b60049252fd5b80628448c760e31b60049252fd5b50346102145760803660031901126102145761039a61299e565b6024356001600160a01b0381168091036105d3576044356001600160a01b0381168091036105cf577ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0e549160ff8360401c16159267ffffffffffffffff811684806105c5575b1590816105a7575b5061057f5767ffffffffffffffff1981166001177ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0e5583610540575b507ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0e549360ff8560401c1615610518576001600160a01b03166001600160a01b03198654161785556001600160a01b031960015416176001556001600160a01b031960065416176006556064356007556104bc575080f35b68ff000000000000000019167ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0e557fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2602060405160018152a180f35b6004867fd7e6bcf8000000000000000000000000000000000000000000000000000000008152fd5b68ffffffffffffffffff191668010000000000000001177ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0e555f610444565b6004867f0dc149f0000000000000000000000000000000000000000000000000000000008152fd5b303b159150816105ba575b50155f610408565b60019150145f6105b2565b5060018110610400565b8380fd5b8280fd5b503461021457806003193601126102145760206040516113888152f35b50346102145760ff61063e604061063860209461061036612a73565b94918391935260038852610626828220546129ee565b50928152600383018852205490612ae1565b50612cd3565b5054166040519015158152f35b50346102145780600319360112610214575060075480610672575060206001604051908152f35b6020906102e6565b50346102145760803660031901126102145760043560443560243567ffffffffffffffff82116105cf57366023830112156105cf57816004013567ffffffffffffffff8111610976573660248285010111610976576001600160a01b0360015416330361096857600254680100000000000000008110156109545760018101600255610705816129ee565b508360018201556004810161071a8154612a0a565b601f811161090f575b508388601f82116001146108a6578991610898575b508460011b905f198660031b1c19161790555b6002810160ff1981541690558054602460206001600160a01b036001541660405192838092637e37c78b60e11b82528c60048301525afa90811561088d578991610857575b505f198101908111610843576107dd606095937fd3106f74c2d30a4b9230e756a3e78bde53865d40f6af4c479bb010ebaab58108989795936003938c5283820160205260408c2055612bca565b5001600160ff1982541617905586885260036020526040882055858752600560205260408720600160ff1982541617905580602460405195869485526040602086015282604086015201848401378181018301879052601f01601f19168101030190a280f35b602489634e487b7160e01b81526011600452fd5b90506020813d602011610885575b816108726020938361291c565b8101031261088157515f610790565b5f80fd5b3d9150610865565b6040513d8b823e3d90fd5b60249150870101355f610738565b828a5260208a20915085601f1981168b5b8a8282106108f2575050106108d6575b5050600184811b01905561074b565b8701602401355f19600387901b60f8161c191690555f806108c7565b8401602401358555600190940193602093840193899350016108b7565b81895260208920601f860160051c8101916020871061094a575b601f0160051c01905b81811061093f5750610723565b898155600101610932565b9091508190610929565b602486634e487b7160e01b81526041600452fd5b600485628448c760e31b8152fd5b8480fd5b50346102145780600319360112610214576020604051614e208152f35b5034610214576109db60406106386080936109b136612a73565b94918391935260036020526109c8828220546129ee565b5092815260038301602052205490612ae1565b5060ff815460026001840154930154604051936001600160a01b038360081c168552602085015260408401521615156060820152f35b503461021457602036600319011261021457610a2b61299e565b815490336001600160a01b03831603610a59576001600160a01b036001600160a01b03199116911617815580f35b600483630b2db9b760e31b8152fd5b50346102145780600319360112610214576020600754604051908152f35b5034610214576040610aa2610a9a366128fa565b5050916130b9565b8151908082526020820152f35b5034610214576040366003190112610214576004356001600160a01b0381160361021457602435908160011b9180830460021490151715610b005760018201809211610b0057602082604051908152f35b80634e487b7160e01b602492526011600452fd5b503461021457602036600319011261021457610b2e61299e565b6001600160a01b038254163303610b5c576001600160a01b03166001600160a01b0319600154161760015580f35b600482630b2db9b760e31b8152fd5b50346102145780600319360112610214576001600160a01b036020915416604051908152f35b50346102145760a03660031901126102145760043560243567ffffffffffffffff81116105d357610bc6903690600401612a42565b90916044359260843567ffffffffffffffff81116110df57610bec90369060040161295a565b92828652600360205260ff6002610c0660408920546129ee565b500154166110d0576001600160a01b036001541660405163564a565d60e01b815284600482015260a081602481855afa9081156110c55788916110a1575b50600581101561108d5760020361106557811561103d57838752600560205260ff6040882054161561102e578387526003602052604087205490610c87826129ee565b50906001820154881161101f5781545f1981019290831161100b5782610cac91612ae1565b509260405163564a565d60e01b815287600482015260a081602481865afa908b8215610fff5760c0926bffffffffffffffffffffffff9260249291610fcc575b506040519586938492630fad06e960e11b84521660048301525afa918215610fc1578a92610f8a575b50610d226064358a612b6e565b908a5b868110610e6b575050505050908160047fa000893c71384499023d2d7b21234f7b9e80c78e0330f357dcd667ff578bd3a4949301610d64838254612bbd565b905560028101908789528160205260408920610d81848254612bbd565b90558760018201928354908183145f14610de7575050506003915001805460ff8116610dda575b50505b610dd4610dc5604051938493604085526040850191613286565b828103602084015233966129ca565b0390a480f35b60ff191690555f80610da8565b828c528060205260408c2054828d528160205260408d2054145f14610e31575050506003915001805460ff811615610e21575b5050610dab565b60ff191660011790555f80610e1a565b828c528060205260408c2054918c5260205260408b205410610e56575b505050610dab565b600392550160ff1981541690555f8087610e4e565b610e80610e7982898b613276565b3587612cd3565b506001600160a01b0333915460081c1603610f7b578380610f4b575b610f235760ff610eb7610eb0838a8c613276565b3588612cd3565b505416610efb57808b6002610ed9610ed26001958c8e613276565b358a612cd3565b500155610eea610eb0828a8c613276565b50805460ff19168317905501610d25565b60048c7fb3808bab000000000000000000000000000000000000000000000000000000008152fd5b60048c7f953075a3000000000000000000000000000000000000000000000000000000008152fd5b50826001610f71610f5d848b8d613276565b3561063889610f6b886129ee565b50612ae1565b5001541415610e9c565b60048c638016bef760e01b8152fd5b610fad91925060c03d60c011610fba575b610fa5818361291c565b810190612c97565b505050509050905f610d15565b503d610f9b565b6040513d8c823e3d90fd5b610fee915060a03d60a011610ff8575b610fe6818361291c565b810190612b20565b505050505f610cec565b503d610fdc565b604051903d90823e3d90fd5b60248a634e487b7160e01b81526011600452fd5b600489637cd5012560e11b8152fd5b6004876333f97f8960e01b8152fd5b6004877fb7a08e6e000000000000000000000000000000000000000000000000000000008152fd5b6004877febd6a5e7000000000000000000000000000000000000000000000000000000008152fd5b602488634e487b7160e01b81526021600452fd5b6110ba915060a03d60a011610ff857610fe6818361291c565b50509150505f610c44565b6040513d8a823e3d90fd5b60048663070f7fa560e51b8152fd5b8580fd5b5034610214576020366003190112610214576001600160a01b03815416330361110f5760043560075580f35b80630b2db9b760e31b60049252fd5b503461021457602036600319011261021457600435808252600360205261114860408320546129ee565b5080545f1981019190821161125e579061116191612ae1565b50906001600160a01b0360015416906040519063564a565d60e01b8252600482015260a081602481855afa80156112535760246bffffffffffffffffffffffff9160c0938791611230575b506040519485938492630fad06e960e11b84521660048301525afa908115611225579260209381926111fe575b5050156111f45760046005820154915b015414604051908152f35b60048154916111e9565b61121891925060c03d60c011610fba57610fa5818361291c565b505050509050905f6111d9565b6040513d85823e3d90fd5b611249915060a03d60a011610ff857610fe6818361291c565b505050505f6111ac565b6040513d86823e3d90fd5b602484634e487b7160e01b81526011600452fd5b50346102145760603660031901126102145761128c61299e565b60443567ffffffffffffffff81116105d3576112ac90369060040161295a565b906001600160a01b038354163303610a5957818392916020849351920190602435905af16112d8612bf0565b50156112e15780f35b807f44125e5e0000000000000000000000000000000000000000000000000000000060049252fd5b50346102145761134a60c09161131e36612a73565b93918352600360205261133460408420546129ee565b5090835260038101602052604083205490612ae1565b509160018301549260ff60038201541692604060048301549160026005850154948054968352016020522054936040519586521515602086015260408501526060840152608083015260a0820152f35b5034610214576020366003190112610214576113b7600435612c1f565b90604051918291602083016020845282518091526020604085019301915b8181106113e3575050500390f35b82518452859450602093840193909201916001016113d5565b50346102145760603660031901126102145760043560243567ffffffffffffffff81116105d357611431903690600401612a42565b60449291923592828552600360205260ff600261145160408820546129ee565b5001541661165f57602460a06001600160a01b03600154166040519283809263564a565d60e01b82528860048301525afa908115611654578691611630575b50600581101561161c576001036115f45783156115cc57828552600560205260ff604086205416156115bd5782855260036020526114d160408620546129ee565b5080545f198101919082116115a957906114ea91612ae1565b50855b83811061154d57507f05cc2f1c94966f1c961b410a50f3d3ffb64501346753a258177097ea23707f089291600561153e920161152a848254612bbd565b905560405192604084526040840191613286565b9360208201528033940390a380f35b61156261155b828686613276565b3583612cd3565b506001600160a01b0333915460081c160361159a578086600161159161158a82958989613276565b3586612cd3565b500155016114ed565b600487638016bef760e01b8152fd5b602487634e487b7160e01b81526011600452fd5b6004856333f97f8960e01b8152fd5b6004857f37b5b73d000000000000000000000000000000000000000000000000000000008152fd5b6004857f97ab7f79000000000000000000000000000000000000000000000000000000008152fd5b602486634e487b7160e01b81526021600452fd5b611649915060a03d60a011610ff857610fe6818361291c565b50509150505f611490565b6040513d88823e3d90fd5b60048563070f7fa560e51b8152fd5b50346102145760203660031901126102145760043560025481101561177657611696906129ee565b5090600182015490600460ff60028501541693019060405191818154916116bc83612a0a565b808652926001811690811561174c575060011461170b575b505050906116e78161170793038261291c565b6040519384938452151560208401526060604084015260608301906129ca565b0390f35b815260208120939250905b808210611732575090915081016020016116e7826117076116d4565b919260018160209254838588010152019101909291611716565b869550611707969350602092506116e794915060ff191682840152151560051b82010192936116d4565b5080fd5b50346102145780600319360112610214575061170760405161179d60408261291c565b600581527f322e302e3000000000000000000000000000000000000000000000000000000060208201526040519182916020835260208301906129ca565b50346102145780600319360112610214576001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001630036118465760206040517f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8152f35b8063703e46dd60e11b60049252fd5b5060403660031901126102145761186a61299e565b9060243567ffffffffffffffff81116117765761188b90369060040161295a565b6001600160a01b038254163303610b5c576001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016803014908115611a84575b50611a75576001600160a01b03831690604051937f52d1902d000000000000000000000000000000000000000000000000000000008552602085600481865afa80958596611a41575b5061194b57602484847f0c760937000000000000000000000000000000000000000000000000000000008252600452fd5b90917f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8503611a1557839450817f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b8480a2815190816119ce575b5050505080f35b6020849301905af46119de612bf0565b50156119ed57805f80806119c7565b807f736436ba0000000000000000000000000000000000000000000000000000000060049252fd5b602484867faa1d49a4000000000000000000000000000000000000000000000000000000008252600452fd5b9095506020813d602011611a6d575b81611a5d6020938361291c565b810103126109765751945f61191a565b3d9150611a50565b60048263703e46dd60e11b8152fd5b90506001600160a01b037f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc541614155f6118d1565b503461021457602036600319011261021457602090604051908152f35b50611ae0366129b4565b90805f52600360205260ff6002611afa60405f20546129ee565b5001541661221e57805f526003602052611b1760405f20546129ee565b509060018201908154841161220f57805f52600560205260ff60405f20541615612200576001600160a01b036001541660405163afe15cfb60e01b8152826004820152604081602481855afa908115611e61575f905f926121ce575b5080421080156121c4575b61219c57604051631c3db16d60e01b8152846004820152606081602481305afa8015611e615788915f9161216b575b5003612106575050612710945b84545f1981019081116120be57611bd19086612ae1565b5060405191637e37c78b60e11b8352846004840152602083602481875afa928315611e61575f936120d2575b505f1983018381116120be576007830198825f528960205260ff60405f205416612096576020602496604051978880927f59ec827e0000000000000000000000000000000000000000000000000000000082528b60048301525afa958615611e61575f96612060575b50612710611c77611c7e9288612ab0565b0486612bbd565b985f996006850190845f528160205260405f20548111611fea575b6001600160a01b0333165f526008860160205260405f20855f5260205260405f20611cc58d8254612bbd565b9055845f528160205260405f20611cdd8d8254612bbd565b9055845f528160205260405f20541015611f34575b505050506001600a82015411611d37575b505050505050803411611d14575080f35b611d21611d349134612aa3565b6001600160a01b03600654169033613173565b80f35b600901611d45838254612aa3565b9055602460206001600160a01b0360015416604051928380927f19b815290000000000000000000000000000000000000000000000000000000082528860048301525afa908115611e61575f91611efa575b5015611ecc575060028401805460ff191660011790555b60046001600160a01b036001541693549401833b15610881576040519485937fc356990200000000000000000000000000000000000000000000000000000000855260048501526024840152606060448401525f90805490611e0f82612a0a565b918260648701526001811690815f14611ea75750600114611e6c575b50505f939183809203925af18015611e6157611e4c575b8080808080611d03565b611e599192505f9061291c565b5f905f611e42565b6040513d5f823e3d90fd5b5f908152602081209092505b818310611e8d57505082016084018183611e2b565b805460848489010152869450602090920191600101611e78565b60ff191660848088019190915292151560051b86019092019250839150849050611e2b565b8454905f526003850160205260405f20556003611ee885612bca565b5001805460ff19166001179055611dae565b90506020813d602011611f2c575b81611f156020938361291c565b8101031261088157611f2690612b13565b5f611d97565b3d9150611f08565b835f5260205260405f2054611f4e60098601918254612bbd565b9055600a8401805468010000000000000000811015611fd65760018101808355811015611fc25784915f5260205f200155825f5260205260405f20600160ff19825416179055857fed764996238e4c1c873ae3af7ae2f00f1f6f4f10b9ac7d4bbea4a764c5dea0095f80a45f808080611cf2565b634e487b7160e01b5f52603260045260245ffd5b634e487b7160e01b5f52604160045260245ffd5b9a50835f528060205261200160405f20548c612aa3565b34101561204557349a5b8b604051908682526020820152848a7fcae597f39a3ad75c2e10d46b031f023c5c2babcd58ca0491b122acda3968d4c060403394a4611c99565b835f528060205261205a60405f20548c612aa3565b9a61200b565b9095506020813d60201161208e575b8161207c6020938361291c565b81010312610881575194612710611c66565b3d915061206f565b7fbcdf54db000000000000000000000000000000000000000000000000000000005f5260045ffd5b634e487b7160e01b5f52601160045260245ffd5b9092506020813d6020116120fe575b816120ee6020938361291c565b810103126108815751915f611bfd565b3d91506120e1565b8061211461211a9242612aa3565b92612aa3565b61138881029080820461138814901517156120be576127109004111561214357614e2094611bba565b7f508aa06c000000000000000000000000000000000000000000000000000000005f5260045ffd5b61218d915060603d606011612195575b612185818361291c565b810190612b94565b50505f611bad565b503d61217b565b7f13e72a50000000000000000000000000000000000000000000000000000000005f5260045ffd5b5081421015611b7e565b90506121f2915060403d6040116121f9575b6121ea818361291c565b810190612a8d565b905f611b73565b503d6121e0565b6333f97f8960e01b5f5260045ffd5b637cd5012560e11b5f5260045ffd5b63070f7fa560e51b5f5260045ffd5b34610881576080366003190112610881576024356004356001600160a01b03821680830361088157604435606435925f936001600160a01b03600154169460405163564a565d60e01b815283600482015260a0816024818a5afa908115611e61575f916125c7575b501561259f576040517f5c975abb0000000000000000000000000000000000000000000000000000000081526020816004818a5afa908115611e61575f91612565575b5061253d57825f52600560205260ff60405f2054161561220057825f5260036020526024606061232461230e60405f20546129ee565b50875f526003810160205260405f205490612ae1565b509760405192838092631c3db16d60e01b82528860048301525afa908115611e61575f9161251c575b506007870190835f528160205260ff60405f205416155f146123ff57505050602095845f5260088601875260405f20825f528752600860405f2054965b865f5201875260405f20825f5287525f6040812055856123af575b8686604051908152f35b7f54b3cab3cb5c4aca3209db1151caff092e878011202e43a36782d4ebe0b963ae916123ea604092886001600160a01b036006541691613173565b81519081528688820152a482808080806123a5565b83810361246d5750505060209560068601825f5280885260405f205415155f146124645761245e600891875f528289018a5260405f20855f528a5261244d60405f205460098b015490612ab0565b90855f528a5260405f205490612ac3565b9661238a565b5060085f61245e565b5f9792975260205260ff60405f2054161561248e575b95600860209761238a565b9450835f526008850160205260405f20815f526020526124b760405f2054600987015490612ab0565b956006860196600a870197885415611fc257885f5260205f20545f528060205260405f205491895460011015611fc25761250c6008936125129360209c5f5260018d5f2001545f528c5260405f205490612bbd565b90612ac3565b9691975050612483565b612535915060603d60601161219557612185818361291c565b50508861234d565b7f88226c22000000000000000000000000000000000000000000000000000000005f5260045ffd5b90506020813d602011612597575b816125806020938361291c565b810103126108815761259190612b13565b886122d8565b3d9150612573565b7f8a7dc9ee000000000000000000000000000000000000000000000000000000005f5260045ffd5b6125e0915060a03d60a011610ff857610fe6818361291c565b509250505088612295565b34610881575f3660031901126108815760206001600160a01b0360065416604051908152f35b34610881575f36600319011261088157602060ff600454166040519015158152f35b346108815760603660031901126108815760443567ffffffffffffffff81116108815761266490369060040161295a565b5060206102e6602435600435612b6e565b34610881576020366003190112610881576004355f90805f5260036020526126a060405f20546129ee565b5080545f1981019081116120be576126b791612ae1565b50600381015460ff169290831561279c57505f5b91602460a06001600160a01b03600154166040519283809263564a565d60e01b82528660048301525afa908115611e61575f91612778575b5060058110156127645760041461272f575b506060926040519283521515602083015215156040820152f35b61273890612c1f565b9283516001811461274b575b5092612715565b9250505015611fc2576020015160609060015f84612744565b634e487b7160e01b5f52602160045260245ffd5b612791915060a03d60a011610ff857610fe6818361291c565b505091505085612703565b600101546126cb565b346108815760206102e6610a9a366128fa565b34610881576020366003190112610881576004355f526003602052602060405f2054604051908152f35b34610881576020366003190112610881576004355f52600360205261280a60405f20546129ee565b5080545f198101919082116120be5760209161282591612ae1565b506005810154905414604051908152f35b3461088157602036600319011261088157600435906040816024816001600160a01b036001541663afe15cfb60e01b82528660048301525afa918215611e61575f915f936128d3575b5061288990612c1f565b5115908161289f575b6020826040519015158152f35b6128ae91506121148142612aa3565b9061138882029180830461138814901517156120be5761271060209204111582612892565b6128f2919350612889925060403d6040116121f9576121ea818361291c565b92909161287f565b60a0906003190112610881576004359060243590604435906064359060843590565b90601f8019910116810190811067ffffffffffffffff821117611fd657604052565b67ffffffffffffffff8111611fd657601f01601f191660200190565b81601f82011215610881576020813591016129748261293e565b92612982604051948561291c565b8284528282011161088157815f92602092838601378301015290565b600435906001600160a01b038216820361088157565b6040906003190112610881576004359060243590565b805180835260209291819084018484015e5f828201840152601f01601f1916010190565b600254811015611fc25760025f52600f60205f20910201905f90565b90600182811c92168015612a38575b6020831014612a2457565b634e487b7160e01b5f52602260045260245ffd5b91607f1691612a19565b9181601f840112156108815782359167ffffffffffffffff8311610881576020808501948460051b01011161088157565b606090600319011261088157600435906024359060443590565b9190826040910312610881576020825192015190565b919082039182116120be57565b818102929181159184041417156120be57565b8115612acd570490565b634e487b7160e01b5f52601260045260245ffd5b8054821015611fc2575f52601660205f20910201905f90565b51906bffffffffffffffffffffffff8216820361088157565b5190811515820361088157565b908160a091031261088157612b3481612afa565b9160208201516001600160a01b038116810361088157916040810151600581101561088157916080612b6860608401612b13565b92015190565b906040519060208201928352604082015260408152612b8e60608261291c565b51902090565b9081606091031261088157805191612bba6040612bb360208501612b13565b9301612b13565b90565b919082018092116120be57565b805468010000000000000000811015611fd657612bec91600182018155612ae1565b9091565b3d15612c1a573d90612c018261293e565b91612c0f604051938461291c565b82523d5f602084013e565b606090565b5f526003602052612c3360405f20546129ee565b5080545f198101919082116120be57600a91612c4e91612ae1565b5001604051808260208294549384815201905f5260205f20925f5b818110612c7e575050612bba9250038261291c565b8454835260019485019486945060209093019201612c69565b91908260c091031261088157612cac82612afa565b91612cb960208201612b13565b9160408201519160608101519160a0608083015192015190565b8054821015611fc2575f52600d60205f20910201905f90565b9091815f526003602052612d0360405f20546129ee565b5080545f1981019081116120be57612d1a91612ae1565b506001600160a01b03600154166040517f2e1daf2f000000000000000000000000000000000000000000000000000000008152602081600481855afa908115611e61575f91612f8d575b5060a06024926040519384809263564a565d60e01b82528960048301525afa918215611e61576040926bffffffffffffffffffffffff926064925f92612f5f575b506001600160a01b03908551998a9586947fd045e0020000000000000000000000000000000000000000000000000000000086521660048501528960248501526044840152165afa928315611e61575f945f94612f0c575b5083856001600160a01b03811615612f0457505060045460ff1615612efc575f526003602052612e3060405f20546129ee565b5080545f198101919082116120be57600b91612e4b91612ae1565b506001600160a01b0386165f520160205260ff60405f205416155b15612ef65780549068010000000000000000821015611fd657612e91826001600b9401835582612cd3565b5080547fffffffffffffffffffffff0000000000000000000000000000000000000000ff74ffffffffffffffffffffffffffffffffffffffff008860081b1691161790556001600160a01b0385165f520160205260405f20600160ff19825416179055565b505f9250565b506001612e66565b955093505050565b945092506040843d604011612f57575b81612f296040938361291c565b81010312610881578351936001600160a01b0385168503610881576020612f509101612afa565b925f612dfd565b3d9150612f1c565b6001600160a01b03919250612f829060a03d60a011610ff857610fe6818361291c565b505050509190612da5565b90506020813d602011612fca575b81612fa86020938361291c565b810103126108815751906001600160a01b0382168203610881579060a0612d64565b3d9150612f9b565b9061300290825f526003602052612fec60405f20546129ee565b50905f526003810160205260405f205490612ae1565b5060606001600160a01b036001541692602460405180958193631c3db16d60e01b835260048301525afa918215611e61575f905f93613094575b5060048201549283158015613075575b1561305957505050505f90565b1561306357505090565b600292505f520160205260405f205490565b508015801561304c5750815f526002830160205260405f20541561304c565b90506130b091925060603d60601161219557612185818361291c565b5091905f61303c565b916106386130d692845f526003602052612fec60405f20546129ee565b509060606001600160a01b036001541691602460405180948193631c3db16d60e01b835260048301525afa908115611e61575f905f92613150575b5060ff8354169283613131575b5050505f1461312d5761271090565b5f90565b600201541491508115613148575b505f808061311e565b90505f61313f565b905061316b915060603d60601161219557612185818361291c565b50905f613111565b6001600160a01b0316905f925f8284811561326c575b5f92839283928392f1613266576001600160a01b031691823b15610881576040517fd0e30db00000000000000000000000000000000000000000000000000000000081525f8160048186885af18015611e6157613251575b50823b156105cf5790604484928360405195869485937fa9059cbb000000000000000000000000000000000000000000000000000000008552600485015260248401525af1801561324657613234575050565b61323f82809261291c565b6102145750565b6040513d84823e3d90fd5b61325e9194505f9061291c565b5f925f6131e1565b50505050565b6108fc9250613189565b9190811015611fc25760051b0190565b90918281527f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83116108815760209260051b80928483013701019056fea2646970667358221220b5aaba208006c2770b2a559bb6595fe7390db7c206ee67f59edf25055757c98c64736f6c634300081e0033",
"devdoc": {
"errors": {
"AlreadyInitialized()": [
@@ -973,21 +1345,10 @@
{
"details": "The contract is not initializing."
}
- ],
- "UUPSUnauthorizedCallContext()": [
- {
- "details": "The call is from an unauthorized context."
- }
- ],
- "UUPSUnsupportedProxiableUUID(bytes32)": [
- {
- "details": "The storage `slot` is unsupported as a UUID."
- }
]
},
"events": {
"ChoiceFunded(uint256,uint256,uint256)": {
- "details": "To be emitted when a choice is fully funded for an appeal.",
"params": {
"_choice": "The choice that is being funded.",
"_coreDisputeID": "The identifier of the dispute in the Arbitrator contract.",
@@ -995,7 +1356,6 @@
}
},
"CommitCast(uint256,address,uint256[],bytes32)": {
- "details": "To be emitted when a vote commitment is cast.",
"params": {
"_commit": "The commitment of the juror.",
"_coreDisputeID": "The identifier of the dispute in the Arbitrator contract.",
@@ -1004,7 +1364,6 @@
}
},
"Contribution(uint256,uint256,uint256,address,uint256)": {
- "details": "To be emitted when a funding contribution is made.",
"params": {
"_amount": "The amount contributed.",
"_choice": "The choice that is being funded.",
@@ -1014,7 +1373,6 @@
}
},
"DisputeCreation(uint256,uint256,bytes)": {
- "details": "To be emitted when a dispute is created.",
"params": {
"_coreDisputeID": "The identifier of the dispute in the Arbitrator contract.",
"_extraData": "The extra data for the dispute.",
@@ -1030,7 +1388,6 @@
}
},
"VoteCast(uint256,address,uint256[],uint256,string)": {
- "details": "Emitted when casting a vote to provide the justification of juror's choice.",
"params": {
"_choice": "The choice juror voted for.",
"_coreDisputeID": "The identifier of the dispute in the Arbitrator contract.",
@@ -1040,7 +1397,6 @@
}
},
"Withdrawal(uint256,uint256,uint256,address,uint256)": {
- "details": "To be emitted when the contributed funds are withdrawn.",
"params": {
"_amount": "The amount withdrawn.",
"_choice": "The choice that is being funded.",
@@ -1053,33 +1409,32 @@
"kind": "dev",
"methods": {
"areCommitsAllCast(uint256)": {
- "details": "Returns true if all of the jurors have cast their commits for the last round.",
"params": {
- "_coreDisputeID": "The ID of the dispute in Kleros Core."
+ "_coreDisputeID": "The ID of the dispute in Kleros Core, not in the Dispute Kit."
},
"returns": {
"_0": "Whether all of the jurors have cast their commits for the last round."
}
},
"areVotesAllCast(uint256)": {
- "details": "Returns true if all of the jurors have cast their votes for the last round.",
+ "details": "This function is to be called directly by the core contract and is not for off-chain usage.",
"params": {
- "_coreDisputeID": "The ID of the dispute in Kleros Core."
+ "_coreDisputeID": "The ID of the dispute in Kleros Core, not in the Dispute Kit."
},
"returns": {
"_0": "Whether all of the jurors have cast their votes for the last round."
}
},
"castCommit(uint256,uint256[],bytes32)": {
- "details": "Sets the caller's commit for the specified votes. It can be called multiple times during the commit period, each call overrides the commits of the previous one. `O(n)` where `n` is the number of votes.",
+ "details": "It can be called multiple times during the commit period, each call overrides the commits of the previous one. `O(n)` where `n` is the number of votes.",
"params": {
- "_commit": "The commit. Note that justification string is a part of the commit.",
+ "_commit": "The commitment hash.",
"_coreDisputeID": "The ID of the dispute in Kleros Core.",
"_voteIDs": "The IDs of the votes."
}
},
"castVote(uint256,uint256[],uint256,uint256,string)": {
- "details": "Sets the caller's choices for the specified votes. `O(n)` where `n` is the number of votes.",
+ "details": "`O(n)` where `n` is the number of votes.",
"params": {
"_choice": "The choice.",
"_coreDisputeID": "The ID of the dispute in Kleros Core.",
@@ -1089,33 +1444,35 @@
}
},
"changeCore(address)": {
- "details": "Changes the `core` storage variable.",
"params": {
"_core": "The new value for the `core` storage variable."
}
},
- "changeGovernor(address)": {
- "details": "Changes the `governor` storage variable.",
+ "changeJumpDisputeKitID(uint256)": {
+ "params": {
+ "_jumpDisputeKitID": "The new value for the `jumpDisputeKitID` storage variable."
+ }
+ },
+ "changeOwner(address)": {
"params": {
- "_governor": "The new value for the `governor` storage variable."
+ "_owner": "The new value for the `owner` storage variable."
}
},
"constructor": {
- "details": "Constructor, initializing the implementation to reduce attack surface."
+ "custom:oz-upgrades-unsafe-allow": "constructor"
},
"createDispute(uint256,uint256,bytes,uint256)": {
- "details": "Creates a local dispute and maps it to the dispute ID in the Core contract. Note: Access restricted to Kleros Core only.",
+ "details": "Access restricted to Kleros Core only.",
"params": {
- "_coreDisputeID": "The ID of the dispute in Kleros Core.",
+ "_coreDisputeID": "The ID of the dispute in Kleros Core, not in the Dispute Kit.",
"_extraData": "Additional info about the dispute, for possible use in future dispute kits.",
- "_nbVotes": "Number of votes for this dispute.",
+ "_nbVotes": "Maximal number of votes this dispute can get. Added for future-proofing.",
"_numberOfChoices": "Number of choices of the dispute"
}
},
"currentRuling(uint256)": {
- "details": "Gets the current ruling of a specified dispute.",
"params": {
- "_coreDisputeID": "The ID of the dispute in Kleros Core."
+ "_coreDisputeID": "The ID of the dispute in Kleros Core, not in the Dispute Kit."
},
"returns": {
"overridden": "Whether the ruling was overridden by appeal funding or not.",
@@ -1124,17 +1481,25 @@
}
},
"draw(uint256,uint256)": {
- "details": "Draws the juror from the sortition tree. The drawn address is picked up by Kleros Core. Note: Access restricted to Kleros Core only.",
+ "details": "Access restricted to Kleros Core only.",
"params": {
- "_coreDisputeID": "The ID of the dispute in Kleros Core.",
- "_nonce": "Nonce of the drawing iteration."
+ "_coreDisputeID": "The ID of the dispute in Kleros Core, not in the Dispute Kit.",
+ "_nonce": "Nonce."
},
"returns": {
"drawnAddress": "The drawn address."
}
},
- "executeGovernorProposal(address,uint256,bytes)": {
- "details": "Allows the governor to call anything on behalf of the contract.",
+ "earlyCourtJump(uint256)": {
+ "details": "Returns true if the dispute is jumping to a parent court.",
+ "params": {
+ "_coreDisputeID": "The ID of the dispute in Kleros Core, not in the Dispute Kit."
+ },
+ "returns": {
+ "_0": "Whether the dispute is jumping to a parent court or not."
+ }
+ },
+ "executeOwnerProposal(address,uint256,bytes)": {
"params": {
"_amount": "The value sent with the call.",
"_data": "The data sent with the call.",
@@ -1142,14 +1507,12 @@
}
},
"fundAppeal(uint256,uint256)": {
- "details": "Manages contributions, and appeals a dispute if at least two choices are fully funded. Note that the surplus deposit will be reimbursed.",
"params": {
"_choice": "A choice that receives funding.",
"_coreDisputeID": "Index of the dispute in Kleros Core."
}
},
"getCoherentCount(uint256,uint256)": {
- "details": "Gets the number of jurors who are eligible to a reward in this round.",
"params": {
"_coreDisputeID": "The ID of the dispute in Kleros Core, not in the Dispute Kit.",
"_coreRoundID": "The ID of the round in Kleros Core, not in the Dispute Kit."
@@ -1158,26 +1521,129 @@
"_0": "The number of coherent jurors."
}
},
- "getDegreeOfCoherence(uint256,uint256,uint256,uint256,uint256)": {
- "details": "Gets the degree of coherence of a particular voter. This function is called by Kleros Core in order to determine the amount of the reward.",
+ "getDegreeOfCoherencePenalty(uint256,uint256,uint256,uint256,uint256)": {
+ "details": "This function is called by Kleros Core in order to determine the amount of the penalty.",
"params": {
"_coreDisputeID": "The ID of the dispute in Kleros Core, not in the Dispute Kit.",
"_coreRoundID": "The ID of the round in Kleros Core, not in the Dispute Kit.",
+ "_feePerJuror": "The fee per juror.",
+ "_pnkAtStakePerJuror": "The PNK at stake per juror.",
"_voteID": "The ID of the vote."
},
"returns": {
- "_0": "The degree of coherence in basis points."
+ "pnkCoherence": "The degree of coherence in basis points for the dispute PNK reward."
}
},
- "initialize(address,address)": {
- "details": "Initializer.",
+ "getDegreeOfCoherenceReward(uint256,uint256,uint256,uint256,uint256)": {
+ "details": "This function is called by Kleros Core in order to determine the amount of the reward.",
+ "params": {
+ "_coreDisputeID": "The ID of the dispute in Kleros Core, not in the Dispute Kit.",
+ "_coreRoundID": "The ID of the round in Kleros Core, not in the Dispute Kit.",
+ "_feePerJuror": "The fee per juror.",
+ "_pnkAtStakePerJuror": "The PNK at stake per juror.",
+ "_voteID": "The ID of the vote."
+ },
+ "returns": {
+ "feeCoherence": "The degree of coherence in basis points for the dispute fee reward.",
+ "pnkCoherence": "The degree of coherence in basis points for the dispute PNK reward."
+ }
+ },
+ "getFundedChoices(uint256)": {
+ "params": {
+ "_coreDisputeID": "The ID of the dispute in Kleros Core."
+ },
+ "returns": {
+ "fundedChoices": "Fully funded rulings."
+ }
+ },
+ "getJumpDisputeKitID()": {
+ "returns": {
+ "_0": "The ID of the dispute kit in Kleros Core disputeKits array."
+ }
+ },
+ "getLocalDisputeRoundID(uint256,uint256)": {
+ "params": {
+ "_coreDisputeID": "The ID of the dispute in Kleros Core.",
+ "_coreRoundID": "The ID of the round in Kleros Core."
+ },
+ "returns": {
+ "localDisputeID": "The ID of the dispute in the Dispute Kit.",
+ "localRoundID": "The ID of the round in the Dispute Kit."
+ }
+ },
+ "getNbVotesAfterAppeal(address,uint256)": {
+ "params": {
+ "_currentNbVotes": "The number of votes before the appeal.",
+ "_previousDisputeKit": "The previous Dispute Kit."
+ },
+ "returns": {
+ "_0": "The number of votes after the appeal."
+ }
+ },
+ "getNumberOfRounds(uint256)": {
+ "params": {
+ "_localDisputeID": "The ID of the dispute in the Dispute Kit."
+ },
+ "returns": {
+ "_0": "The number of rounds in the dispute."
+ }
+ },
+ "getRoundInfo(uint256,uint256,uint256)": {
+ "params": {
+ "_choice": "The choice to query.",
+ "_coreDisputeID": "The ID of the dispute in Kleros Core, not in the Dispute Kit.",
+ "_coreRoundID": "The ID of the round in Kleros Core, not in the Dispute Kit."
+ },
+ "returns": {
+ "choiceCount": "Number of votes cast for the queried choice.",
+ "nbVoters": "Total number of voters in this round.",
+ "tied": "Whether it's a tie or not.",
+ "totalCommitted": "Number of jurors who cast the commit already (only relevant for hidden votes).",
+ "totalVoted": "Number of jurors who cast the vote already.",
+ "winningChoice": "The winning choice of this round."
+ }
+ },
+ "getVoteInfo(uint256,uint256,uint256)": {
+ "params": {
+ "_coreDisputeID": "The ID of the dispute in Kleros Core.",
+ "_coreRoundID": "The ID of the round in Kleros Core.",
+ "_voteID": "The ID of the vote."
+ },
+ "returns": {
+ "account": "The address of the juror who cast the vote.",
+ "choice": "The choice that got the vote.",
+ "commit": "The commit of the vote.",
+ "voted": "Whether the vote was cast or not."
+ }
+ },
+ "hashVote(uint256,uint256,string)": {
+ "details": "The unused parameters may be used by overriding contracts.",
+ "params": {
+ "_choice": "The choice being voted for",
+ "_salt": "A random salt for commitment"
+ },
+ "returns": {
+ "_0": "bytes32 The hash of the encoded vote parameters"
+ }
+ },
+ "initialize(address,address,address,uint256)": {
"params": {
"_core": "The KlerosCore arbitrator.",
- "_governor": "The governor's address."
+ "_jumpDisputeKitID": "The ID of the dispute kit to switch to after the court jump.",
+ "_owner": "The owner's address.",
+ "_wNative": "The wrapped native token address, typically wETH."
+ }
+ },
+ "isAppealFunded(uint256)": {
+ "details": "This function is to be called directly by the core contract and is not for off-chain usage.",
+ "params": {
+ "_coreDisputeID": "The ID of the dispute in Kleros Core, not in the Dispute Kit."
+ },
+ "returns": {
+ "_0": "Whether the appeal funding is finished."
}
},
"isVoteActive(uint256,uint256,uint256)": {
- "details": "Returns true if the specified voter was active in this round.",
"params": {
"_coreDisputeID": "The ID of the dispute in Kleros Core, not in the Dispute Kit.",
"_coreRoundID": "The ID of the round in Kleros Core, not in the Dispute Kit.",
@@ -1188,17 +1654,17 @@
}
},
"proxiableUUID()": {
- "details": "Implementation of the ERC1822 `proxiableUUID` function. This returns the storage slot used by the implementation. It is used to validate the implementation's compatibility when performing an upgrade. IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this function revert if invoked through a proxy. This is guaranteed by the if statement."
+ "details": "IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this function revert if invoked through a proxy. This is guaranteed by the if statement."
},
"upgradeToAndCall(address,bytes)": {
- "details": "Upgrade mechanism including access control and UUPS-compliance.Reverts if the execution is not performed via delegatecall or the execution context is not of a proxy with an ERC1967-compliant implementation pointing to self.",
+ "details": "Reverts if the execution is not performed via delegatecall or the execution context is not of a proxy with an ERC1967-compliant implementation pointing to self.",
"params": {
"data": "Data used in a delegate call to `newImplementation` if non-empty. This will typically be an encoded function call, and allows initializing the storage of the proxy like a Solidity constructor.",
"newImplementation": "Address of the new implementation contract."
}
},
"withdrawFeesAndRewards(uint256,address,uint256,uint256)": {
- "details": "Allows those contributors who attempted to fund an appeal round to withdraw any reimbursable fees or rewards after the dispute gets resolved. Note that withdrawals are not possible if the core contract is paused.",
+ "details": "Withdrawals are not possible if the core contract is paused.",
"params": {
"_beneficiary": "The address whose rewards to withdraw.",
"_choice": "The ruling option that the caller wants to withdraw from.",
@@ -1210,7 +1676,15 @@
}
}
},
- "title": "DisputeKitClassic Dispute kit implementation of the Kleros v1 features including: - a drawing system: proportional to staked PNK, - a vote aggregation system: plurality, - an incentive system: equal split between coherent votes, - an appeal system: fund 2 choices only, vote on any choice.",
+ "stateVariables": {
+ "version": {
+ "return": "Version string.",
+ "returns": {
+ "_0": "Version string."
+ }
+ }
+ },
+ "title": "DisputeKitClassic",
"version": 1
},
"userdoc": {
@@ -1224,50 +1698,210 @@
{
"notice": "The `implementation` is not UUPS-compliant"
}
+ ],
+ "UUPSUnauthorizedCallContext()": [
+ {
+ "notice": "The call is from an unauthorized context."
+ }
+ ],
+ "UUPSUnsupportedProxiableUUID(bytes32)": [
+ {
+ "notice": "The storage `slot` is unsupported as a UUID."
+ }
]
},
"events": {
+ "ChoiceFunded(uint256,uint256,uint256)": {
+ "notice": "To be emitted when a choice is fully funded for an appeal."
+ },
+ "CommitCast(uint256,address,uint256[],bytes32)": {
+ "notice": "To be emitted when a vote commitment is cast."
+ },
+ "Contribution(uint256,uint256,uint256,address,uint256)": {
+ "notice": "To be emitted when a funding contribution is made."
+ },
+ "DisputeCreation(uint256,uint256,bytes)": {
+ "notice": "To be emitted when a dispute is created."
+ },
"Upgraded(address)": {
"notice": "Emitted when the `implementation` has been successfully upgraded."
+ },
+ "VoteCast(uint256,address,uint256[],uint256,string)": {
+ "notice": "Emitted when casting a vote to provide the justification of juror's choice."
+ },
+ "Withdrawal(uint256,uint256,uint256,address,uint256)": {
+ "notice": "To be emitted when the contributed funds are withdrawn."
}
},
"kind": "user",
- "methods": {},
+ "methods": {
+ "areCommitsAllCast(uint256)": {
+ "notice": "Returns true if all of the jurors have cast their commits for the last round."
+ },
+ "areVotesAllCast(uint256)": {
+ "notice": "Returns true if all of the jurors have cast their votes for the last round."
+ },
+ "castCommit(uint256,uint256[],bytes32)": {
+ "notice": "Sets the caller's commit for the specified votes."
+ },
+ "castVote(uint256,uint256[],uint256,uint256,string)": {
+ "notice": "Sets the caller's choices for the specified votes."
+ },
+ "changeCore(address)": {
+ "notice": "Changes the `core` storage variable."
+ },
+ "changeJumpDisputeKitID(uint256)": {
+ "notice": "Changes the dispute kit ID used for the jump."
+ },
+ "changeOwner(address)": {
+ "notice": "Changes the `owner` storage variable."
+ },
+ "createDispute(uint256,uint256,bytes,uint256)": {
+ "notice": "Creates a local dispute and maps it to the dispute ID in the Core contract."
+ },
+ "currentRuling(uint256)": {
+ "notice": "Gets the current ruling of a specified dispute."
+ },
+ "draw(uint256,uint256)": {
+ "notice": "Draws the juror from the sortition tree. The drawn address is picked up by Kleros Core."
+ },
+ "executeOwnerProposal(address,uint256,bytes)": {
+ "notice": "Allows the owner to call anything on behalf of the contract."
+ },
+ "fundAppeal(uint256,uint256)": {
+ "notice": "Manages contributions, and appeals a dispute if at least two choices are fully funded. Note that the surplus deposit will be reimbursed."
+ },
+ "getCoherentCount(uint256,uint256)": {
+ "notice": "Gets the number of jurors who are eligible to a reward in this round."
+ },
+ "getDegreeOfCoherencePenalty(uint256,uint256,uint256,uint256,uint256)": {
+ "notice": "Gets the degree of coherence of a particular voter."
+ },
+ "getDegreeOfCoherenceReward(uint256,uint256,uint256,uint256,uint256)": {
+ "notice": "Gets the degree of coherence of a particular voter."
+ },
+ "getFundedChoices(uint256)": {
+ "notice": "Returns the rulings that were fully funded in the latest appeal round."
+ },
+ "getJumpDisputeKitID()": {
+ "notice": "Returns the dispute kit ID to be used after court jump by Kleros Core."
+ },
+ "getLocalDisputeRoundID(uint256,uint256)": {
+ "notice": "Returns the local dispute ID and round ID for a given core dispute ID and core round ID."
+ },
+ "getNbVotesAfterAppeal(address,uint256)": {
+ "notice": "Returns the number of votes after the appeal."
+ },
+ "getNumberOfRounds(uint256)": {
+ "notice": "Returns the number of rounds in a dispute."
+ },
+ "getRoundInfo(uint256,uint256,uint256)": {
+ "notice": "Returns the info of the specified round in the core contract."
+ },
+ "getVoteInfo(uint256,uint256,uint256)": {
+ "notice": "Returns the vote information for a given vote ID."
+ },
+ "hashVote(uint256,uint256,string)": {
+ "notice": "Computes the hash of a vote using ABI encoding"
+ },
+ "initialize(address,address,address,uint256)": {
+ "notice": "Initializer."
+ },
+ "isAppealFunded(uint256)": {
+ "notice": "Returns true if the appeal funding is finished prematurely (e.g. when losing side didn't fund)."
+ },
+ "isVoteActive(uint256,uint256,uint256)": {
+ "notice": "Returns true if the specified voter was active in this round."
+ },
+ "proxiableUUID()": {
+ "notice": "Implementation of the ERC1822 `proxiableUUID` function. This returns the storage slot used by the implementation. It is used to validate the implementation's compatibility when performing an upgrade."
+ },
+ "upgradeToAndCall(address,bytes)": {
+ "notice": "Upgrade mechanism including access control and UUPS-compliance."
+ },
+ "version()": {
+ "notice": "Returns the version of the implementation."
+ },
+ "withdrawFeesAndRewards(uint256,address,uint256,uint256)": {
+ "notice": "Allows those contributors who attempted to fund an appeal round to withdraw any reimbursable fees or rewards after the dispute gets resolved."
+ }
+ },
+ "notice": "Dispute kit implementation of the Kleros v1 features including: - a drawing system: proportional to staked PNK, - a vote aggregation system: plurality, - an incentive system: equal split between coherent votes, - an appeal system: fund 2 choices only, vote on any choice.",
"version": 1
},
"storageLayout": {
"storage": [
{
- "astId": 17736,
+ "astId": 21251,
"contract": "src/arbitration/dispute-kits/DisputeKitClassic.sol:DisputeKitClassic",
- "label": "governor",
+ "label": "owner",
"offset": 0,
"slot": "0",
"type": "t_address"
},
{
- "astId": 17739,
+ "astId": 21254,
"contract": "src/arbitration/dispute-kits/DisputeKitClassic.sol:DisputeKitClassic",
"label": "core",
"offset": 0,
"slot": "1",
- "type": "t_contract(KlerosCore)7051"
+ "type": "t_contract(KlerosCore)15195"
},
{
- "astId": 17743,
+ "astId": 21258,
"contract": "src/arbitration/dispute-kits/DisputeKitClassic.sol:DisputeKitClassic",
"label": "disputes",
"offset": 0,
"slot": "2",
- "type": "t_array(t_struct(Dispute)17675_storage)dyn_storage"
+ "type": "t_array(t_struct(Dispute)21183_storage)dyn_storage"
},
{
- "astId": 17747,
+ "astId": 21262,
"contract": "src/arbitration/dispute-kits/DisputeKitClassic.sol:DisputeKitClassic",
"label": "coreDisputeIDToLocal",
"offset": 0,
"slot": "3",
"type": "t_mapping(t_uint256,t_uint256)"
+ },
+ {
+ "astId": 21264,
+ "contract": "src/arbitration/dispute-kits/DisputeKitClassic.sol:DisputeKitClassic",
+ "label": "singleDrawPerJuror",
+ "offset": 0,
+ "slot": "4",
+ "type": "t_bool"
+ },
+ {
+ "astId": 21268,
+ "contract": "src/arbitration/dispute-kits/DisputeKitClassic.sol:DisputeKitClassic",
+ "label": "coreDisputeIDToActive",
+ "offset": 0,
+ "slot": "5",
+ "type": "t_mapping(t_uint256,t_bool)"
+ },
+ {
+ "astId": 21270,
+ "contract": "src/arbitration/dispute-kits/DisputeKitClassic.sol:DisputeKitClassic",
+ "label": "wNative",
+ "offset": 0,
+ "slot": "6",
+ "type": "t_address"
+ },
+ {
+ "astId": 21272,
+ "contract": "src/arbitration/dispute-kits/DisputeKitClassic.sol:DisputeKitClassic",
+ "label": "jumpDisputeKitID",
+ "offset": 0,
+ "slot": "7",
+ "type": "t_uint256"
+ },
+ {
+ "astId": 21276,
+ "contract": "src/arbitration/dispute-kits/DisputeKitClassic.sol:DisputeKitClassic",
+ "label": "__gap",
+ "offset": 0,
+ "slot": "8",
+ "type": "t_array(t_uint256)50_storage"
}
],
"types": {
@@ -1276,24 +1910,36 @@
"label": "address",
"numberOfBytes": "20"
},
- "t_array(t_struct(Dispute)17675_storage)dyn_storage": {
- "base": "t_struct(Dispute)17675_storage",
+ "t_array(t_struct(Dispute)21183_storage)dyn_storage": {
+ "base": "t_struct(Dispute)21183_storage",
"encoding": "dynamic_array",
- "label": "struct DisputeKitClassic.Dispute[]",
+ "label": "struct DisputeKitClassicBase.Dispute[]",
"numberOfBytes": "32"
},
- "t_array(t_struct(Round)17713_storage)dyn_storage": {
- "base": "t_struct(Round)17713_storage",
+ "t_array(t_struct(Round)21227_storage)dyn_storage": {
+ "base": "t_struct(Round)21227_storage",
"encoding": "dynamic_array",
- "label": "struct DisputeKitClassic.Round[]",
+ "label": "struct DisputeKitClassicBase.Round[]",
"numberOfBytes": "32"
},
- "t_array(t_struct(Vote)17722_storage)dyn_storage": {
- "base": "t_struct(Vote)17722_storage",
+ "t_array(t_struct(Vote)21240_storage)dyn_storage": {
+ "base": "t_struct(Vote)21240_storage",
"encoding": "dynamic_array",
- "label": "struct DisputeKitClassic.Vote[]",
+ "label": "struct DisputeKitClassicBase.Vote[]",
"numberOfBytes": "32"
},
+ "t_array(t_uint256)10_storage": {
+ "base": "t_uint256",
+ "encoding": "inplace",
+ "label": "uint256[10]",
+ "numberOfBytes": "320"
+ },
+ "t_array(t_uint256)50_storage": {
+ "base": "t_uint256",
+ "encoding": "inplace",
+ "label": "uint256[50]",
+ "numberOfBytes": "1600"
+ },
"t_array(t_uint256)dyn_storage": {
"base": "t_uint256",
"encoding": "dynamic_array",
@@ -1315,11 +1961,18 @@
"label": "bytes",
"numberOfBytes": "32"
},
- "t_contract(KlerosCore)7051": {
+ "t_contract(KlerosCore)15195": {
"encoding": "inplace",
"label": "contract KlerosCore",
"numberOfBytes": "20"
},
+ "t_mapping(t_address,t_bool)": {
+ "encoding": "mapping",
+ "key": "t_address",
+ "label": "mapping(address => bool)",
+ "numberOfBytes": "32",
+ "value": "t_bool"
+ },
"t_mapping(t_address,t_mapping(t_uint256,t_uint256))": {
"encoding": "mapping",
"key": "t_address",
@@ -1341,20 +1994,20 @@
"numberOfBytes": "32",
"value": "t_uint256"
},
- "t_struct(Dispute)17675_storage": {
+ "t_struct(Dispute)21183_storage": {
"encoding": "inplace",
- "label": "struct DisputeKitClassic.Dispute",
+ "label": "struct DisputeKitClassicBase.Dispute",
"members": [
{
- "astId": 17664,
+ "astId": 21168,
"contract": "src/arbitration/dispute-kits/DisputeKitClassic.sol:DisputeKitClassic",
"label": "rounds",
"offset": 0,
"slot": "0",
- "type": "t_array(t_struct(Round)17713_storage)dyn_storage"
+ "type": "t_array(t_struct(Round)21227_storage)dyn_storage"
},
{
- "astId": 17666,
+ "astId": 21170,
"contract": "src/arbitration/dispute-kits/DisputeKitClassic.sol:DisputeKitClassic",
"label": "numberOfChoices",
"offset": 0,
@@ -1362,7 +2015,7 @@
"type": "t_uint256"
},
{
- "astId": 17668,
+ "astId": 21172,
"contract": "src/arbitration/dispute-kits/DisputeKitClassic.sol:DisputeKitClassic",
"label": "jumped",
"offset": 0,
@@ -1370,7 +2023,7 @@
"type": "t_bool"
},
{
- "astId": 17672,
+ "astId": 21176,
"contract": "src/arbitration/dispute-kits/DisputeKitClassic.sol:DisputeKitClassic",
"label": "coreRoundIDToLocal",
"offset": 0,
@@ -1378,30 +2031,38 @@
"type": "t_mapping(t_uint256,t_uint256)"
},
{
- "astId": 17674,
+ "astId": 21178,
"contract": "src/arbitration/dispute-kits/DisputeKitClassic.sol:DisputeKitClassic",
"label": "extraData",
"offset": 0,
"slot": "4",
"type": "t_bytes_storage"
+ },
+ {
+ "astId": 21182,
+ "contract": "src/arbitration/dispute-kits/DisputeKitClassic.sol:DisputeKitClassic",
+ "label": "__gap",
+ "offset": 0,
+ "slot": "5",
+ "type": "t_array(t_uint256)10_storage"
}
],
- "numberOfBytes": "160"
+ "numberOfBytes": "480"
},
- "t_struct(Round)17713_storage": {
+ "t_struct(Round)21227_storage": {
"encoding": "inplace",
- "label": "struct DisputeKitClassic.Round",
+ "label": "struct DisputeKitClassicBase.Round",
"members": [
{
- "astId": 17679,
+ "astId": 21187,
"contract": "src/arbitration/dispute-kits/DisputeKitClassic.sol:DisputeKitClassic",
"label": "votes",
"offset": 0,
"slot": "0",
- "type": "t_array(t_struct(Vote)17722_storage)dyn_storage"
+ "type": "t_array(t_struct(Vote)21240_storage)dyn_storage"
},
{
- "astId": 17681,
+ "astId": 21189,
"contract": "src/arbitration/dispute-kits/DisputeKitClassic.sol:DisputeKitClassic",
"label": "winningChoice",
"offset": 0,
@@ -1409,7 +2070,7 @@
"type": "t_uint256"
},
{
- "astId": 17685,
+ "astId": 21193,
"contract": "src/arbitration/dispute-kits/DisputeKitClassic.sol:DisputeKitClassic",
"label": "counts",
"offset": 0,
@@ -1417,7 +2078,7 @@
"type": "t_mapping(t_uint256,t_uint256)"
},
{
- "astId": 17687,
+ "astId": 21195,
"contract": "src/arbitration/dispute-kits/DisputeKitClassic.sol:DisputeKitClassic",
"label": "tied",
"offset": 0,
@@ -1425,7 +2086,7 @@
"type": "t_bool"
},
{
- "astId": 17689,
+ "astId": 21197,
"contract": "src/arbitration/dispute-kits/DisputeKitClassic.sol:DisputeKitClassic",
"label": "totalVoted",
"offset": 0,
@@ -1433,7 +2094,7 @@
"type": "t_uint256"
},
{
- "astId": 17691,
+ "astId": 21199,
"contract": "src/arbitration/dispute-kits/DisputeKitClassic.sol:DisputeKitClassic",
"label": "totalCommitted",
"offset": 0,
@@ -1441,7 +2102,7 @@
"type": "t_uint256"
},
{
- "astId": 17695,
+ "astId": 21203,
"contract": "src/arbitration/dispute-kits/DisputeKitClassic.sol:DisputeKitClassic",
"label": "paidFees",
"offset": 0,
@@ -1449,7 +2110,7 @@
"type": "t_mapping(t_uint256,t_uint256)"
},
{
- "astId": 17699,
+ "astId": 21207,
"contract": "src/arbitration/dispute-kits/DisputeKitClassic.sol:DisputeKitClassic",
"label": "hasPaid",
"offset": 0,
@@ -1457,7 +2118,7 @@
"type": "t_mapping(t_uint256,t_bool)"
},
{
- "astId": 17705,
+ "astId": 21213,
"contract": "src/arbitration/dispute-kits/DisputeKitClassic.sol:DisputeKitClassic",
"label": "contributions",
"offset": 0,
@@ -1465,7 +2126,7 @@
"type": "t_mapping(t_address,t_mapping(t_uint256,t_uint256))"
},
{
- "astId": 17707,
+ "astId": 21215,
"contract": "src/arbitration/dispute-kits/DisputeKitClassic.sol:DisputeKitClassic",
"label": "feeRewards",
"offset": 0,
@@ -1473,7 +2134,7 @@
"type": "t_uint256"
},
{
- "astId": 17710,
+ "astId": 21218,
"contract": "src/arbitration/dispute-kits/DisputeKitClassic.sol:DisputeKitClassic",
"label": "fundedChoices",
"offset": 0,
@@ -1481,30 +2142,46 @@
"type": "t_array(t_uint256)dyn_storage"
},
{
- "astId": 17712,
+ "astId": 21222,
"contract": "src/arbitration/dispute-kits/DisputeKitClassic.sol:DisputeKitClassic",
- "label": "nbVotes",
+ "label": "alreadyDrawn",
"offset": 0,
"slot": "11",
- "type": "t_uint256"
+ "type": "t_mapping(t_address,t_bool)"
+ },
+ {
+ "astId": 21226,
+ "contract": "src/arbitration/dispute-kits/DisputeKitClassic.sol:DisputeKitClassic",
+ "label": "__gap",
+ "offset": 0,
+ "slot": "12",
+ "type": "t_array(t_uint256)10_storage"
}
],
- "numberOfBytes": "384"
+ "numberOfBytes": "704"
},
- "t_struct(Vote)17722_storage": {
+ "t_struct(Vote)21240_storage": {
"encoding": "inplace",
- "label": "struct DisputeKitClassic.Vote",
+ "label": "struct DisputeKitClassicBase.Vote",
"members": [
{
- "astId": 17715,
+ "astId": 21229,
"contract": "src/arbitration/dispute-kits/DisputeKitClassic.sol:DisputeKitClassic",
- "label": "account",
+ "label": "voted",
"offset": 0,
"slot": "0",
+ "type": "t_bool"
+ },
+ {
+ "astId": 21231,
+ "contract": "src/arbitration/dispute-kits/DisputeKitClassic.sol:DisputeKitClassic",
+ "label": "account",
+ "offset": 1,
+ "slot": "0",
"type": "t_address"
},
{
- "astId": 17717,
+ "astId": 21233,
"contract": "src/arbitration/dispute-kits/DisputeKitClassic.sol:DisputeKitClassic",
"label": "commit",
"offset": 0,
@@ -1512,7 +2189,7 @@
"type": "t_bytes32"
},
{
- "astId": 17719,
+ "astId": 21235,
"contract": "src/arbitration/dispute-kits/DisputeKitClassic.sol:DisputeKitClassic",
"label": "choice",
"offset": 0,
@@ -1520,15 +2197,15 @@
"type": "t_uint256"
},
{
- "astId": 17721,
+ "astId": 21239,
"contract": "src/arbitration/dispute-kits/DisputeKitClassic.sol:DisputeKitClassic",
- "label": "voted",
+ "label": "__gap",
"offset": 0,
"slot": "3",
- "type": "t_bool"
+ "type": "t_array(t_uint256)10_storage"
}
],
- "numberOfBytes": "128"
+ "numberOfBytes": "416"
},
"t_uint256": {
"encoding": "inplace",
diff --git a/contracts/deployments/arbitrumSepoliaDevnet/DisputeKitClassicUniversity_Proxy.json b/contracts/deployments/arbitrumSepoliaDevnet/DisputeKitClassicUniversity_Proxy.json
index 90c310630..9e6ff1681 100644
--- a/contracts/deployments/arbitrumSepoliaDevnet/DisputeKitClassicUniversity_Proxy.json
+++ b/contracts/deployments/arbitrumSepoliaDevnet/DisputeKitClassicUniversity_Proxy.json
@@ -1,5 +1,5 @@
{
- "address": "0xd6E96b7c993763B5CDDa1139C7387B82A7c8B8B5",
+ "address": "0x82F2089442979A6b56c80274D144575980092F91",
"abi": [
{
"inputs": [
@@ -26,44 +26,44 @@
"type": "receive"
}
],
- "transactionHash": "0xbe90d4066f62381a1a2c725364c3d35093e1ff685736f3fa0a7b75c3b0e82f93",
+ "transactionHash": "0xbc5117fa79c44f4304b16dfe26f072d80a71dce7cf9986f10f363c6e20457bd5",
"receipt": {
"to": null,
"from": "0xf1C7c037891525E360C59f708739Ac09A7670c59",
- "contractAddress": "0xd6E96b7c993763B5CDDa1139C7387B82A7c8B8B5",
- "transactionIndex": 1,
- "gasUsed": "189732",
- "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000004000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
- "blockHash": "0x1e4647532736ec4a239971727f05a17b1bb50fc89c0ec7a8da6e34f4f5bfcc90",
- "transactionHash": "0xbe90d4066f62381a1a2c725364c3d35093e1ff685736f3fa0a7b75c3b0e82f93",
+ "contractAddress": "0x82F2089442979A6b56c80274D144575980092F91",
+ "transactionIndex": 2,
+ "gasUsed": "205891",
+ "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000080000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ "blockHash": "0x11a1f340150df5f9ad32caef5cb1157e97be0914fb56af4c3835a86a743a5184",
+ "transactionHash": "0xbc5117fa79c44f4304b16dfe26f072d80a71dce7cf9986f10f363c6e20457bd5",
"logs": [
{
- "transactionIndex": 1,
- "blockNumber": 96308536,
- "transactionHash": "0xbe90d4066f62381a1a2c725364c3d35093e1ff685736f3fa0a7b75c3b0e82f93",
- "address": "0xd6E96b7c993763B5CDDa1139C7387B82A7c8B8B5",
+ "transactionIndex": 2,
+ "blockNumber": 193533776,
+ "transactionHash": "0xbc5117fa79c44f4304b16dfe26f072d80a71dce7cf9986f10f363c6e20457bd5",
+ "address": "0x82F2089442979A6b56c80274D144575980092F91",
"topics": [
"0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2"
],
"data": "0x0000000000000000000000000000000000000000000000000000000000000001",
- "logIndex": 0,
- "blockHash": "0x1e4647532736ec4a239971727f05a17b1bb50fc89c0ec7a8da6e34f4f5bfcc90"
+ "logIndex": 4,
+ "blockHash": "0x11a1f340150df5f9ad32caef5cb1157e97be0914fb56af4c3835a86a743a5184"
}
],
- "blockNumber": 96308536,
- "cumulativeGasUsed": "189732",
+ "blockNumber": 193533776,
+ "cumulativeGasUsed": "320063",
"status": 1,
"byzantium": true
},
"args": [
- "0x87e863b94d2CB79A8aB53bD87Dc4A10E11C0918B",
- "0x485cc955000000000000000000000000f1c7c037891525e360c59f708739ac09a7670c590000000000000000000000000000000000000000000000000000000000000000"
+ "0x602ADa1cE706404BFb5417e497cdDae934436081",
+ "0xcf756fdf000000000000000000000000f1c7c037891525e360c59f708739ac09a7670c5900000000000000000000000000000000000000000000000000000000000000000000000000000000000000003829a2486d53ee984a0ca2d76552715726b771380000000000000000000000000000000000000000000000000000000000000001"
],
"numDeployments": 1,
- "solcInputHash": "a5602534c00c2f67ca4b6a1cab8c717e",
- "metadata": "{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_implementation\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"stateMutability\":\"payable\",\"type\":\"fallback\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/proxy/KlerosProxies.sol\":\"DisputeKitClassicUniversityProxy\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":100},\"remappings\":[]},\"sources\":{\"src/proxy/KlerosProxies.sol\":{\"content\":\"//SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.24;\\n\\nimport \\\"./UUPSProxy.sol\\\";\\n\\n/// Workaround to get meaningful names for the proxy contracts\\n/// Otherwise all the contracts are called `UUPSProxy` on the chain explorers\\n\\ncontract DisputeKitClassicNeoProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract DisputeKitClassicUniversityProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract DisputeKitClassicProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract DisputeTemplateRegistryProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract EvidenceModuleProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract ForeignGatewayOnEthereumProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract HomeGatewayToEthereumProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract KlerosCoreNeoProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract KlerosCoreRulerProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract KlerosCoreUniversityProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract KlerosCoreProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract PolicyRegistryProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract RandomizerRNGProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract SortitionModuleNeoProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract SortitionModuleUniversityProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract SortitionModuleProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\",\"keccak256\":\"0x4393c05bbfda204b9992e1e546142a0fbf4c92a1c4061f5985463d02a71b84d4\",\"license\":\"MIT\"},\"src/proxy/UUPSProxy.sol\":{\"content\":\"//SPDX-License-Identifier: MIT\\n// Adapted from \\n\\n/**\\n * @authors: [@malatrax]\\n * @reviewers: []\\n * @auditors: []\\n * @bounties: []\\n * @deployments: []\\n */\\npragma solidity 0.8.24;\\n\\n/**\\n * @title UUPS Proxy\\n * @author Simon Malatrait \\n * @dev This contract implements a UUPS Proxy compliant with ERC-1967 & ERC-1822.\\n * @dev This contract delegates all calls to another contract (UUPS Proxiable) through a fallback function and the use of the `delegatecall` EVM instruction.\\n * @dev We refer to the Proxiable contract (as per ERC-1822) with `implementation`.\\n */\\ncontract UUPSProxy {\\n /**\\n * @dev Storage slot with the address of the current implementation.\\n * This is the keccak-256 hash of \\\"eip1967.proxy.implementation\\\" subtracted by 1, and is\\n * validated in the constructor.\\n * NOTE: bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1)\\n */\\n bytes32 private constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\\n\\n // ************************************* //\\n // * Constructor * //\\n // ************************************* //\\n\\n /**\\n * @dev Initializes the upgradeable proxy with an initial implementation specified by `_implementation`.\\n *\\n * If `_data` is nonempty, it's used as data in a delegate call to `_implementation`. This will typically be an encoded\\n * function call, and allows initializing the storage of the proxy like a Solidity constructor.\\n */\\n constructor(address _implementation, bytes memory _data) {\\n assembly {\\n sstore(IMPLEMENTATION_SLOT, _implementation)\\n }\\n\\n if (_data.length != 0) {\\n (bool success, ) = _implementation.delegatecall(_data);\\n require(success, \\\"Proxy Constructor failed\\\");\\n }\\n }\\n\\n // ************************************* //\\n // * State Modifiers * //\\n // ************************************* //\\n\\n /**\\n * @dev Delegates the current call to `implementation`.\\n *\\n * NOTE: This function does not return to its internal call site, it will return directly to the external caller.\\n */\\n function _delegate(address implementation) internal {\\n assembly {\\n // Copy msg.data. We take full control of memory in this inline assembly\\n // block because it will not return to Solidity code. We overwrite the\\n // Solidity scratch pad at memory position 0.\\n calldatacopy(0, 0, calldatasize())\\n\\n // Call the implementation.\\n // out and outsize are 0 because we don't know the size yet.\\n let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)\\n\\n // Copy the returned data.\\n returndatacopy(0, 0, returndatasize())\\n\\n switch result\\n // delegatecall returns 0 on error.\\n case 0 {\\n revert(0, returndatasize())\\n }\\n default {\\n return(0, returndatasize())\\n }\\n }\\n }\\n\\n // ************************************* //\\n // * Internal Views * //\\n // ************************************* //\\n\\n function _getImplementation() internal view returns (address implementation) {\\n assembly {\\n implementation := sload(IMPLEMENTATION_SLOT)\\n }\\n }\\n\\n // ************************************* //\\n // * Fallback * //\\n // ************************************* //\\n\\n /**\\n * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other\\n * function in the contract matches the call data.\\n */\\n fallback() external payable {\\n _delegate(_getImplementation());\\n }\\n\\n receive() external payable {\\n _delegate(_getImplementation());\\n }\\n}\\n\",\"keccak256\":\"0x7aa5f14ce351299722ac1a1afca9e65e1c795f32ea3e9702b0d5faaf7ca822a0\",\"license\":\"MIT\"}},\"version\":1}",
- "bytecode": "0x608060405234801561001057600080fd5b5060405161030238038061030283398101604081905261002f91610151565b8181817f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc55805160001461010e576000826001600160a01b031682604051610077919061021f565b600060405180830381855af49150503d80600081146100b2576040519150601f19603f3d011682016040523d82523d6000602084013e6100b7565b606091505b505090508061010c5760405162461bcd60e51b815260206004820152601860248201527f50726f787920436f6e7374727563746f72206661696c65640000000000000000604482015260640160405180910390fd5b505b5050505061023b565b634e487b7160e01b600052604160045260246000fd5b60005b83811015610148578181015183820152602001610130565b50506000910152565b6000806040838503121561016457600080fd5b82516001600160a01b038116811461017b57600080fd5b60208401519092506001600160401b038082111561019857600080fd5b818501915085601f8301126101ac57600080fd5b8151818111156101be576101be610117565b604051601f8201601f19908116603f011681019083821181831017156101e6576101e6610117565b816040528281528860208487010111156101ff57600080fd5b61021083602083016020880161012d565b80955050505050509250929050565b6000825161023181846020870161012d565b9190910192915050565b60b9806102496000396000f3fe608060405236603757603560317f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5490565b6060565b005b603560317f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5490565b3660008037600080366000845af43d6000803e808015607e573d6000f35b3d6000fdfea2646970667358221220a67e53546ab2c83f023c185d90506ad48d4e7af6339cf6db0c4ed97ec9ed376f64736f6c63430008180033",
- "deployedBytecode": "0x608060405236603757603560317f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5490565b6060565b005b603560317f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5490565b3660008037600080366000845af43d6000803e808015607e573d6000f35b3d6000fdfea2646970667358221220a67e53546ab2c83f023c185d90506ad48d4e7af6339cf6db0c4ed97ec9ed376f64736f6c63430008180033",
+ "solcInputHash": "d547d738900bce1310e91a5d1adfc179",
+ "metadata": "{\"compiler\":{\"version\":\"0.8.30+commit.73712a01\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_implementation\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"stateMutability\":\"payable\",\"type\":\"fallback\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"notice\":\"Workaround to get meaningful names for the proxy contracts Otherwise all the contracts are called `UUPSProxy` on the chain explorers\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/proxy/KlerosProxies.sol\":\"DisputeKitClassicUniversityProxy\"},\"evmVersion\":\"cancun\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000},\"remappings\":[],\"viaIR\":true},\"sources\":{\"src/proxy/KlerosProxies.sol\":{\"content\":\"//SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.24;\\n\\nimport \\\"./UUPSProxy.sol\\\";\\n\\n/// Workaround to get meaningful names for the proxy contracts\\n/// Otherwise all the contracts are called `UUPSProxy` on the chain explorers\\n\\ncontract DisputeKitClassicUniversityProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract DisputeKitClassicProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract DisputeKitGatedProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract DisputeKitGatedShutterProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract DisputeKitShutterProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract DisputeKitSybilResistantProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract DisputeTemplateRegistryProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract EvidenceModuleProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract ForeignGatewayOnEthereumProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract HomeGatewayToEthereumProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract KlerosCoreRulerProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract KlerosCoreUniversityProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract KlerosCoreProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract PolicyRegistryProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract RandomizerRNGProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract SortitionModuleUniversityProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract SortitionModuleProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\",\"keccak256\":\"0x3160bd320b23c6ec0c21862b455c3044a9b33654ae84a1b6cd76255626c9154b\",\"license\":\"MIT\"},\"src/proxy/UUPSProxy.sol\":{\"content\":\"//SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.24;\\n\\n/// @title UUPS Proxy\\n/// @author Simon Malatrait \\n/// @notice This contract implements a UUPS Proxy compliant with ERC-1967 & ERC-1822.\\n///\\n/// @dev This contract delegates all calls to another contract (UUPS Proxiable) through a fallback function and the use of the `delegatecall` EVM instruction.\\n/// We refer to the Proxiable contract (as per ERC-1822) with `implementation`.\\n/// Adapted from \\ncontract UUPSProxy {\\n /// @dev Storage slot with the address of the current implementation.\\n /// This is the keccak-256 hash of \\\"eip1967.proxy.implementation\\\" subtracted by 1, and is\\n /// validated in the constructor.\\n /// NOTE: bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1)\\n bytes32 private constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\\n\\n // ************************************* //\\n // * Constructor * //\\n // ************************************* //\\n\\n /// @notice Initializes the upgradeable proxy with an initial implementation specified by `_implementation`.\\n /// @dev If `_data` is nonempty, it's used as data in a delegate call to `_implementation`.\\n /// This will typically be an encoded function call, and allows initializing the storage of the proxy like a Solidity constructor.\\n constructor(address _implementation, bytes memory _data) {\\n assembly {\\n sstore(IMPLEMENTATION_SLOT, _implementation)\\n }\\n\\n if (_data.length != 0) {\\n (bool success, ) = _implementation.delegatecall(_data);\\n require(success, \\\"Proxy Constructor failed\\\");\\n }\\n }\\n\\n // ************************************* //\\n // * State Modifiers * //\\n // ************************************* //\\n\\n /// @dev Delegates the current call to `implementation`.\\n /// NOTE: This function does not return to its internal call site, it will return directly to the external caller.\\n function _delegate(address implementation) internal {\\n assembly {\\n // Copy msg.data. We take full control of memory in this inline assembly\\n // block because it will not return to Solidity code. We overwrite the\\n // Solidity scratch pad at memory position 0.\\n calldatacopy(0, 0, calldatasize())\\n\\n // Call the implementation.\\n // out and outsize are 0 because we don't know the size yet.\\n let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)\\n\\n // Copy the returned data.\\n returndatacopy(0, 0, returndatasize())\\n\\n switch result\\n // delegatecall returns 0 on error.\\n case 0 {\\n revert(0, returndatasize())\\n }\\n default {\\n return(0, returndatasize())\\n }\\n }\\n }\\n\\n // ************************************* //\\n // * Internal Views * //\\n // ************************************* //\\n\\n function _getImplementation() internal view returns (address implementation) {\\n assembly {\\n implementation := sload(IMPLEMENTATION_SLOT)\\n }\\n }\\n\\n // ************************************* //\\n // * Fallback * //\\n // ************************************* //\\n\\n /// @dev Fallback function that delegates calls to the address returned by `_implementation()`.\\n /// @dev Will run if no other function in the contract matches the call data.\\n fallback() external payable {\\n _delegate(_getImplementation());\\n }\\n\\n receive() external payable {\\n _delegate(_getImplementation());\\n }\\n}\\n\",\"keccak256\":\"0x2d7b1f81e525787f1b8b033ce381a81cb5f39e411ff31490e019113205a661cd\",\"license\":\"MIT\"}},\"version\":1}",
+ "bytecode": "0x608060405234610144576102148038038061001981610148565b928339810190604081830312610144578051906001600160a01b0382168203610144576020810151906001600160401b038211610144570182601f8201121561014457805161006f61006a82610181565b610148565b9181835260208301946020838301011161014457815f926020809301875e83010152817f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5551806100c9575b6040516077908161019d8239f35b5f9283925af43d1561013f573d6100e261006a82610181565b9081525f60203d92013e5b156100fa575f80806100bb565b60405162461bcd60e51b815260206004820152601860248201527f50726f787920436f6e7374727563746f72206661696c656400000000000000006044820152606490fd5b6100ed565b5f80fd5b6040519190601f01601f191682016001600160401b0381118382101761016d57604052565b634e487b7160e01b5f52604160045260245ffd5b6001600160401b03811161016d57601f01601f19166020019056fe60806040525f807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc54368280378136915af43d5f803e15603d573d5ff35b3d5ffdfea264697066735822122078e638e186ffb95282090eae06b37667016702ebe14876894d9cb231ea135b1264736f6c634300081e0033",
+ "deployedBytecode": "0x60806040525f807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc54368280378136915af43d5f803e15603d573d5ff35b3d5ffdfea264697066735822122078e638e186ffb95282090eae06b37667016702ebe14876894d9cb231ea135b1264736f6c634300081e0033",
"devdoc": {
"kind": "dev",
"methods": {},
@@ -72,6 +72,7 @@
"userdoc": {
"kind": "user",
"methods": {},
+ "notice": "Workaround to get meaningful names for the proxy contracts Otherwise all the contracts are called `UUPSProxy` on the chain explorers",
"version": 1
},
"storageLayout": {
diff --git a/contracts/deployments/arbitrumSepoliaDevnet/DisputeResolverUniversity.json b/contracts/deployments/arbitrumSepoliaDevnet/DisputeResolverUniversity.json
index df70ac2d7..ced6acaaf 100644
--- a/contracts/deployments/arbitrumSepoliaDevnet/DisputeResolverUniversity.json
+++ b/contracts/deployments/arbitrumSepoliaDevnet/DisputeResolverUniversity.json
@@ -1,5 +1,5 @@
{
- "address": "0x2Aa1a94307E772BeE42E9EfbD137b1053F1fCfd4",
+ "address": "0x8a7902Ef9a5308C7DF0A68A28EEDd6D83436993D",
"abi": [
{
"inputs": [
@@ -17,6 +17,31 @@
"stateMutability": "nonpayable",
"type": "constructor"
},
+ {
+ "inputs": [],
+ "name": "ArbitratorOnly",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "DisputeAlreadyRuled",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "OwnerOnly",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "RulingOutOfBounds",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "ShouldBeAtLeastTwoRulingOptions",
+ "type": "error"
+ },
{
"anonymous": false,
"inputs": [
@@ -43,12 +68,6 @@
"internalType": "uint256",
"name": "_templateId",
"type": "uint256"
- },
- {
- "indexed": false,
- "internalType": "string",
- "name": "_templateUri",
- "type": "string"
}
],
"name": "DisputeRequest",
@@ -128,11 +147,11 @@
"inputs": [
{
"internalType": "address",
- "name": "_governor",
+ "name": "_owner",
"type": "address"
}
],
- "name": "changeGovernor",
+ "name": "changeOwner",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
@@ -184,35 +203,6 @@
"stateMutability": "payable",
"type": "function"
},
- {
- "inputs": [
- {
- "internalType": "bytes",
- "name": "_arbitratorExtraData",
- "type": "bytes"
- },
- {
- "internalType": "string",
- "name": "_disputeTemplateUri",
- "type": "string"
- },
- {
- "internalType": "uint256",
- "name": "_numberOfRulingOptions",
- "type": "uint256"
- }
- ],
- "name": "createDisputeForTemplateUri",
- "outputs": [
- {
- "internalType": "uint256",
- "name": "disputeID",
- "type": "uint256"
- }
- ],
- "stateMutability": "payable",
- "type": "function"
- },
{
"inputs": [
{
@@ -249,7 +239,7 @@
},
{
"inputs": [],
- "name": "governor",
+ "name": "owner",
"outputs": [
{
"internalType": "address",
@@ -292,45 +282,43 @@
"type": "function"
}
],
- "transactionHash": "0x6e6144da838df488664fec992cf96ff6d6d7e6d6b2239d15dbaa4db970be6116",
+ "transactionHash": "0x4f3a4aa6c10dc5486a14af9edbc0f2115240604e431b9902d5694f2e9bd893de",
"receipt": {
"to": null,
"from": "0xf1C7c037891525E360C59f708739Ac09A7670c59",
- "contractAddress": "0x2Aa1a94307E772BeE42E9EfbD137b1053F1fCfd4",
+ "contractAddress": "0x8a7902Ef9a5308C7DF0A68A28EEDd6D83436993D",
"transactionIndex": 1,
- "gasUsed": "935568",
+ "gasUsed": "676666",
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
- "blockHash": "0x581b5decfadcbf1085c9383e7378b7f2738f8a0050031424ce6c036cf809ff5d",
- "transactionHash": "0x6e6144da838df488664fec992cf96ff6d6d7e6d6b2239d15dbaa4db970be6116",
+ "blockHash": "0x9775b98bdf7d48f5236d3471c48cef965244309e2f8efa2435e030236005bc91",
+ "transactionHash": "0x4f3a4aa6c10dc5486a14af9edbc0f2115240604e431b9902d5694f2e9bd893de",
"logs": [],
- "blockNumber": 96308731,
- "cumulativeGasUsed": "935568",
+ "blockNumber": 193533879,
+ "cumulativeGasUsed": "676666",
"status": 1,
"byzantium": true
},
"args": [
- "0x5AB37F38778Bc175852fA353056591D91c744ce6",
- "0x596D3B09E684D62217682216e9b7a0De75933391"
+ "0xA34dBBD0E5e1d09bd683455f9dbC393797BC558f",
+ "0xc852F94f90E3B06Da6eCfB61d76561ECfb94613f"
],
"numDeployments": 1,
- "solcInputHash": "a5602534c00c2f67ca4b6a1cab8c717e",
- "metadata": "{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract IArbitratorV2\",\"name\":\"_arbitrator\",\"type\":\"address\"},{\"internalType\":\"contract IDisputeTemplateRegistry\",\"name\":\"_templateRegistry\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"contract IArbitratorV2\",\"name\":\"_arbitrator\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_arbitratorDisputeID\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_externalDisputeID\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_templateId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"_templateUri\",\"type\":\"string\"}],\"name\":\"DisputeRequest\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"contract IArbitratorV2\",\"name\":\"_arbitrator\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_disputeID\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_ruling\",\"type\":\"uint256\"}],\"name\":\"Ruling\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"arbitrator\",\"outputs\":[{\"internalType\":\"contract IArbitratorV2\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"arbitratorDisputeIDToLocalID\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract IArbitratorV2\",\"name\":\"_arbitrator\",\"type\":\"address\"}],\"name\":\"changeArbitrator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_governor\",\"type\":\"address\"}],\"name\":\"changeGovernor\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract IDisputeTemplateRegistry\",\"name\":\"_templateRegistry\",\"type\":\"address\"}],\"name\":\"changeTemplateRegistry\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_arbitratorExtraData\",\"type\":\"bytes\"},{\"internalType\":\"string\",\"name\":\"_disputeTemplate\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"_disputeTemplateDataMappings\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"_numberOfRulingOptions\",\"type\":\"uint256\"}],\"name\":\"createDisputeForTemplate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"disputeID\",\"type\":\"uint256\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_arbitratorExtraData\",\"type\":\"bytes\"},{\"internalType\":\"string\",\"name\":\"_disputeTemplateUri\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"_numberOfRulingOptions\",\"type\":\"uint256\"}],\"name\":\"createDisputeForTemplateUri\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"disputeID\",\"type\":\"uint256\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"disputes\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"arbitratorExtraData\",\"type\":\"bytes\"},{\"internalType\":\"bool\",\"name\":\"isRuled\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"ruling\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"numberOfRulingOptions\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"governor\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_arbitratorDisputeID\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_ruling\",\"type\":\"uint256\"}],\"name\":\"rule\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"templateRegistry\",\"outputs\":[{\"internalType\":\"contract IDisputeTemplateRegistry\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"events\":{\"DisputeRequest(address,uint256,uint256,uint256,string)\":{\"details\":\"To be emitted when a dispute is created to link the correct meta-evidence to the disputeID.\",\"params\":{\"_arbitrator\":\"The arbitrator of the contract.\",\"_arbitratorDisputeID\":\"The identifier of the dispute in the Arbitrator contract.\",\"_externalDisputeID\":\"An identifier created outside Kleros by the protocol requesting arbitration.\",\"_templateId\":\"The identifier of the dispute template. Should not be used with _templateUri.\",\"_templateUri\":\"The URI to the dispute template. For example on IPFS: starting with '/ipfs/'. Should not be used with _templateId.\"}},\"Ruling(address,uint256,uint256)\":{\"details\":\"To be raised when a ruling is given.\",\"params\":{\"_arbitrator\":\"The arbitrator giving the ruling.\",\"_disputeID\":\"The identifier of the dispute in the Arbitrator contract.\",\"_ruling\":\"The ruling which was given.\"}}},\"kind\":\"dev\",\"methods\":{\"changeGovernor(address)\":{\"details\":\"Changes the governor.\",\"params\":{\"_governor\":\"The address of the new governor.\"}},\"constructor\":{\"details\":\"Constructor\",\"params\":{\"_arbitrator\":\"Target global arbitrator for any disputes.\"}},\"createDisputeForTemplate(bytes,string,string,uint256)\":{\"details\":\"Calls createDispute function of the specified arbitrator to create a dispute. Note that we don\\u2019t need to check that msg.value is enough to pay arbitration fees as it\\u2019s the responsibility of the arbitrator contract.\",\"params\":{\"_arbitratorExtraData\":\"Extra data for the arbitrator of the dispute.\",\"_disputeTemplate\":\"Dispute template.\",\"_disputeTemplateDataMappings\":\"The data mappings.\",\"_numberOfRulingOptions\":\"Number of ruling options.\"},\"returns\":{\"disputeID\":\"Dispute id (on arbitrator side) of the created dispute.\"}},\"createDisputeForTemplateUri(bytes,string,uint256)\":{\"details\":\"Calls createDispute function of the specified arbitrator to create a dispute. Note that we don\\u2019t need to check that msg.value is enough to pay arbitration fees as it\\u2019s the responsibility of the arbitrator contract.\",\"params\":{\"_arbitratorExtraData\":\"Extra data for the arbitrator of the dispute.\",\"_disputeTemplateUri\":\"The URI to the dispute template. For example on IPFS: starting with '/ipfs/'.\",\"_numberOfRulingOptions\":\"Number of ruling options.\"},\"returns\":{\"disputeID\":\"Dispute id (on arbitrator side) of the created dispute.\"}},\"rule(uint256,uint256)\":{\"details\":\"To be called by the arbitrator of the dispute, to declare the winning ruling.\",\"params\":{\"_arbitratorDisputeID\":\"ID of the dispute in arbitrator contract.\",\"_ruling\":\"The ruling choice of the arbitration.\"}}},\"title\":\"DisputeResolver DisputeResolver contract adapted for V2 from https://github.com/kleros/arbitrable-proxy-contracts/blob/master/contracts/ArbitrableProxy.sol.\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/arbitration/arbitrables/DisputeResolver.sol\":\"DisputeResolver\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":100},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.20;\\n\\n/**\\n * @dev Interface of the ERC-20 standard as defined in the ERC.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n\\n /**\\n * @dev Returns the value of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the value of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 value) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\\n * caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 value) external returns (bool);\\n\\n /**\\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\\n * allowance mechanism. `value` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(address from, address to, uint256 value) external returns (bool);\\n}\\n\",\"keccak256\":\"0xe06a3f08a987af6ad2e1c1e774405d4fe08f1694b67517438b467cecf0da0ef7\",\"license\":\"MIT\"},\"src/arbitration/arbitrables/DisputeResolver.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\n/// @custom:authors: [@unknownunknown1, @jaybuidl]\\n/// @custom:reviewers: []\\n/// @custom:auditors: []\\n/// @custom:bounties: []\\n\\nimport {IArbitrableV2, IArbitratorV2} from \\\"../interfaces/IArbitrableV2.sol\\\";\\nimport \\\"../interfaces/IDisputeTemplateRegistry.sol\\\";\\n\\npragma solidity 0.8.24;\\n\\n/// @title DisputeResolver\\n/// DisputeResolver contract adapted for V2 from https://github.com/kleros/arbitrable-proxy-contracts/blob/master/contracts/ArbitrableProxy.sol.\\ncontract DisputeResolver is IArbitrableV2 {\\n // ************************************* //\\n // * Enums / Structs * //\\n // ************************************* //\\n\\n struct DisputeStruct {\\n bytes arbitratorExtraData; // Extra data for the dispute.\\n bool isRuled; // True if the dispute has been ruled.\\n uint256 ruling; // Ruling given to the dispute.\\n uint256 numberOfRulingOptions; // The number of choices the arbitrator can give.\\n }\\n\\n // ************************************* //\\n // * Storage * //\\n // ************************************* //\\n\\n address public governor; // The governor.\\n IArbitratorV2 public arbitrator; // The arbitrator.\\n IDisputeTemplateRegistry public templateRegistry; // The dispute template registry.\\n DisputeStruct[] public disputes; // Local disputes.\\n mapping(uint256 => uint256) public arbitratorDisputeIDToLocalID; // Maps arbitrator-side dispute IDs to local dispute IDs.\\n\\n // ************************************* //\\n // * Constructor * //\\n // ************************************* //\\n\\n /// @dev Constructor\\n /// @param _arbitrator Target global arbitrator for any disputes.\\n constructor(IArbitratorV2 _arbitrator, IDisputeTemplateRegistry _templateRegistry) {\\n governor = msg.sender;\\n arbitrator = _arbitrator;\\n templateRegistry = _templateRegistry;\\n }\\n\\n // ************************************* //\\n // * Governance * //\\n // ************************************* //\\n\\n /// @dev Changes the governor.\\n /// @param _governor The address of the new governor.\\n function changeGovernor(address _governor) external {\\n require(governor == msg.sender, \\\"Access not allowed: Governor only.\\\");\\n governor = _governor;\\n }\\n\\n function changeArbitrator(IArbitratorV2 _arbitrator) external {\\n require(governor == msg.sender, \\\"Access not allowed: Governor only.\\\");\\n arbitrator = _arbitrator;\\n }\\n\\n function changeTemplateRegistry(IDisputeTemplateRegistry _templateRegistry) external {\\n require(governor == msg.sender, \\\"Access not allowed: Governor only.\\\");\\n templateRegistry = _templateRegistry;\\n }\\n\\n // ************************************* //\\n // * State Modifiers * //\\n // ************************************* //\\n\\n /// @dev Calls createDispute function of the specified arbitrator to create a dispute.\\n /// Note that we don\\u2019t need to check that msg.value is enough to pay arbitration fees as it\\u2019s the responsibility of the arbitrator contract.\\n /// @param _arbitratorExtraData Extra data for the arbitrator of the dispute.\\n /// @param _disputeTemplate Dispute template.\\n /// @param _disputeTemplateDataMappings The data mappings.\\n /// @param _numberOfRulingOptions Number of ruling options.\\n /// @return disputeID Dispute id (on arbitrator side) of the created dispute.\\n function createDisputeForTemplate(\\n bytes calldata _arbitratorExtraData,\\n string calldata _disputeTemplate,\\n string memory _disputeTemplateDataMappings,\\n uint256 _numberOfRulingOptions\\n ) external payable returns (uint256 disputeID) {\\n return\\n _createDispute(\\n _arbitratorExtraData,\\n _disputeTemplate,\\n _disputeTemplateDataMappings,\\n \\\"\\\",\\n _numberOfRulingOptions\\n );\\n }\\n\\n /// @dev Calls createDispute function of the specified arbitrator to create a dispute.\\n /// Note that we don\\u2019t need to check that msg.value is enough to pay arbitration fees as it\\u2019s the responsibility of the arbitrator contract.\\n /// @param _arbitratorExtraData Extra data for the arbitrator of the dispute.\\n /// @param _disputeTemplateUri The URI to the dispute template. For example on IPFS: starting with '/ipfs/'.\\n /// @param _numberOfRulingOptions Number of ruling options.\\n /// @return disputeID Dispute id (on arbitrator side) of the created dispute.\\n function createDisputeForTemplateUri(\\n bytes calldata _arbitratorExtraData,\\n string calldata _disputeTemplateUri,\\n uint256 _numberOfRulingOptions\\n ) external payable returns (uint256 disputeID) {\\n return _createDispute(_arbitratorExtraData, \\\"\\\", \\\"\\\", _disputeTemplateUri, _numberOfRulingOptions);\\n }\\n\\n /// @dev To be called by the arbitrator of the dispute, to declare the winning ruling.\\n /// @param _arbitratorDisputeID ID of the dispute in arbitrator contract.\\n /// @param _ruling The ruling choice of the arbitration.\\n function rule(uint256 _arbitratorDisputeID, uint256 _ruling) external override {\\n uint256 localDisputeID = arbitratorDisputeIDToLocalID[_arbitratorDisputeID];\\n DisputeStruct storage dispute = disputes[localDisputeID];\\n require(msg.sender == address(arbitrator), \\\"Only the arbitrator can execute this.\\\");\\n require(_ruling <= dispute.numberOfRulingOptions, \\\"Invalid ruling.\\\");\\n require(!dispute.isRuled, \\\"This dispute has been ruled already.\\\");\\n\\n dispute.isRuled = true;\\n dispute.ruling = _ruling;\\n\\n emit Ruling(IArbitratorV2(msg.sender), _arbitratorDisputeID, dispute.ruling);\\n }\\n\\n // ************************************* //\\n // * Internal * //\\n // ************************************* //\\n\\n function _createDispute(\\n bytes calldata _arbitratorExtraData,\\n string memory _disputeTemplate,\\n string memory _disputeTemplateDataMappings,\\n string memory _disputeTemplateUri,\\n uint256 _numberOfRulingOptions\\n ) internal virtual returns (uint256 arbitratorDisputeID) {\\n require(_numberOfRulingOptions > 1, \\\"Should be at least 2 ruling options.\\\");\\n\\n arbitratorDisputeID = arbitrator.createDispute{value: msg.value}(_numberOfRulingOptions, _arbitratorExtraData);\\n uint256 localDisputeID = disputes.length;\\n disputes.push(\\n DisputeStruct({\\n arbitratorExtraData: _arbitratorExtraData,\\n isRuled: false,\\n ruling: 0,\\n numberOfRulingOptions: _numberOfRulingOptions\\n })\\n );\\n arbitratorDisputeIDToLocalID[arbitratorDisputeID] = localDisputeID;\\n uint256 templateId = templateRegistry.setDisputeTemplate(\\\"\\\", _disputeTemplate, _disputeTemplateDataMappings);\\n emit DisputeRequest(arbitrator, arbitratorDisputeID, localDisputeID, templateId, _disputeTemplateUri);\\n }\\n}\\n\",\"keccak256\":\"0xee61f409399f0e66be187def6fcbe2e23717475b2b752d913dfac0a32c7dca1a\",\"license\":\"MIT\"},\"src/arbitration/interfaces/IArbitrableV2.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.24;\\n\\nimport \\\"./IArbitratorV2.sol\\\";\\n\\n/// @title IArbitrableV2\\n/// @notice Arbitrable interface.\\n/// @dev When developing arbitrable contracts, we need to:\\n/// - Define the action taken when a ruling is received by the contract.\\n/// - Allow dispute creation. For this a function must call arbitrator.createDispute{value: _fee}(_choices,_extraData);\\ninterface IArbitrableV2 {\\n /// @dev To be emitted when a dispute is created to link the correct meta-evidence to the disputeID.\\n /// @param _arbitrator The arbitrator of the contract.\\n /// @param _arbitratorDisputeID The identifier of the dispute in the Arbitrator contract.\\n /// @param _externalDisputeID An identifier created outside Kleros by the protocol requesting arbitration.\\n /// @param _templateId The identifier of the dispute template. Should not be used with _templateUri.\\n /// @param _templateUri The URI to the dispute template. For example on IPFS: starting with '/ipfs/'. Should not be used with _templateId.\\n event DisputeRequest(\\n IArbitratorV2 indexed _arbitrator,\\n uint256 indexed _arbitratorDisputeID,\\n uint256 _externalDisputeID,\\n uint256 _templateId,\\n string _templateUri\\n );\\n\\n /// @dev To be raised when a ruling is given.\\n /// @param _arbitrator The arbitrator giving the ruling.\\n /// @param _disputeID The identifier of the dispute in the Arbitrator contract.\\n /// @param _ruling The ruling which was given.\\n event Ruling(IArbitratorV2 indexed _arbitrator, uint256 indexed _disputeID, uint256 _ruling);\\n\\n /// @dev Give a ruling for a dispute.\\n /// Must be called by the arbitrator.\\n /// The purpose of this function is to ensure that the address calling it has the right to rule on the contract.\\n /// @param _disputeID The identifier of the dispute in the Arbitrator contract.\\n /// @param _ruling Ruling given by the arbitrator.\\n /// Note that 0 is reserved for \\\"Not able/wanting to make a decision\\\".\\n function rule(uint256 _disputeID, uint256 _ruling) external;\\n}\\n\",\"keccak256\":\"0xe841a4fe8ec109ce17dde4457bf1583c8b499109b05887c53a49a3207fc6e80b\",\"license\":\"MIT\"},\"src/arbitration/interfaces/IArbitratorV2.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"./IArbitrableV2.sol\\\";\\n\\n/// @title Arbitrator\\n/// Arbitrator interface that implements the new arbitration standard.\\n/// Unlike the ERC-792 this standard is not concerned with appeals, so each arbitrator can implement an appeal system that suits it the most.\\n/// When developing arbitrator contracts we need to:\\n/// - Define the functions for dispute creation (createDispute). Don't forget to store the arbitrated contract and the disputeID (which should be unique, may nbDisputes).\\n/// - Define the functions for cost display (arbitrationCost).\\n/// - Allow giving rulings. For this a function must call arbitrable.rule(disputeID, ruling).\\ninterface IArbitratorV2 {\\n /// @dev To be emitted when a dispute is created.\\n /// @param _disputeID The identifier of the dispute in the Arbitrator contract.\\n /// @param _arbitrable The contract which created the dispute.\\n event DisputeCreation(uint256 indexed _disputeID, IArbitrableV2 indexed _arbitrable);\\n\\n /// @dev To be raised when a ruling is given.\\n /// @param _arbitrable The arbitrable receiving the ruling.\\n /// @param _disputeID The identifier of the dispute in the Arbitrator contract.\\n /// @param _ruling The ruling which was given.\\n event Ruling(IArbitrableV2 indexed _arbitrable, uint256 indexed _disputeID, uint256 _ruling);\\n\\n /// @dev To be emitted when an ERC20 token is added or removed as a method to pay fees.\\n /// @param _token The ERC20 token.\\n /// @param _accepted Whether the token is accepted or not.\\n event AcceptedFeeToken(IERC20 indexed _token, bool indexed _accepted);\\n\\n /// @dev To be emitted when the fee for a particular ERC20 token is updated.\\n /// @param _feeToken The ERC20 token.\\n /// @param _rateInEth The new rate of the fee token in ETH.\\n /// @param _rateDecimals The new decimals of the fee token rate.\\n event NewCurrencyRate(IERC20 indexed _feeToken, uint64 _rateInEth, uint8 _rateDecimals);\\n\\n /// @dev Create a dispute and pay for the fees in the native currency, typically ETH.\\n /// Must be called by the arbitrable contract.\\n /// Must pay at least arbitrationCost(_extraData).\\n /// @param _numberOfChoices The number of choices the arbitrator can choose from in this dispute.\\n /// @param _extraData Additional info about the dispute. We use it to pass the ID of the dispute's court (first 32 bytes), the minimum number of jurors required (next 32 bytes) and the ID of the specific dispute kit (last 32 bytes).\\n /// @return disputeID The identifier of the dispute created.\\n function createDispute(\\n uint256 _numberOfChoices,\\n bytes calldata _extraData\\n ) external payable returns (uint256 disputeID);\\n\\n /// @dev Create a dispute and pay for the fees in a supported ERC20 token.\\n /// Must be called by the arbitrable contract.\\n /// Must pay at least arbitrationCost(_extraData).\\n /// @param _numberOfChoices The number of choices the arbitrator can choose from in this dispute.\\n /// @param _extraData Additional info about the dispute. We use it to pass the ID of the dispute's court (first 32 bytes), the minimum number of jurors required (next 32 bytes) and the ID of the specific dispute kit (last 32 bytes).\\n /// @param _feeToken The ERC20 token used to pay fees.\\n /// @param _feeAmount Amount of the ERC20 token used to pay fees.\\n /// @return disputeID The identifier of the dispute created.\\n function createDispute(\\n uint256 _numberOfChoices,\\n bytes calldata _extraData,\\n IERC20 _feeToken,\\n uint256 _feeAmount\\n ) external returns (uint256 disputeID);\\n\\n /// @dev Compute the cost of arbitration denominated in the native currency, typically ETH.\\n /// It is recommended not to increase it often, as it can be highly time and gas consuming for the arbitrated contracts to cope with fee augmentation.\\n /// @param _extraData Additional info about the dispute. We use it to pass the ID of the dispute's court (first 32 bytes), the minimum number of jurors required (next 32 bytes) and the ID of the specific dispute kit (last 32 bytes).\\n /// @return cost The arbitration cost in ETH.\\n function arbitrationCost(bytes calldata _extraData) external view returns (uint256 cost);\\n\\n /// @dev Compute the cost of arbitration denominated in `_feeToken`.\\n /// It is recommended not to increase it often, as it can be highly time and gas consuming for the arbitrated contracts to cope with fee augmentation.\\n /// @param _extraData Additional info about the dispute. We use it to pass the ID of the dispute's court (first 32 bytes), the minimum number of jurors required (next 32 bytes) and the ID of the specific dispute kit (last 32 bytes).\\n /// @param _feeToken The ERC20 token used to pay fees.\\n /// @return cost The arbitration cost in `_feeToken`.\\n function arbitrationCost(bytes calldata _extraData, IERC20 _feeToken) external view returns (uint256 cost);\\n\\n /// @dev Gets the current ruling of a specified dispute.\\n /// @param _disputeID The ID of the dispute.\\n /// @return ruling The current ruling.\\n /// @return tied Whether it's a tie or not.\\n /// @return overridden Whether the ruling was overridden by appeal funding or not.\\n function currentRuling(uint256 _disputeID) external view returns (uint256 ruling, bool tied, bool overridden);\\n}\\n\",\"keccak256\":\"0xa4dc6b958197adead238de4246cd04e7389c3dc1b9f968acd10985f8fc5b74cf\",\"license\":\"MIT\"},\"src/arbitration/interfaces/IDisputeTemplateRegistry.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.24;\\n\\n/// @title IDisputeTemplate\\n/// @notice Dispute Template interface.\\ninterface IDisputeTemplateRegistry {\\n /// @dev To be emitted when a new dispute template is created.\\n /// @param _templateId The identifier of the dispute template.\\n /// @param _templateTag An optional tag for the dispute template, such as \\\"registration\\\" or \\\"removal\\\".\\n /// @param _templateData The template data.\\n /// @param _templateDataMappings The data mappings.\\n event DisputeTemplate(\\n uint256 indexed _templateId,\\n string indexed _templateTag,\\n string _templateData,\\n string _templateDataMappings\\n );\\n\\n function setDisputeTemplate(\\n string memory _templateTag,\\n string memory _templateData,\\n string memory _templateDataMappings\\n ) external returns (uint256 templateId);\\n}\\n\",\"keccak256\":\"0xb46ff71c32a524a865fe8ca99d94c9daeb690bc9d7d49d963a45b06f60af19f3\",\"license\":\"MIT\"}},\"version\":1}",
- "bytecode": "0x608060405234801561001057600080fd5b50604051610ed7380380610ed783398101604081905261002f91610083565b600080546001600160a01b03199081163317909155600180546001600160a01b03948516908316179055600280549290931691161790556100bd565b6001600160a01b038116811461008057600080fd5b50565b6000806040838503121561009657600080fd5b82516100a18161006b565b60208401519092506100b28161006b565b809150509250929050565b610e0b806100cc6000396000f3fe60806040526004361061009c5760003560e01c8063908bb29511610064578063908bb29514610170578063a0af81f014610191578063dc653511146101b1578063e09997d9146101c4578063e4c0aaf4146101f1578063fc548f081461021157600080fd5b80630c340a24146100a1578063311a6c56146100de5780634660ebbe14610100578063564a565d146101205780636cc6cde114610150575b600080fd5b3480156100ad57600080fd5b506000546100c1906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156100ea57600080fd5b506100fe6100f93660046108bb565b610231565b005b34801561010c57600080fd5b506100fe61011b3660046108f5565b6103d1565b34801561012c57600080fd5b5061014061013b366004610919565b61041d565b6040516100d59493929190610978565b34801561015c57600080fd5b506001546100c1906001600160a01b031681565b61018361017e3660046109f0565b6104eb565b6040519081526020016100d5565b34801561019d57600080fd5b506002546100c1906001600160a01b031681565b6101836101bf366004610a7a565b61055a565b3480156101d057600080fd5b506101836101df366004610919565b60046020526000908152604090205481565b3480156101fd57600080fd5b506100fe61020c3660046108f5565b6105b9565b34801561021d57600080fd5b506100fe61022c3660046108f5565b610605565b600082815260046020526040812054600380549192918390811061025757610257610b88565b6000918252602090912060015460049092020191506001600160a01b031633146102d65760405162461bcd60e51b815260206004820152602560248201527f4f6e6c79207468652061726269747261746f722063616e2065786563757465206044820152643a3434b99760d91b60648201526084015b60405180910390fd5b806003015483111561031c5760405162461bcd60e51b815260206004820152600f60248201526e24b73b30b634b210393ab634b7339760891b60448201526064016102cd565b600181015460ff161561037d5760405162461bcd60e51b8152602060048201526024808201527f54686973206469737075746520686173206265656e2072756c656420616c726560448201526330b23c9760e11b60648201526084016102cd565b6001818101805460ff1916909117905560028101839055604051838152849033907f394027a5fa6e098a1191094d1719d6929b9abc535fcc0c8f448d6a4e756222769060200160405180910390a350505050565b6000546001600160a01b031633146103fb5760405162461bcd60e51b81526004016102cd90610b9e565b600280546001600160a01b0319166001600160a01b0392909216919091179055565b6003818154811061042d57600080fd5b906000526020600020906004020160009150905080600001805461045090610be0565b80601f016020809104026020016040519081016040528092919081815260200182805461047c90610be0565b80156104c95780601f1061049e576101008083540402835291602001916104c9565b820191906000526020600020905b8154815290600101906020018083116104ac57829003601f168201915b5050505060018301546002840154600390940154929360ff9091169290915084565b60006105508686604051806020016040528060008152506040518060200160405280600081525088888080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508a9250610651915050565b9695505050505050565b60006105ae878787878080601f016020809104026020016040519081016040528093929190818152602001838380828437600092018290525060408051602081019091529081528a93509150889050610651565b979650505050505050565b6000546001600160a01b031633146105e35760405162461bcd60e51b81526004016102cd90610b9e565b600080546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b0316331461062f5760405162461bcd60e51b81526004016102cd90610b9e565b600180546001600160a01b0319166001600160a01b0392909216919091179055565b6000600182116106af5760405162461bcd60e51b8152602060048201526024808201527f53686f756c64206265206174206c6561737420322072756c696e67206f70746960448201526337b7399760e11b60648201526084016102cd565b60015460405163c13517e160e01b81526001600160a01b039091169063c13517e19034906106e59086908c908c90600401610c1a565b60206040518083038185885af1158015610703573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906107289190610c50565b600380546040805160a06020601f8d018190040282018101909252608081018b8152949550919382918c908c90819085018382808284376000920182905250938552505050602080830182905260408301829052606090920187905283546001810185559381522081519192600402019081906107a59082610cba565b5060208281015160018301805460ff19169115159190911790556040808401516002808501919091556060909401516003909301929092556000858152600491829052828120859055925491516312a6505d60e21b81526001600160a01b0390921691634a9941749161081c918b918b9101610d7a565b6020604051808303816000875af115801561083b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061085f9190610c50565b60015460405191925084916001600160a01b03909116907f8bd32f430ff060e6bd204709b3790c9807987263d3230c580dc80b5f89e27186906108a790869086908b90610db6565b60405180910390a350509695505050505050565b600080604083850312156108ce57600080fd5b50508035926020909101359150565b6001600160a01b03811681146108f257600080fd5b50565b60006020828403121561090757600080fd5b8135610912816108dd565b9392505050565b60006020828403121561092b57600080fd5b5035919050565b6000815180845260005b818110156109585760208185018101518683018201520161093c565b506000602082860101526020601f19601f83011685010191505092915050565b60808152600061098b6080830187610932565b9415156020830152506040810192909252606090910152919050565b60008083601f8401126109b957600080fd5b50813567ffffffffffffffff8111156109d157600080fd5b6020830191508360208285010111156109e957600080fd5b9250929050565b600080600080600060608688031215610a0857600080fd5b853567ffffffffffffffff80821115610a2057600080fd5b610a2c89838a016109a7565b90975095506020880135915080821115610a4557600080fd5b50610a52888289016109a7565b96999598509660400135949350505050565b634e487b7160e01b600052604160045260246000fd5b60008060008060008060808789031215610a9357600080fd5b863567ffffffffffffffff80821115610aab57600080fd5b610ab78a838b016109a7565b90985096506020890135915080821115610ad057600080fd5b610adc8a838b016109a7565b90965094506040890135915080821115610af557600080fd5b818901915089601f830112610b0957600080fd5b813581811115610b1b57610b1b610a64565b604051601f8201601f19908116603f01168101908382118183101715610b4357610b43610a64565b816040528281528c6020848701011115610b5c57600080fd5b826020860160208301376000602084830101528096505050505050606087013590509295509295509295565b634e487b7160e01b600052603260045260246000fd5b60208082526022908201527f416363657373206e6f7420616c6c6f7765643a20476f7665726e6f72206f6e6c6040820152613c9760f11b606082015260800190565b600181811c90821680610bf457607f821691505b602082108103610c1457634e487b7160e01b600052602260045260246000fd5b50919050565b83815260406020820152816040820152818360608301376000818301606090810191909152601f909201601f1916010192915050565b600060208284031215610c6257600080fd5b5051919050565b601f821115610cb5576000816000526020600020601f850160051c81016020861015610c925750805b601f850160051c820191505b81811015610cb157828155600101610c9e565b5050505b505050565b815167ffffffffffffffff811115610cd457610cd4610a64565b610ce881610ce28454610be0565b84610c69565b602080601f831160018114610d1d5760008415610d055750858301515b600019600386901b1c1916600185901b178555610cb1565b600085815260208120601f198616915b82811015610d4c57888601518255948401946001909101908401610d2d565b5085821015610d6a5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6060815260006060820152608060208201526000610d9b6080830185610932565b8281036040840152610dad8185610932565b95945050505050565b838152826020820152606060408201526000610dad606083018461093256fea264697066735822122028e3f1561d663e8479b35f936c2645829463b01bf5fedd3e120b732867bda19a64736f6c63430008180033",
- "deployedBytecode": "0x60806040526004361061009c5760003560e01c8063908bb29511610064578063908bb29514610170578063a0af81f014610191578063dc653511146101b1578063e09997d9146101c4578063e4c0aaf4146101f1578063fc548f081461021157600080fd5b80630c340a24146100a1578063311a6c56146100de5780634660ebbe14610100578063564a565d146101205780636cc6cde114610150575b600080fd5b3480156100ad57600080fd5b506000546100c1906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156100ea57600080fd5b506100fe6100f93660046108bb565b610231565b005b34801561010c57600080fd5b506100fe61011b3660046108f5565b6103d1565b34801561012c57600080fd5b5061014061013b366004610919565b61041d565b6040516100d59493929190610978565b34801561015c57600080fd5b506001546100c1906001600160a01b031681565b61018361017e3660046109f0565b6104eb565b6040519081526020016100d5565b34801561019d57600080fd5b506002546100c1906001600160a01b031681565b6101836101bf366004610a7a565b61055a565b3480156101d057600080fd5b506101836101df366004610919565b60046020526000908152604090205481565b3480156101fd57600080fd5b506100fe61020c3660046108f5565b6105b9565b34801561021d57600080fd5b506100fe61022c3660046108f5565b610605565b600082815260046020526040812054600380549192918390811061025757610257610b88565b6000918252602090912060015460049092020191506001600160a01b031633146102d65760405162461bcd60e51b815260206004820152602560248201527f4f6e6c79207468652061726269747261746f722063616e2065786563757465206044820152643a3434b99760d91b60648201526084015b60405180910390fd5b806003015483111561031c5760405162461bcd60e51b815260206004820152600f60248201526e24b73b30b634b210393ab634b7339760891b60448201526064016102cd565b600181015460ff161561037d5760405162461bcd60e51b8152602060048201526024808201527f54686973206469737075746520686173206265656e2072756c656420616c726560448201526330b23c9760e11b60648201526084016102cd565b6001818101805460ff1916909117905560028101839055604051838152849033907f394027a5fa6e098a1191094d1719d6929b9abc535fcc0c8f448d6a4e756222769060200160405180910390a350505050565b6000546001600160a01b031633146103fb5760405162461bcd60e51b81526004016102cd90610b9e565b600280546001600160a01b0319166001600160a01b0392909216919091179055565b6003818154811061042d57600080fd5b906000526020600020906004020160009150905080600001805461045090610be0565b80601f016020809104026020016040519081016040528092919081815260200182805461047c90610be0565b80156104c95780601f1061049e576101008083540402835291602001916104c9565b820191906000526020600020905b8154815290600101906020018083116104ac57829003601f168201915b5050505060018301546002840154600390940154929360ff9091169290915084565b60006105508686604051806020016040528060008152506040518060200160405280600081525088888080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508a9250610651915050565b9695505050505050565b60006105ae878787878080601f016020809104026020016040519081016040528093929190818152602001838380828437600092018290525060408051602081019091529081528a93509150889050610651565b979650505050505050565b6000546001600160a01b031633146105e35760405162461bcd60e51b81526004016102cd90610b9e565b600080546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b0316331461062f5760405162461bcd60e51b81526004016102cd90610b9e565b600180546001600160a01b0319166001600160a01b0392909216919091179055565b6000600182116106af5760405162461bcd60e51b8152602060048201526024808201527f53686f756c64206265206174206c6561737420322072756c696e67206f70746960448201526337b7399760e11b60648201526084016102cd565b60015460405163c13517e160e01b81526001600160a01b039091169063c13517e19034906106e59086908c908c90600401610c1a565b60206040518083038185885af1158015610703573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906107289190610c50565b600380546040805160a06020601f8d018190040282018101909252608081018b8152949550919382918c908c90819085018382808284376000920182905250938552505050602080830182905260408301829052606090920187905283546001810185559381522081519192600402019081906107a59082610cba565b5060208281015160018301805460ff19169115159190911790556040808401516002808501919091556060909401516003909301929092556000858152600491829052828120859055925491516312a6505d60e21b81526001600160a01b0390921691634a9941749161081c918b918b9101610d7a565b6020604051808303816000875af115801561083b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061085f9190610c50565b60015460405191925084916001600160a01b03909116907f8bd32f430ff060e6bd204709b3790c9807987263d3230c580dc80b5f89e27186906108a790869086908b90610db6565b60405180910390a350509695505050505050565b600080604083850312156108ce57600080fd5b50508035926020909101359150565b6001600160a01b03811681146108f257600080fd5b50565b60006020828403121561090757600080fd5b8135610912816108dd565b9392505050565b60006020828403121561092b57600080fd5b5035919050565b6000815180845260005b818110156109585760208185018101518683018201520161093c565b506000602082860101526020601f19601f83011685010191505092915050565b60808152600061098b6080830187610932565b9415156020830152506040810192909252606090910152919050565b60008083601f8401126109b957600080fd5b50813567ffffffffffffffff8111156109d157600080fd5b6020830191508360208285010111156109e957600080fd5b9250929050565b600080600080600060608688031215610a0857600080fd5b853567ffffffffffffffff80821115610a2057600080fd5b610a2c89838a016109a7565b90975095506020880135915080821115610a4557600080fd5b50610a52888289016109a7565b96999598509660400135949350505050565b634e487b7160e01b600052604160045260246000fd5b60008060008060008060808789031215610a9357600080fd5b863567ffffffffffffffff80821115610aab57600080fd5b610ab78a838b016109a7565b90985096506020890135915080821115610ad057600080fd5b610adc8a838b016109a7565b90965094506040890135915080821115610af557600080fd5b818901915089601f830112610b0957600080fd5b813581811115610b1b57610b1b610a64565b604051601f8201601f19908116603f01168101908382118183101715610b4357610b43610a64565b816040528281528c6020848701011115610b5c57600080fd5b826020860160208301376000602084830101528096505050505050606087013590509295509295509295565b634e487b7160e01b600052603260045260246000fd5b60208082526022908201527f416363657373206e6f7420616c6c6f7765643a20476f7665726e6f72206f6e6c6040820152613c9760f11b606082015260800190565b600181811c90821680610bf457607f821691505b602082108103610c1457634e487b7160e01b600052602260045260246000fd5b50919050565b83815260406020820152816040820152818360608301376000818301606090810191909152601f909201601f1916010192915050565b600060208284031215610c6257600080fd5b5051919050565b601f821115610cb5576000816000526020600020601f850160051c81016020861015610c925750805b601f850160051c820191505b81811015610cb157828155600101610c9e565b5050505b505050565b815167ffffffffffffffff811115610cd457610cd4610a64565b610ce881610ce28454610be0565b84610c69565b602080601f831160018114610d1d5760008415610d055750858301515b600019600386901b1c1916600185901b178555610cb1565b600085815260208120601f198616915b82811015610d4c57888601518255948401946001909101908401610d2d565b5085821015610d6a5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6060815260006060820152608060208201526000610d9b6080830185610932565b8281036040840152610dad8185610932565b95945050505050565b838152826020820152606060408201526000610dad606083018461093256fea264697066735822122028e3f1561d663e8479b35f936c2645829463b01bf5fedd3e120b732867bda19a64736f6c63430008180033",
+ "solcInputHash": "d547d738900bce1310e91a5d1adfc179",
+ "metadata": "{\"compiler\":{\"version\":\"0.8.30+commit.73712a01\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract IArbitratorV2\",\"name\":\"_arbitrator\",\"type\":\"address\"},{\"internalType\":\"contract IDisputeTemplateRegistry\",\"name\":\"_templateRegistry\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"ArbitratorOnly\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputeAlreadyRuled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OwnerOnly\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RulingOutOfBounds\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ShouldBeAtLeastTwoRulingOptions\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"contract IArbitratorV2\",\"name\":\"_arbitrator\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_arbitratorDisputeID\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_externalDisputeID\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_templateId\",\"type\":\"uint256\"}],\"name\":\"DisputeRequest\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"contract IArbitratorV2\",\"name\":\"_arbitrator\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_disputeID\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_ruling\",\"type\":\"uint256\"}],\"name\":\"Ruling\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"arbitrator\",\"outputs\":[{\"internalType\":\"contract IArbitratorV2\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"arbitratorDisputeIDToLocalID\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract IArbitratorV2\",\"name\":\"_arbitrator\",\"type\":\"address\"}],\"name\":\"changeArbitrator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"name\":\"changeOwner\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract IDisputeTemplateRegistry\",\"name\":\"_templateRegistry\",\"type\":\"address\"}],\"name\":\"changeTemplateRegistry\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_arbitratorExtraData\",\"type\":\"bytes\"},{\"internalType\":\"string\",\"name\":\"_disputeTemplate\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"_disputeTemplateDataMappings\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"_numberOfRulingOptions\",\"type\":\"uint256\"}],\"name\":\"createDisputeForTemplate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"disputeID\",\"type\":\"uint256\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"disputes\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"arbitratorExtraData\",\"type\":\"bytes\"},{\"internalType\":\"bool\",\"name\":\"isRuled\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"ruling\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"numberOfRulingOptions\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_arbitratorDisputeID\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_ruling\",\"type\":\"uint256\"}],\"name\":\"rule\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"templateRegistry\",\"outputs\":[{\"internalType\":\"contract IDisputeTemplateRegistry\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Adapted for V2 from https://github.com/kleros/arbitrable-proxy-contracts/blob/master/contracts/ArbitrableProxy.sol.\",\"events\":{\"DisputeRequest(address,uint256,uint256,uint256)\":{\"params\":{\"_arbitrator\":\"The arbitrator of the contract.\",\"_arbitratorDisputeID\":\"The identifier of the dispute in the Arbitrator contract.\",\"_externalDisputeID\":\"An identifier created outside Kleros by the protocol requesting arbitration.\",\"_templateId\":\"The identifier of the dispute template.\"}},\"Ruling(address,uint256,uint256)\":{\"params\":{\"_arbitrator\":\"The arbitrator giving the ruling.\",\"_disputeID\":\"The identifier of the dispute in the Arbitrator contract.\",\"_ruling\":\"The ruling which was given.\"}}},\"kind\":\"dev\",\"methods\":{\"changeOwner(address)\":{\"params\":{\"_owner\":\"The address of the new owner.\"}},\"constructor\":{\"params\":{\"_arbitrator\":\"Target global arbitrator for any disputes.\"}},\"createDisputeForTemplate(bytes,string,string,uint256)\":{\"details\":\"No need to check that msg.value is enough to pay arbitration fees as it\\u2019s the responsibility of the arbitrator contract.\",\"params\":{\"_arbitratorExtraData\":\"Extra data for the arbitrator of the dispute.\",\"_disputeTemplate\":\"Dispute template.\",\"_disputeTemplateDataMappings\":\"The data mappings.\",\"_numberOfRulingOptions\":\"Number of ruling options.\"},\"returns\":{\"disputeID\":\"Dispute id (on arbitrator side) of the created dispute.\"}},\"rule(uint256,uint256)\":{\"details\":\"This is a callback function for the arbitrator to provide the ruling to this contract. Only the arbitrator must be allowed to call this function. Ruling 0 is reserved for \\\"Not able/wanting to make a decision\\\".\",\"params\":{\"_disputeID\":\"The identifier of the dispute in the Arbitrator contract.\",\"_ruling\":\"Ruling given by the arbitrator.\"}}},\"title\":\"DisputeResolver\",\"version\":1},\"userdoc\":{\"events\":{\"DisputeRequest(address,uint256,uint256,uint256)\":{\"notice\":\"To be emitted when a dispute is created to link the correct template to the disputeID.\"},\"Ruling(address,uint256,uint256)\":{\"notice\":\"To be raised when a ruling is given.\"}},\"kind\":\"user\",\"methods\":{\"changeOwner(address)\":{\"notice\":\"Changes the owner.\"},\"constructor\":{\"notice\":\"Constructor\"},\"createDisputeForTemplate(bytes,string,string,uint256)\":{\"notice\":\"Calls createDispute function of the specified arbitrator to create a dispute.\"},\"rule(uint256,uint256)\":{\"notice\":\"Give a ruling for a dispute.\"}},\"notice\":\"DisputeResolver contract\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/arbitration/arbitrables/DisputeResolver.sol\":\"DisputeResolver\"},\"evmVersion\":\"cancun\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000},\"remappings\":[],\"viaIR\":true},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity >=0.4.16;\\n\\n/**\\n * @dev Interface of the ERC-20 standard as defined in the ERC.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n\\n /**\\n * @dev Returns the value of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the value of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 value) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\\n * caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 value) external returns (bool);\\n\\n /**\\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\\n * allowance mechanism. `value` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(address from, address to, uint256 value) external returns (bool);\\n}\\n\",\"keccak256\":\"0x74ed01eb66b923d0d0cfe3be84604ac04b76482a55f9dd655e1ef4d367f95bc2\",\"license\":\"MIT\"},\"src/arbitration/arbitrables/DisputeResolver.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\nimport {IArbitrableV2, IArbitratorV2} from \\\"../interfaces/IArbitrableV2.sol\\\";\\nimport \\\"../interfaces/IDisputeTemplateRegistry.sol\\\";\\n\\npragma solidity ^0.8.24;\\n\\n/// @title DisputeResolver\\n/// @notice DisputeResolver contract\\n/// @dev Adapted for V2 from https://github.com/kleros/arbitrable-proxy-contracts/blob/master/contracts/ArbitrableProxy.sol.\\ncontract DisputeResolver is IArbitrableV2 {\\n // ************************************* //\\n // * Enums / Structs * //\\n // ************************************* //\\n\\n struct DisputeStruct {\\n bytes arbitratorExtraData; // Extra data for the dispute.\\n bool isRuled; // True if the dispute has been ruled.\\n uint256 ruling; // Ruling given to the dispute.\\n uint256 numberOfRulingOptions; // The number of choices the arbitrator can give.\\n }\\n\\n // ************************************* //\\n // * Storage * //\\n // ************************************* //\\n\\n address public owner; // The owner.\\n IArbitratorV2 public arbitrator; // The arbitrator.\\n IDisputeTemplateRegistry public templateRegistry; // The dispute template registry.\\n DisputeStruct[] public disputes; // Local disputes.\\n mapping(uint256 => uint256) public arbitratorDisputeIDToLocalID; // Maps arbitrator-side dispute IDs to local dispute IDs.\\n\\n // ************************************* //\\n // * Constructor * //\\n // ************************************* //\\n\\n /// @notice Constructor\\n /// @param _arbitrator Target global arbitrator for any disputes.\\n constructor(IArbitratorV2 _arbitrator, IDisputeTemplateRegistry _templateRegistry) {\\n owner = msg.sender;\\n arbitrator = _arbitrator;\\n templateRegistry = _templateRegistry;\\n }\\n\\n // ************************************* //\\n // * Governance * //\\n // ************************************* //\\n\\n /// @notice Changes the owner.\\n /// @param _owner The address of the new owner.\\n function changeOwner(address _owner) external {\\n if (owner != msg.sender) revert OwnerOnly();\\n owner = _owner;\\n }\\n\\n function changeArbitrator(IArbitratorV2 _arbitrator) external {\\n if (owner != msg.sender) revert OwnerOnly();\\n arbitrator = _arbitrator;\\n }\\n\\n function changeTemplateRegistry(IDisputeTemplateRegistry _templateRegistry) external {\\n if (owner != msg.sender) revert OwnerOnly();\\n templateRegistry = _templateRegistry;\\n }\\n\\n // ************************************* //\\n // * State Modifiers * //\\n // ************************************* //\\n\\n /// @notice Calls createDispute function of the specified arbitrator to create a dispute.\\n /// @dev No need to check that msg.value is enough to pay arbitration fees as it\\u2019s the responsibility of the arbitrator contract.\\n /// @param _arbitratorExtraData Extra data for the arbitrator of the dispute.\\n /// @param _disputeTemplate Dispute template.\\n /// @param _disputeTemplateDataMappings The data mappings.\\n /// @param _numberOfRulingOptions Number of ruling options.\\n /// @return disputeID Dispute id (on arbitrator side) of the created dispute.\\n function createDisputeForTemplate(\\n bytes calldata _arbitratorExtraData,\\n string calldata _disputeTemplate,\\n string memory _disputeTemplateDataMappings,\\n uint256 _numberOfRulingOptions\\n ) external payable returns (uint256 disputeID) {\\n return\\n _createDispute(\\n _arbitratorExtraData,\\n _disputeTemplate,\\n _disputeTemplateDataMappings,\\n _numberOfRulingOptions\\n );\\n }\\n\\n /// @inheritdoc IArbitrableV2\\n function rule(uint256 _arbitratorDisputeID, uint256 _ruling) external override {\\n uint256 localDisputeID = arbitratorDisputeIDToLocalID[_arbitratorDisputeID];\\n DisputeStruct storage dispute = disputes[localDisputeID];\\n if (msg.sender != address(arbitrator)) revert ArbitratorOnly();\\n if (_ruling > dispute.numberOfRulingOptions) revert RulingOutOfBounds();\\n if (dispute.isRuled) revert DisputeAlreadyRuled();\\n\\n dispute.isRuled = true;\\n dispute.ruling = _ruling;\\n\\n emit Ruling(IArbitratorV2(msg.sender), _arbitratorDisputeID, dispute.ruling);\\n }\\n\\n // ************************************* //\\n // * Internal * //\\n // ************************************* //\\n\\n function _createDispute(\\n bytes calldata _arbitratorExtraData,\\n string memory _disputeTemplate,\\n string memory _disputeTemplateDataMappings,\\n uint256 _numberOfRulingOptions\\n ) internal virtual returns (uint256 arbitratorDisputeID) {\\n if (_numberOfRulingOptions <= 1) revert ShouldBeAtLeastTwoRulingOptions();\\n\\n arbitratorDisputeID = arbitrator.createDispute{value: msg.value}(_numberOfRulingOptions, _arbitratorExtraData);\\n uint256 localDisputeID = disputes.length;\\n disputes.push(\\n DisputeStruct({\\n arbitratorExtraData: _arbitratorExtraData,\\n isRuled: false,\\n ruling: 0,\\n numberOfRulingOptions: _numberOfRulingOptions\\n })\\n );\\n arbitratorDisputeIDToLocalID[arbitratorDisputeID] = localDisputeID;\\n uint256 templateId = templateRegistry.setDisputeTemplate(\\\"\\\", _disputeTemplate, _disputeTemplateDataMappings);\\n emit DisputeRequest(arbitrator, arbitratorDisputeID, localDisputeID, templateId);\\n }\\n\\n // ************************************* //\\n // * Errors * //\\n // ************************************* //\\n\\n error OwnerOnly();\\n error ArbitratorOnly();\\n error RulingOutOfBounds();\\n error DisputeAlreadyRuled();\\n error ShouldBeAtLeastTwoRulingOptions();\\n}\\n\",\"keccak256\":\"0xba17fdaa371403c1b9c1e6673e640aa4c70f409b479e5147a8db9755f6154f0f\",\"license\":\"MIT\"},\"src/arbitration/interfaces/IArbitrableV2.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity >=0.8.0 <0.9.0;\\n\\nimport \\\"./IArbitratorV2.sol\\\";\\n\\n/// @title IArbitrableV2\\n/// @notice Arbitrable interface.\\n/// @dev When developing arbitrable contracts, we need to:\\n/// - Define the action taken when a ruling is received by the contract.\\n/// - Allow dispute creation which calls `arbitrator.createDispute{value: _fee}(_choices,_extraData)`.\\ninterface IArbitrableV2 {\\n // ************************************* //\\n // * Events * //\\n // ************************************* //\\n\\n /// @notice To be emitted when a dispute is created to link the correct template to the disputeID.\\n /// @param _arbitrator The arbitrator of the contract.\\n /// @param _arbitratorDisputeID The identifier of the dispute in the Arbitrator contract.\\n /// @param _externalDisputeID An identifier created outside Kleros by the protocol requesting arbitration.\\n /// @param _templateId The identifier of the dispute template.\\n event DisputeRequest(\\n IArbitratorV2 indexed _arbitrator,\\n uint256 indexed _arbitratorDisputeID,\\n uint256 _externalDisputeID,\\n uint256 _templateId\\n );\\n\\n /// @notice To be raised when a ruling is given.\\n /// @param _arbitrator The arbitrator giving the ruling.\\n /// @param _disputeID The identifier of the dispute in the Arbitrator contract.\\n /// @param _ruling The ruling which was given.\\n event Ruling(IArbitratorV2 indexed _arbitrator, uint256 indexed _disputeID, uint256 _ruling);\\n\\n // ************************************* //\\n // * State Modifiers * //\\n // ************************************* //\\n\\n /// @notice Give a ruling for a dispute.\\n ///\\n /// @dev This is a callback function for the arbitrator to provide the ruling to this contract.\\n /// Only the arbitrator must be allowed to call this function.\\n /// Ruling 0 is reserved for \\\"Not able/wanting to make a decision\\\".\\n ///\\n /// @param _disputeID The identifier of the dispute in the Arbitrator contract.\\n /// @param _ruling Ruling given by the arbitrator.\\n function rule(uint256 _disputeID, uint256 _ruling) external;\\n}\\n\",\"keccak256\":\"0x3afa29a93847399c8705103350b69bb70706b2075ca41b39d523b007e69e23db\",\"license\":\"MIT\"},\"src/arbitration/interfaces/IArbitratorV2.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity >=0.8.0 <0.9.0;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"./IArbitrableV2.sol\\\";\\n\\n/// @title Arbitrator\\n/// @notice Arbitrator interface for the Kleros V2 protocol.\\n/// @dev Unlike the ERC-792 this standard is not concerned with appeals, so each arbitrator can implement an appeal system that suits it the most.\\ninterface IArbitratorV2 {\\n // ************************************* //\\n // * Events * //\\n // ************************************* //\\n\\n /// @notice To be emitted when a dispute is created.\\n /// @param _disputeID The identifier of the dispute in the Arbitrator contract.\\n /// @param _arbitrable The contract which created the dispute.\\n event DisputeCreation(uint256 indexed _disputeID, IArbitrableV2 indexed _arbitrable);\\n\\n /// @notice To be raised when a ruling is given.\\n /// @param _arbitrable The arbitrable receiving the ruling.\\n /// @param _disputeID The identifier of the dispute in the Arbitrator contract.\\n /// @param _ruling The ruling which was given.\\n event Ruling(IArbitrableV2 indexed _arbitrable, uint256 indexed _disputeID, uint256 _ruling);\\n\\n /// @notice To be emitted when an ERC20 token is added or removed as a method to pay fees.\\n /// @param _token The ERC20 token.\\n /// @param _accepted Whether the token is accepted or not.\\n event AcceptedFeeToken(IERC20 indexed _token, bool indexed _accepted);\\n\\n /// @notice To be emitted when the fee for a particular ERC20 token is updated.\\n /// @param _feeToken The ERC20 token.\\n /// @param _rateInEth The new rate of the fee token in ETH.\\n /// @param _rateDecimals The new decimals of the fee token rate.\\n event NewCurrencyRate(IERC20 indexed _feeToken, uint64 _rateInEth, uint8 _rateDecimals);\\n\\n // ************************************* //\\n // * State Modifiers * //\\n // ************************************* //\\n\\n /// @notice Create a dispute and pay for the fees in the native currency, typically ETH.\\n /// @dev Must be called by the arbitrable contract and pay at least `arbitrationCost(_extraData)` in ETH.\\n /// @param _numberOfChoices The number of choices the arbitrator can choose from in this dispute.\\n /// @param _extraData Additional info about the dispute. We use it to pass the ID of the dispute's court (first 32 bytes), the minimum number of jurors required (next 32 bytes) and the ID of the specific dispute kit (last 32 bytes).\\n /// @return disputeID The identifier of the dispute created.\\n function createDispute(\\n uint256 _numberOfChoices,\\n bytes calldata _extraData\\n ) external payable returns (uint256 disputeID);\\n\\n /// @notice Create a dispute and pay for the fees in a supported ERC20 token.\\n /// @dev Must be called by the arbitrable contract and pay at least `arbitrationCost(_extraData)` in the supported ERC20 token.\\n /// @param _numberOfChoices The number of choices the arbitrator can choose from in this dispute.\\n /// @param _extraData Additional info about the dispute. We use it to pass the ID of the dispute's court (first 32 bytes), the minimum number of jurors required (next 32 bytes) and the ID of the specific dispute kit (last 32 bytes).\\n /// @param _feeToken The ERC20 token used to pay fees.\\n /// @param _feeAmount Amount of the ERC20 token used to pay fees.\\n /// @return disputeID The identifier of the dispute created.\\n function createDispute(\\n uint256 _numberOfChoices,\\n bytes calldata _extraData,\\n IERC20 _feeToken,\\n uint256 _feeAmount\\n ) external returns (uint256 disputeID);\\n\\n // ************************************* //\\n // * Public Views * //\\n // ************************************* //\\n\\n /// @notice Compute the cost of arbitration denominated in the native currency, typically ETH.\\n /// @dev It is recommended not to increase it often, as it can be highly time and gas consuming for the arbitrated contracts to cope with fee augmentation.\\n /// @param _extraData Additional info about the dispute. We use it to pass the ID of the dispute's court (first 32 bytes), the minimum number of jurors required (next 32 bytes) and the ID of the specific dispute kit (last 32 bytes).\\n /// @return cost The arbitration cost in ETH.\\n function arbitrationCost(bytes calldata _extraData) external view returns (uint256 cost);\\n\\n /// @notice Compute the cost of arbitration denominated in `_feeToken`.\\n /// @dev It is recommended not to increase it often, as it can be highly time and gas consuming for the arbitrated contracts to cope with fee augmentation.\\n /// @param _extraData Additional info about the dispute. We use it to pass the ID of the dispute's court (first 32 bytes), the minimum number of jurors required (next 32 bytes) and the ID of the specific dispute kit (last 32 bytes).\\n /// @param _feeToken The ERC20 token used to pay fees.\\n /// @return cost The arbitration cost in `_feeToken`.\\n function arbitrationCost(bytes calldata _extraData, IERC20 _feeToken) external view returns (uint256 cost);\\n\\n /// @notice Gets the current ruling of a specified dispute.\\n /// @param _disputeID The ID of the dispute.\\n /// @return ruling The current ruling.\\n /// @return tied Whether it's a tie or not.\\n /// @return overridden Whether the ruling was overridden by appeal funding or not.\\n function currentRuling(uint256 _disputeID) external view returns (uint256 ruling, bool tied, bool overridden);\\n}\\n\",\"keccak256\":\"0x65ba87c5309cd6e6562e569f79778ca423c9be7b0a44b9407e5bd2bdf8fdc3b0\",\"license\":\"MIT\"},\"src/arbitration/interfaces/IDisputeTemplateRegistry.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity >=0.8.0 <0.9.0;\\n\\n/// @title IDisputeTemplate\\n/// @notice Dispute Template interface.\\ninterface IDisputeTemplateRegistry {\\n // ************************************* //\\n // * Events * //\\n // ************************************* //\\n\\n /// @notice To be emitted when a new dispute template is created.\\n /// @param _templateId The identifier of the dispute template.\\n /// @param _templateTag An optional tag for the dispute template, such as \\\"registration\\\" or \\\"removal\\\".\\n /// @param _templateData The template data.\\n /// @param _templateDataMappings The data mappings.\\n event DisputeTemplate(\\n uint256 indexed _templateId,\\n string indexed _templateTag,\\n string _templateData,\\n string _templateDataMappings\\n );\\n\\n // ************************************* //\\n // * State Modifiers * //\\n // ************************************* //\\n\\n /// @notice Registers a new dispute template.\\n /// @param _templateTag An optional tag for the dispute template, such as \\\"registration\\\" or \\\"removal\\\".\\n /// @param _templateData The template data.\\n /// @param _templateDataMappings The data mappings for the template.\\n /// @return templateId The identifier of the dispute template.\\n function setDisputeTemplate(\\n string memory _templateTag,\\n string memory _templateData,\\n string memory _templateDataMappings\\n ) external returns (uint256 templateId);\\n}\\n\",\"keccak256\":\"0x07ea0d9c5aea94cb73ca90f9a9f7689dcca2b37e7ec49bc6e02ee660ce2cee4f\",\"license\":\"MIT\"}},\"version\":1}",
+ "bytecode": "0x60803460a157601f610ac438819003918201601f19168301916001600160401b0383118484101760a557808492604094855283398101031260a15780516001600160a01b038116919082900360a157602001516001600160a01b038116919082900360a1575f80546001600160a01b031990811633179091556001805482169290921790915560028054909116919091179055604051610a0a90816100ba8239f35b5f80fd5b634e487b7160e01b5f52604160045260245ffdfe60806040526004361015610011575f80fd5b5f3560e01c8063311a6c56146107a25780634660ebbe1461074a578063564a565d1461064f5780636cc6cde1146106295780638da5cb5b14610604578063a0af81f0146105de578063a6f9dae11461058b578063dc65351114610135578063e09997d91461010b5763fc548f0814610087575f80fd5b34610107576020366003190112610107576004356001600160a01b038116809103610107576001600160a01b035f541633036100df5773ffffffffffffffffffffffffffffffffffffffff1960015416176001555f80f35b7f596dcdb8000000000000000000000000000000000000000000000000000000005f5260045ffd5b5f80fd5b34610107576020366003190112610107576004355f526004602052602060405f2054604051908152f35b60803660031901126101075760043567ffffffffffffffff811161010757610161903690600401610960565b9060243567ffffffffffffffff811161010757610182903690600401610960565b9160443567ffffffffffffffff81116101075736602382011215610107576101b76101c391369060248160040135910161098e565b9260643594369161098e565b906001841115610563576001600160a01b036001541693602060405180967fc13517e100000000000000000000000000000000000000000000000000000000825283600483015260406024830152886044830152888560648401375f60648a8401015281606481601f19601f8d0116810103019134905af194851561043e575f9561052f575b506003549560405192608084019184831067ffffffffffffffff8411176105085761027892604052369161098e565b8252602082015f815260408301905f8252606084019283526801000000000000000088101561050857600188016003556102b1886108b2565b94909461051c575180519067ffffffffffffffff8211610508576102d586546108e2565b601f81116104c3575b50602090601f831160011461045457928260209896936103b19a9896936003965f92610449575b50508160011b915f1990871b1c19161785555b600185019051151560ff8019835416911617905551600284015551910155845f52600483528560405f205561039f5f6001600160a01b036002541692604051968795869485937f4a9941740000000000000000000000000000000000000000000000000000000085526060600486015285606486015260806024860152608485019061093c565b8381036003190160448501529061093c565b03925af190811561043e575f9161040b575b5081907fa8a9266995639bff048ad93524a5a561269d3f742d2ee429089990d4d1bb09d460406020956001600160a01b036001541693825191825287820152a3604051908152f35b90506020813d602011610436575b816104266020938361091a565b81010312610107575160206103c3565b3d9150610419565b6040513d5f823e3d90fd5b015190508d80610305565b90601f19831691875f52815f20925f5b8181106104ab5750936103b19a989693600396936001938360209d9b9810610494575b505050811b018555610318565b01515f1983891b60f8161c191690558d8080610487565b92936020600181928786015181550195019301610464565b865f5260205f20601f840160051c810191602085106104fe575b601f0160051c01905b8181106104f357506102de565b5f81556001016104e6565b90915081906104dd565b634e487b7160e01b5f52604160045260245ffd5b634e487b7160e01b5f525f60045260245ffd5b9094506020813d60201161055b575b8161054b6020938361091a565b8101031261010757519386610249565b3d915061053e565b7f5fea5b86000000000000000000000000000000000000000000000000000000005f5260045ffd5b34610107576020366003190112610107576004356001600160a01b038116809103610107575f54336001600160a01b038216036100df5773ffffffffffffffffffffffffffffffffffffffff1916175f55005b34610107575f3660031901126101075760206001600160a01b0360025416604051908152f35b34610107575f3660031901126101075760206001600160a01b035f5416604051908152f35b34610107575f3660031901126101075760206001600160a01b0360015416604051908152f35b346101075760203660031901126101075760043560035481101561010757610676906108b2565b506040515f918054610687816108e2565b808452906001811690811561072657506001146106ed575b506106af826106d794038361091a565b60ff60018201541690600360028201549101549060405194859460808652608086019061093c565b9215156020850152604084015260608301520390f35b9250805f5260205f205f905b8482106107105750820160200192506106af61069f565b60018160209254838588010152019101906106f9565b60ff191660208086019190915291151560051b840190910193506106af905061069f565b34610107576020366003190112610107576004356001600160a01b038116809103610107576001600160a01b035f541633036100df5773ffffffffffffffffffffffffffffffffffffffff1960025416176002555f80f35b3461010757604036600319011261010757600435602435815f5260046020526107ce60405f20546108b2565b506001600160a01b0360015416330361088a576003810154821161086257600181019081549060ff821661083a578392600160029360ff191617905501556040519081527f394027a5fa6e098a1191094d1719d6929b9abc535fcc0c8f448d6a4e7562227660203392a3005b7fcbb4c9f3000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f1f6edbfd000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f4aafc238000000000000000000000000000000000000000000000000000000005f5260045ffd5b6003548110156108ce5760035f5260205f209060021b01905f90565b634e487b7160e01b5f52603260045260245ffd5b90600182811c92168015610910575b60208310146108fc57565b634e487b7160e01b5f52602260045260245ffd5b91607f16916108f1565b90601f8019910116810190811067ffffffffffffffff82111761050857604052565b805180835260209291819084018484015e5f828201840152601f01601f1916010190565b9181601f840112156101075782359167ffffffffffffffff8311610107576020838186019501011161010757565b92919267ffffffffffffffff821161050857604051916109b8601f8201601f19166020018461091a565b829481845281830111610107578281602093845f96013701015256fea2646970667358221220e532d202945144342a4a2c1b0b99b885b88a09bbedafe262a405f2c73673c2c464736f6c634300081e0033",
+ "deployedBytecode": "0x60806040526004361015610011575f80fd5b5f3560e01c8063311a6c56146107a25780634660ebbe1461074a578063564a565d1461064f5780636cc6cde1146106295780638da5cb5b14610604578063a0af81f0146105de578063a6f9dae11461058b578063dc65351114610135578063e09997d91461010b5763fc548f0814610087575f80fd5b34610107576020366003190112610107576004356001600160a01b038116809103610107576001600160a01b035f541633036100df5773ffffffffffffffffffffffffffffffffffffffff1960015416176001555f80f35b7f596dcdb8000000000000000000000000000000000000000000000000000000005f5260045ffd5b5f80fd5b34610107576020366003190112610107576004355f526004602052602060405f2054604051908152f35b60803660031901126101075760043567ffffffffffffffff811161010757610161903690600401610960565b9060243567ffffffffffffffff811161010757610182903690600401610960565b9160443567ffffffffffffffff81116101075736602382011215610107576101b76101c391369060248160040135910161098e565b9260643594369161098e565b906001841115610563576001600160a01b036001541693602060405180967fc13517e100000000000000000000000000000000000000000000000000000000825283600483015260406024830152886044830152888560648401375f60648a8401015281606481601f19601f8d0116810103019134905af194851561043e575f9561052f575b506003549560405192608084019184831067ffffffffffffffff8411176105085761027892604052369161098e565b8252602082015f815260408301905f8252606084019283526801000000000000000088101561050857600188016003556102b1886108b2565b94909461051c575180519067ffffffffffffffff8211610508576102d586546108e2565b601f81116104c3575b50602090601f831160011461045457928260209896936103b19a9896936003965f92610449575b50508160011b915f1990871b1c19161785555b600185019051151560ff8019835416911617905551600284015551910155845f52600483528560405f205561039f5f6001600160a01b036002541692604051968795869485937f4a9941740000000000000000000000000000000000000000000000000000000085526060600486015285606486015260806024860152608485019061093c565b8381036003190160448501529061093c565b03925af190811561043e575f9161040b575b5081907fa8a9266995639bff048ad93524a5a561269d3f742d2ee429089990d4d1bb09d460406020956001600160a01b036001541693825191825287820152a3604051908152f35b90506020813d602011610436575b816104266020938361091a565b81010312610107575160206103c3565b3d9150610419565b6040513d5f823e3d90fd5b015190508d80610305565b90601f19831691875f52815f20925f5b8181106104ab5750936103b19a989693600396936001938360209d9b9810610494575b505050811b018555610318565b01515f1983891b60f8161c191690558d8080610487565b92936020600181928786015181550195019301610464565b865f5260205f20601f840160051c810191602085106104fe575b601f0160051c01905b8181106104f357506102de565b5f81556001016104e6565b90915081906104dd565b634e487b7160e01b5f52604160045260245ffd5b634e487b7160e01b5f525f60045260245ffd5b9094506020813d60201161055b575b8161054b6020938361091a565b8101031261010757519386610249565b3d915061053e565b7f5fea5b86000000000000000000000000000000000000000000000000000000005f5260045ffd5b34610107576020366003190112610107576004356001600160a01b038116809103610107575f54336001600160a01b038216036100df5773ffffffffffffffffffffffffffffffffffffffff1916175f55005b34610107575f3660031901126101075760206001600160a01b0360025416604051908152f35b34610107575f3660031901126101075760206001600160a01b035f5416604051908152f35b34610107575f3660031901126101075760206001600160a01b0360015416604051908152f35b346101075760203660031901126101075760043560035481101561010757610676906108b2565b506040515f918054610687816108e2565b808452906001811690811561072657506001146106ed575b506106af826106d794038361091a565b60ff60018201541690600360028201549101549060405194859460808652608086019061093c565b9215156020850152604084015260608301520390f35b9250805f5260205f205f905b8482106107105750820160200192506106af61069f565b60018160209254838588010152019101906106f9565b60ff191660208086019190915291151560051b840190910193506106af905061069f565b34610107576020366003190112610107576004356001600160a01b038116809103610107576001600160a01b035f541633036100df5773ffffffffffffffffffffffffffffffffffffffff1960025416176002555f80f35b3461010757604036600319011261010757600435602435815f5260046020526107ce60405f20546108b2565b506001600160a01b0360015416330361088a576003810154821161086257600181019081549060ff821661083a578392600160029360ff191617905501556040519081527f394027a5fa6e098a1191094d1719d6929b9abc535fcc0c8f448d6a4e7562227660203392a3005b7fcbb4c9f3000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f1f6edbfd000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f4aafc238000000000000000000000000000000000000000000000000000000005f5260045ffd5b6003548110156108ce5760035f5260205f209060021b01905f90565b634e487b7160e01b5f52603260045260245ffd5b90600182811c92168015610910575b60208310146108fc57565b634e487b7160e01b5f52602260045260245ffd5b91607f16916108f1565b90601f8019910116810190811067ffffffffffffffff82111761050857604052565b805180835260209291819084018484015e5f828201840152601f01601f1916010190565b9181601f840112156101075782359167ffffffffffffffff8311610107576020838186019501011161010757565b92919267ffffffffffffffff821161050857604051916109b8601f8201601f19166020018461091a565b829481845281830111610107578281602093845f96013701015256fea2646970667358221220e532d202945144342a4a2c1b0b99b885b88a09bbedafe262a405f2c73673c2c464736f6c634300081e0033",
"devdoc": {
+ "details": "Adapted for V2 from https://github.com/kleros/arbitrable-proxy-contracts/blob/master/contracts/ArbitrableProxy.sol.",
"events": {
- "DisputeRequest(address,uint256,uint256,uint256,string)": {
- "details": "To be emitted when a dispute is created to link the correct meta-evidence to the disputeID.",
+ "DisputeRequest(address,uint256,uint256,uint256)": {
"params": {
"_arbitrator": "The arbitrator of the contract.",
"_arbitratorDisputeID": "The identifier of the dispute in the Arbitrator contract.",
"_externalDisputeID": "An identifier created outside Kleros by the protocol requesting arbitration.",
- "_templateId": "The identifier of the dispute template. Should not be used with _templateUri.",
- "_templateUri": "The URI to the dispute template. For example on IPFS: starting with '/ipfs/'. Should not be used with _templateId."
+ "_templateId": "The identifier of the dispute template."
}
},
"Ruling(address,uint256,uint256)": {
- "details": "To be raised when a ruling is given.",
"params": {
"_arbitrator": "The arbitrator giving the ruling.",
"_disputeID": "The identifier of the dispute in the Arbitrator contract.",
@@ -340,20 +328,18 @@
},
"kind": "dev",
"methods": {
- "changeGovernor(address)": {
- "details": "Changes the governor.",
+ "changeOwner(address)": {
"params": {
- "_governor": "The address of the new governor."
+ "_owner": "The address of the new owner."
}
},
"constructor": {
- "details": "Constructor",
"params": {
"_arbitrator": "Target global arbitrator for any disputes."
}
},
"createDisputeForTemplate(bytes,string,string,uint256)": {
- "details": "Calls createDispute function of the specified arbitrator to create a dispute. Note that we don’t need to check that msg.value is enough to pay arbitration fees as it’s the responsibility of the arbitrator contract.",
+ "details": "No need to check that msg.value is enough to pay arbitration fees as it’s the responsibility of the arbitrator contract.",
"params": {
"_arbitratorExtraData": "Extra data for the arbitrator of the dispute.",
"_disputeTemplate": "Dispute template.",
@@ -364,69 +350,80 @@
"disputeID": "Dispute id (on arbitrator side) of the created dispute."
}
},
- "createDisputeForTemplateUri(bytes,string,uint256)": {
- "details": "Calls createDispute function of the specified arbitrator to create a dispute. Note that we don’t need to check that msg.value is enough to pay arbitration fees as it’s the responsibility of the arbitrator contract.",
- "params": {
- "_arbitratorExtraData": "Extra data for the arbitrator of the dispute.",
- "_disputeTemplateUri": "The URI to the dispute template. For example on IPFS: starting with '/ipfs/'.",
- "_numberOfRulingOptions": "Number of ruling options."
- },
- "returns": {
- "disputeID": "Dispute id (on arbitrator side) of the created dispute."
- }
- },
"rule(uint256,uint256)": {
- "details": "To be called by the arbitrator of the dispute, to declare the winning ruling.",
+ "details": "This is a callback function for the arbitrator to provide the ruling to this contract. Only the arbitrator must be allowed to call this function. Ruling 0 is reserved for \"Not able/wanting to make a decision\".",
"params": {
- "_arbitratorDisputeID": "ID of the dispute in arbitrator contract.",
- "_ruling": "The ruling choice of the arbitration."
+ "_disputeID": "The identifier of the dispute in the Arbitrator contract.",
+ "_ruling": "Ruling given by the arbitrator."
}
}
},
- "title": "DisputeResolver DisputeResolver contract adapted for V2 from https://github.com/kleros/arbitrable-proxy-contracts/blob/master/contracts/ArbitrableProxy.sol.",
+ "title": "DisputeResolver",
"version": 1
},
"userdoc": {
+ "events": {
+ "DisputeRequest(address,uint256,uint256,uint256)": {
+ "notice": "To be emitted when a dispute is created to link the correct template to the disputeID."
+ },
+ "Ruling(address,uint256,uint256)": {
+ "notice": "To be raised when a ruling is given."
+ }
+ },
"kind": "user",
- "methods": {},
+ "methods": {
+ "changeOwner(address)": {
+ "notice": "Changes the owner."
+ },
+ "constructor": {
+ "notice": "Constructor"
+ },
+ "createDisputeForTemplate(bytes,string,string,uint256)": {
+ "notice": "Calls createDispute function of the specified arbitrator to create a dispute."
+ },
+ "rule(uint256,uint256)": {
+ "notice": "Give a ruling for a dispute."
+ }
+ },
+ "notice": "DisputeResolver contract",
"version": 1
},
"storageLayout": {
"storage": [
{
- "astId": 14991,
+ "astId": 18721,
"contract": "src/arbitration/arbitrables/DisputeResolver.sol:DisputeResolver",
- "label": "governor",
+ "label": "owner",
"offset": 0,
"slot": "0",
"type": "t_address"
},
{
- "astId": 14994,
+ "astId": 18724,
"contract": "src/arbitration/arbitrables/DisputeResolver.sol:DisputeResolver",
"label": "arbitrator",
"offset": 0,
"slot": "1",
- "type": "t_contract(IArbitratorV2)23044"
+ "type": "t_contract(IArbitratorV2)26051"
},
{
- "astId": 14997,
+ "astId": 18727,
"contract": "src/arbitration/arbitrables/DisputeResolver.sol:DisputeResolver",
"label": "templateRegistry",
"offset": 0,
"slot": "2",
- "type": "t_contract(IDisputeTemplateRegistry)23215"
+ "type": "t_contract(IDisputeTemplateRegistry)26278"
},
{
- "astId": 15001,
+ "astId": 18731,
"contract": "src/arbitration/arbitrables/DisputeResolver.sol:DisputeResolver",
"label": "disputes",
"offset": 0,
"slot": "3",
- "type": "t_array(t_struct(DisputeStruct)14989_storage)dyn_storage"
+ "type": "t_array(t_struct(DisputeStruct)18719_storage)dyn_storage"
},
{
- "astId": 15005,
+ "astId": 18735,
"contract": "src/arbitration/arbitrables/DisputeResolver.sol:DisputeResolver",
"label": "arbitratorDisputeIDToLocalID",
"offset": 0,
@@ -440,8 +437,8 @@
"label": "address",
"numberOfBytes": "20"
},
- "t_array(t_struct(DisputeStruct)14989_storage)dyn_storage": {
- "base": "t_struct(DisputeStruct)14989_storage",
+ "t_array(t_struct(DisputeStruct)18719_storage)dyn_storage": {
+ "base": "t_struct(DisputeStruct)18719_storage",
"encoding": "dynamic_array",
"label": "struct DisputeResolver.DisputeStruct[]",
"numberOfBytes": "32"
@@ -456,12 +453,12 @@
"label": "bytes",
"numberOfBytes": "32"
},
- "t_contract(IArbitratorV2)23044": {
+ "t_contract(IArbitratorV2)26051": {
"encoding": "inplace",
"label": "contract IArbitratorV2",
"numberOfBytes": "20"
},
- "t_contract(IDisputeTemplateRegistry)23215": {
+ "t_contract(IDisputeTemplateRegistry)26278": {
"encoding": "inplace",
"label": "contract IDisputeTemplateRegistry",
"numberOfBytes": "20"
@@ -473,12 +470,12 @@
"numberOfBytes": "32",
"value": "t_uint256"
},
- "t_struct(DisputeStruct)14989_storage": {
+ "t_struct(DisputeStruct)18719_storage": {
"encoding": "inplace",
"label": "struct DisputeResolver.DisputeStruct",
"members": [
{
- "astId": 14982,
+ "astId": 18712,
"contract": "src/arbitration/arbitrables/DisputeResolver.sol:DisputeResolver",
"label": "arbitratorExtraData",
"offset": 0,
@@ -486,7 +483,7 @@
"type": "t_bytes_storage"
},
{
- "astId": 14984,
+ "astId": 18714,
"contract": "src/arbitration/arbitrables/DisputeResolver.sol:DisputeResolver",
"label": "isRuled",
"offset": 0,
@@ -494,7 +491,7 @@
"type": "t_bool"
},
{
- "astId": 14986,
+ "astId": 18716,
"contract": "src/arbitration/arbitrables/DisputeResolver.sol:DisputeResolver",
"label": "ruling",
"offset": 0,
@@ -502,7 +499,7 @@
"type": "t_uint256"
},
{
- "astId": 14988,
+ "astId": 18718,
"contract": "src/arbitration/arbitrables/DisputeResolver.sol:DisputeResolver",
"label": "numberOfRulingOptions",
"offset": 0,
diff --git a/contracts/deployments/arbitrumSepoliaDevnet/DisputeTemplateRegistryUniversity.json b/contracts/deployments/arbitrumSepoliaDevnet/DisputeTemplateRegistryUniversity.json
new file mode 100644
index 000000000..0586cb4bf
--- /dev/null
+++ b/contracts/deployments/arbitrumSepoliaDevnet/DisputeTemplateRegistryUniversity.json
@@ -0,0 +1,317 @@
+{
+ "address": "0x75A5D16e9A699162506E4d79D68CF646e6600ba1",
+ "abi": [
+ {
+ "stateMutability": "payable",
+ "type": "fallback"
+ },
+ {
+ "stateMutability": "payable",
+ "type": "receive"
+ },
+ {
+ "inputs": [],
+ "name": "AlreadyInitialized",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "FailedDelegateCall",
+ "type": "error"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "implementation",
+ "type": "address"
+ }
+ ],
+ "name": "InvalidImplementation",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "NotInitializing",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "OwnerOnly",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "UUPSUnauthorizedCallContext",
+ "type": "error"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "bytes32",
+ "name": "slot",
+ "type": "bytes32"
+ }
+ ],
+ "name": "UUPSUnsupportedProxiableUUID",
+ "type": "error"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "uint256",
+ "name": "_templateId",
+ "type": "uint256"
+ },
+ {
+ "indexed": true,
+ "internalType": "string",
+ "name": "_templateTag",
+ "type": "string"
+ },
+ {
+ "indexed": false,
+ "internalType": "string",
+ "name": "_templateData",
+ "type": "string"
+ },
+ {
+ "indexed": false,
+ "internalType": "string",
+ "name": "_templateDataMappings",
+ "type": "string"
+ }
+ ],
+ "name": "DisputeTemplate",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": false,
+ "internalType": "uint64",
+ "name": "version",
+ "type": "uint64"
+ }
+ ],
+ "name": "Initialized",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "newImplementation",
+ "type": "address"
+ }
+ ],
+ "name": "Upgraded",
+ "type": "event"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "_owner",
+ "type": "address"
+ }
+ ],
+ "name": "changeOwner",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "_owner",
+ "type": "address"
+ }
+ ],
+ "name": "initialize",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "owner",
+ "outputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "proxiableUUID",
+ "outputs": [
+ {
+ "internalType": "bytes32",
+ "name": "",
+ "type": "bytes32"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "string",
+ "name": "_templateTag",
+ "type": "string"
+ },
+ {
+ "internalType": "string",
+ "name": "_templateData",
+ "type": "string"
+ },
+ {
+ "internalType": "string",
+ "name": "_templateDataMappings",
+ "type": "string"
+ }
+ ],
+ "name": "setDisputeTemplate",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "templateId",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "templates",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "newImplementation",
+ "type": "address"
+ },
+ {
+ "internalType": "bytes",
+ "name": "data",
+ "type": "bytes"
+ }
+ ],
+ "name": "upgradeToAndCall",
+ "outputs": [],
+ "stateMutability": "payable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "version",
+ "outputs": [
+ {
+ "internalType": "string",
+ "name": "",
+ "type": "string"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "_implementation",
+ "type": "address"
+ },
+ {
+ "internalType": "bytes",
+ "name": "_data",
+ "type": "bytes"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "constructor"
+ }
+ ],
+ "transactionHash": "0xbc50b201f6d4dfa0a74e83aeb201df1f0390ab361ba76bf72a696a36d3a5ffe4",
+ "receipt": {
+ "to": null,
+ "from": "0xf1C7c037891525E360C59f708739Ac09A7670c59",
+ "contractAddress": "0x75A5D16e9A699162506E4d79D68CF646e6600ba1",
+ "transactionIndex": 1,
+ "gasUsed": "157979",
+ "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000800000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000004000000000000000000000000000000000000000000000000000000000000",
+ "blockHash": "0x9656d572eb28bbdc716c7b34860d4e05442e4a488ce69c9f410f69a3d125df0c",
+ "transactionHash": "0xbc50b201f6d4dfa0a74e83aeb201df1f0390ab361ba76bf72a696a36d3a5ffe4",
+ "logs": [
+ {
+ "transactionIndex": 1,
+ "blockNumber": 193661064,
+ "transactionHash": "0xbc50b201f6d4dfa0a74e83aeb201df1f0390ab361ba76bf72a696a36d3a5ffe4",
+ "address": "0x75A5D16e9A699162506E4d79D68CF646e6600ba1",
+ "topics": [
+ "0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2"
+ ],
+ "data": "0x0000000000000000000000000000000000000000000000000000000000000001",
+ "logIndex": 0,
+ "blockHash": "0x9656d572eb28bbdc716c7b34860d4e05442e4a488ce69c9f410f69a3d125df0c"
+ }
+ ],
+ "blockNumber": 193661064,
+ "cumulativeGasUsed": "157979",
+ "status": 1,
+ "byzantium": true
+ },
+ "args": [
+ "0xC3f638389635bF33E019c845FdaF2ed9bca3DF67",
+ "0xc4d66de8000000000000000000000000f1c7c037891525e360c59f708739ac09a7670c59"
+ ],
+ "numDeployments": 1,
+ "solcInputHash": "cff4f5de661c6299ed3bdc0f8613457a",
+ "metadata": "{\"compiler\":{\"version\":\"0.8.30+commit.73712a01\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_implementation\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"stateMutability\":\"payable\",\"type\":\"fallback\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/proxy/KlerosProxies.sol\":\"DisputeTemplateRegistryUniversityProxy\"},\"evmVersion\":\"cancun\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000},\"remappings\":[],\"viaIR\":true},\"sources\":{\"src/proxy/KlerosProxies.sol\":{\"content\":\"//SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.24;\\n\\nimport \\\"./UUPSProxy.sol\\\";\\n\\n/// Workaround to get meaningful names for the proxy contracts\\n/// Otherwise all the contracts are called `UUPSProxy` on the chain explorers\\n\\ncontract DisputeKitClassicUniversityProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract DisputeKitClassicProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract DisputeKitGatedProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract DisputeKitGatedShutterProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract DisputeKitShutterProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract DisputeKitSybilResistantProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract DisputeTemplateRegistryUniversityProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract DisputeTemplateRegistryProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract EvidenceModuleProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract ForeignGatewayOnEthereumProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract HomeGatewayToEthereumProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract KlerosCoreRulerProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract KlerosCoreUniversityProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract KlerosCoreProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract PolicyRegistryProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract RandomizerRNGProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract SortitionModuleUniversityProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract SortitionModuleProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\",\"keccak256\":\"0x9dbd26ac5a026a32fc38e394188ab4a8dce0d7e8f249fa1412f757611f948767\",\"license\":\"MIT\"},\"src/proxy/UUPSProxy.sol\":{\"content\":\"//SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.24;\\n\\n/// @title UUPS Proxy\\n/// @author Simon Malatrait \\n/// @notice This contract implements a UUPS Proxy compliant with ERC-1967 & ERC-1822.\\n///\\n/// @dev This contract delegates all calls to another contract (UUPS Proxiable) through a fallback function and the use of the `delegatecall` EVM instruction.\\n/// We refer to the Proxiable contract (as per ERC-1822) with `implementation`.\\n/// Adapted from \\ncontract UUPSProxy {\\n /// @dev Storage slot with the address of the current implementation.\\n /// This is the keccak-256 hash of \\\"eip1967.proxy.implementation\\\" subtracted by 1, and is\\n /// validated in the constructor.\\n /// NOTE: bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1)\\n bytes32 private constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\\n\\n // ************************************* //\\n // * Constructor * //\\n // ************************************* //\\n\\n /// @notice Initializes the upgradeable proxy with an initial implementation specified by `_implementation`.\\n /// @dev If `_data` is nonempty, it's used as data in a delegate call to `_implementation`.\\n /// This will typically be an encoded function call, and allows initializing the storage of the proxy like a Solidity constructor.\\n constructor(address _implementation, bytes memory _data) {\\n assembly {\\n sstore(IMPLEMENTATION_SLOT, _implementation)\\n }\\n\\n if (_data.length != 0) {\\n (bool success, ) = _implementation.delegatecall(_data);\\n require(success, \\\"Proxy Constructor failed\\\");\\n }\\n }\\n\\n // ************************************* //\\n // * State Modifiers * //\\n // ************************************* //\\n\\n /// @dev Delegates the current call to `implementation`.\\n /// NOTE: This function does not return to its internal call site, it will return directly to the external caller.\\n function _delegate(address implementation) internal {\\n assembly {\\n // Copy msg.data. We take full control of memory in this inline assembly\\n // block because it will not return to Solidity code. We overwrite the\\n // Solidity scratch pad at memory position 0.\\n calldatacopy(0, 0, calldatasize())\\n\\n // Call the implementation.\\n // out and outsize are 0 because we don't know the size yet.\\n let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)\\n\\n // Copy the returned data.\\n returndatacopy(0, 0, returndatasize())\\n\\n switch result\\n // delegatecall returns 0 on error.\\n case 0 {\\n revert(0, returndatasize())\\n }\\n default {\\n return(0, returndatasize())\\n }\\n }\\n }\\n\\n // ************************************* //\\n // * Internal Views * //\\n // ************************************* //\\n\\n function _getImplementation() internal view returns (address implementation) {\\n assembly {\\n implementation := sload(IMPLEMENTATION_SLOT)\\n }\\n }\\n\\n // ************************************* //\\n // * Fallback * //\\n // ************************************* //\\n\\n /// @dev Fallback function that delegates calls to the address returned by `_implementation()`.\\n /// @dev Will run if no other function in the contract matches the call data.\\n fallback() external payable {\\n _delegate(_getImplementation());\\n }\\n\\n receive() external payable {\\n _delegate(_getImplementation());\\n }\\n}\\n\",\"keccak256\":\"0x2d7b1f81e525787f1b8b033ce381a81cb5f39e411ff31490e019113205a661cd\",\"license\":\"MIT\"}},\"version\":1}",
+ "bytecode": "0x608060405234610144576102148038038061001981610148565b928339810190604081830312610144578051906001600160a01b0382168203610144576020810151906001600160401b038211610144570182601f8201121561014457805161006f61006a82610181565b610148565b9181835260208301946020838301011161014457815f926020809301875e83010152817f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5551806100c9575b6040516077908161019d8239f35b5f9283925af43d1561013f573d6100e261006a82610181565b9081525f60203d92013e5b156100fa575f80806100bb565b60405162461bcd60e51b815260206004820152601860248201527f50726f787920436f6e7374727563746f72206661696c656400000000000000006044820152606490fd5b6100ed565b5f80fd5b6040519190601f01601f191682016001600160401b0381118382101761016d57604052565b634e487b7160e01b5f52604160045260245ffd5b6001600160401b03811161016d57601f01601f19166020019056fe60806040525f807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc54368280378136915af43d5f803e15603d573d5ff35b3d5ffdfea2646970667358221220e347285b4ca364b0c82598fe294ad8b02e9adfbbac26ab00c24b1b747375019464736f6c634300081e0033",
+ "deployedBytecode": "0x60806040525f807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc54368280378136915af43d5f803e15603d573d5ff35b3d5ffdfea2646970667358221220e347285b4ca364b0c82598fe294ad8b02e9adfbbac26ab00c24b1b747375019464736f6c634300081e0033",
+ "execute": {
+ "methodName": "initialize",
+ "args": [
+ "0xf1C7c037891525E360C59f708739Ac09A7670c59"
+ ]
+ },
+ "implementation": "0xC3f638389635bF33E019c845FdaF2ed9bca3DF67",
+ "devdoc": {
+ "kind": "dev",
+ "methods": {},
+ "version": 1
+ },
+ "userdoc": {
+ "kind": "user",
+ "methods": {},
+ "version": 1
+ },
+ "storageLayout": {
+ "storage": [],
+ "types": null
+ }
+}
diff --git a/contracts/deployments/arbitrumSepoliaDevnet/DisputeTemplateRegistryUniversity_Implementation.json b/contracts/deployments/arbitrumSepoliaDevnet/DisputeTemplateRegistryUniversity_Implementation.json
new file mode 100644
index 000000000..bb5d17755
--- /dev/null
+++ b/contracts/deployments/arbitrumSepoliaDevnet/DisputeTemplateRegistryUniversity_Implementation.json
@@ -0,0 +1,445 @@
+{
+ "address": "0xC3f638389635bF33E019c845FdaF2ed9bca3DF67",
+ "abi": [
+ {
+ "inputs": [],
+ "stateMutability": "nonpayable",
+ "type": "constructor"
+ },
+ {
+ "inputs": [],
+ "name": "AlreadyInitialized",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "FailedDelegateCall",
+ "type": "error"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "implementation",
+ "type": "address"
+ }
+ ],
+ "name": "InvalidImplementation",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "NotInitializing",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "OwnerOnly",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "UUPSUnauthorizedCallContext",
+ "type": "error"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "bytes32",
+ "name": "slot",
+ "type": "bytes32"
+ }
+ ],
+ "name": "UUPSUnsupportedProxiableUUID",
+ "type": "error"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "uint256",
+ "name": "_templateId",
+ "type": "uint256"
+ },
+ {
+ "indexed": true,
+ "internalType": "string",
+ "name": "_templateTag",
+ "type": "string"
+ },
+ {
+ "indexed": false,
+ "internalType": "string",
+ "name": "_templateData",
+ "type": "string"
+ },
+ {
+ "indexed": false,
+ "internalType": "string",
+ "name": "_templateDataMappings",
+ "type": "string"
+ }
+ ],
+ "name": "DisputeTemplate",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": false,
+ "internalType": "uint64",
+ "name": "version",
+ "type": "uint64"
+ }
+ ],
+ "name": "Initialized",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "newImplementation",
+ "type": "address"
+ }
+ ],
+ "name": "Upgraded",
+ "type": "event"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "_owner",
+ "type": "address"
+ }
+ ],
+ "name": "changeOwner",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "_owner",
+ "type": "address"
+ }
+ ],
+ "name": "initialize",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "owner",
+ "outputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "proxiableUUID",
+ "outputs": [
+ {
+ "internalType": "bytes32",
+ "name": "",
+ "type": "bytes32"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "string",
+ "name": "_templateTag",
+ "type": "string"
+ },
+ {
+ "internalType": "string",
+ "name": "_templateData",
+ "type": "string"
+ },
+ {
+ "internalType": "string",
+ "name": "_templateDataMappings",
+ "type": "string"
+ }
+ ],
+ "name": "setDisputeTemplate",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "templateId",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "templates",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "newImplementation",
+ "type": "address"
+ },
+ {
+ "internalType": "bytes",
+ "name": "data",
+ "type": "bytes"
+ }
+ ],
+ "name": "upgradeToAndCall",
+ "outputs": [],
+ "stateMutability": "payable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "version",
+ "outputs": [
+ {
+ "internalType": "string",
+ "name": "",
+ "type": "string"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ }
+ ],
+ "transactionHash": "0xa6a4958a5881803297025fcb6b02ff4623b6c196dfc1c63ecdcc5dbca371f59c",
+ "receipt": {
+ "to": null,
+ "from": "0xf1C7c037891525E360C59f708739Ac09A7670c59",
+ "contractAddress": "0xC3f638389635bF33E019c845FdaF2ed9bca3DF67",
+ "transactionIndex": 1,
+ "gasUsed": "550773",
+ "logsBloom": "0x00080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000100000000000000000000000000000",
+ "blockHash": "0x3831b40eb48160858d03c9e32ad925255ab201a6d738d0d223b347c63193ab27",
+ "transactionHash": "0xa6a4958a5881803297025fcb6b02ff4623b6c196dfc1c63ecdcc5dbca371f59c",
+ "logs": [
+ {
+ "transactionIndex": 1,
+ "blockNumber": 193661055,
+ "transactionHash": "0xa6a4958a5881803297025fcb6b02ff4623b6c196dfc1c63ecdcc5dbca371f59c",
+ "address": "0xC3f638389635bF33E019c845FdaF2ed9bca3DF67",
+ "topics": [
+ "0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2"
+ ],
+ "data": "0x000000000000000000000000000000000000000000000000ffffffffffffffff",
+ "logIndex": 0,
+ "blockHash": "0x3831b40eb48160858d03c9e32ad925255ab201a6d738d0d223b347c63193ab27"
+ }
+ ],
+ "blockNumber": 193661055,
+ "cumulativeGasUsed": "550773",
+ "status": 1,
+ "byzantium": true
+ },
+ "args": [],
+ "numDeployments": 1,
+ "solcInputHash": "d547d738900bce1310e91a5d1adfc179",
+ "metadata": "{\"compiler\":{\"version\":\"0.8.30+commit.73712a01\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"AlreadyInitialized\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedDelegateCall\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"implementation\",\"type\":\"address\"}],\"name\":\"InvalidImplementation\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotInitializing\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OwnerOnly\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UUPSUnauthorizedCallContext\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"slot\",\"type\":\"bytes32\"}],\"name\":\"UUPSUnsupportedProxiableUUID\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_templateId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"string\",\"name\":\"_templateTag\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"_templateData\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"_templateDataMappings\",\"type\":\"string\"}],\"name\":\"DisputeTemplate\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"version\",\"type\":\"uint64\"}],\"name\":\"Initialized\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newImplementation\",\"type\":\"address\"}],\"name\":\"Upgraded\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"name\":\"changeOwner\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"proxiableUUID\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"_templateTag\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"_templateData\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"_templateDataMappings\",\"type\":\"string\"}],\"name\":\"setDisputeTemplate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"templateId\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"templates\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newImplementation\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"upgradeToAndCall\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"version\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"errors\":{\"AlreadyInitialized()\":[{\"details\":\"The contract is already initialized.\"}],\"NotInitializing()\":[{\"details\":\"The contract is not initializing.\"}]},\"events\":{\"DisputeTemplate(uint256,string,string,string)\":{\"params\":{\"_templateData\":\"The template data.\",\"_templateDataMappings\":\"The data mappings.\",\"_templateId\":\"The identifier of the dispute template.\",\"_templateTag\":\"An optional tag for the dispute template, such as \\\"registration\\\" or \\\"removal\\\".\"}},\"Initialized(uint64)\":{\"details\":\"Triggered when the contract has been initialized or reinitialized.\"},\"Upgraded(address)\":{\"params\":{\"newImplementation\":\"Address of the new implementation the proxy is now forwarding calls to.\"}}},\"kind\":\"dev\",\"methods\":{\"changeOwner(address)\":{\"params\":{\"_owner\":\"The new owner.\"}},\"constructor\":{\"custom:oz-upgrades-unsafe-allow\":\"constructor\"},\"initialize(address)\":{\"params\":{\"_owner\":\"Owner of the contract.\"}},\"proxiableUUID()\":{\"details\":\"IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this function revert if invoked through a proxy. This is guaranteed by the if statement.\"},\"setDisputeTemplate(string,string,string)\":{\"params\":{\"_templateData\":\"The template data.\",\"_templateDataMappings\":\"The data mappings for the template.\",\"_templateTag\":\"An optional tag for the dispute template, such as \\\"registration\\\" or \\\"removal\\\".\"},\"returns\":{\"templateId\":\"The identifier of the dispute template.\"}},\"upgradeToAndCall(address,bytes)\":{\"details\":\"Reverts if the execution is not performed via delegatecall or the execution context is not of a proxy with an ERC1967-compliant implementation pointing to self.\",\"params\":{\"data\":\"Data used in a delegate call to `newImplementation` if non-empty. This will typically be an encoded function call, and allows initializing the storage of the proxy like a Solidity constructor.\",\"newImplementation\":\"Address of the new implementation contract.\"}}},\"stateVariables\":{\"version\":{\"return\":\"Version string.\",\"returns\":{\"_0\":\"Version string.\"}}},\"title\":\"Dispute Template Registry\",\"version\":1},\"userdoc\":{\"errors\":{\"FailedDelegateCall()\":[{\"notice\":\"Failed Delegated call\"}],\"InvalidImplementation(address)\":[{\"notice\":\"The `implementation` is not UUPS-compliant\"}],\"UUPSUnauthorizedCallContext()\":[{\"notice\":\"The call is from an unauthorized context.\"}],\"UUPSUnsupportedProxiableUUID(bytes32)\":[{\"notice\":\"The storage `slot` is unsupported as a UUID.\"}]},\"events\":{\"DisputeTemplate(uint256,string,string,string)\":{\"notice\":\"To be emitted when a new dispute template is created.\"},\"Upgraded(address)\":{\"notice\":\"Emitted when the `implementation` has been successfully upgraded.\"}},\"kind\":\"user\",\"methods\":{\"changeOwner(address)\":{\"notice\":\"Changes the owner of the contract.\"},\"initialize(address)\":{\"notice\":\"Initializer\"},\"owner()\":{\"notice\":\"The owner of the contract.\"},\"proxiableUUID()\":{\"notice\":\"Implementation of the ERC1822 `proxiableUUID` function. This returns the storage slot used by the implementation. It is used to validate the implementation's compatibility when performing an upgrade.\"},\"setDisputeTemplate(string,string,string)\":{\"notice\":\"Registers a new dispute template.\"},\"templates()\":{\"notice\":\"The number of templates.\"},\"upgradeToAndCall(address,bytes)\":{\"notice\":\"Upgrade mechanism including access control and UUPS-compliance.\"},\"version()\":{\"notice\":\"Returns the version of the implementation.\"}},\"notice\":\"A contract to maintain a registry of dispute templates.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/arbitration/DisputeTemplateRegistry.sol\":\"DisputeTemplateRegistry\"},\"evmVersion\":\"cancun\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000},\"remappings\":[],\"viaIR\":true},\"sources\":{\"src/arbitration/DisputeTemplateRegistry.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.24;\\n\\nimport \\\"../proxy/UUPSProxiable.sol\\\";\\nimport \\\"../proxy/Initializable.sol\\\";\\nimport \\\"./interfaces/IDisputeTemplateRegistry.sol\\\";\\n\\n/// @title Dispute Template Registry\\n/// @notice A contract to maintain a registry of dispute templates.\\ncontract DisputeTemplateRegistry is IDisputeTemplateRegistry, UUPSProxiable, Initializable {\\n string public constant override version = \\\"2.0.0\\\";\\n\\n // ************************************* //\\n // * Storage * //\\n // ************************************* //\\n\\n /// @notice The owner of the contract.\\n address public owner;\\n\\n /// @notice The number of templates.\\n uint256 public templates;\\n\\n // ************************************* //\\n // * Function Modifiers * //\\n // ************************************* //\\n\\n modifier onlyByOwner() {\\n if (owner != msg.sender) revert OwnerOnly();\\n _;\\n }\\n\\n // ************************************* //\\n // * Constructor * //\\n // ************************************* //\\n\\n /// @custom:oz-upgrades-unsafe-allow constructor\\n constructor() {\\n _disableInitializers();\\n }\\n\\n /// @notice Initializer\\n /// @param _owner Owner of the contract.\\n function initialize(address _owner) external initializer {\\n owner = _owner;\\n }\\n\\n // ************************ //\\n // * Governance * //\\n // ************************ //\\n\\n /// @dev Access Control to perform implementation upgrades (UUPS Proxiable)\\n /// Only the owner can perform upgrades (`onlyByOwner`)\\n function _authorizeUpgrade(address) internal view override onlyByOwner {\\n // NOP\\n }\\n\\n /// @notice Changes the owner of the contract.\\n /// @param _owner The new owner.\\n function changeOwner(address _owner) external onlyByOwner {\\n owner = _owner;\\n }\\n\\n // ************************************* //\\n // * State Modifiers * //\\n // ************************************* //\\n\\n /// @inheritdoc IDisputeTemplateRegistry\\n function setDisputeTemplate(\\n string memory _templateTag,\\n string memory _templateData,\\n string memory _templateDataMappings\\n ) external returns (uint256 templateId) {\\n templateId = templates++;\\n emit DisputeTemplate(templateId, _templateTag, _templateData, _templateDataMappings);\\n }\\n\\n // ************************************* //\\n // * Errors * //\\n // ************************************* //\\n\\n error OwnerOnly();\\n}\\n\",\"keccak256\":\"0x9790f4e6f1a6b77063f3d95595ad70d86b5076371b3c3e04e2ce73ec0f9365f4\",\"license\":\"MIT\"},\"src/arbitration/interfaces/IDisputeTemplateRegistry.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity >=0.8.0 <0.9.0;\\n\\n/// @title IDisputeTemplate\\n/// @notice Dispute Template interface.\\ninterface IDisputeTemplateRegistry {\\n // ************************************* //\\n // * Events * //\\n // ************************************* //\\n\\n /// @notice To be emitted when a new dispute template is created.\\n /// @param _templateId The identifier of the dispute template.\\n /// @param _templateTag An optional tag for the dispute template, such as \\\"registration\\\" or \\\"removal\\\".\\n /// @param _templateData The template data.\\n /// @param _templateDataMappings The data mappings.\\n event DisputeTemplate(\\n uint256 indexed _templateId,\\n string indexed _templateTag,\\n string _templateData,\\n string _templateDataMappings\\n );\\n\\n // ************************************* //\\n // * State Modifiers * //\\n // ************************************* //\\n\\n /// @notice Registers a new dispute template.\\n /// @param _templateTag An optional tag for the dispute template, such as \\\"registration\\\" or \\\"removal\\\".\\n /// @param _templateData The template data.\\n /// @param _templateDataMappings The data mappings for the template.\\n /// @return templateId The identifier of the dispute template.\\n function setDisputeTemplate(\\n string memory _templateTag,\\n string memory _templateData,\\n string memory _templateDataMappings\\n ) external returns (uint256 templateId);\\n}\\n\",\"keccak256\":\"0x07ea0d9c5aea94cb73ca90f9a9f7689dcca2b37e7ec49bc6e02ee660ce2cee4f\",\"license\":\"MIT\"},\"src/proxy/Initializable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol) \\n\\npragma solidity ^0.8.24;\\n\\n/**\\n * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed\\n * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an\\n * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer\\n * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.\\n *\\n * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be\\n * reused. This mechanism prevents re-execution of each \\\"step\\\" but allows the creation of new initialization steps in\\n * case an upgrade adds a module that needs to be initialized.\\n *\\n * For example:\\n *\\n * ```solidity\\n * contract MyToken is ERC20Upgradeable {\\n * function initialize() initializer public {\\n * __ERC20_init(\\\"MyToken\\\", \\\"MTK\\\");\\n * }\\n * }\\n *\\n * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {\\n * function initializeV2() reinitializer(2) public {\\n * __ERC20Permit_init(\\\"MyToken\\\");\\n * }\\n * }\\n * ```\\n *\\n * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as\\n * possible by providing the encoded function call as the `_data` argument to the proxy constructor\\n *\\n * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure\\n * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.\\n *\\n * [CAUTION]\\n * ====\\n * Avoid leaving a contract uninitialized.\\n *\\n * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation\\n * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke\\n * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:\\n *\\n * ```\\n * /// @custom:oz-upgrades-unsafe-allow constructor\\n * constructor() {\\n * _disableInitializers();\\n * }\\n * ```\\n */\\nabstract contract Initializable {\\n /**\\n * @dev Storage of the initializable contract.\\n *\\n * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions\\n * when using with upgradeable contracts.\\n *\\n * @custom:storage-location erc7201:openzeppelin.storage.Initializable\\n */\\n struct InitializableStorage {\\n /**\\n * @dev Indicates that the contract has been initialized.\\n */\\n uint64 _initialized;\\n /**\\n * @dev Indicates that the contract is in the process of being initialized.\\n */\\n bool _initializing;\\n }\\n\\n // keccak256(abi.encode(uint256(keccak256(\\\"openzeppelin.storage.Initializable\\\")) - 1))\\n bytes32 private constant _INITIALIZABLE_STORAGE =\\n 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0e;\\n\\n /**\\n * @dev The contract is already initialized.\\n */\\n error AlreadyInitialized();\\n\\n /**\\n * @dev The contract is not initializing.\\n */\\n error NotInitializing();\\n\\n /**\\n * @dev Triggered when the contract has been initialized or reinitialized.\\n */\\n event Initialized(uint64 version);\\n\\n /**\\n * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,\\n * `onlyInitializing` functions can be used to initialize parent contracts.\\n *\\n * Similar to `initializer()`, except that functions marked with `initializer` can be nested in the context of a\\n * constructor.\\n *\\n * Emits an {Initialized} event.\\n */\\n modifier initializer() {\\n // solhint-disable-next-line var-name-mixedcase\\n InitializableStorage storage $ = _getInitializableStorage();\\n\\n bool isTopLevelCall = !$._initializing;\\n uint64 initialized = $._initialized;\\n if (!(isTopLevelCall && initialized < 1) && !(address(this).code.length == 0 && initialized == 1)) {\\n revert AlreadyInitialized();\\n }\\n $._initialized = 1;\\n if (isTopLevelCall) {\\n $._initializing = true;\\n }\\n _;\\n if (isTopLevelCall) {\\n $._initializing = false;\\n emit Initialized(1);\\n }\\n }\\n\\n /**\\n * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the\\n * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be\\n * used to initialize parent contracts.\\n *\\n * A reinitializer may be used after the original initialization step. This is essential to configure modules that\\n * are added through upgrades and that require initialization.\\n *\\n * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`\\n * cannot be nested. If one is invoked in the context of another, execution will revert.\\n *\\n * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in\\n * a contract, executing them in the right order is up to the developer or operator.\\n *\\n * WARNING: setting the version to 255 will prevent any future reinitialization.\\n *\\n * Emits an {Initialized} event.\\n */\\n modifier reinitializer(uint64 version) {\\n // solhint-disable-next-line var-name-mixedcase\\n InitializableStorage storage $ = _getInitializableStorage();\\n\\n if ($._initializing || $._initialized >= version) {\\n revert AlreadyInitialized();\\n }\\n $._initialized = version;\\n $._initializing = true;\\n _;\\n $._initializing = false;\\n emit Initialized(version);\\n }\\n\\n /**\\n * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the\\n * {initializer} and {reinitializer} modifiers, directly or indirectly.\\n */\\n modifier onlyInitializing() {\\n _checkInitializing();\\n _;\\n }\\n\\n /**\\n * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.\\n */\\n function _checkInitializing() internal view virtual {\\n if (!_isInitializing()) {\\n revert NotInitializing();\\n }\\n }\\n\\n /**\\n * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.\\n * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized\\n * to any version. It is recommended to use this to lock implementation contracts that are designed to be called\\n * through proxies.\\n *\\n * Emits an {Initialized} event the first time it is successfully executed.\\n */\\n function _disableInitializers() internal virtual {\\n // solhint-disable-next-line var-name-mixedcase\\n InitializableStorage storage $ = _getInitializableStorage();\\n\\n if ($._initializing) {\\n revert AlreadyInitialized();\\n }\\n if ($._initialized != type(uint64).max) {\\n $._initialized = type(uint64).max;\\n emit Initialized(type(uint64).max);\\n }\\n }\\n\\n /**\\n * @dev Returns the highest version that has been initialized. See {reinitializer}.\\n */\\n function _getInitializedVersion() internal view returns (uint64) {\\n return _getInitializableStorage()._initialized;\\n }\\n\\n /**\\n * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.\\n */\\n function _isInitializing() internal view returns (bool) {\\n return _getInitializableStorage()._initializing;\\n }\\n\\n /**\\n * @dev Returns a pointer to the storage namespace.\\n */\\n // solhint-disable-next-line var-name-mixedcase\\n function _getInitializableStorage() private pure returns (InitializableStorage storage $) {\\n assembly {\\n $.slot := _INITIALIZABLE_STORAGE\\n }\\n }\\n}\\n\",\"keccak256\":\"0xdad09e5f773fa6940dbd8c28480f602a7eaa3c70d3da9d06df140187cbf5dad4\",\"license\":\"MIT\"},\"src/proxy/UUPSProxiable.sol\":{\"content\":\"//SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.24;\\n\\n/// @title UUPS Proxiable\\n/// @author Simon Malatrait \\n/// @notice This contract implements an upgradeability mechanism designed for UUPS proxies.\\n///\\n/// @dev Adapted from \\n/// The functions included here can perform an upgrade of an UUPS Proxy, when this contract is set as the implementation behind such a proxy.\\n///\\n/// IMPORTANT: A UUPS proxy requires its upgradeability functions to be in the implementation as opposed to the transparent proxy.\\n/// This means that if the proxy is upgraded to an implementation that does not support this interface, it will no longer be upgradeable.\\n///\\n/// A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is\\n/// reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing\\n/// `UUPSProxiable` with a custom implementation of upgrades.\\n///\\n/// The `_authorizeUpgrade` function must be overridden to include access restriction to the upgrade mechanism.\\nabstract contract UUPSProxiable {\\n // ************************************* //\\n // * Event * //\\n // ************************************* //\\n\\n /// @notice Emitted when the `implementation` has been successfully upgraded.\\n /// @param newImplementation Address of the new implementation the proxy is now forwarding calls to.\\n event Upgraded(address indexed newImplementation);\\n\\n // ************************************* //\\n // * Error * //\\n // ************************************* //\\n\\n /// @notice The call is from an unauthorized context.\\n error UUPSUnauthorizedCallContext();\\n\\n /// @notice The storage `slot` is unsupported as a UUID.\\n error UUPSUnsupportedProxiableUUID(bytes32 slot);\\n\\n /// @notice The `implementation` is not UUPS-compliant\\n error InvalidImplementation(address implementation);\\n\\n /// Failed Delegated call\\n error FailedDelegateCall();\\n\\n // ************************************* //\\n // * Storage * //\\n // ************************************* //\\n\\n /// @dev Storage slot with the address of the current implementation.\\n /// @dev This is the keccak-256 hash of \\\"eip1967.proxy.implementation\\\" subtracted by 1, and is\\n /// @dev validated in the constructor.\\n /// @dev NOTE: bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1)\\n bytes32 private constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\\n\\n /// @dev Storage variable of the proxiable contract address.\\n /// @dev It is used to check whether or not the current call is from the proxy.\\n /// @custom:oz-upgrades-unsafe-allow state-variable-immutable\\n address private immutable __self = address(this);\\n\\n // ************************************* //\\n // * Governance * //\\n // ************************************* //\\n\\n /// @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract.\\n /// @dev Called by {upgradeToAndCall}.\\n function _authorizeUpgrade(address newImplementation) internal virtual;\\n\\n // ************************************* //\\n // * State Modifiers * //\\n // ************************************* //\\n\\n /// @notice Upgrade mechanism including access control and UUPS-compliance.\\n /// @param newImplementation Address of the new implementation contract.\\n /// @param data Data used in a delegate call to `newImplementation` if non-empty. This will typically be an encoded\\n /// function call, and allows initializing the storage of the proxy like a Solidity constructor.\\n /// @dev Reverts if the execution is not performed via delegatecall or the execution\\n /// context is not of a proxy with an ERC1967-compliant implementation pointing to self.\\n function upgradeToAndCall(address newImplementation, bytes memory data) public payable virtual {\\n _authorizeUpgrade(newImplementation);\\n\\n // Check that the execution is being performed through a delegatecall call and that the execution context is\\n // a proxy contract with an implementation (as defined in ERC1967) pointing to self.\\n if (address(this) == __self || _getImplementation() != __self) {\\n revert UUPSUnauthorizedCallContext();\\n }\\n\\n try UUPSProxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {\\n if (slot != IMPLEMENTATION_SLOT) {\\n revert UUPSUnsupportedProxiableUUID(slot);\\n }\\n // Store the new implementation address to the implementation storage slot.\\n assembly {\\n sstore(IMPLEMENTATION_SLOT, newImplementation)\\n }\\n emit Upgraded(newImplementation);\\n\\n if (data.length != 0) {\\n // The return data is not checked (checking, in case of success, that the newImplementation code is non-empty if the return data is empty) because the authorized callee is trusted.\\n /// @custom:oz-upgrades-unsafe-allow delegatecall\\n (bool success, ) = newImplementation.delegatecall(data);\\n if (!success) {\\n revert FailedDelegateCall();\\n }\\n }\\n } catch {\\n revert InvalidImplementation(newImplementation);\\n }\\n }\\n\\n // ************************************* //\\n // * Public Views * //\\n // ************************************* //\\n\\n /// @notice Implementation of the ERC1822 `proxiableUUID` function. This returns the storage slot used by the\\n /// implementation. It is used to validate the implementation's compatibility when performing an upgrade.\\n ///\\n /// @dev IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks\\n /// bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this\\n /// function revert if invoked through a proxy. This is guaranteed by the if statement.\\n function proxiableUUID() external view virtual returns (bytes32) {\\n if (address(this) != __self) {\\n // Must not be called through delegatecall\\n revert UUPSUnauthorizedCallContext();\\n }\\n return IMPLEMENTATION_SLOT;\\n }\\n\\n /// @notice Returns the version of the implementation.\\n /// @return Version string.\\n function version() external view virtual returns (string memory);\\n\\n // ************************************* //\\n // * Internal Views * //\\n // ************************************* //\\n\\n function _getImplementation() internal view returns (address implementation) {\\n assembly {\\n implementation := sload(IMPLEMENTATION_SLOT)\\n }\\n }\\n}\\n\",\"keccak256\":\"0xa369061748e8a7b02873d597d4c78a2a09328111f04a97428b1c209e82cf5414\",\"license\":\"MIT\"}},\"version\":1}",
+ "bytecode": "0x60a080604052346100c157306080525f5160206109585f395f51905f525460ff8160401c166100b3576002600160401b03196001600160401b03821601610060575b60405161089290816100c6823960805181818161036a01526104430152f35b6001600160401b0319166001600160401b039081175f5160206109585f395f51905f525581527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a15f80610041565b62dc149f60e41b5f5260045ffd5b5f80fdfe6080806040526004361015610012575f80fd5b5f3560e01c9081633a283d7d14610762575080634a9941741461065a5780634f1ef286146103e257806352d1902d1461035057806354fd4d50146102ed5780638da5cb5b146102c8578063a6f9dae11461024b5763c4d66de814610074575f80fd5b346102475760203660031901126102475761008d610822565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0e5460ff8160401c16159167ffffffffffffffff8216838061023d575b15908161021f575b506101f75767ffffffffffffffff1982166001177ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0e556001600160a01b0391836101b8575b501673ffffffffffffffffffffffffffffffffffffffff195f5416175f5561013b57005b68ff0000000000000000197ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0e54167ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0e557fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2602060405160018152a1005b68ffffffffffffffffff191668010000000000000001177ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0e555f610117565b7f0dc149f0000000000000000000000000000000000000000000000000000000005f5260045ffd5b303b15915081610232575b50155f6100d2565b60019150145f61022a565b50600181106100ca565b5f80fd5b3461024757602036600319011261024757610264610822565b5f5490336001600160a01b038316036102a0576001600160a01b0373ffffffffffffffffffffffffffffffffffffffff1991169116175f555f80f35b7f596dcdb8000000000000000000000000000000000000000000000000000000005f5260045ffd5b34610247575f3660031901126102475760206001600160a01b035f5416604051908152f35b34610247575f3660031901126102475761034c60405161030e60408261077c565b600581527f322e302e300000000000000000000000000000000000000000000000000000006020820152604051918291602083526020830190610838565b0390f35b34610247575f366003190112610247576001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001630036103ba5760206040517f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8152f35b7fe07c8dba000000000000000000000000000000000000000000000000000000005f5260045ffd5b6040366003190112610247576103f6610822565b60243567ffffffffffffffff81116102475736602382011215610247576104279036906024816004013591016107ce565b906001600160a01b035f541633036102a0576001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016803014908115610625575b506103ba576001600160a01b038116916040517f52d1902d000000000000000000000000000000000000000000000000000000008152602081600481875afa5f91816105f1575b506104e657837f0c760937000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8592036105c65750827f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a280518061056057005b5f926020849301905af43d156105c1573d61057a816107b2565b90610588604051928361077c565b81525f60203d92013e5b1561059957005b7f736436ba000000000000000000000000000000000000000000000000000000005f5260045ffd5b610592565b7faa1d49a4000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b9091506020813d60201161061d575b8161060d6020938361077c565b81010312610247575190856104b5565b3d9150610600565b90506001600160a01b037f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc541614158361046e565b346102475760603660031901126102475760043567ffffffffffffffff81116102475761068b903690600401610804565b60243567ffffffffffffffff8111610247576106ab903690600401610804565b9060443567ffffffffffffffff8111610247576106cc903690600401610804565b600154915f19831461074e577ef7cd7255d1073b4e136dd477c38ea0020c051ab17110cc5bfab0c840ff992461073660209561074387879560018701600155604051918183925191829101835e81015f815203902095604051938493604085526040850190610838565b908382038a850152610838565b0390a3604051908152f35b634e487b7160e01b5f52601160045260245ffd5b34610247575f366003190112610247576020906001548152f35b90601f8019910116810190811067ffffffffffffffff82111761079e57604052565b634e487b7160e01b5f52604160045260245ffd5b67ffffffffffffffff811161079e57601f01601f191660200190565b9291926107da826107b2565b916107e8604051938461077c565b829481845281830111610247578281602093845f960137010152565b9080601f830112156102475781602061081f933591016107ce565b90565b600435906001600160a01b038216820361024757565b805180835260209291819084018484015e5f828201840152601f01601f191601019056fea2646970667358221220bb75c0a527977368a7b8fd2e1e5a73e20d804eb35645fe757271a9acd08c759764736f6c634300081e0033f0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0e",
+ "deployedBytecode": "0x6080806040526004361015610012575f80fd5b5f3560e01c9081633a283d7d14610762575080634a9941741461065a5780634f1ef286146103e257806352d1902d1461035057806354fd4d50146102ed5780638da5cb5b146102c8578063a6f9dae11461024b5763c4d66de814610074575f80fd5b346102475760203660031901126102475761008d610822565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0e5460ff8160401c16159167ffffffffffffffff8216838061023d575b15908161021f575b506101f75767ffffffffffffffff1982166001177ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0e556001600160a01b0391836101b8575b501673ffffffffffffffffffffffffffffffffffffffff195f5416175f5561013b57005b68ff0000000000000000197ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0e54167ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0e557fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2602060405160018152a1005b68ffffffffffffffffff191668010000000000000001177ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0e555f610117565b7f0dc149f0000000000000000000000000000000000000000000000000000000005f5260045ffd5b303b15915081610232575b50155f6100d2565b60019150145f61022a565b50600181106100ca565b5f80fd5b3461024757602036600319011261024757610264610822565b5f5490336001600160a01b038316036102a0576001600160a01b0373ffffffffffffffffffffffffffffffffffffffff1991169116175f555f80f35b7f596dcdb8000000000000000000000000000000000000000000000000000000005f5260045ffd5b34610247575f3660031901126102475760206001600160a01b035f5416604051908152f35b34610247575f3660031901126102475761034c60405161030e60408261077c565b600581527f322e302e300000000000000000000000000000000000000000000000000000006020820152604051918291602083526020830190610838565b0390f35b34610247575f366003190112610247576001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001630036103ba5760206040517f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8152f35b7fe07c8dba000000000000000000000000000000000000000000000000000000005f5260045ffd5b6040366003190112610247576103f6610822565b60243567ffffffffffffffff81116102475736602382011215610247576104279036906024816004013591016107ce565b906001600160a01b035f541633036102a0576001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016803014908115610625575b506103ba576001600160a01b038116916040517f52d1902d000000000000000000000000000000000000000000000000000000008152602081600481875afa5f91816105f1575b506104e657837f0c760937000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8592036105c65750827f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a280518061056057005b5f926020849301905af43d156105c1573d61057a816107b2565b90610588604051928361077c565b81525f60203d92013e5b1561059957005b7f736436ba000000000000000000000000000000000000000000000000000000005f5260045ffd5b610592565b7faa1d49a4000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b9091506020813d60201161061d575b8161060d6020938361077c565b81010312610247575190856104b5565b3d9150610600565b90506001600160a01b037f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc541614158361046e565b346102475760603660031901126102475760043567ffffffffffffffff81116102475761068b903690600401610804565b60243567ffffffffffffffff8111610247576106ab903690600401610804565b9060443567ffffffffffffffff8111610247576106cc903690600401610804565b600154915f19831461074e577ef7cd7255d1073b4e136dd477c38ea0020c051ab17110cc5bfab0c840ff992461073660209561074387879560018701600155604051918183925191829101835e81015f815203902095604051938493604085526040850190610838565b908382038a850152610838565b0390a3604051908152f35b634e487b7160e01b5f52601160045260245ffd5b34610247575f366003190112610247576020906001548152f35b90601f8019910116810190811067ffffffffffffffff82111761079e57604052565b634e487b7160e01b5f52604160045260245ffd5b67ffffffffffffffff811161079e57601f01601f191660200190565b9291926107da826107b2565b916107e8604051938461077c565b829481845281830111610247578281602093845f960137010152565b9080601f830112156102475781602061081f933591016107ce565b90565b600435906001600160a01b038216820361024757565b805180835260209291819084018484015e5f828201840152601f01601f191601019056fea2646970667358221220bb75c0a527977368a7b8fd2e1e5a73e20d804eb35645fe757271a9acd08c759764736f6c634300081e0033",
+ "devdoc": {
+ "errors": {
+ "AlreadyInitialized()": [
+ {
+ "details": "The contract is already initialized."
+ }
+ ],
+ "NotInitializing()": [
+ {
+ "details": "The contract is not initializing."
+ }
+ ]
+ },
+ "events": {
+ "DisputeTemplate(uint256,string,string,string)": {
+ "params": {
+ "_templateData": "The template data.",
+ "_templateDataMappings": "The data mappings.",
+ "_templateId": "The identifier of the dispute template.",
+ "_templateTag": "An optional tag for the dispute template, such as \"registration\" or \"removal\"."
+ }
+ },
+ "Initialized(uint64)": {
+ "details": "Triggered when the contract has been initialized or reinitialized."
+ },
+ "Upgraded(address)": {
+ "params": {
+ "newImplementation": "Address of the new implementation the proxy is now forwarding calls to."
+ }
+ }
+ },
+ "kind": "dev",
+ "methods": {
+ "changeOwner(address)": {
+ "params": {
+ "_owner": "The new owner."
+ }
+ },
+ "constructor": {
+ "custom:oz-upgrades-unsafe-allow": "constructor"
+ },
+ "initialize(address)": {
+ "params": {
+ "_owner": "Owner of the contract."
+ }
+ },
+ "proxiableUUID()": {
+ "details": "IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this function revert if invoked through a proxy. This is guaranteed by the if statement."
+ },
+ "setDisputeTemplate(string,string,string)": {
+ "params": {
+ "_templateData": "The template data.",
+ "_templateDataMappings": "The data mappings for the template.",
+ "_templateTag": "An optional tag for the dispute template, such as \"registration\" or \"removal\"."
+ },
+ "returns": {
+ "templateId": "The identifier of the dispute template."
+ }
+ },
+ "upgradeToAndCall(address,bytes)": {
+ "details": "Reverts if the execution is not performed via delegatecall or the execution context is not of a proxy with an ERC1967-compliant implementation pointing to self.",
+ "params": {
+ "data": "Data used in a delegate call to `newImplementation` if non-empty. This will typically be an encoded function call, and allows initializing the storage of the proxy like a Solidity constructor.",
+ "newImplementation": "Address of the new implementation contract."
+ }
+ }
+ },
+ "stateVariables": {
+ "version": {
+ "return": "Version string.",
+ "returns": {
+ "_0": "Version string."
+ }
+ }
+ },
+ "title": "Dispute Template Registry",
+ "version": 1
+ },
+ "userdoc": {
+ "errors": {
+ "FailedDelegateCall()": [
+ {
+ "notice": "Failed Delegated call"
+ }
+ ],
+ "InvalidImplementation(address)": [
+ {
+ "notice": "The `implementation` is not UUPS-compliant"
+ }
+ ],
+ "UUPSUnauthorizedCallContext()": [
+ {
+ "notice": "The call is from an unauthorized context."
+ }
+ ],
+ "UUPSUnsupportedProxiableUUID(bytes32)": [
+ {
+ "notice": "The storage `slot` is unsupported as a UUID."
+ }
+ ]
+ },
+ "events": {
+ "DisputeTemplate(uint256,string,string,string)": {
+ "notice": "To be emitted when a new dispute template is created."
+ },
+ "Upgraded(address)": {
+ "notice": "Emitted when the `implementation` has been successfully upgraded."
+ }
+ },
+ "kind": "user",
+ "methods": {
+ "changeOwner(address)": {
+ "notice": "Changes the owner of the contract."
+ },
+ "initialize(address)": {
+ "notice": "Initializer"
+ },
+ "owner()": {
+ "notice": "The owner of the contract."
+ },
+ "proxiableUUID()": {
+ "notice": "Implementation of the ERC1822 `proxiableUUID` function. This returns the storage slot used by the implementation. It is used to validate the implementation's compatibility when performing an upgrade."
+ },
+ "setDisputeTemplate(string,string,string)": {
+ "notice": "Registers a new dispute template."
+ },
+ "templates()": {
+ "notice": "The number of templates."
+ },
+ "upgradeToAndCall(address,bytes)": {
+ "notice": "Upgrade mechanism including access control and UUPS-compliance."
+ },
+ "version()": {
+ "notice": "Returns the version of the implementation."
+ }
+ },
+ "notice": "A contract to maintain a registry of dispute templates.",
+ "version": 1
+ },
+ "storageLayout": {
+ "storage": [
+ {
+ "astId": 11041,
+ "contract": "src/arbitration/DisputeTemplateRegistry.sol:DisputeTemplateRegistry",
+ "label": "owner",
+ "offset": 0,
+ "slot": "0",
+ "type": "t_address"
+ },
+ {
+ "astId": 11044,
+ "contract": "src/arbitration/DisputeTemplateRegistry.sol:DisputeTemplateRegistry",
+ "label": "templates",
+ "offset": 0,
+ "slot": "1",
+ "type": "t_uint256"
+ }
+ ],
+ "types": {
+ "t_address": {
+ "encoding": "inplace",
+ "label": "address",
+ "numberOfBytes": "20"
+ },
+ "t_uint256": {
+ "encoding": "inplace",
+ "label": "uint256",
+ "numberOfBytes": "32"
+ }
+ }
+ }
+}
diff --git a/contracts/deployments/arbitrumSepoliaDevnet/DisputeTemplateRegistryUniversity_Proxy.json b/contracts/deployments/arbitrumSepoliaDevnet/DisputeTemplateRegistryUniversity_Proxy.json
new file mode 100644
index 000000000..618d75a4e
--- /dev/null
+++ b/contracts/deployments/arbitrumSepoliaDevnet/DisputeTemplateRegistryUniversity_Proxy.json
@@ -0,0 +1,81 @@
+{
+ "address": "0x75A5D16e9A699162506E4d79D68CF646e6600ba1",
+ "abi": [
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "_implementation",
+ "type": "address"
+ },
+ {
+ "internalType": "bytes",
+ "name": "_data",
+ "type": "bytes"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "constructor"
+ },
+ {
+ "stateMutability": "payable",
+ "type": "fallback"
+ },
+ {
+ "stateMutability": "payable",
+ "type": "receive"
+ }
+ ],
+ "transactionHash": "0xbc50b201f6d4dfa0a74e83aeb201df1f0390ab361ba76bf72a696a36d3a5ffe4",
+ "receipt": {
+ "to": null,
+ "from": "0xf1C7c037891525E360C59f708739Ac09A7670c59",
+ "contractAddress": "0x75A5D16e9A699162506E4d79D68CF646e6600ba1",
+ "transactionIndex": 1,
+ "gasUsed": "157979",
+ "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000800000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000004000000000000000000000000000000000000000000000000000000000000",
+ "blockHash": "0x9656d572eb28bbdc716c7b34860d4e05442e4a488ce69c9f410f69a3d125df0c",
+ "transactionHash": "0xbc50b201f6d4dfa0a74e83aeb201df1f0390ab361ba76bf72a696a36d3a5ffe4",
+ "logs": [
+ {
+ "transactionIndex": 1,
+ "blockNumber": 193661064,
+ "transactionHash": "0xbc50b201f6d4dfa0a74e83aeb201df1f0390ab361ba76bf72a696a36d3a5ffe4",
+ "address": "0x75A5D16e9A699162506E4d79D68CF646e6600ba1",
+ "topics": [
+ "0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2"
+ ],
+ "data": "0x0000000000000000000000000000000000000000000000000000000000000001",
+ "logIndex": 0,
+ "blockHash": "0x9656d572eb28bbdc716c7b34860d4e05442e4a488ce69c9f410f69a3d125df0c"
+ }
+ ],
+ "blockNumber": 193661064,
+ "cumulativeGasUsed": "157979",
+ "status": 1,
+ "byzantium": true
+ },
+ "args": [
+ "0xC3f638389635bF33E019c845FdaF2ed9bca3DF67",
+ "0xc4d66de8000000000000000000000000f1c7c037891525e360c59f708739ac09a7670c59"
+ ],
+ "numDeployments": 1,
+ "solcInputHash": "cff4f5de661c6299ed3bdc0f8613457a",
+ "metadata": "{\"compiler\":{\"version\":\"0.8.30+commit.73712a01\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_implementation\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"stateMutability\":\"payable\",\"type\":\"fallback\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/proxy/KlerosProxies.sol\":\"DisputeTemplateRegistryUniversityProxy\"},\"evmVersion\":\"cancun\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000},\"remappings\":[],\"viaIR\":true},\"sources\":{\"src/proxy/KlerosProxies.sol\":{\"content\":\"//SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.24;\\n\\nimport \\\"./UUPSProxy.sol\\\";\\n\\n/// Workaround to get meaningful names for the proxy contracts\\n/// Otherwise all the contracts are called `UUPSProxy` on the chain explorers\\n\\ncontract DisputeKitClassicUniversityProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract DisputeKitClassicProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract DisputeKitGatedProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract DisputeKitGatedShutterProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract DisputeKitShutterProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract DisputeKitSybilResistantProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract DisputeTemplateRegistryUniversityProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract DisputeTemplateRegistryProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract EvidenceModuleProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract ForeignGatewayOnEthereumProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract HomeGatewayToEthereumProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract KlerosCoreRulerProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract KlerosCoreUniversityProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract KlerosCoreProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract PolicyRegistryProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract RandomizerRNGProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract SortitionModuleUniversityProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract SortitionModuleProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\",\"keccak256\":\"0x9dbd26ac5a026a32fc38e394188ab4a8dce0d7e8f249fa1412f757611f948767\",\"license\":\"MIT\"},\"src/proxy/UUPSProxy.sol\":{\"content\":\"//SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.24;\\n\\n/// @title UUPS Proxy\\n/// @author Simon Malatrait \\n/// @notice This contract implements a UUPS Proxy compliant with ERC-1967 & ERC-1822.\\n///\\n/// @dev This contract delegates all calls to another contract (UUPS Proxiable) through a fallback function and the use of the `delegatecall` EVM instruction.\\n/// We refer to the Proxiable contract (as per ERC-1822) with `implementation`.\\n/// Adapted from \\ncontract UUPSProxy {\\n /// @dev Storage slot with the address of the current implementation.\\n /// This is the keccak-256 hash of \\\"eip1967.proxy.implementation\\\" subtracted by 1, and is\\n /// validated in the constructor.\\n /// NOTE: bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1)\\n bytes32 private constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\\n\\n // ************************************* //\\n // * Constructor * //\\n // ************************************* //\\n\\n /// @notice Initializes the upgradeable proxy with an initial implementation specified by `_implementation`.\\n /// @dev If `_data` is nonempty, it's used as data in a delegate call to `_implementation`.\\n /// This will typically be an encoded function call, and allows initializing the storage of the proxy like a Solidity constructor.\\n constructor(address _implementation, bytes memory _data) {\\n assembly {\\n sstore(IMPLEMENTATION_SLOT, _implementation)\\n }\\n\\n if (_data.length != 0) {\\n (bool success, ) = _implementation.delegatecall(_data);\\n require(success, \\\"Proxy Constructor failed\\\");\\n }\\n }\\n\\n // ************************************* //\\n // * State Modifiers * //\\n // ************************************* //\\n\\n /// @dev Delegates the current call to `implementation`.\\n /// NOTE: This function does not return to its internal call site, it will return directly to the external caller.\\n function _delegate(address implementation) internal {\\n assembly {\\n // Copy msg.data. We take full control of memory in this inline assembly\\n // block because it will not return to Solidity code. We overwrite the\\n // Solidity scratch pad at memory position 0.\\n calldatacopy(0, 0, calldatasize())\\n\\n // Call the implementation.\\n // out and outsize are 0 because we don't know the size yet.\\n let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)\\n\\n // Copy the returned data.\\n returndatacopy(0, 0, returndatasize())\\n\\n switch result\\n // delegatecall returns 0 on error.\\n case 0 {\\n revert(0, returndatasize())\\n }\\n default {\\n return(0, returndatasize())\\n }\\n }\\n }\\n\\n // ************************************* //\\n // * Internal Views * //\\n // ************************************* //\\n\\n function _getImplementation() internal view returns (address implementation) {\\n assembly {\\n implementation := sload(IMPLEMENTATION_SLOT)\\n }\\n }\\n\\n // ************************************* //\\n // * Fallback * //\\n // ************************************* //\\n\\n /// @dev Fallback function that delegates calls to the address returned by `_implementation()`.\\n /// @dev Will run if no other function in the contract matches the call data.\\n fallback() external payable {\\n _delegate(_getImplementation());\\n }\\n\\n receive() external payable {\\n _delegate(_getImplementation());\\n }\\n}\\n\",\"keccak256\":\"0x2d7b1f81e525787f1b8b033ce381a81cb5f39e411ff31490e019113205a661cd\",\"license\":\"MIT\"}},\"version\":1}",
+ "bytecode": "0x608060405234610144576102148038038061001981610148565b928339810190604081830312610144578051906001600160a01b0382168203610144576020810151906001600160401b038211610144570182601f8201121561014457805161006f61006a82610181565b610148565b9181835260208301946020838301011161014457815f926020809301875e83010152817f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5551806100c9575b6040516077908161019d8239f35b5f9283925af43d1561013f573d6100e261006a82610181565b9081525f60203d92013e5b156100fa575f80806100bb565b60405162461bcd60e51b815260206004820152601860248201527f50726f787920436f6e7374727563746f72206661696c656400000000000000006044820152606490fd5b6100ed565b5f80fd5b6040519190601f01601f191682016001600160401b0381118382101761016d57604052565b634e487b7160e01b5f52604160045260245ffd5b6001600160401b03811161016d57601f01601f19166020019056fe60806040525f807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc54368280378136915af43d5f803e15603d573d5ff35b3d5ffdfea2646970667358221220e347285b4ca364b0c82598fe294ad8b02e9adfbbac26ab00c24b1b747375019464736f6c634300081e0033",
+ "deployedBytecode": "0x60806040525f807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc54368280378136915af43d5f803e15603d573d5ff35b3d5ffdfea2646970667358221220e347285b4ca364b0c82598fe294ad8b02e9adfbbac26ab00c24b1b747375019464736f6c634300081e0033",
+ "devdoc": {
+ "kind": "dev",
+ "methods": {},
+ "version": 1
+ },
+ "userdoc": {
+ "kind": "user",
+ "methods": {},
+ "version": 1
+ },
+ "storageLayout": {
+ "storage": [],
+ "types": null
+ }
+}
diff --git a/contracts/deployments/arbitrumSepoliaDevnet/KlerosCoreUniversity.json b/contracts/deployments/arbitrumSepoliaDevnet/KlerosCoreUniversity.json
index b6b4080c4..f5511de8f 100644
--- a/contracts/deployments/arbitrumSepoliaDevnet/KlerosCoreUniversity.json
+++ b/contracts/deployments/arbitrumSepoliaDevnet/KlerosCoreUniversity.json
@@ -1,5 +1,5 @@
{
- "address": "0x5AB37F38778Bc175852fA353056591D91c744ce6",
+ "address": "0xA34dBBD0E5e1d09bd683455f9dbC393797BC558f",
"abi": [
{
"stateMutability": "payable",
@@ -34,11 +34,6 @@
"name": "ArbitrationFeesNotEnough",
"type": "error"
},
- {
- "inputs": [],
- "name": "ArraysLengthMismatch",
- "type": "error"
- },
{
"inputs": [],
"name": "CannotDisableClassicDK",
@@ -49,11 +44,6 @@
"name": "CommitPeriodNotPassed",
"type": "error"
},
- {
- "inputs": [],
- "name": "DepthLevelMax",
- "type": "error"
- },
{
"inputs": [],
"name": "DisputeKitNotSupportedByCourt",
@@ -89,16 +79,6 @@
"name": "FailedDelegateCall",
"type": "error"
},
- {
- "inputs": [],
- "name": "GovernorOnly",
- "type": "error"
- },
- {
- "inputs": [],
- "name": "GovernorOrInstructorOnly",
- "type": "error"
- },
{
"inputs": [],
"name": "InstructorOnly",
@@ -155,6 +135,16 @@
"name": "NotInitializing",
"type": "error"
},
+ {
+ "inputs": [],
+ "name": "OwnerOnly",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "OwnerOrInstructorOnly",
+ "type": "error"
+ },
{
"inputs": [],
"name": "RulingAlreadyExecuted",
@@ -177,7 +167,7 @@
},
{
"inputs": [],
- "name": "StakingNotPossibeInThisCourt",
+ "name": "StakingNotPossibleInThisCourt",
"type": "error"
},
{
@@ -185,6 +175,11 @@
"name": "StakingTransferFailed",
"type": "error"
},
+ {
+ "inputs": [],
+ "name": "StakingZeroWhenNoStake",
+ "type": "error"
+ },
{
"inputs": [],
"name": "TokenNotAccepted",
@@ -298,9 +293,9 @@
"inputs": [
{
"indexed": true,
- "internalType": "uint256",
+ "internalType": "uint96",
"name": "_courtID",
- "type": "uint256"
+ "type": "uint96"
},
{
"indexed": true,
@@ -575,6 +570,12 @@
{
"anonymous": false,
"inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "_account",
+ "type": "address"
+ },
{
"indexed": true,
"internalType": "uint256",
@@ -590,13 +591,62 @@
{
"indexed": false,
"internalType": "uint256",
- "name": "_pnkAmount",
+ "name": "_degreeOfCoherencyPnk",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
- "name": "_feeAmount",
+ "name": "_degreeOfCoherencyFee",
+ "type": "uint256"
+ },
+ {
+ "indexed": false,
+ "internalType": "int256",
+ "name": "_amountPnk",
+ "type": "int256"
+ },
+ {
+ "indexed": false,
+ "internalType": "int256",
+ "name": "_amountFee",
+ "type": "int256"
+ },
+ {
+ "indexed": false,
+ "internalType": "contract IERC20",
+ "name": "_feeToken",
+ "type": "address"
+ }
+ ],
+ "name": "JurorRewardPenalty",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "uint256",
+ "name": "_disputeID",
+ "type": "uint256"
+ },
+ {
+ "indexed": true,
+ "internalType": "uint256",
+ "name": "_roundID",
+ "type": "uint256"
+ },
+ {
+ "indexed": false,
+ "internalType": "uint256",
+ "name": "_amountPnk",
+ "type": "uint256"
+ },
+ {
+ "indexed": false,
+ "internalType": "uint256",
+ "name": "_amountFee",
"type": "uint256"
},
{
@@ -678,55 +728,6 @@
"name": "Ruling",
"type": "event"
},
- {
- "anonymous": false,
- "inputs": [
- {
- "indexed": true,
- "internalType": "address",
- "name": "_account",
- "type": "address"
- },
- {
- "indexed": true,
- "internalType": "uint256",
- "name": "_disputeID",
- "type": "uint256"
- },
- {
- "indexed": true,
- "internalType": "uint256",
- "name": "_roundID",
- "type": "uint256"
- },
- {
- "indexed": false,
- "internalType": "uint256",
- "name": "_degreeOfCoherency",
- "type": "uint256"
- },
- {
- "indexed": false,
- "internalType": "int256",
- "name": "_pnkAmount",
- "type": "int256"
- },
- {
- "indexed": false,
- "internalType": "int256",
- "name": "_feeAmount",
- "type": "int256"
- },
- {
- "indexed": false,
- "internalType": "contract IERC20",
- "name": "_feeToken",
- "type": "address"
- }
- ],
- "name": "TokenAndETHShift",
- "type": "event"
- },
{
"anonymous": false,
"inputs": [
@@ -949,12 +950,12 @@
{
"inputs": [
{
- "internalType": "address payable",
- "name": "_governor",
+ "internalType": "address",
+ "name": "_instructor",
"type": "address"
}
],
- "name": "changeGovernor",
+ "name": "changeInstructor",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
@@ -963,11 +964,11 @@
"inputs": [
{
"internalType": "address",
- "name": "_instructor",
+ "name": "_jurorProsecutionModule",
"type": "address"
}
],
- "name": "changeInstructor",
+ "name": "changeJurorProsecutionModule",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
@@ -975,12 +976,12 @@
{
"inputs": [
{
- "internalType": "address",
- "name": "_jurorProsecutionModule",
+ "internalType": "address payable",
+ "name": "_owner",
"type": "address"
}
],
- "name": "changeJurorProsecutionModule",
+ "name": "changeOwner",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
@@ -1074,11 +1075,6 @@
"internalType": "uint256",
"name": "jurorsForCourtJump",
"type": "uint256"
- },
- {
- "internalType": "bool",
- "name": "disabled",
- "type": "bool"
}
],
"stateMutability": "view",
@@ -1388,7 +1384,7 @@
"type": "bytes"
}
],
- "name": "executeGovernorProposal",
+ "name": "executeOwnerProposal",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
@@ -1457,6 +1453,30 @@
"stateMutability": "view",
"type": "function"
},
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "_disputeID",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "_round",
+ "type": "uint256"
+ }
+ ],
+ "name": "getPnkAtStakePerJuror",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
{
"inputs": [
{
@@ -1509,6 +1529,11 @@
"name": "drawnJurors",
"type": "address[]"
},
+ {
+ "internalType": "uint96[]",
+ "name": "drawnJurorFromCourtIDs",
+ "type": "uint96[]"
+ },
{
"internalType": "uint256",
"name": "sumFeeRewardPaid",
@@ -1528,6 +1553,11 @@
"internalType": "uint256",
"name": "drawIterations",
"type": "uint256"
+ },
+ {
+ "internalType": "uint256[10]",
+ "name": "__gap",
+ "type": "uint256[10]"
}
],
"internalType": "struct KlerosCoreUniversity.Round",
@@ -1557,24 +1587,11 @@
"stateMutability": "view",
"type": "function"
},
- {
- "inputs": [],
- "name": "governor",
- "outputs": [
- {
- "internalType": "address",
- "name": "",
- "type": "address"
- }
- ],
- "stateMutability": "view",
- "type": "function"
- },
{
"inputs": [
{
"internalType": "address",
- "name": "_governor",
+ "name": "_owner",
"type": "address"
},
{
@@ -1692,6 +1709,19 @@
"stateMutability": "view",
"type": "function"
},
+ {
+ "inputs": [],
+ "name": "owner",
+ "outputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
{
"inputs": [
{
@@ -1765,11 +1795,6 @@
"internalType": "uint256",
"name": "_newStake",
"type": "uint256"
- },
- {
- "internalType": "bool",
- "name": "_alreadyTransferred",
- "type": "bool"
}
],
"name": "setStakeBySortitionModule",
@@ -1790,6 +1815,24 @@
"stateMutability": "view",
"type": "function"
},
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "_account",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "_amount",
+ "type": "uint256"
+ }
+ ],
+ "name": "transferBySortitionModule",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
{
"inputs": [
{
@@ -1808,6 +1851,19 @@
"stateMutability": "payable",
"type": "function"
},
+ {
+ "inputs": [],
+ "name": "version",
+ "outputs": [
+ {
+ "internalType": "string",
+ "name": "",
+ "type": "string"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
{
"inputs": [
{
@@ -1825,50 +1881,50 @@
"type": "constructor"
}
],
- "transactionHash": "0x6d19fdb430b5611f9aedf5792b44a297c36bd84d34e66ddaf82844f33eb1748a",
+ "transactionHash": "0x998456e4bf88144d618ef98fb44d1c7bb857cbbbefe8b7c523399abc23f581c1",
"receipt": {
"to": null,
"from": "0xf1C7c037891525E360C59f708739Ac09A7670c59",
- "contractAddress": "0x5AB37F38778Bc175852fA353056591D91c744ce6",
- "transactionIndex": 1,
- "gasUsed": "484460",
- "logsBloom": "0x00000000000000000000000020000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000080000000000000040000000000000000000000000000020000000000000010200800402000000000000008000000000000008000000000000000000800000000000000000000000080000000000000000000000000000000800008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000060000000001001000000000000000000000008000000000200000000000000000000",
- "blockHash": "0x152fd5195e3f7b8e0ab803f90700d35d20f4452193858d10558fc31c226227c8",
- "transactionHash": "0x6d19fdb430b5611f9aedf5792b44a297c36bd84d34e66ddaf82844f33eb1748a",
+ "contractAddress": "0xA34dBBD0E5e1d09bd683455f9dbC393797BC558f",
+ "transactionIndex": 2,
+ "gasUsed": "453977",
+ "logsBloom": "0x000000000000000000000000200000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000800000000400000000000000000000000000000200000000000000100008004020000000000000000000000000040000008000000000000008000000000000000000000000800000000000100000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000e4000000001000000000000001000000000000000000000000000800000000000000",
+ "blockHash": "0xe5a6d446390c5a4cfe779ab765b5c591e177b2dcfe4263135a1943f55babc82f",
+ "transactionHash": "0x998456e4bf88144d618ef98fb44d1c7bb857cbbbefe8b7c523399abc23f581c1",
"logs": [
{
- "transactionIndex": 1,
- "blockNumber": 96308609,
- "transactionHash": "0x6d19fdb430b5611f9aedf5792b44a297c36bd84d34e66ddaf82844f33eb1748a",
- "address": "0x5AB37F38778Bc175852fA353056591D91c744ce6",
+ "transactionIndex": 2,
+ "blockNumber": 193533818,
+ "transactionHash": "0x998456e4bf88144d618ef98fb44d1c7bb857cbbbefe8b7c523399abc23f581c1",
+ "address": "0xA34dBBD0E5e1d09bd683455f9dbC393797BC558f",
"topics": [
"0x44063d258760b98116d53815adbc906a56b3563e540148cc0fc2457f83b5eeb2",
"0x0000000000000000000000000000000000000000000000000000000000000001",
- "0x000000000000000000000000d6e96b7c993763b5cdda1139c7387b82a7c8b8b5"
+ "0x00000000000000000000000082f2089442979a6b56c80274d144575980092f91"
],
"data": "0x",
- "logIndex": 0,
- "blockHash": "0x152fd5195e3f7b8e0ab803f90700d35d20f4452193858d10558fc31c226227c8"
+ "logIndex": 3,
+ "blockHash": "0xe5a6d446390c5a4cfe779ab765b5c591e177b2dcfe4263135a1943f55babc82f"
},
{
- "transactionIndex": 1,
- "blockNumber": 96308609,
- "transactionHash": "0x6d19fdb430b5611f9aedf5792b44a297c36bd84d34e66ddaf82844f33eb1748a",
- "address": "0x5AB37F38778Bc175852fA353056591D91c744ce6",
+ "transactionIndex": 2,
+ "blockNumber": 193533818,
+ "transactionHash": "0x998456e4bf88144d618ef98fb44d1c7bb857cbbbefe8b7c523399abc23f581c1",
+ "address": "0xA34dBBD0E5e1d09bd683455f9dbC393797BC558f",
"topics": [
- "0x3475f0ed7216dd7d453db663a1c3024e4f36cc925521d54edb9d13e022cbee3d",
+ "0x550ff678017abc294b4786a99a046628d5a1eac07be0f1ea7e89543f13576ee6",
"0x0000000000000000000000000000000000000000000000000000000000000001",
"0x0000000000000000000000000000000000000000000000000000000000000000"
],
"data": "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ad78ebc5ac62000000000000000000000000000000000000000000000000000000000000000002710000000000000000000000000000000000000000000000000016345785d8a00000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000000000",
- "logIndex": 1,
- "blockHash": "0x152fd5195e3f7b8e0ab803f90700d35d20f4452193858d10558fc31c226227c8"
+ "logIndex": 4,
+ "blockHash": "0xe5a6d446390c5a4cfe779ab765b5c591e177b2dcfe4263135a1943f55babc82f"
},
{
- "transactionIndex": 1,
- "blockNumber": 96308609,
- "transactionHash": "0x6d19fdb430b5611f9aedf5792b44a297c36bd84d34e66ddaf82844f33eb1748a",
- "address": "0x5AB37F38778Bc175852fA353056591D91c744ce6",
+ "transactionIndex": 2,
+ "blockNumber": 193533818,
+ "transactionHash": "0x998456e4bf88144d618ef98fb44d1c7bb857cbbbefe8b7c523399abc23f581c1",
+ "address": "0xA34dBBD0E5e1d09bd683455f9dbC393797BC558f",
"topics": [
"0xb47629acdf64971062d40984f77d3dee212d735b11e3e8c7a4222d9f0572cc79",
"0x0000000000000000000000000000000000000000000000000000000000000001",
@@ -1876,36 +1932,36 @@
"0x0000000000000000000000000000000000000000000000000000000000000001"
],
"data": "0x",
- "logIndex": 2,
- "blockHash": "0x152fd5195e3f7b8e0ab803f90700d35d20f4452193858d10558fc31c226227c8"
+ "logIndex": 5,
+ "blockHash": "0xe5a6d446390c5a4cfe779ab765b5c591e177b2dcfe4263135a1943f55babc82f"
},
{
- "transactionIndex": 1,
- "blockNumber": 96308609,
- "transactionHash": "0x6d19fdb430b5611f9aedf5792b44a297c36bd84d34e66ddaf82844f33eb1748a",
- "address": "0x5AB37F38778Bc175852fA353056591D91c744ce6",
+ "transactionIndex": 2,
+ "blockNumber": 193533818,
+ "transactionHash": "0x998456e4bf88144d618ef98fb44d1c7bb857cbbbefe8b7c523399abc23f581c1",
+ "address": "0xA34dBBD0E5e1d09bd683455f9dbC393797BC558f",
"topics": [
"0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2"
],
"data": "0x0000000000000000000000000000000000000000000000000000000000000001",
- "logIndex": 3,
- "blockHash": "0x152fd5195e3f7b8e0ab803f90700d35d20f4452193858d10558fc31c226227c8"
+ "logIndex": 6,
+ "blockHash": "0xe5a6d446390c5a4cfe779ab765b5c591e177b2dcfe4263135a1943f55babc82f"
}
],
- "blockNumber": 96308609,
- "cumulativeGasUsed": "484460",
+ "blockNumber": 193533818,
+ "cumulativeGasUsed": "582464",
"status": 1,
"byzantium": true
},
"args": [
- "0xF74DaBfC5F5dbdBD07636637204d9C35326D2906",
- "0xe399d29b000000000000000000000000f1c7c037891525e360c59f708739ac09a7670c59000000000000000000000000f1c7c037891525e360c59f708739ac09a7670c5900000000000000000000000034b944d42cacfc8266955d07a80181d2054aa2250000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d6e96b7c993763b5cdda1139c7387b82a7c8b8b5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ad78ebc5ac62000000000000000000000000000000000000000000000000000000000000000002710000000000000000000000000000000000000000000000000016345785d8a00000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000004b2c2d048921f694cce3aea35698c6b1f5fcbb79"
+ "0xb75b0cc01af4aD0D65D50082ae0717004D479Aa0",
+ "0xe399d29b000000000000000000000000f1c7c037891525e360c59f708739ac09a7670c59000000000000000000000000f1c7c037891525e360c59f708739ac09a7670c5900000000000000000000000034b944d42cacfc8266955d07a80181d2054aa225000000000000000000000000000000000000000000000000000000000000000000000000000000000000000082f2089442979a6b56c80274d144575980092f91000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ad78ebc5ac62000000000000000000000000000000000000000000000000000000000000000002710000000000000000000000000000000000000000000000000016345785d8a00000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000009f55804177e7e44e558616cd7d06b865788214ca"
],
"numDeployments": 1,
- "solcInputHash": "a5602534c00c2f67ca4b6a1cab8c717e",
- "metadata": "{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_implementation\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"stateMutability\":\"payable\",\"type\":\"fallback\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/proxy/KlerosProxies.sol\":\"KlerosCoreUniversityProxy\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":100},\"remappings\":[]},\"sources\":{\"src/proxy/KlerosProxies.sol\":{\"content\":\"//SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.24;\\n\\nimport \\\"./UUPSProxy.sol\\\";\\n\\n/// Workaround to get meaningful names for the proxy contracts\\n/// Otherwise all the contracts are called `UUPSProxy` on the chain explorers\\n\\ncontract DisputeKitClassicNeoProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract DisputeKitClassicUniversityProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract DisputeKitClassicProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract DisputeTemplateRegistryProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract EvidenceModuleProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract ForeignGatewayOnEthereumProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract HomeGatewayToEthereumProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract KlerosCoreNeoProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract KlerosCoreRulerProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract KlerosCoreUniversityProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract KlerosCoreProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract PolicyRegistryProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract RandomizerRNGProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract SortitionModuleNeoProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract SortitionModuleUniversityProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract SortitionModuleProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\",\"keccak256\":\"0x4393c05bbfda204b9992e1e546142a0fbf4c92a1c4061f5985463d02a71b84d4\",\"license\":\"MIT\"},\"src/proxy/UUPSProxy.sol\":{\"content\":\"//SPDX-License-Identifier: MIT\\n// Adapted from \\n\\n/**\\n * @authors: [@malatrax]\\n * @reviewers: []\\n * @auditors: []\\n * @bounties: []\\n * @deployments: []\\n */\\npragma solidity 0.8.24;\\n\\n/**\\n * @title UUPS Proxy\\n * @author Simon Malatrait \\n * @dev This contract implements a UUPS Proxy compliant with ERC-1967 & ERC-1822.\\n * @dev This contract delegates all calls to another contract (UUPS Proxiable) through a fallback function and the use of the `delegatecall` EVM instruction.\\n * @dev We refer to the Proxiable contract (as per ERC-1822) with `implementation`.\\n */\\ncontract UUPSProxy {\\n /**\\n * @dev Storage slot with the address of the current implementation.\\n * This is the keccak-256 hash of \\\"eip1967.proxy.implementation\\\" subtracted by 1, and is\\n * validated in the constructor.\\n * NOTE: bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1)\\n */\\n bytes32 private constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\\n\\n // ************************************* //\\n // * Constructor * //\\n // ************************************* //\\n\\n /**\\n * @dev Initializes the upgradeable proxy with an initial implementation specified by `_implementation`.\\n *\\n * If `_data` is nonempty, it's used as data in a delegate call to `_implementation`. This will typically be an encoded\\n * function call, and allows initializing the storage of the proxy like a Solidity constructor.\\n */\\n constructor(address _implementation, bytes memory _data) {\\n assembly {\\n sstore(IMPLEMENTATION_SLOT, _implementation)\\n }\\n\\n if (_data.length != 0) {\\n (bool success, ) = _implementation.delegatecall(_data);\\n require(success, \\\"Proxy Constructor failed\\\");\\n }\\n }\\n\\n // ************************************* //\\n // * State Modifiers * //\\n // ************************************* //\\n\\n /**\\n * @dev Delegates the current call to `implementation`.\\n *\\n * NOTE: This function does not return to its internal call site, it will return directly to the external caller.\\n */\\n function _delegate(address implementation) internal {\\n assembly {\\n // Copy msg.data. We take full control of memory in this inline assembly\\n // block because it will not return to Solidity code. We overwrite the\\n // Solidity scratch pad at memory position 0.\\n calldatacopy(0, 0, calldatasize())\\n\\n // Call the implementation.\\n // out and outsize are 0 because we don't know the size yet.\\n let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)\\n\\n // Copy the returned data.\\n returndatacopy(0, 0, returndatasize())\\n\\n switch result\\n // delegatecall returns 0 on error.\\n case 0 {\\n revert(0, returndatasize())\\n }\\n default {\\n return(0, returndatasize())\\n }\\n }\\n }\\n\\n // ************************************* //\\n // * Internal Views * //\\n // ************************************* //\\n\\n function _getImplementation() internal view returns (address implementation) {\\n assembly {\\n implementation := sload(IMPLEMENTATION_SLOT)\\n }\\n }\\n\\n // ************************************* //\\n // * Fallback * //\\n // ************************************* //\\n\\n /**\\n * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other\\n * function in the contract matches the call data.\\n */\\n fallback() external payable {\\n _delegate(_getImplementation());\\n }\\n\\n receive() external payable {\\n _delegate(_getImplementation());\\n }\\n}\\n\",\"keccak256\":\"0x7aa5f14ce351299722ac1a1afca9e65e1c795f32ea3e9702b0d5faaf7ca822a0\",\"license\":\"MIT\"}},\"version\":1}",
- "bytecode": "0x608060405234801561001057600080fd5b5060405161030238038061030283398101604081905261002f91610151565b8181817f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc55805160001461010e576000826001600160a01b031682604051610077919061021f565b600060405180830381855af49150503d80600081146100b2576040519150601f19603f3d011682016040523d82523d6000602084013e6100b7565b606091505b505090508061010c5760405162461bcd60e51b815260206004820152601860248201527f50726f787920436f6e7374727563746f72206661696c65640000000000000000604482015260640160405180910390fd5b505b5050505061023b565b634e487b7160e01b600052604160045260246000fd5b60005b83811015610148578181015183820152602001610130565b50506000910152565b6000806040838503121561016457600080fd5b82516001600160a01b038116811461017b57600080fd5b60208401519092506001600160401b038082111561019857600080fd5b818501915085601f8301126101ac57600080fd5b8151818111156101be576101be610117565b604051601f8201601f19908116603f011681019083821181831017156101e6576101e6610117565b816040528281528860208487010111156101ff57600080fd5b61021083602083016020880161012d565b80955050505050509250929050565b6000825161023181846020870161012d565b9190910192915050565b60b9806102496000396000f3fe608060405236603757603560317f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5490565b6060565b005b603560317f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5490565b3660008037600080366000845af43d6000803e808015607e573d6000f35b3d6000fdfea2646970667358221220025ed3e852b24305c0ac2e202b83cf5fed6ae313e772bad4b0c1340efea75f0764736f6c63430008180033",
- "deployedBytecode": "0x608060405236603757603560317f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5490565b6060565b005b603560317f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5490565b3660008037600080366000845af43d6000803e808015607e573d6000f35b3d6000fdfea2646970667358221220025ed3e852b24305c0ac2e202b83cf5fed6ae313e772bad4b0c1340efea75f0764736f6c63430008180033",
+ "solcInputHash": "d547d738900bce1310e91a5d1adfc179",
+ "metadata": "{\"compiler\":{\"version\":\"0.8.30+commit.73712a01\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_implementation\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"stateMutability\":\"payable\",\"type\":\"fallback\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/proxy/KlerosProxies.sol\":\"KlerosCoreUniversityProxy\"},\"evmVersion\":\"cancun\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000},\"remappings\":[],\"viaIR\":true},\"sources\":{\"src/proxy/KlerosProxies.sol\":{\"content\":\"//SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.24;\\n\\nimport \\\"./UUPSProxy.sol\\\";\\n\\n/// Workaround to get meaningful names for the proxy contracts\\n/// Otherwise all the contracts are called `UUPSProxy` on the chain explorers\\n\\ncontract DisputeKitClassicUniversityProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract DisputeKitClassicProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract DisputeKitGatedProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract DisputeKitGatedShutterProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract DisputeKitShutterProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract DisputeKitSybilResistantProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract DisputeTemplateRegistryProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract EvidenceModuleProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract ForeignGatewayOnEthereumProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract HomeGatewayToEthereumProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract KlerosCoreRulerProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract KlerosCoreUniversityProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract KlerosCoreProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract PolicyRegistryProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract RandomizerRNGProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract SortitionModuleUniversityProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract SortitionModuleProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\",\"keccak256\":\"0x3160bd320b23c6ec0c21862b455c3044a9b33654ae84a1b6cd76255626c9154b\",\"license\":\"MIT\"},\"src/proxy/UUPSProxy.sol\":{\"content\":\"//SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.24;\\n\\n/// @title UUPS Proxy\\n/// @author Simon Malatrait \\n/// @notice This contract implements a UUPS Proxy compliant with ERC-1967 & ERC-1822.\\n///\\n/// @dev This contract delegates all calls to another contract (UUPS Proxiable) through a fallback function and the use of the `delegatecall` EVM instruction.\\n/// We refer to the Proxiable contract (as per ERC-1822) with `implementation`.\\n/// Adapted from \\ncontract UUPSProxy {\\n /// @dev Storage slot with the address of the current implementation.\\n /// This is the keccak-256 hash of \\\"eip1967.proxy.implementation\\\" subtracted by 1, and is\\n /// validated in the constructor.\\n /// NOTE: bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1)\\n bytes32 private constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\\n\\n // ************************************* //\\n // * Constructor * //\\n // ************************************* //\\n\\n /// @notice Initializes the upgradeable proxy with an initial implementation specified by `_implementation`.\\n /// @dev If `_data` is nonempty, it's used as data in a delegate call to `_implementation`.\\n /// This will typically be an encoded function call, and allows initializing the storage of the proxy like a Solidity constructor.\\n constructor(address _implementation, bytes memory _data) {\\n assembly {\\n sstore(IMPLEMENTATION_SLOT, _implementation)\\n }\\n\\n if (_data.length != 0) {\\n (bool success, ) = _implementation.delegatecall(_data);\\n require(success, \\\"Proxy Constructor failed\\\");\\n }\\n }\\n\\n // ************************************* //\\n // * State Modifiers * //\\n // ************************************* //\\n\\n /// @dev Delegates the current call to `implementation`.\\n /// NOTE: This function does not return to its internal call site, it will return directly to the external caller.\\n function _delegate(address implementation) internal {\\n assembly {\\n // Copy msg.data. We take full control of memory in this inline assembly\\n // block because it will not return to Solidity code. We overwrite the\\n // Solidity scratch pad at memory position 0.\\n calldatacopy(0, 0, calldatasize())\\n\\n // Call the implementation.\\n // out and outsize are 0 because we don't know the size yet.\\n let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)\\n\\n // Copy the returned data.\\n returndatacopy(0, 0, returndatasize())\\n\\n switch result\\n // delegatecall returns 0 on error.\\n case 0 {\\n revert(0, returndatasize())\\n }\\n default {\\n return(0, returndatasize())\\n }\\n }\\n }\\n\\n // ************************************* //\\n // * Internal Views * //\\n // ************************************* //\\n\\n function _getImplementation() internal view returns (address implementation) {\\n assembly {\\n implementation := sload(IMPLEMENTATION_SLOT)\\n }\\n }\\n\\n // ************************************* //\\n // * Fallback * //\\n // ************************************* //\\n\\n /// @dev Fallback function that delegates calls to the address returned by `_implementation()`.\\n /// @dev Will run if no other function in the contract matches the call data.\\n fallback() external payable {\\n _delegate(_getImplementation());\\n }\\n\\n receive() external payable {\\n _delegate(_getImplementation());\\n }\\n}\\n\",\"keccak256\":\"0x2d7b1f81e525787f1b8b033ce381a81cb5f39e411ff31490e019113205a661cd\",\"license\":\"MIT\"}},\"version\":1}",
+ "bytecode": "0x608060405234610144576102148038038061001981610148565b928339810190604081830312610144578051906001600160a01b0382168203610144576020810151906001600160401b038211610144570182601f8201121561014457805161006f61006a82610181565b610148565b9181835260208301946020838301011161014457815f926020809301875e83010152817f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5551806100c9575b6040516077908161019d8239f35b5f9283925af43d1561013f573d6100e261006a82610181565b9081525f60203d92013e5b156100fa575f80806100bb565b60405162461bcd60e51b815260206004820152601860248201527f50726f787920436f6e7374727563746f72206661696c656400000000000000006044820152606490fd5b6100ed565b5f80fd5b6040519190601f01601f191682016001600160401b0381118382101761016d57604052565b634e487b7160e01b5f52604160045260245ffd5b6001600160401b03811161016d57601f01601f19166020019056fe60806040525f807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc54368280378136915af43d5f803e15603d573d5ff35b3d5ffdfea264697066735822122094c812c85dc437a2ab3eda19f621c1ecfc3fbf77e5465f816bde0529d28053a664736f6c634300081e0033",
+ "deployedBytecode": "0x60806040525f807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc54368280378136915af43d5f803e15603d573d5ff35b3d5ffdfea264697066735822122094c812c85dc437a2ab3eda19f621c1ecfc3fbf77e5465f816bde0529d28053a664736f6c634300081e0033",
"execute": {
"methodName": "initialize",
"args": [
@@ -1913,7 +1969,7 @@
"0xf1C7c037891525E360C59f708739Ac09A7670c59",
"0x34B944D42cAcfC8266955D07A80181D2054aa225",
"0x0000000000000000000000000000000000000000",
- "0xd6E96b7c993763B5CDDa1139C7387B82A7c8B8B5",
+ "0x82F2089442979A6b56c80274D144575980092F91",
false,
[
"200000000000000000000",
@@ -1927,10 +1983,10 @@
0,
10
],
- "0x4B2c2d048921f694cCE3AEa35698c6B1f5fcbb79"
+ "0x9f55804177e7E44E558616cD7d06B865788214cA"
]
},
- "implementation": "0xF74DaBfC5F5dbdBD07636637204d9C35326D2906",
+ "implementation": "0xb75b0cc01af4aD0D65D50082ae0717004D479Aa0",
"devdoc": {
"kind": "dev",
"methods": {},
diff --git a/contracts/deployments/arbitrumSepoliaDevnet/KlerosCoreUniversity_Implementation.json b/contracts/deployments/arbitrumSepoliaDevnet/KlerosCoreUniversity_Implementation.json
index c8261658d..30c8cb622 100644
--- a/contracts/deployments/arbitrumSepoliaDevnet/KlerosCoreUniversity_Implementation.json
+++ b/contracts/deployments/arbitrumSepoliaDevnet/KlerosCoreUniversity_Implementation.json
@@ -1,5 +1,5 @@
{
- "address": "0xF74DaBfC5F5dbdBD07636637204d9C35326D2906",
+ "address": "0xb75b0cc01af4aD0D65D50082ae0717004D479Aa0",
"abi": [
{
"inputs": [],
@@ -31,11 +31,6 @@
"name": "ArbitrationFeesNotEnough",
"type": "error"
},
- {
- "inputs": [],
- "name": "ArraysLengthMismatch",
- "type": "error"
- },
{
"inputs": [],
"name": "CannotDisableClassicDK",
@@ -46,11 +41,6 @@
"name": "CommitPeriodNotPassed",
"type": "error"
},
- {
- "inputs": [],
- "name": "DepthLevelMax",
- "type": "error"
- },
{
"inputs": [],
"name": "DisputeKitNotSupportedByCourt",
@@ -86,16 +76,6 @@
"name": "FailedDelegateCall",
"type": "error"
},
- {
- "inputs": [],
- "name": "GovernorOnly",
- "type": "error"
- },
- {
- "inputs": [],
- "name": "GovernorOrInstructorOnly",
- "type": "error"
- },
{
"inputs": [],
"name": "InstructorOnly",
@@ -152,6 +132,16 @@
"name": "NotInitializing",
"type": "error"
},
+ {
+ "inputs": [],
+ "name": "OwnerOnly",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "OwnerOrInstructorOnly",
+ "type": "error"
+ },
{
"inputs": [],
"name": "RulingAlreadyExecuted",
@@ -174,7 +164,7 @@
},
{
"inputs": [],
- "name": "StakingNotPossibeInThisCourt",
+ "name": "StakingNotPossibleInThisCourt",
"type": "error"
},
{
@@ -182,6 +172,11 @@
"name": "StakingTransferFailed",
"type": "error"
},
+ {
+ "inputs": [],
+ "name": "StakingZeroWhenNoStake",
+ "type": "error"
+ },
{
"inputs": [],
"name": "TokenNotAccepted",
@@ -295,9 +290,9 @@
"inputs": [
{
"indexed": true,
- "internalType": "uint256",
+ "internalType": "uint96",
"name": "_courtID",
- "type": "uint256"
+ "type": "uint96"
},
{
"indexed": true,
@@ -572,6 +567,12 @@
{
"anonymous": false,
"inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "_account",
+ "type": "address"
+ },
{
"indexed": true,
"internalType": "uint256",
@@ -587,13 +588,62 @@
{
"indexed": false,
"internalType": "uint256",
- "name": "_pnkAmount",
+ "name": "_degreeOfCoherencyPnk",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
- "name": "_feeAmount",
+ "name": "_degreeOfCoherencyFee",
+ "type": "uint256"
+ },
+ {
+ "indexed": false,
+ "internalType": "int256",
+ "name": "_amountPnk",
+ "type": "int256"
+ },
+ {
+ "indexed": false,
+ "internalType": "int256",
+ "name": "_amountFee",
+ "type": "int256"
+ },
+ {
+ "indexed": false,
+ "internalType": "contract IERC20",
+ "name": "_feeToken",
+ "type": "address"
+ }
+ ],
+ "name": "JurorRewardPenalty",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "uint256",
+ "name": "_disputeID",
+ "type": "uint256"
+ },
+ {
+ "indexed": true,
+ "internalType": "uint256",
+ "name": "_roundID",
+ "type": "uint256"
+ },
+ {
+ "indexed": false,
+ "internalType": "uint256",
+ "name": "_amountPnk",
+ "type": "uint256"
+ },
+ {
+ "indexed": false,
+ "internalType": "uint256",
+ "name": "_amountFee",
"type": "uint256"
},
{
@@ -675,55 +725,6 @@
"name": "Ruling",
"type": "event"
},
- {
- "anonymous": false,
- "inputs": [
- {
- "indexed": true,
- "internalType": "address",
- "name": "_account",
- "type": "address"
- },
- {
- "indexed": true,
- "internalType": "uint256",
- "name": "_disputeID",
- "type": "uint256"
- },
- {
- "indexed": true,
- "internalType": "uint256",
- "name": "_roundID",
- "type": "uint256"
- },
- {
- "indexed": false,
- "internalType": "uint256",
- "name": "_degreeOfCoherency",
- "type": "uint256"
- },
- {
- "indexed": false,
- "internalType": "int256",
- "name": "_pnkAmount",
- "type": "int256"
- },
- {
- "indexed": false,
- "internalType": "int256",
- "name": "_feeAmount",
- "type": "int256"
- },
- {
- "indexed": false,
- "internalType": "contract IERC20",
- "name": "_feeToken",
- "type": "address"
- }
- ],
- "name": "TokenAndETHShift",
- "type": "event"
- },
{
"anonymous": false,
"inputs": [
@@ -946,12 +947,12 @@
{
"inputs": [
{
- "internalType": "address payable",
- "name": "_governor",
+ "internalType": "address",
+ "name": "_instructor",
"type": "address"
}
],
- "name": "changeGovernor",
+ "name": "changeInstructor",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
@@ -960,11 +961,11 @@
"inputs": [
{
"internalType": "address",
- "name": "_instructor",
+ "name": "_jurorProsecutionModule",
"type": "address"
}
],
- "name": "changeInstructor",
+ "name": "changeJurorProsecutionModule",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
@@ -972,12 +973,12 @@
{
"inputs": [
{
- "internalType": "address",
- "name": "_jurorProsecutionModule",
+ "internalType": "address payable",
+ "name": "_owner",
"type": "address"
}
],
- "name": "changeJurorProsecutionModule",
+ "name": "changeOwner",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
@@ -1071,11 +1072,6 @@
"internalType": "uint256",
"name": "jurorsForCourtJump",
"type": "uint256"
- },
- {
- "internalType": "bool",
- "name": "disabled",
- "type": "bool"
}
],
"stateMutability": "view",
@@ -1385,7 +1381,7 @@
"type": "bytes"
}
],
- "name": "executeGovernorProposal",
+ "name": "executeOwnerProposal",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
@@ -1454,6 +1450,30 @@
"stateMutability": "view",
"type": "function"
},
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "_disputeID",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "_round",
+ "type": "uint256"
+ }
+ ],
+ "name": "getPnkAtStakePerJuror",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
{
"inputs": [
{
@@ -1506,6 +1526,11 @@
"name": "drawnJurors",
"type": "address[]"
},
+ {
+ "internalType": "uint96[]",
+ "name": "drawnJurorFromCourtIDs",
+ "type": "uint96[]"
+ },
{
"internalType": "uint256",
"name": "sumFeeRewardPaid",
@@ -1525,6 +1550,11 @@
"internalType": "uint256",
"name": "drawIterations",
"type": "uint256"
+ },
+ {
+ "internalType": "uint256[10]",
+ "name": "__gap",
+ "type": "uint256[10]"
}
],
"internalType": "struct KlerosCoreUniversity.Round",
@@ -1554,24 +1584,11 @@
"stateMutability": "view",
"type": "function"
},
- {
- "inputs": [],
- "name": "governor",
- "outputs": [
- {
- "internalType": "address",
- "name": "",
- "type": "address"
- }
- ],
- "stateMutability": "view",
- "type": "function"
- },
{
"inputs": [
{
"internalType": "address",
- "name": "_governor",
+ "name": "_owner",
"type": "address"
},
{
@@ -1689,6 +1706,19 @@
"stateMutability": "view",
"type": "function"
},
+ {
+ "inputs": [],
+ "name": "owner",
+ "outputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
{
"inputs": [
{
@@ -1762,11 +1792,6 @@
"internalType": "uint256",
"name": "_newStake",
"type": "uint256"
- },
- {
- "internalType": "bool",
- "name": "_alreadyTransferred",
- "type": "bool"
}
],
"name": "setStakeBySortitionModule",
@@ -1787,6 +1812,24 @@
"stateMutability": "view",
"type": "function"
},
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "_account",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "_amount",
+ "type": "uint256"
+ }
+ ],
+ "name": "transferBySortitionModule",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
{
"inputs": [
{
@@ -1804,43 +1847,56 @@
"outputs": [],
"stateMutability": "payable",
"type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "version",
+ "outputs": [
+ {
+ "internalType": "string",
+ "name": "",
+ "type": "string"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
}
],
- "transactionHash": "0xf99e544be3b28ba3d5d7dc89481e4698807522d7dd1d431faf2305c6cbb9265f",
+ "transactionHash": "0x6733cea855fc3ea83280d8dd2bc1de31a95423f55539cb924ed683d4444bf016",
"receipt": {
"to": null,
"from": "0xf1C7c037891525E360C59f708739Ac09A7670c59",
- "contractAddress": "0xF74DaBfC5F5dbdBD07636637204d9C35326D2906",
+ "contractAddress": "0xb75b0cc01af4aD0D65D50082ae0717004D479Aa0",
"transactionIndex": 2,
- "gasUsed": "5019437",
- "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000008000000000000000000000000000000000000000000000000000000000000000000000000000000",
- "blockHash": "0x02db98181f92e8759b1936b6812ee2468550ddd547787f25f966d5f49f589fc4",
- "transactionHash": "0xf99e544be3b28ba3d5d7dc89481e4698807522d7dd1d431faf2305c6cbb9265f",
+ "gasUsed": "4792792",
+ "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000200000000000000080000000000000000000000000000000000000000004000000000000000000000000000000000000004000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ "blockHash": "0x355195241087caacd449d7bcbb83dcb810fc9e09cfc475e69287a5285d1b23bb",
+ "transactionHash": "0x6733cea855fc3ea83280d8dd2bc1de31a95423f55539cb924ed683d4444bf016",
"logs": [
{
"transactionIndex": 2,
- "blockNumber": 96308594,
- "transactionHash": "0xf99e544be3b28ba3d5d7dc89481e4698807522d7dd1d431faf2305c6cbb9265f",
- "address": "0xF74DaBfC5F5dbdBD07636637204d9C35326D2906",
+ "blockNumber": 193533808,
+ "transactionHash": "0x6733cea855fc3ea83280d8dd2bc1de31a95423f55539cb924ed683d4444bf016",
+ "address": "0xb75b0cc01af4aD0D65D50082ae0717004D479Aa0",
"topics": [
"0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2"
],
"data": "0x000000000000000000000000000000000000000000000000ffffffffffffffff",
"logIndex": 1,
- "blockHash": "0x02db98181f92e8759b1936b6812ee2468550ddd547787f25f966d5f49f589fc4"
+ "blockHash": "0x355195241087caacd449d7bcbb83dcb810fc9e09cfc475e69287a5285d1b23bb"
}
],
- "blockNumber": 96308594,
- "cumulativeGasUsed": "5609813",
+ "blockNumber": 193533808,
+ "cumulativeGasUsed": "4827069",
"status": 1,
"byzantium": true
},
"args": [],
"numDeployments": 1,
- "solcInputHash": "a5602534c00c2f67ca4b6a1cab8c717e",
- "metadata": "{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"AllJurorsDrawn\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"AlreadyInitialized\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"AppealFeesNotEnough\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"AppealPeriodNotPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ArbitrationFeesNotEnough\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ArraysLengthMismatch\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CannotDisableClassicDK\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CommitPeriodNotPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DepthLevelMax\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputeKitNotSupportedByCourt\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputeKitOnly\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputeNotAppealable\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputePeriodIsFinal\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputeStillDrawing\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"EvidenceNotPassedAndNotAppeal\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedDelegateCall\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"GovernorOnly\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"GovernorOrInstructorOnly\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InstructorOnly\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidDisputKitParent\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidForkingCourtAsParent\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"implementation\",\"type\":\"address\"}],\"name\":\"InvalidImplementation\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MinStakeLowerThanParentCourt\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MustSupportDisputeKitClassic\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NoJurorDrawn\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotEvidencePeriod\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotExecutionPeriod\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotInitializing\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RulingAlreadyExecuted\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SortitionModuleOnly\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"StakingInTooManyCourts\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"StakingLessThanCourtMinStake\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"StakingNotPossibeInThisCourt\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"StakingTransferFailed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TokenNotAccepted\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TransferFailed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UUPSUnauthorizedCallContext\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"slot\",\"type\":\"bytes32\"}],\"name\":\"UUPSUnsupportedProxiableUUID\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnstakingTransferFailed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnsuccessfulCall\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnsupportedDisputeKit\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"VotePeriodNotPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"WrongDisputeKitIndex\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"contract IERC20\",\"name\":\"_token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"bool\",\"name\":\"_accepted\",\"type\":\"bool\"}],\"name\":\"AcceptedFeeToken\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_disputeID\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"contract IArbitrableV2\",\"name\":\"_arbitrable\",\"type\":\"address\"}],\"name\":\"AppealDecision\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_disputeID\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"contract IArbitrableV2\",\"name\":\"_arbitrable\",\"type\":\"address\"}],\"name\":\"AppealPossible\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_courtID\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint96\",\"name\":\"_parent\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"_hiddenVotes\",\"type\":\"bool\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_minStake\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_alpha\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_feeForJuror\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_jurorsForCourtJump\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256[4]\",\"name\":\"_timesPerPeriod\",\"type\":\"uint256[4]\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"_supportedDisputeKits\",\"type\":\"uint256[]\"}],\"name\":\"CourtCreated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_disputeID\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_roundID\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint96\",\"name\":\"_fromCourtID\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"_toCourtID\",\"type\":\"uint96\"}],\"name\":\"CourtJump\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint96\",\"name\":\"_courtID\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"_hiddenVotes\",\"type\":\"bool\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_minStake\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_alpha\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_feeForJuror\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_jurorsForCourtJump\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256[4]\",\"name\":\"_timesPerPeriod\",\"type\":\"uint256[4]\"}],\"name\":\"CourtModified\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_disputeID\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"contract IArbitrableV2\",\"name\":\"_arbitrable\",\"type\":\"address\"}],\"name\":\"DisputeCreation\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_disputeKitID\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"contract IDisputeKit\",\"name\":\"_disputeKitAddress\",\"type\":\"address\"}],\"name\":\"DisputeKitCreated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint96\",\"name\":\"_courtID\",\"type\":\"uint96\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_disputeKitID\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"bool\",\"name\":\"_enable\",\"type\":\"bool\"}],\"name\":\"DisputeKitEnabled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_disputeID\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_roundID\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_fromDisputeKitID\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_toDisputeKitID\",\"type\":\"uint256\"}],\"name\":\"DisputeKitJump\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_disputeID\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_roundID\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_voteID\",\"type\":\"uint256\"}],\"name\":\"Draw\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"version\",\"type\":\"uint64\"}],\"name\":\"Initialized\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_disputeID\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_roundID\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_pnkAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_feeAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"contract IERC20\",\"name\":\"_feeToken\",\"type\":\"address\"}],\"name\":\"LeftoverRewardSent\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"contract IERC20\",\"name\":\"_feeToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"_rateInEth\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"_rateDecimals\",\"type\":\"uint8\"}],\"name\":\"NewCurrencyRate\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_disputeID\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"enum KlerosCoreUniversity.Period\",\"name\":\"_period\",\"type\":\"uint8\"}],\"name\":\"NewPeriod\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"contract IArbitrableV2\",\"name\":\"_arbitrable\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_disputeID\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_ruling\",\"type\":\"uint256\"}],\"name\":\"Ruling\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_disputeID\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_roundID\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_degreeOfCoherency\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"_pnkAmount\",\"type\":\"int256\"},{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"_feeAmount\",\"type\":\"int256\"},{\"indexed\":false,\"internalType\":\"contract IERC20\",\"name\":\"_feeToken\",\"type\":\"address\"}],\"name\":\"TokenAndETHShift\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newImplementation\",\"type\":\"address\"}],\"name\":\"Upgraded\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"contract IDisputeKit\",\"name\":\"_disputeKitAddress\",\"type\":\"address\"}],\"name\":\"addNewDisputeKit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_disputeID\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_numberOfChoices\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"_extraData\",\"type\":\"bytes\"}],\"name\":\"appeal\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_disputeID\",\"type\":\"uint256\"}],\"name\":\"appealCost\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"cost\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_disputeID\",\"type\":\"uint256\"}],\"name\":\"appealPeriod\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"start\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"end\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_extraData\",\"type\":\"bytes\"},{\"internalType\":\"contract IERC20\",\"name\":\"_feeToken\",\"type\":\"address\"}],\"name\":\"arbitrationCost\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"cost\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_extraData\",\"type\":\"bytes\"}],\"name\":\"arbitrationCost\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"cost\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract IERC20\",\"name\":\"_feeToken\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"_accepted\",\"type\":\"bool\"}],\"name\":\"changeAcceptedFeeTokens\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint96\",\"name\":\"_courtID\",\"type\":\"uint96\"},{\"internalType\":\"bool\",\"name\":\"_hiddenVotes\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"_minStake\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_alpha\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_feeForJuror\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_jurorsForCourtJump\",\"type\":\"uint256\"},{\"internalType\":\"uint256[4]\",\"name\":\"_timesPerPeriod\",\"type\":\"uint256[4]\"}],\"name\":\"changeCourtParameters\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract IERC20\",\"name\":\"_feeToken\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"_rateInEth\",\"type\":\"uint64\"},{\"internalType\":\"uint8\",\"name\":\"_rateDecimals\",\"type\":\"uint8\"}],\"name\":\"changeCurrencyRates\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address payable\",\"name\":\"_governor\",\"type\":\"address\"}],\"name\":\"changeGovernor\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_instructor\",\"type\":\"address\"}],\"name\":\"changeInstructor\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_jurorProsecutionModule\",\"type\":\"address\"}],\"name\":\"changeJurorProsecutionModule\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract IERC20\",\"name\":\"_pinakion\",\"type\":\"address\"}],\"name\":\"changePinakion\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract ISortitionModuleUniversity\",\"name\":\"_sortitionModule\",\"type\":\"address\"}],\"name\":\"changeSortitionModule\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract IERC20\",\"name\":\"_toToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amountInEth\",\"type\":\"uint256\"}],\"name\":\"convertEthToTokenAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"courts\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"parent\",\"type\":\"uint96\"},{\"internalType\":\"bool\",\"name\":\"hiddenVotes\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"minStake\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"alpha\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"feeForJuror\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"jurorsForCourtJump\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"disabled\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint96\",\"name\":\"_parent\",\"type\":\"uint96\"},{\"internalType\":\"bool\",\"name\":\"_hiddenVotes\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"_minStake\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_alpha\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_feeForJuror\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_jurorsForCourtJump\",\"type\":\"uint256\"},{\"internalType\":\"uint256[4]\",\"name\":\"_timesPerPeriod\",\"type\":\"uint256[4]\"},{\"internalType\":\"uint256[]\",\"name\":\"_supportedDisputeKits\",\"type\":\"uint256[]\"}],\"name\":\"createCourt\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_numberOfChoices\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"_extraData\",\"type\":\"bytes\"}],\"name\":\"createDispute\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"disputeID\",\"type\":\"uint256\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_numberOfChoices\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"_extraData\",\"type\":\"bytes\"},{\"internalType\":\"contract IERC20\",\"name\":\"_feeToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_feeAmount\",\"type\":\"uint256\"}],\"name\":\"createDispute\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"disputeID\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract IERC20\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"currencyRates\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"feePaymentAccepted\",\"type\":\"bool\"},{\"internalType\":\"uint64\",\"name\":\"rateInEth\",\"type\":\"uint64\"},{\"internalType\":\"uint8\",\"name\":\"rateDecimals\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_disputeID\",\"type\":\"uint256\"}],\"name\":\"currentRuling\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"ruling\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"tied\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"overridden\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"disputeKits\",\"outputs\":[{\"internalType\":\"contract IDisputeKit\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"disputes\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"courtID\",\"type\":\"uint96\"},{\"internalType\":\"contract IArbitrableV2\",\"name\":\"arbitrated\",\"type\":\"address\"},{\"internalType\":\"enum KlerosCoreUniversity.Period\",\"name\":\"period\",\"type\":\"uint8\"},{\"internalType\":\"bool\",\"name\":\"ruled\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"lastPeriodChange\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_disputeID\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_juror\",\"type\":\"address\"}],\"name\":\"draw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint96\",\"name\":\"_courtID\",\"type\":\"uint96\"},{\"internalType\":\"uint256[]\",\"name\":\"_disputeKitIDs\",\"type\":\"uint256[]\"},{\"internalType\":\"bool\",\"name\":\"_enable\",\"type\":\"bool\"}],\"name\":\"enableDisputeKits\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_disputeID\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_round\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_iterations\",\"type\":\"uint256\"}],\"name\":\"execute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_destination\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"executeGovernorProposal\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_disputeID\",\"type\":\"uint256\"}],\"name\":\"executeRuling\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getDisputeKitsLength\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_disputeID\",\"type\":\"uint256\"}],\"name\":\"getNumberOfRounds\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_disputeID\",\"type\":\"uint256\"}],\"name\":\"getNumberOfVotes\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_disputeID\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_round\",\"type\":\"uint256\"}],\"name\":\"getRoundInfo\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"disputeKitID\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"pnkAtStakePerJuror\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"totalFeesForJurors\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nbVotes\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repartitions\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"pnkPenalties\",\"type\":\"uint256\"},{\"internalType\":\"address[]\",\"name\":\"drawnJurors\",\"type\":\"address[]\"},{\"internalType\":\"uint256\",\"name\":\"sumFeeRewardPaid\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"sumPnkRewardPaid\",\"type\":\"uint256\"},{\"internalType\":\"contract IERC20\",\"name\":\"feeToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"drawIterations\",\"type\":\"uint256\"}],\"internalType\":\"struct KlerosCoreUniversity.Round\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint96\",\"name\":\"_courtID\",\"type\":\"uint96\"}],\"name\":\"getTimesPerPeriod\",\"outputs\":[{\"internalType\":\"uint256[4]\",\"name\":\"timesPerPeriod\",\"type\":\"uint256[4]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"governor\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_governor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_instructor\",\"type\":\"address\"},{\"internalType\":\"contract IERC20\",\"name\":\"_pinakion\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_jurorProsecutionModule\",\"type\":\"address\"},{\"internalType\":\"contract IDisputeKit\",\"name\":\"_disputeKit\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"_hiddenVotes\",\"type\":\"bool\"},{\"internalType\":\"uint256[4]\",\"name\":\"_courtParameters\",\"type\":\"uint256[4]\"},{\"internalType\":\"uint256[4]\",\"name\":\"_timesPerPeriod\",\"type\":\"uint256[4]\"},{\"internalType\":\"contract ISortitionModuleUniversity\",\"name\":\"_sortitionModuleAddress\",\"type\":\"address\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"instructor\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_disputeID\",\"type\":\"uint256\"}],\"name\":\"isDisputeKitJumping\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint96\",\"name\":\"_courtID\",\"type\":\"uint96\"},{\"internalType\":\"uint256\",\"name\":\"_disputeKitID\",\"type\":\"uint256\"}],\"name\":\"isSupported\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"jurorProsecutionModule\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_disputeID\",\"type\":\"uint256\"}],\"name\":\"passPeriod\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pinakion\",\"outputs\":[{\"internalType\":\"contract IERC20\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"proxiableUUID\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint96\",\"name\":\"_courtID\",\"type\":\"uint96\"},{\"internalType\":\"uint256\",\"name\":\"_newStake\",\"type\":\"uint256\"}],\"name\":\"setStake\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_account\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"_courtID\",\"type\":\"uint96\"},{\"internalType\":\"uint256\",\"name\":\"_newStake\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"_alreadyTransferred\",\"type\":\"bool\"}],\"name\":\"setStakeBySortitionModule\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"sortitionModule\",\"outputs\":[{\"internalType\":\"contract ISortitionModuleUniversity\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newImplementation\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"upgradeToAndCall\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"errors\":{\"AlreadyInitialized()\":[{\"details\":\"The contract is already initialized.\"}],\"NotInitializing()\":[{\"details\":\"The contract is not initializing.\"}],\"UUPSUnauthorizedCallContext()\":[{\"details\":\"The call is from an unauthorized context.\"}],\"UUPSUnsupportedProxiableUUID(bytes32)\":[{\"details\":\"The storage `slot` is unsupported as a UUID.\"}]},\"events\":{\"AcceptedFeeToken(address,bool)\":{\"details\":\"To be emitted when an ERC20 token is added or removed as a method to pay fees.\",\"params\":{\"_accepted\":\"Whether the token is accepted or not.\",\"_token\":\"The ERC20 token.\"}},\"DisputeCreation(uint256,address)\":{\"details\":\"To be emitted when a dispute is created.\",\"params\":{\"_arbitrable\":\"The contract which created the dispute.\",\"_disputeID\":\"The identifier of the dispute in the Arbitrator contract.\"}},\"Initialized(uint64)\":{\"details\":\"Triggered when the contract has been initialized or reinitialized.\"},\"NewCurrencyRate(address,uint64,uint8)\":{\"details\":\"To be emitted when the fee for a particular ERC20 token is updated.\",\"params\":{\"_feeToken\":\"The ERC20 token.\",\"_rateDecimals\":\"The new decimals of the fee token rate.\",\"_rateInEth\":\"The new rate of the fee token in ETH.\"}},\"Ruling(address,uint256,uint256)\":{\"details\":\"To be raised when a ruling is given.\",\"params\":{\"_arbitrable\":\"The arbitrable receiving the ruling.\",\"_disputeID\":\"The identifier of the dispute in the Arbitrator contract.\",\"_ruling\":\"The ruling which was given.\"}},\"Upgraded(address)\":{\"params\":{\"newImplementation\":\"Address of the new implementation the proxy is now forwarding calls to.\"}}},\"kind\":\"dev\",\"methods\":{\"addNewDisputeKit(address)\":{\"details\":\"Add a new supported dispute kit module to the court.\",\"params\":{\"_disputeKitAddress\":\"The address of the dispute kit contract.\"}},\"appeal(uint256,uint256,bytes)\":{\"details\":\"Appeals the ruling of a specified dispute. Note: Access restricted to the Dispute Kit for this `disputeID`.\",\"params\":{\"_disputeID\":\"The ID of the dispute.\",\"_extraData\":\"Extradata for the dispute. Can be required during court jump.\",\"_numberOfChoices\":\"Number of choices for the dispute. Can be required during court jump.\"}},\"appealCost(uint256)\":{\"details\":\"Gets the cost of appealing a specified dispute.\",\"params\":{\"_disputeID\":\"The ID of the dispute.\"},\"returns\":{\"cost\":\"The appeal cost.\"}},\"appealPeriod(uint256)\":{\"details\":\"Gets the start and the end of a specified dispute's current appeal period.\",\"params\":{\"_disputeID\":\"The ID of the dispute.\"},\"returns\":{\"end\":\"The end of the appeal period.\",\"start\":\"The start of the appeal period.\"}},\"arbitrationCost(bytes)\":{\"details\":\"Compute the cost of arbitration denominated in ETH. It is recommended not to increase it often, as it can be highly time and gas consuming for the arbitrated contracts to cope with fee augmentation.\",\"params\":{\"_extraData\":\"Additional info about the dispute. We use it to pass the ID of the dispute's court (first 32 bytes), the minimum number of jurors required (next 32 bytes) and the ID of the specific dispute kit (last 32 bytes).\"},\"returns\":{\"cost\":\"The arbitration cost in ETH.\"}},\"arbitrationCost(bytes,address)\":{\"details\":\"Compute the cost of arbitration denominated in `_feeToken`. It is recommended not to increase it often, as it can be highly time and gas consuming for the arbitrated contracts to cope with fee augmentation.\",\"params\":{\"_extraData\":\"Additional info about the dispute. We use it to pass the ID of the dispute's court (first 32 bytes), the minimum number of jurors required (next 32 bytes) and the ID of the specific dispute kit (last 32 bytes).\",\"_feeToken\":\"The ERC20 token used to pay fees.\"},\"returns\":{\"cost\":\"The arbitration cost in `_feeToken`.\"}},\"changeAcceptedFeeTokens(address,bool)\":{\"details\":\"Changes the supported fee tokens.\",\"params\":{\"_accepted\":\"Whether the token is supported or not as a method of fee payment.\",\"_feeToken\":\"The fee token.\"}},\"changeCurrencyRates(address,uint64,uint8)\":{\"details\":\"Changes the currency rate of a fee token.\",\"params\":{\"_feeToken\":\"The fee token.\",\"_rateDecimals\":\"The new decimals of the fee token rate.\",\"_rateInEth\":\"The new rate of the fee token in ETH.\"}},\"changeGovernor(address)\":{\"details\":\"Changes the `governor` storage variable.\",\"params\":{\"_governor\":\"The new value for the `governor` storage variable.\"}},\"changeInstructor(address)\":{\"details\":\"Changes the `instructor` storage variable.\",\"params\":{\"_instructor\":\"The new value for the `instructor` storage variable.\"}},\"changeJurorProsecutionModule(address)\":{\"details\":\"Changes the `jurorProsecutionModule` storage variable.\",\"params\":{\"_jurorProsecutionModule\":\"The new value for the `jurorProsecutionModule` storage variable.\"}},\"changePinakion(address)\":{\"details\":\"Changes the `pinakion` storage variable.\",\"params\":{\"_pinakion\":\"The new value for the `pinakion` storage variable.\"}},\"changeSortitionModule(address)\":{\"details\":\"Changes the `_sortitionModule` storage variable. Note that the new module should be initialized for all courts.\",\"params\":{\"_sortitionModule\":\"The new value for the `sortitionModule` storage variable.\"}},\"constructor\":{\"details\":\"Constructor, initializing the implementation to reduce attack surface.\"},\"createCourt(uint96,bool,uint256,uint256,uint256,uint256,uint256[4],uint256[])\":{\"details\":\"Creates a court under a specified parent court.\",\"params\":{\"_alpha\":\"The `alpha` property value of the court.\",\"_feeForJuror\":\"The `feeForJuror` property value of the court.\",\"_hiddenVotes\":\"The `hiddenVotes` property value of the court.\",\"_jurorsForCourtJump\":\"The `jurorsForCourtJump` property value of the court.\",\"_minStake\":\"The `minStake` property value of the court.\",\"_parent\":\"The `parent` property value of the court.\",\"_supportedDisputeKits\":\"Indexes of dispute kits that this court will support.\",\"_timesPerPeriod\":\"The `timesPerPeriod` property value of the court.\"}},\"createDispute(uint256,bytes)\":{\"details\":\"Create a dispute and pay for the fees in the native currency, typically ETH. Must be called by the arbitrable contract. Must pay at least arbitrationCost(_extraData).\",\"params\":{\"_extraData\":\"Additional info about the dispute. We use it to pass the ID of the dispute's court (first 32 bytes), the minimum number of jurors required (next 32 bytes) and the ID of the specific dispute kit (last 32 bytes).\",\"_numberOfChoices\":\"The number of choices the arbitrator can choose from in this dispute.\"},\"returns\":{\"disputeID\":\"The identifier of the dispute created.\"}},\"createDispute(uint256,bytes,address,uint256)\":{\"details\":\"Create a dispute and pay for the fees in a supported ERC20 token. Must be called by the arbitrable contract. Must pay at least arbitrationCost(_extraData).\",\"params\":{\"_extraData\":\"Additional info about the dispute. We use it to pass the ID of the dispute's court (first 32 bytes), the minimum number of jurors required (next 32 bytes) and the ID of the specific dispute kit (last 32 bytes).\",\"_feeAmount\":\"Amount of the ERC20 token used to pay fees.\",\"_feeToken\":\"The ERC20 token used to pay fees.\",\"_numberOfChoices\":\"The number of choices the arbitrator can choose from in this dispute.\"},\"returns\":{\"disputeID\":\"The identifier of the dispute created.\"}},\"currentRuling(uint256)\":{\"details\":\"Gets the current ruling of a specified dispute.\",\"params\":{\"_disputeID\":\"The ID of the dispute.\"},\"returns\":{\"overridden\":\"Whether the ruling was overridden by appeal funding or not.\",\"ruling\":\"The current ruling.\",\"tied\":\"Whether it's a tie or not.\"}},\"draw(uint256,address)\":{\"details\":\"Draws one juror for the dispute until the number votes paid for is reached.\",\"params\":{\"_disputeID\":\"The ID of the dispute.\",\"_juror\":\"The address of the juror to draw.\"}},\"enableDisputeKits(uint96,uint256[],bool)\":{\"details\":\"Adds/removes court's support for specified dispute kits.\",\"params\":{\"_courtID\":\"The ID of the court.\",\"_disputeKitIDs\":\"The IDs of dispute kits which support should be added/removed.\",\"_enable\":\"Whether add or remove the dispute kits from the court.\"}},\"execute(uint256,uint256,uint256)\":{\"details\":\"Distribute the PNKs at stake and the dispute fees for the specific round of the dispute. Can be called in parts.\",\"params\":{\"_disputeID\":\"The ID of the dispute.\",\"_iterations\":\"The number of iterations to run.\",\"_round\":\"The appeal round.\"}},\"executeGovernorProposal(address,uint256,bytes)\":{\"details\":\"Allows the governor to call anything on behalf of the contract.\",\"params\":{\"_amount\":\"The value sent with the call.\",\"_data\":\"The data sent with the call.\",\"_destination\":\"The destination of the call.\"}},\"executeRuling(uint256)\":{\"details\":\"Executes a specified dispute's ruling.\",\"params\":{\"_disputeID\":\"The ID of the dispute.\"}},\"getNumberOfVotes(uint256)\":{\"details\":\"Gets the number of votes permitted for the specified dispute in the latest round.\",\"params\":{\"_disputeID\":\"The ID of the dispute.\"}},\"getTimesPerPeriod(uint96)\":{\"details\":\"Gets the timesPerPeriod array for a given court.\",\"params\":{\"_courtID\":\"The ID of the court to get the times from.\"},\"returns\":{\"timesPerPeriod\":\"The timesPerPeriod array for the given court.\"}},\"initialize(address,address,address,address,address,bool,uint256[4],uint256[4],address)\":{\"details\":\"Initializer (constructor equivalent for upgradable contracts).\",\"params\":{\"_courtParameters\":\"Numeric parameters of General court (minStake, alpha, feeForJuror and jurorsForCourtJump respectively).\",\"_disputeKit\":\"The address of the default dispute kit.\",\"_governor\":\"The governor's address.\",\"_hiddenVotes\":\"The `hiddenVotes` property value of the general court.\",\"_instructor\":\"The address of the instructor.\",\"_jurorProsecutionModule\":\"The address of the juror prosecution module.\",\"_pinakion\":\"The address of the token contract.\",\"_sortitionModuleAddress\":\"The sortition module responsible for sortition of the jurors.\",\"_timesPerPeriod\":\"The `timesPerPeriod` property value of the general court.\"}},\"isDisputeKitJumping(uint256)\":{\"details\":\"Returns true if the dispute kit will be switched to a parent DK.\",\"params\":{\"_disputeID\":\"The ID of the dispute.\"},\"returns\":{\"_0\":\"Whether DK will be switched or not.\"}},\"passPeriod(uint256)\":{\"details\":\"Passes the period of a specified dispute.\",\"params\":{\"_disputeID\":\"The ID of the dispute.\"}},\"proxiableUUID()\":{\"details\":\"Implementation of the ERC1822 `proxiableUUID` function. This returns the storage slot used by the implementation. It is used to validate the implementation's compatibility when performing an upgrade. IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this function revert if invoked through a proxy. This is guaranteed by the if statement.\"},\"setStake(uint96,uint256)\":{\"details\":\"Sets the caller's stake in a court.\",\"params\":{\"_courtID\":\"The ID of the court.\",\"_newStake\":\"The new stake. Note that the existing delayed stake will be nullified as non-relevant.\"}},\"setStakeBySortitionModule(address,uint96,uint256,bool)\":{\"details\":\"Sets the stake of a specified account in a court, typically to apply a delayed stake or unstake inactive jurors.\",\"params\":{\"_account\":\"The account whose stake is being set.\",\"_alreadyTransferred\":\"Whether the PNKs have already been transferred to the contract.\",\"_courtID\":\"The ID of the court.\",\"_newStake\":\"The new stake.\"}},\"upgradeToAndCall(address,bytes)\":{\"details\":\"Upgrade mechanism including access control and UUPS-compliance.Reverts if the execution is not performed via delegatecall or the execution context is not of a proxy with an ERC1967-compliant implementation pointing to self.\",\"params\":{\"data\":\"Data used in a delegate call to `newImplementation` if non-empty. This will typically be an encoded function call, and allows initializing the storage of the proxy like a Solidity constructor.\",\"newImplementation\":\"Address of the new implementation contract.\"}}},\"title\":\"KlerosCoreUniversity Core arbitrator contract for educational purposes.\",\"version\":1},\"userdoc\":{\"errors\":{\"FailedDelegateCall()\":[{\"notice\":\"Failed Delegated call\"}],\"InvalidImplementation(address)\":[{\"notice\":\"The `implementation` is not UUPS-compliant\"}]},\"events\":{\"Upgraded(address)\":{\"notice\":\"Emitted when the `implementation` has been successfully upgraded.\"}},\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/arbitration/university/KlerosCoreUniversity.sol\":\"KlerosCoreUniversity\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":100},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.20;\\n\\n/**\\n * @dev Interface of the ERC-20 standard as defined in the ERC.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n\\n /**\\n * @dev Returns the value of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the value of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 value) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\\n * caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 value) external returns (bool);\\n\\n /**\\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\\n * allowance mechanism. `value` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(address from, address to, uint256 value) external returns (bool);\\n}\\n\",\"keccak256\":\"0xe06a3f08a987af6ad2e1c1e774405d4fe08f1694b67517438b467cecf0da0ef7\",\"license\":\"MIT\"},\"src/arbitration/interfaces/IArbitrableV2.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.24;\\n\\nimport \\\"./IArbitratorV2.sol\\\";\\n\\n/// @title IArbitrableV2\\n/// @notice Arbitrable interface.\\n/// @dev When developing arbitrable contracts, we need to:\\n/// - Define the action taken when a ruling is received by the contract.\\n/// - Allow dispute creation. For this a function must call arbitrator.createDispute{value: _fee}(_choices,_extraData);\\ninterface IArbitrableV2 {\\n /// @dev To be emitted when a dispute is created to link the correct meta-evidence to the disputeID.\\n /// @param _arbitrator The arbitrator of the contract.\\n /// @param _arbitratorDisputeID The identifier of the dispute in the Arbitrator contract.\\n /// @param _externalDisputeID An identifier created outside Kleros by the protocol requesting arbitration.\\n /// @param _templateId The identifier of the dispute template. Should not be used with _templateUri.\\n /// @param _templateUri The URI to the dispute template. For example on IPFS: starting with '/ipfs/'. Should not be used with _templateId.\\n event DisputeRequest(\\n IArbitratorV2 indexed _arbitrator,\\n uint256 indexed _arbitratorDisputeID,\\n uint256 _externalDisputeID,\\n uint256 _templateId,\\n string _templateUri\\n );\\n\\n /// @dev To be raised when a ruling is given.\\n /// @param _arbitrator The arbitrator giving the ruling.\\n /// @param _disputeID The identifier of the dispute in the Arbitrator contract.\\n /// @param _ruling The ruling which was given.\\n event Ruling(IArbitratorV2 indexed _arbitrator, uint256 indexed _disputeID, uint256 _ruling);\\n\\n /// @dev Give a ruling for a dispute.\\n /// Must be called by the arbitrator.\\n /// The purpose of this function is to ensure that the address calling it has the right to rule on the contract.\\n /// @param _disputeID The identifier of the dispute in the Arbitrator contract.\\n /// @param _ruling Ruling given by the arbitrator.\\n /// Note that 0 is reserved for \\\"Not able/wanting to make a decision\\\".\\n function rule(uint256 _disputeID, uint256 _ruling) external;\\n}\\n\",\"keccak256\":\"0xe841a4fe8ec109ce17dde4457bf1583c8b499109b05887c53a49a3207fc6e80b\",\"license\":\"MIT\"},\"src/arbitration/interfaces/IArbitratorV2.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"./IArbitrableV2.sol\\\";\\n\\n/// @title Arbitrator\\n/// Arbitrator interface that implements the new arbitration standard.\\n/// Unlike the ERC-792 this standard is not concerned with appeals, so each arbitrator can implement an appeal system that suits it the most.\\n/// When developing arbitrator contracts we need to:\\n/// - Define the functions for dispute creation (createDispute). Don't forget to store the arbitrated contract and the disputeID (which should be unique, may nbDisputes).\\n/// - Define the functions for cost display (arbitrationCost).\\n/// - Allow giving rulings. For this a function must call arbitrable.rule(disputeID, ruling).\\ninterface IArbitratorV2 {\\n /// @dev To be emitted when a dispute is created.\\n /// @param _disputeID The identifier of the dispute in the Arbitrator contract.\\n /// @param _arbitrable The contract which created the dispute.\\n event DisputeCreation(uint256 indexed _disputeID, IArbitrableV2 indexed _arbitrable);\\n\\n /// @dev To be raised when a ruling is given.\\n /// @param _arbitrable The arbitrable receiving the ruling.\\n /// @param _disputeID The identifier of the dispute in the Arbitrator contract.\\n /// @param _ruling The ruling which was given.\\n event Ruling(IArbitrableV2 indexed _arbitrable, uint256 indexed _disputeID, uint256 _ruling);\\n\\n /// @dev To be emitted when an ERC20 token is added or removed as a method to pay fees.\\n /// @param _token The ERC20 token.\\n /// @param _accepted Whether the token is accepted or not.\\n event AcceptedFeeToken(IERC20 indexed _token, bool indexed _accepted);\\n\\n /// @dev To be emitted when the fee for a particular ERC20 token is updated.\\n /// @param _feeToken The ERC20 token.\\n /// @param _rateInEth The new rate of the fee token in ETH.\\n /// @param _rateDecimals The new decimals of the fee token rate.\\n event NewCurrencyRate(IERC20 indexed _feeToken, uint64 _rateInEth, uint8 _rateDecimals);\\n\\n /// @dev Create a dispute and pay for the fees in the native currency, typically ETH.\\n /// Must be called by the arbitrable contract.\\n /// Must pay at least arbitrationCost(_extraData).\\n /// @param _numberOfChoices The number of choices the arbitrator can choose from in this dispute.\\n /// @param _extraData Additional info about the dispute. We use it to pass the ID of the dispute's court (first 32 bytes), the minimum number of jurors required (next 32 bytes) and the ID of the specific dispute kit (last 32 bytes).\\n /// @return disputeID The identifier of the dispute created.\\n function createDispute(\\n uint256 _numberOfChoices,\\n bytes calldata _extraData\\n ) external payable returns (uint256 disputeID);\\n\\n /// @dev Create a dispute and pay for the fees in a supported ERC20 token.\\n /// Must be called by the arbitrable contract.\\n /// Must pay at least arbitrationCost(_extraData).\\n /// @param _numberOfChoices The number of choices the arbitrator can choose from in this dispute.\\n /// @param _extraData Additional info about the dispute. We use it to pass the ID of the dispute's court (first 32 bytes), the minimum number of jurors required (next 32 bytes) and the ID of the specific dispute kit (last 32 bytes).\\n /// @param _feeToken The ERC20 token used to pay fees.\\n /// @param _feeAmount Amount of the ERC20 token used to pay fees.\\n /// @return disputeID The identifier of the dispute created.\\n function createDispute(\\n uint256 _numberOfChoices,\\n bytes calldata _extraData,\\n IERC20 _feeToken,\\n uint256 _feeAmount\\n ) external returns (uint256 disputeID);\\n\\n /// @dev Compute the cost of arbitration denominated in the native currency, typically ETH.\\n /// It is recommended not to increase it often, as it can be highly time and gas consuming for the arbitrated contracts to cope with fee augmentation.\\n /// @param _extraData Additional info about the dispute. We use it to pass the ID of the dispute's court (first 32 bytes), the minimum number of jurors required (next 32 bytes) and the ID of the specific dispute kit (last 32 bytes).\\n /// @return cost The arbitration cost in ETH.\\n function arbitrationCost(bytes calldata _extraData) external view returns (uint256 cost);\\n\\n /// @dev Compute the cost of arbitration denominated in `_feeToken`.\\n /// It is recommended not to increase it often, as it can be highly time and gas consuming for the arbitrated contracts to cope with fee augmentation.\\n /// @param _extraData Additional info about the dispute. We use it to pass the ID of the dispute's court (first 32 bytes), the minimum number of jurors required (next 32 bytes) and the ID of the specific dispute kit (last 32 bytes).\\n /// @param _feeToken The ERC20 token used to pay fees.\\n /// @return cost The arbitration cost in `_feeToken`.\\n function arbitrationCost(bytes calldata _extraData, IERC20 _feeToken) external view returns (uint256 cost);\\n\\n /// @dev Gets the current ruling of a specified dispute.\\n /// @param _disputeID The ID of the dispute.\\n /// @return ruling The current ruling.\\n /// @return tied Whether it's a tie or not.\\n /// @return overridden Whether the ruling was overridden by appeal funding or not.\\n function currentRuling(uint256 _disputeID) external view returns (uint256 ruling, bool tied, bool overridden);\\n}\\n\",\"keccak256\":\"0xa4dc6b958197adead238de4246cd04e7389c3dc1b9f968acd10985f8fc5b74cf\",\"license\":\"MIT\"},\"src/arbitration/interfaces/IDisputeKit.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\n/// @custom:authors: [@unknownunknown1, @jaybuidl]\\n/// @custom:reviewers: []\\n/// @custom:auditors: []\\n/// @custom:bounties: []\\n/// @custom:deployments: []\\n\\npragma solidity 0.8.24;\\n\\nimport \\\"./IArbitratorV2.sol\\\";\\n\\n/// @title IDisputeKit\\n/// An abstraction of the Dispute Kits intended for interfacing with KlerosCore.\\n/// It does not intend to abstract the interactions with the user (such as voting or appeal funding) to allow for implementation-specific parameters.\\ninterface IDisputeKit {\\n // ************************************ //\\n // * Events * //\\n // ************************************ //\\n\\n /// @dev Emitted when casting a vote to provide the justification of juror's choice.\\n /// @param _coreDisputeID The identifier of the dispute in the Arbitrator contract.\\n /// @param _juror Address of the juror.\\n /// @param _voteIDs The identifiers of the votes in the dispute.\\n /// @param _choice The choice juror voted for.\\n /// @param _justification Justification of the choice.\\n event VoteCast(\\n uint256 indexed _coreDisputeID,\\n address indexed _juror,\\n uint256[] _voteIDs,\\n uint256 indexed _choice,\\n string _justification\\n );\\n\\n // ************************************* //\\n // * State Modifiers * //\\n // ************************************* //\\n\\n /// @dev Creates a local dispute and maps it to the dispute ID in the Core contract.\\n /// Note: Access restricted to Kleros Core only.\\n /// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.\\n /// @param _numberOfChoices Number of choices of the dispute\\n /// @param _extraData Additional info about the dispute, for possible use in future dispute kits.\\n function createDispute(\\n uint256 _coreDisputeID,\\n uint256 _numberOfChoices,\\n bytes calldata _extraData,\\n uint256 _nbVotes\\n ) external;\\n\\n /// @dev Draws the juror from the sortition tree. The drawn address is picked up by Kleros Core.\\n /// Note: Access restricted to Kleros Core only.\\n /// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.\\n /// @param _nonce Nonce.\\n /// @return drawnAddress The drawn address.\\n function draw(uint256 _coreDisputeID, uint256 _nonce) external returns (address drawnAddress);\\n\\n // ************************************* //\\n // * Public Views * //\\n // ************************************* //\\n\\n /// @dev Gets the current ruling of a specified dispute.\\n /// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.\\n /// @return ruling The current ruling.\\n /// @return tied Whether it's a tie or not.\\n /// @return overridden Whether the ruling was overridden by appeal funding or not.\\n function currentRuling(uint256 _coreDisputeID) external view returns (uint256 ruling, bool tied, bool overridden);\\n\\n /// @dev Gets the degree of coherence of a particular voter. This function is called by Kleros Core in order to determine the amount of the reward.\\n /// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.\\n /// @param _coreRoundID The ID of the round in Kleros Core, not in the Dispute Kit.\\n /// @param _voteID The ID of the vote.\\n /// @param _feePerJuror The fee per juror.\\n /// @param _pnkAtStakePerJuror The PNK at stake per juror.\\n /// @return The degree of coherence in basis points.\\n function getDegreeOfCoherence(\\n uint256 _coreDisputeID,\\n uint256 _coreRoundID,\\n uint256 _voteID,\\n uint256 _feePerJuror,\\n uint256 _pnkAtStakePerJuror\\n ) external view returns (uint256);\\n\\n /// @dev Gets the number of jurors who are eligible to a reward in this round.\\n /// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.\\n /// @param _coreRoundID The ID of the round in Kleros Core, not in the Dispute Kit.\\n /// @return The number of coherent jurors.\\n function getCoherentCount(uint256 _coreDisputeID, uint256 _coreRoundID) external view returns (uint256);\\n\\n /// @dev Returns true if all of the jurors have cast their commits for the last round.\\n /// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.\\n /// @return Whether all of the jurors have cast their commits for the last round.\\n function areCommitsAllCast(uint256 _coreDisputeID) external view returns (bool);\\n\\n /// @dev Returns true if all of the jurors have cast their votes for the last round.\\n /// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.\\n /// @return Whether all of the jurors have cast their votes for the last round.\\n function areVotesAllCast(uint256 _coreDisputeID) external view returns (bool);\\n\\n /// @dev Returns true if the specified voter was active in this round.\\n /// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.\\n /// @param _coreRoundID The ID of the round in Kleros Core, not in the Dispute Kit.\\n /// @param _voteID The ID of the voter.\\n /// @return Whether the voter was active or not.\\n function isVoteActive(uint256 _coreDisputeID, uint256 _coreRoundID, uint256 _voteID) external view returns (bool);\\n\\n function getRoundInfo(\\n uint256 _coreDisputeID,\\n uint256 _coreRoundID,\\n uint256 _choice\\n )\\n external\\n view\\n returns (\\n uint256 winningChoice,\\n bool tied,\\n uint256 totalVoted,\\n uint256 totalCommited,\\n uint256 nbVoters,\\n uint256 choiceCount\\n );\\n\\n function getVoteInfo(\\n uint256 _coreDisputeID,\\n uint256 _coreRoundID,\\n uint256 _voteID\\n ) external view returns (address account, bytes32 commit, uint256 choice, bool voted);\\n}\\n\",\"keccak256\":\"0xb9590d05f9df08dd0ed027b2eb40c7b1885b7574a121b1b0b7da0920429bb4d5\",\"license\":\"MIT\"},\"src/arbitration/interfaces/ISortitionModule.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.24;\\n\\nimport \\\"../../libraries/Constants.sol\\\";\\n\\ninterface ISortitionModule {\\n enum Phase {\\n staking, // Stake sum trees can be updated. Pass after `minStakingTime` passes and there is at least one dispute without jurors.\\n generating, // Waiting for a random number. Pass as soon as it is ready.\\n drawing // Jurors can be drawn. Pass after all disputes have jurors or `maxDrawingTime` passes.\\n }\\n\\n event NewPhase(Phase _phase);\\n\\n function createTree(bytes32 _key, bytes memory _extraData) external;\\n\\n function setStake(\\n address _account,\\n uint96 _courtID,\\n uint256 _newStake,\\n bool _alreadyTransferred\\n ) external returns (uint256 pnkDeposit, uint256 pnkWithdrawal, StakingResult stakingResult);\\n\\n function setJurorInactive(address _account) external;\\n\\n function lockStake(address _account, uint256 _relativeAmount) external;\\n\\n function unlockStake(address _account, uint256 _relativeAmount) external;\\n\\n function penalizeStake(address _account, uint256 _relativeAmount) external;\\n\\n function notifyRandomNumber(uint256 _drawnNumber) external;\\n\\n function draw(bytes32 _court, uint256 _coreDisputeID, uint256 _nonce) external view returns (address);\\n\\n function getJurorBalance(\\n address _juror,\\n uint96 _courtID\\n ) external view returns (uint256 totalStaked, uint256 totalLocked, uint256 stakedInCourt, uint256 nbCourts);\\n\\n function getJurorCourtIDs(address _juror) external view returns (uint96[] memory);\\n\\n function isJurorStaked(address _juror) external view returns (bool);\\n\\n function createDisputeHook(uint256 _disputeID, uint256 _roundID) external;\\n\\n function postDrawHook(uint256 _disputeID, uint256 _roundID) external;\\n}\\n\",\"keccak256\":\"0x18a4ff126bb51e7b5b0e3fbff7cf0dbbcfff7195ad79307e69cdbc9226e63502\",\"license\":\"MIT\"},\"src/arbitration/university/ISortitionModuleUniversity.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.24;\\n\\nimport {ISortitionModule} from \\\"../interfaces/ISortitionModule.sol\\\";\\n\\ninterface ISortitionModuleUniversity is ISortitionModule {\\n function setTransientJuror(address _juror) external;\\n}\\n\",\"keccak256\":\"0x57fee0787ae90af01c57a7d2850f8e4ade1ca72163a388341cac017bfdbf163a\",\"license\":\"MIT\"},\"src/arbitration/university/KlerosCoreUniversity.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.24;\\n\\nimport {IArbitrableV2, IArbitratorV2} from \\\"../interfaces/IArbitratorV2.sol\\\";\\nimport {IDisputeKit} from \\\"../interfaces/IDisputeKit.sol\\\";\\nimport {ISortitionModuleUniversity} from \\\"./ISortitionModuleUniversity.sol\\\";\\nimport {SafeERC20, IERC20} from \\\"../../libraries/SafeERC20.sol\\\";\\nimport \\\"../../libraries/Constants.sol\\\";\\nimport {UUPSProxiable} from \\\"../../proxy/UUPSProxiable.sol\\\";\\nimport {Initializable} from \\\"../../proxy/Initializable.sol\\\";\\n\\n/// @title KlerosCoreUniversity\\n/// Core arbitrator contract for educational purposes.\\ncontract KlerosCoreUniversity is IArbitratorV2, UUPSProxiable, Initializable {\\n using SafeERC20 for IERC20;\\n\\n // ************************************* //\\n // * Enums / Structs * //\\n // ************************************* //\\n\\n enum Period {\\n evidence, // Evidence can be submitted. This is also when drawing has to take place.\\n commit, // Jurors commit a hashed vote. This is skipped for courts without hidden votes.\\n vote, // Jurors reveal/cast their vote depending on whether the court has hidden votes or not.\\n appeal, // The dispute can be appealed.\\n execution // Tokens are redistributed and the ruling is executed.\\n }\\n\\n struct Court {\\n uint96 parent; // The parent court.\\n bool hiddenVotes; // Whether to use commit and reveal or not.\\n uint256[] children; // List of child courts.\\n uint256 minStake; // Minimum PNKs needed to stake in the court.\\n uint256 alpha; // Basis point of PNKs that are lost when incoherent.\\n uint256 feeForJuror; // Arbitration fee paid per juror.\\n uint256 jurorsForCourtJump; // The appeal after the one that reaches this number of jurors will go to the parent court if any.\\n uint256[4] timesPerPeriod; // The time allotted to each dispute period in the form `timesPerPeriod[period]`.\\n mapping(uint256 disputeKitId => bool) supportedDisputeKits; // True if DK with this ID is supported by the court. Note that each court must support classic dispute kit.\\n bool disabled; // True if the court is disabled. Unused for now, will be implemented later.\\n }\\n\\n struct Dispute {\\n uint96 courtID; // The ID of the court the dispute is in.\\n IArbitrableV2 arbitrated; // The arbitrable contract.\\n Period period; // The current period of the dispute.\\n bool ruled; // True if the ruling has been executed, false otherwise.\\n uint256 lastPeriodChange; // The last time the period was changed.\\n Round[] rounds;\\n }\\n\\n struct Round {\\n uint256 disputeKitID; // Index of the dispute kit in the array.\\n uint256 pnkAtStakePerJuror; // The amount of PNKs at stake for each juror in this round.\\n uint256 totalFeesForJurors; // The total juror fees paid in this round.\\n uint256 nbVotes; // The total number of votes the dispute can possibly have in the current round. Former votes[_round].length.\\n uint256 repartitions; // A counter of reward repartitions made in this round.\\n uint256 pnkPenalties; // The amount of PNKs collected from penalties in this round.\\n address[] drawnJurors; // Addresses of the jurors that were drawn in this round.\\n uint256 sumFeeRewardPaid; // Total sum of arbitration fees paid to coherent jurors as a reward in this round.\\n uint256 sumPnkRewardPaid; // Total sum of PNK paid to coherent jurors as a reward in this round.\\n IERC20 feeToken; // The token used for paying fees in this round.\\n uint256 drawIterations; // The number of iterations passed drawing the jurors for this round.\\n }\\n\\n // Workaround \\\"stack too deep\\\" errors\\n struct ExecuteParams {\\n uint256 disputeID; // The ID of the dispute to execute.\\n uint256 round; // The round to execute.\\n uint256 coherentCount; // The number of coherent votes in the round.\\n uint256 numberOfVotesInRound; // The number of votes in the round.\\n uint256 feePerJurorInRound; // The fee per juror in the round.\\n uint256 pnkAtStakePerJurorInRound; // The amount of PNKs at stake for each juror in the round.\\n uint256 pnkPenaltiesInRound; // The amount of PNKs collected from penalties in the round.\\n uint256 repartition; // The index of the repartition to execute.\\n }\\n\\n struct CurrencyRate {\\n bool feePaymentAccepted;\\n uint64 rateInEth;\\n uint8 rateDecimals;\\n }\\n\\n // ************************************* //\\n // * Storage * //\\n // ************************************* //\\n\\n uint256 private constant ALPHA_DIVISOR = 1e4; // The number to divide `Court.alpha` by.\\n uint256 private constant NON_PAYABLE_AMOUNT = (2 ** 256 - 2) / 2; // An amount higher than the supply of ETH.\\n\\n address public governor; // The governor of the contract.\\n address public instructor; // The instructor who is allowed to choose the jurors.\\n IERC20 public pinakion; // The Pinakion token contract.\\n address public jurorProsecutionModule; // The module for juror's prosecution.\\n ISortitionModuleUniversity public sortitionModule; // Sortition module for drawing.\\n Court[] public courts; // The courts.\\n IDisputeKit[] public disputeKits; // Array of dispute kits.\\n Dispute[] public disputes; // The disputes.\\n mapping(IERC20 => CurrencyRate) public currencyRates; // The price of each token in ETH.\\n\\n // ************************************* //\\n // * Events * //\\n // ************************************* //\\n\\n event NewPeriod(uint256 indexed _disputeID, Period _period);\\n event AppealPossible(uint256 indexed _disputeID, IArbitrableV2 indexed _arbitrable);\\n event AppealDecision(uint256 indexed _disputeID, IArbitrableV2 indexed _arbitrable);\\n event Draw(address indexed _address, uint256 indexed _disputeID, uint256 _roundID, uint256 _voteID);\\n event CourtCreated(\\n uint256 indexed _courtID,\\n uint96 indexed _parent,\\n bool _hiddenVotes,\\n uint256 _minStake,\\n uint256 _alpha,\\n uint256 _feeForJuror,\\n uint256 _jurorsForCourtJump,\\n uint256[4] _timesPerPeriod,\\n uint256[] _supportedDisputeKits\\n );\\n event CourtModified(\\n uint96 indexed _courtID,\\n bool _hiddenVotes,\\n uint256 _minStake,\\n uint256 _alpha,\\n uint256 _feeForJuror,\\n uint256 _jurorsForCourtJump,\\n uint256[4] _timesPerPeriod\\n );\\n event DisputeKitCreated(uint256 indexed _disputeKitID, IDisputeKit indexed _disputeKitAddress);\\n event DisputeKitEnabled(uint96 indexed _courtID, uint256 indexed _disputeKitID, bool indexed _enable);\\n event CourtJump(\\n uint256 indexed _disputeID,\\n uint256 indexed _roundID,\\n uint96 indexed _fromCourtID,\\n uint96 _toCourtID\\n );\\n event DisputeKitJump(\\n uint256 indexed _disputeID,\\n uint256 indexed _roundID,\\n uint256 indexed _fromDisputeKitID,\\n uint256 _toDisputeKitID\\n );\\n event TokenAndETHShift(\\n address indexed _account,\\n uint256 indexed _disputeID,\\n uint256 indexed _roundID,\\n uint256 _degreeOfCoherency,\\n int256 _pnkAmount,\\n int256 _feeAmount,\\n IERC20 _feeToken\\n );\\n event LeftoverRewardSent(\\n uint256 indexed _disputeID,\\n uint256 indexed _roundID,\\n uint256 _pnkAmount,\\n uint256 _feeAmount,\\n IERC20 _feeToken\\n );\\n\\n // ************************************* //\\n // * Function Modifiers * //\\n // ************************************* //\\n\\n modifier onlyByGovernor() {\\n if (governor != msg.sender) revert GovernorOnly();\\n _;\\n }\\n\\n modifier onlyByInstructor() {\\n if (instructor != msg.sender) revert InstructorOnly();\\n _;\\n }\\n\\n modifier onlyByGovernorOrInstructor() {\\n if (msg.sender != governor && msg.sender != instructor) revert GovernorOrInstructorOnly();\\n _;\\n }\\n\\n // ************************************* //\\n // * Constructor * //\\n // ************************************* //\\n\\n /// @dev Constructor, initializing the implementation to reduce attack surface.\\n constructor() {\\n _disableInitializers();\\n }\\n\\n /// @dev Initializer (constructor equivalent for upgradable contracts).\\n /// @param _governor The governor's address.\\n /// @param _instructor The address of the instructor.\\n /// @param _pinakion The address of the token contract.\\n /// @param _jurorProsecutionModule The address of the juror prosecution module.\\n /// @param _disputeKit The address of the default dispute kit.\\n /// @param _hiddenVotes The `hiddenVotes` property value of the general court.\\n /// @param _courtParameters Numeric parameters of General court (minStake, alpha, feeForJuror and jurorsForCourtJump respectively).\\n /// @param _timesPerPeriod The `timesPerPeriod` property value of the general court.\\n /// @param _sortitionModuleAddress The sortition module responsible for sortition of the jurors.\\n function initialize(\\n address _governor,\\n address _instructor,\\n IERC20 _pinakion,\\n address _jurorProsecutionModule,\\n IDisputeKit _disputeKit,\\n bool _hiddenVotes,\\n uint256[4] memory _courtParameters,\\n uint256[4] memory _timesPerPeriod,\\n ISortitionModuleUniversity _sortitionModuleAddress\\n ) external reinitializer(1) {\\n governor = _governor;\\n instructor = _instructor;\\n pinakion = _pinakion;\\n jurorProsecutionModule = _jurorProsecutionModule;\\n sortitionModule = _sortitionModuleAddress;\\n\\n // NULL_DISPUTE_KIT: an empty element at index 0 to indicate when a dispute kit is not supported.\\n disputeKits.push();\\n\\n // DISPUTE_KIT_CLASSIC\\n disputeKits.push(_disputeKit);\\n\\n emit DisputeKitCreated(DISPUTE_KIT_CLASSIC, _disputeKit);\\n\\n // FORKING_COURT\\n // TODO: Fill the properties for the Forking court, emit CourtCreated.\\n courts.push();\\n\\n // GENERAL_COURT\\n Court storage court = courts.push();\\n court.parent = FORKING_COURT;\\n court.children = new uint256[](0);\\n court.hiddenVotes = _hiddenVotes;\\n court.minStake = _courtParameters[0];\\n court.alpha = _courtParameters[1];\\n court.feeForJuror = _courtParameters[2];\\n court.jurorsForCourtJump = _courtParameters[3];\\n court.timesPerPeriod = _timesPerPeriod;\\n\\n emit CourtCreated(\\n 1,\\n court.parent,\\n _hiddenVotes,\\n _courtParameters[0],\\n _courtParameters[1],\\n _courtParameters[2],\\n _courtParameters[3],\\n _timesPerPeriod,\\n new uint256[](0)\\n );\\n _enableDisputeKit(GENERAL_COURT, DISPUTE_KIT_CLASSIC, true);\\n }\\n\\n // ************************************* //\\n // * Governance * //\\n // ************************************* //\\n\\n /* @dev Access Control to perform implementation upgrades (UUPS Proxiable)\\n * @dev Only the governor can perform upgrades (`onlyByGovernor`)\\n */\\n function _authorizeUpgrade(address) internal view override onlyByGovernor {\\n // NOP\\n }\\n\\n /// @dev Allows the governor to call anything on behalf of the contract.\\n /// @param _destination The destination of the call.\\n /// @param _amount The value sent with the call.\\n /// @param _data The data sent with the call.\\n function executeGovernorProposal(\\n address _destination,\\n uint256 _amount,\\n bytes memory _data\\n ) external onlyByGovernor {\\n (bool success, ) = _destination.call{value: _amount}(_data);\\n if (!success) revert UnsuccessfulCall();\\n }\\n\\n /// @dev Changes the `governor` storage variable.\\n /// @param _governor The new value for the `governor` storage variable.\\n function changeGovernor(address payable _governor) external onlyByGovernor {\\n governor = _governor;\\n }\\n\\n /// @dev Changes the `instructor` storage variable.\\n /// @param _instructor The new value for the `instructor` storage variable.\\n function changeInstructor(address _instructor) external onlyByGovernorOrInstructor {\\n instructor = _instructor;\\n }\\n\\n /// @dev Changes the `pinakion` storage variable.\\n /// @param _pinakion The new value for the `pinakion` storage variable.\\n function changePinakion(IERC20 _pinakion) external onlyByGovernor {\\n pinakion = _pinakion;\\n }\\n\\n /// @dev Changes the `jurorProsecutionModule` storage variable.\\n /// @param _jurorProsecutionModule The new value for the `jurorProsecutionModule` storage variable.\\n function changeJurorProsecutionModule(address _jurorProsecutionModule) external onlyByGovernor {\\n jurorProsecutionModule = _jurorProsecutionModule;\\n }\\n\\n /// @dev Changes the `_sortitionModule` storage variable.\\n /// Note that the new module should be initialized for all courts.\\n /// @param _sortitionModule The new value for the `sortitionModule` storage variable.\\n function changeSortitionModule(ISortitionModuleUniversity _sortitionModule) external onlyByGovernor {\\n sortitionModule = _sortitionModule;\\n }\\n\\n /// @dev Add a new supported dispute kit module to the court.\\n /// @param _disputeKitAddress The address of the dispute kit contract.\\n function addNewDisputeKit(IDisputeKit _disputeKitAddress) external onlyByGovernor {\\n uint256 disputeKitID = disputeKits.length;\\n disputeKits.push(_disputeKitAddress);\\n emit DisputeKitCreated(disputeKitID, _disputeKitAddress);\\n }\\n\\n /// @dev Creates a court under a specified parent court.\\n /// @param _parent The `parent` property value of the court.\\n /// @param _hiddenVotes The `hiddenVotes` property value of the court.\\n /// @param _minStake The `minStake` property value of the court.\\n /// @param _alpha The `alpha` property value of the court.\\n /// @param _feeForJuror The `feeForJuror` property value of the court.\\n /// @param _jurorsForCourtJump The `jurorsForCourtJump` property value of the court.\\n /// @param _timesPerPeriod The `timesPerPeriod` property value of the court.\\n /// @param _supportedDisputeKits Indexes of dispute kits that this court will support.\\n function createCourt(\\n uint96 _parent,\\n bool _hiddenVotes,\\n uint256 _minStake,\\n uint256 _alpha,\\n uint256 _feeForJuror,\\n uint256 _jurorsForCourtJump,\\n uint256[4] memory _timesPerPeriod,\\n uint256[] memory _supportedDisputeKits\\n ) external onlyByGovernor {\\n if (courts[_parent].minStake > _minStake) revert MinStakeLowerThanParentCourt();\\n if (_supportedDisputeKits.length == 0) revert UnsupportedDisputeKit();\\n if (_parent == FORKING_COURT) revert InvalidForkingCourtAsParent();\\n\\n uint256 courtID = courts.length;\\n Court storage court = courts.push();\\n\\n for (uint256 i = 0; i < _supportedDisputeKits.length; i++) {\\n if (_supportedDisputeKits[i] == 0 || _supportedDisputeKits[i] >= disputeKits.length) {\\n revert WrongDisputeKitIndex();\\n }\\n court.supportedDisputeKits[_supportedDisputeKits[i]] = true;\\n }\\n // Check that Classic DK support was added.\\n if (!court.supportedDisputeKits[DISPUTE_KIT_CLASSIC]) revert MustSupportDisputeKitClassic();\\n\\n court.parent = _parent;\\n court.children = new uint256[](0);\\n court.hiddenVotes = _hiddenVotes;\\n court.minStake = _minStake;\\n court.alpha = _alpha;\\n court.feeForJuror = _feeForJuror;\\n court.jurorsForCourtJump = _jurorsForCourtJump;\\n court.timesPerPeriod = _timesPerPeriod;\\n\\n // Update the parent.\\n courts[_parent].children.push(courtID);\\n emit CourtCreated(\\n courtID,\\n _parent,\\n _hiddenVotes,\\n _minStake,\\n _alpha,\\n _feeForJuror,\\n _jurorsForCourtJump,\\n _timesPerPeriod,\\n _supportedDisputeKits\\n );\\n }\\n\\n function changeCourtParameters(\\n uint96 _courtID,\\n bool _hiddenVotes,\\n uint256 _minStake,\\n uint256 _alpha,\\n uint256 _feeForJuror,\\n uint256 _jurorsForCourtJump,\\n uint256[4] memory _timesPerPeriod\\n ) external onlyByGovernor {\\n Court storage court = courts[_courtID];\\n if (_courtID != GENERAL_COURT && courts[court.parent].minStake > _minStake) {\\n revert MinStakeLowerThanParentCourt();\\n }\\n for (uint256 i = 0; i < court.children.length; i++) {\\n if (courts[court.children[i]].minStake < _minStake) {\\n revert MinStakeLowerThanParentCourt();\\n }\\n }\\n court.minStake = _minStake;\\n court.hiddenVotes = _hiddenVotes;\\n court.alpha = _alpha;\\n court.feeForJuror = _feeForJuror;\\n court.jurorsForCourtJump = _jurorsForCourtJump;\\n court.timesPerPeriod = _timesPerPeriod;\\n emit CourtModified(\\n _courtID,\\n _hiddenVotes,\\n _minStake,\\n _alpha,\\n _feeForJuror,\\n _jurorsForCourtJump,\\n _timesPerPeriod\\n );\\n }\\n\\n /// @dev Adds/removes court's support for specified dispute kits.\\n /// @param _courtID The ID of the court.\\n /// @param _disputeKitIDs The IDs of dispute kits which support should be added/removed.\\n /// @param _enable Whether add or remove the dispute kits from the court.\\n function enableDisputeKits(uint96 _courtID, uint256[] memory _disputeKitIDs, bool _enable) external onlyByGovernor {\\n for (uint256 i = 0; i < _disputeKitIDs.length; i++) {\\n if (_enable) {\\n if (_disputeKitIDs[i] == 0 || _disputeKitIDs[i] >= disputeKits.length) {\\n revert WrongDisputeKitIndex();\\n }\\n _enableDisputeKit(_courtID, _disputeKitIDs[i], true);\\n } else {\\n // Classic dispute kit must be supported by all courts.\\n if (_disputeKitIDs[i] == DISPUTE_KIT_CLASSIC) {\\n revert CannotDisableClassicDK();\\n }\\n _enableDisputeKit(_courtID, _disputeKitIDs[i], false);\\n }\\n }\\n }\\n\\n /// @dev Changes the supported fee tokens.\\n /// @param _feeToken The fee token.\\n /// @param _accepted Whether the token is supported or not as a method of fee payment.\\n function changeAcceptedFeeTokens(IERC20 _feeToken, bool _accepted) external onlyByGovernor {\\n currencyRates[_feeToken].feePaymentAccepted = _accepted;\\n emit AcceptedFeeToken(_feeToken, _accepted);\\n }\\n\\n /// @dev Changes the currency rate of a fee token.\\n /// @param _feeToken The fee token.\\n /// @param _rateInEth The new rate of the fee token in ETH.\\n /// @param _rateDecimals The new decimals of the fee token rate.\\n function changeCurrencyRates(IERC20 _feeToken, uint64 _rateInEth, uint8 _rateDecimals) external onlyByGovernor {\\n currencyRates[_feeToken].rateInEth = _rateInEth;\\n currencyRates[_feeToken].rateDecimals = _rateDecimals;\\n emit NewCurrencyRate(_feeToken, _rateInEth, _rateDecimals);\\n }\\n\\n // ************************************* //\\n // * State Modifiers * //\\n // ************************************* //\\n\\n /// @dev Sets the caller's stake in a court.\\n /// @param _courtID The ID of the court.\\n /// @param _newStake The new stake.\\n /// Note that the existing delayed stake will be nullified as non-relevant.\\n function setStake(uint96 _courtID, uint256 _newStake) external {\\n _setStake(msg.sender, _courtID, _newStake, false, OnError.Revert);\\n }\\n\\n /// @dev Sets the stake of a specified account in a court, typically to apply a delayed stake or unstake inactive jurors.\\n /// @param _account The account whose stake is being set.\\n /// @param _courtID The ID of the court.\\n /// @param _newStake The new stake.\\n /// @param _alreadyTransferred Whether the PNKs have already been transferred to the contract.\\n function setStakeBySortitionModule(\\n address _account,\\n uint96 _courtID,\\n uint256 _newStake,\\n bool _alreadyTransferred\\n ) external {\\n if (msg.sender != address(sortitionModule)) revert SortitionModuleOnly();\\n _setStake(_account, _courtID, _newStake, _alreadyTransferred, OnError.Return);\\n }\\n\\n /// @inheritdoc IArbitratorV2\\n function createDispute(\\n uint256 _numberOfChoices,\\n bytes memory _extraData\\n ) external payable override returns (uint256 disputeID) {\\n if (msg.value < arbitrationCost(_extraData)) revert ArbitrationFeesNotEnough();\\n\\n return _createDispute(_numberOfChoices, _extraData, NATIVE_CURRENCY, msg.value);\\n }\\n\\n /// @inheritdoc IArbitratorV2\\n function createDispute(\\n uint256 _numberOfChoices,\\n bytes calldata _extraData,\\n IERC20 _feeToken,\\n uint256 _feeAmount\\n ) external override returns (uint256 disputeID) {\\n if (!currencyRates[_feeToken].feePaymentAccepted) revert TokenNotAccepted();\\n if (_feeAmount < arbitrationCost(_extraData, _feeToken)) revert ArbitrationFeesNotEnough();\\n\\n if (!_feeToken.safeTransferFrom(msg.sender, address(this), _feeAmount)) revert TransferFailed();\\n return _createDispute(_numberOfChoices, _extraData, _feeToken, _feeAmount);\\n }\\n\\n function _createDispute(\\n uint256 _numberOfChoices,\\n bytes memory _extraData,\\n IERC20 _feeToken,\\n uint256 _feeAmount\\n ) internal returns (uint256 disputeID) {\\n (uint96 courtID, , uint256 disputeKitID) = _extraDataToCourtIDMinJurorsDisputeKit(_extraData);\\n if (!courts[courtID].supportedDisputeKits[disputeKitID]) revert DisputeKitNotSupportedByCourt();\\n\\n disputeID = disputes.length;\\n Dispute storage dispute = disputes.push();\\n dispute.courtID = courtID;\\n dispute.arbitrated = IArbitrableV2(msg.sender);\\n dispute.lastPeriodChange = block.timestamp;\\n\\n IDisputeKit disputeKit = disputeKits[disputeKitID];\\n Court storage court = courts[courtID];\\n Round storage round = dispute.rounds.push();\\n\\n // Obtain the feeForJuror in the same currency as the _feeAmount\\n uint256 feeForJuror = (_feeToken == NATIVE_CURRENCY)\\n ? court.feeForJuror\\n : convertEthToTokenAmount(_feeToken, court.feeForJuror);\\n round.nbVotes = _feeAmount / feeForJuror;\\n round.disputeKitID = disputeKitID;\\n round.pnkAtStakePerJuror = (court.minStake * court.alpha) / ALPHA_DIVISOR;\\n round.totalFeesForJurors = _feeAmount;\\n round.feeToken = IERC20(_feeToken);\\n\\n sortitionModule.createDisputeHook(disputeID, 0); // Default round ID.\\n\\n disputeKit.createDispute(disputeID, _numberOfChoices, _extraData, round.nbVotes);\\n emit DisputeCreation(disputeID, IArbitrableV2(msg.sender));\\n }\\n\\n /// @dev Passes the period of a specified dispute.\\n /// @param _disputeID The ID of the dispute.\\n function passPeriod(uint256 _disputeID) external {\\n Dispute storage dispute = disputes[_disputeID];\\n Court storage court = courts[dispute.courtID];\\n\\n uint256 currentRound = dispute.rounds.length - 1;\\n Round storage round = dispute.rounds[currentRound];\\n if (dispute.period == Period.evidence) {\\n if (\\n currentRound == 0 &&\\n block.timestamp - dispute.lastPeriodChange < court.timesPerPeriod[uint256(dispute.period)]\\n ) {\\n revert EvidenceNotPassedAndNotAppeal();\\n }\\n if (round.drawnJurors.length != round.nbVotes) revert DisputeStillDrawing();\\n dispute.period = court.hiddenVotes ? Period.commit : Period.vote;\\n } else if (dispute.period == Period.commit) {\\n if (\\n block.timestamp - dispute.lastPeriodChange < court.timesPerPeriod[uint256(dispute.period)] &&\\n !disputeKits[round.disputeKitID].areCommitsAllCast(_disputeID)\\n ) {\\n revert CommitPeriodNotPassed();\\n }\\n dispute.period = Period.vote;\\n } else if (dispute.period == Period.vote) {\\n if (\\n block.timestamp - dispute.lastPeriodChange < court.timesPerPeriod[uint256(dispute.period)] &&\\n !disputeKits[round.disputeKitID].areVotesAllCast(_disputeID)\\n ) {\\n revert VotePeriodNotPassed();\\n }\\n dispute.period = Period.appeal;\\n emit AppealPossible(_disputeID, dispute.arbitrated);\\n } else if (dispute.period == Period.appeal) {\\n if (block.timestamp - dispute.lastPeriodChange < court.timesPerPeriod[uint256(dispute.period)]) {\\n revert AppealPeriodNotPassed();\\n }\\n dispute.period = Period.execution;\\n } else if (dispute.period == Period.execution) {\\n revert DisputePeriodIsFinal();\\n }\\n\\n dispute.lastPeriodChange = block.timestamp;\\n emit NewPeriod(_disputeID, dispute.period);\\n }\\n\\n /// @dev Draws one juror for the dispute until the number votes paid for is reached.\\n /// @param _disputeID The ID of the dispute.\\n /// @param _juror The address of the juror to draw.\\n function draw(uint256 _disputeID, address _juror) external onlyByGovernorOrInstructor {\\n Dispute storage dispute = disputes[_disputeID];\\n uint256 currentRound = dispute.rounds.length - 1;\\n Round storage round = dispute.rounds[currentRound];\\n if (dispute.period != Period.evidence) revert NotEvidencePeriod();\\n if (round.drawnJurors.length >= round.nbVotes) revert AllJurorsDrawn();\\n\\n sortitionModule.setTransientJuror(_juror);\\n {\\n IDisputeKit disputeKit = disputeKits[round.disputeKitID];\\n uint256 iteration = round.drawIterations + 1;\\n address drawnAddress = disputeKit.draw(_disputeID, iteration);\\n if (drawnAddress == address(0)) {\\n revert NoJurorDrawn();\\n }\\n sortitionModule.lockStake(drawnAddress, round.pnkAtStakePerJuror);\\n emit Draw(drawnAddress, _disputeID, currentRound, round.drawnJurors.length);\\n round.drawnJurors.push(drawnAddress);\\n if (round.drawnJurors.length == round.nbVotes) {\\n sortitionModule.postDrawHook(_disputeID, currentRound);\\n }\\n round.drawIterations = iteration;\\n }\\n sortitionModule.setTransientJuror(address(0));\\n }\\n\\n /// @dev Appeals the ruling of a specified dispute.\\n /// Note: Access restricted to the Dispute Kit for this `disputeID`.\\n /// @param _disputeID The ID of the dispute.\\n /// @param _numberOfChoices Number of choices for the dispute. Can be required during court jump.\\n /// @param _extraData Extradata for the dispute. Can be required during court jump.\\n function appeal(uint256 _disputeID, uint256 _numberOfChoices, bytes memory _extraData) external payable {\\n if (msg.value < appealCost(_disputeID)) revert AppealFeesNotEnough();\\n\\n Dispute storage dispute = disputes[_disputeID];\\n if (dispute.period != Period.appeal) revert DisputeNotAppealable();\\n\\n Round storage round = dispute.rounds[dispute.rounds.length - 1];\\n if (msg.sender != address(disputeKits[round.disputeKitID])) revert DisputeKitOnly();\\n\\n uint96 newCourtID = dispute.courtID;\\n uint256 newDisputeKitID = round.disputeKitID;\\n\\n // Warning: the extra round must be created before calling disputeKit.createDispute()\\n Round storage extraRound = dispute.rounds.push();\\n\\n if (round.nbVotes >= courts[newCourtID].jurorsForCourtJump) {\\n // Jump to parent court.\\n newCourtID = courts[newCourtID].parent;\\n\\n if (!courts[newCourtID].supportedDisputeKits[newDisputeKitID]) {\\n // Switch to classic dispute kit if parent court doesn't support the current one.\\n newDisputeKitID = DISPUTE_KIT_CLASSIC;\\n }\\n\\n if (newCourtID != dispute.courtID) {\\n emit CourtJump(_disputeID, dispute.rounds.length - 1, dispute.courtID, newCourtID);\\n }\\n }\\n\\n dispute.courtID = newCourtID;\\n dispute.period = Period.evidence;\\n dispute.lastPeriodChange = block.timestamp;\\n\\n Court storage court = courts[newCourtID];\\n extraRound.nbVotes = msg.value / court.feeForJuror; // As many votes that can be afforded by the provided funds.\\n extraRound.pnkAtStakePerJuror = (court.minStake * court.alpha) / ALPHA_DIVISOR;\\n extraRound.totalFeesForJurors = msg.value;\\n extraRound.disputeKitID = newDisputeKitID;\\n\\n sortitionModule.createDisputeHook(_disputeID, dispute.rounds.length - 1);\\n\\n // Dispute kit was changed, so create a dispute in the new DK contract.\\n if (extraRound.disputeKitID != round.disputeKitID) {\\n emit DisputeKitJump(_disputeID, dispute.rounds.length - 1, round.disputeKitID, extraRound.disputeKitID);\\n disputeKits[extraRound.disputeKitID].createDispute(\\n _disputeID,\\n _numberOfChoices,\\n _extraData,\\n extraRound.nbVotes\\n );\\n }\\n\\n emit AppealDecision(_disputeID, dispute.arbitrated);\\n emit NewPeriod(_disputeID, Period.evidence);\\n }\\n\\n /// @dev Distribute the PNKs at stake and the dispute fees for the specific round of the dispute. Can be called in parts.\\n /// @param _disputeID The ID of the dispute.\\n /// @param _round The appeal round.\\n /// @param _iterations The number of iterations to run.\\n function execute(uint256 _disputeID, uint256 _round, uint256 _iterations) external {\\n Round storage round;\\n {\\n Dispute storage dispute = disputes[_disputeID];\\n if (dispute.period != Period.execution) revert NotExecutionPeriod();\\n\\n round = dispute.rounds[_round];\\n } // stack too deep workaround\\n\\n uint256 start = round.repartitions;\\n uint256 end = round.repartitions + _iterations;\\n\\n uint256 pnkPenaltiesInRound = round.pnkPenalties; // Keep in memory to save gas.\\n uint256 numberOfVotesInRound = round.drawnJurors.length;\\n uint256 feePerJurorInRound = round.totalFeesForJurors / numberOfVotesInRound;\\n uint256 pnkAtStakePerJurorInRound = round.pnkAtStakePerJuror;\\n uint256 coherentCount;\\n {\\n IDisputeKit disputeKit = disputeKits[round.disputeKitID];\\n coherentCount = disputeKit.getCoherentCount(_disputeID, _round); // Total number of jurors that are eligible to a reward in this round.\\n } // stack too deep workaround\\n\\n if (coherentCount == 0) {\\n // We loop over the votes once as there are no rewards because it is not a tie and no one in this round is coherent with the final outcome.\\n if (end > numberOfVotesInRound) end = numberOfVotesInRound;\\n } else {\\n // We loop over the votes twice, first to collect the PNK penalties, and second to distribute them as rewards along with arbitration fees.\\n if (end > numberOfVotesInRound * 2) end = numberOfVotesInRound * 2;\\n }\\n round.repartitions = end;\\n\\n for (uint256 i = start; i < end; i++) {\\n if (i < numberOfVotesInRound) {\\n pnkPenaltiesInRound = _executePenalties(\\n ExecuteParams({\\n disputeID: _disputeID,\\n round: _round,\\n coherentCount: coherentCount,\\n numberOfVotesInRound: numberOfVotesInRound,\\n feePerJurorInRound: feePerJurorInRound,\\n pnkAtStakePerJurorInRound: pnkAtStakePerJurorInRound,\\n pnkPenaltiesInRound: pnkPenaltiesInRound,\\n repartition: i\\n })\\n );\\n } else {\\n _executeRewards(\\n ExecuteParams({\\n disputeID: _disputeID,\\n round: _round,\\n coherentCount: coherentCount,\\n numberOfVotesInRound: numberOfVotesInRound,\\n feePerJurorInRound: feePerJurorInRound,\\n pnkAtStakePerJurorInRound: pnkAtStakePerJurorInRound,\\n pnkPenaltiesInRound: pnkPenaltiesInRound,\\n repartition: i\\n })\\n );\\n }\\n }\\n if (round.pnkPenalties != pnkPenaltiesInRound) {\\n round.pnkPenalties = pnkPenaltiesInRound; // Reentrancy risk: breaks Check-Effect-Interact\\n }\\n }\\n\\n /// @dev Distribute the PNKs at stake and the dispute fees for the specific round of the dispute, penalties only.\\n /// @param _params The parameters for the execution, see `ExecuteParams`.\\n /// @return pnkPenaltiesInRoundCache The updated penalties in round cache.\\n function _executePenalties(ExecuteParams memory _params) internal returns (uint256) {\\n Dispute storage dispute = disputes[_params.disputeID];\\n Round storage round = dispute.rounds[_params.round];\\n IDisputeKit disputeKit = disputeKits[round.disputeKitID];\\n\\n // [0, 1] value that determines how coherent the juror was in this round, in basis points.\\n uint256 degreeOfCoherence = disputeKit.getDegreeOfCoherence(\\n _params.disputeID,\\n _params.round,\\n _params.repartition,\\n _params.feePerJurorInRound,\\n _params.pnkAtStakePerJurorInRound\\n );\\n if (degreeOfCoherence > ALPHA_DIVISOR) {\\n // Make sure the degree doesn't exceed 1, though it should be ensured by the dispute kit.\\n degreeOfCoherence = ALPHA_DIVISOR;\\n }\\n\\n // Fully coherent jurors won't be penalized.\\n uint256 penalty = (round.pnkAtStakePerJuror * (ALPHA_DIVISOR - degreeOfCoherence)) / ALPHA_DIVISOR;\\n _params.pnkPenaltiesInRound += penalty;\\n\\n // Unlock the PNKs affected by the penalty\\n address account = round.drawnJurors[_params.repartition];\\n sortitionModule.unlockStake(account, penalty);\\n\\n // Apply the penalty to the staked PNKs.\\n sortitionModule.penalizeStake(account, penalty);\\n emit TokenAndETHShift(\\n account,\\n _params.disputeID,\\n _params.round,\\n degreeOfCoherence,\\n -int256(penalty),\\n 0,\\n round.feeToken\\n );\\n\\n if (!disputeKit.isVoteActive(_params.disputeID, _params.round, _params.repartition)) {\\n // The juror is inactive, unstake them.\\n sortitionModule.setJurorInactive(account);\\n }\\n if (_params.repartition == _params.numberOfVotesInRound - 1 && _params.coherentCount == 0) {\\n // No one was coherent, send the rewards to the governor.\\n if (round.feeToken == NATIVE_CURRENCY) {\\n // The dispute fees were paid in ETH\\n payable(governor).send(round.totalFeesForJurors);\\n } else {\\n // The dispute fees were paid in ERC20\\n round.feeToken.safeTransfer(governor, round.totalFeesForJurors);\\n }\\n pinakion.safeTransfer(governor, _params.pnkPenaltiesInRound);\\n emit LeftoverRewardSent(\\n _params.disputeID,\\n _params.round,\\n _params.pnkPenaltiesInRound,\\n round.totalFeesForJurors,\\n round.feeToken\\n );\\n }\\n return _params.pnkPenaltiesInRound;\\n }\\n\\n /// @dev Distribute the PNKs at stake and the dispute fees for the specific round of the dispute, rewards only.\\n /// @param _params The parameters for the execution, see `ExecuteParams`.\\n function _executeRewards(ExecuteParams memory _params) internal {\\n Dispute storage dispute = disputes[_params.disputeID];\\n Round storage round = dispute.rounds[_params.round];\\n IDisputeKit disputeKit = disputeKits[round.disputeKitID];\\n\\n // [0, 1] value that determines how coherent the juror was in this round, in basis points.\\n uint256 degreeOfCoherence = disputeKit.getDegreeOfCoherence(\\n _params.disputeID,\\n _params.round,\\n _params.repartition % _params.numberOfVotesInRound,\\n _params.feePerJurorInRound,\\n _params.pnkAtStakePerJurorInRound\\n );\\n\\n // Make sure the degree doesn't exceed 1, though it should be ensured by the dispute kit.\\n if (degreeOfCoherence > ALPHA_DIVISOR) {\\n degreeOfCoherence = ALPHA_DIVISOR;\\n }\\n\\n address account = round.drawnJurors[_params.repartition % _params.numberOfVotesInRound];\\n uint256 pnkLocked = (round.pnkAtStakePerJuror * degreeOfCoherence) / ALPHA_DIVISOR;\\n\\n // Release the rest of the PNKs of the juror for this round.\\n sortitionModule.unlockStake(account, pnkLocked);\\n\\n // Give back the locked PNKs in case the juror fully unstaked earlier.\\n if (!sortitionModule.isJurorStaked(account)) {\\n pinakion.safeTransfer(account, pnkLocked);\\n }\\n\\n // Transfer the rewards\\n uint256 pnkReward = ((_params.pnkPenaltiesInRound / _params.coherentCount) * degreeOfCoherence) / ALPHA_DIVISOR;\\n round.sumPnkRewardPaid += pnkReward;\\n uint256 feeReward = ((round.totalFeesForJurors / _params.coherentCount) * degreeOfCoherence) / ALPHA_DIVISOR;\\n round.sumFeeRewardPaid += feeReward;\\n pinakion.safeTransfer(account, pnkReward);\\n if (round.feeToken == NATIVE_CURRENCY) {\\n // The dispute fees were paid in ETH\\n payable(account).send(feeReward);\\n } else {\\n // The dispute fees were paid in ERC20\\n round.feeToken.safeTransfer(account, feeReward);\\n }\\n emit TokenAndETHShift(\\n account,\\n _params.disputeID,\\n _params.round,\\n degreeOfCoherence,\\n int256(pnkReward),\\n int256(feeReward),\\n round.feeToken\\n );\\n\\n // Transfer any residual rewards to the governor. It may happen due to partial coherence of the jurors.\\n if (_params.repartition == _params.numberOfVotesInRound * 2 - 1) {\\n uint256 leftoverPnkReward = _params.pnkPenaltiesInRound - round.sumPnkRewardPaid;\\n uint256 leftoverFeeReward = round.totalFeesForJurors - round.sumFeeRewardPaid;\\n if (leftoverPnkReward != 0 || leftoverFeeReward != 0) {\\n if (leftoverPnkReward != 0) {\\n pinakion.safeTransfer(governor, leftoverPnkReward);\\n }\\n if (leftoverFeeReward != 0) {\\n if (round.feeToken == NATIVE_CURRENCY) {\\n // The dispute fees were paid in ETH\\n payable(governor).send(leftoverFeeReward);\\n } else {\\n // The dispute fees were paid in ERC20\\n round.feeToken.safeTransfer(governor, leftoverFeeReward);\\n }\\n }\\n emit LeftoverRewardSent(\\n _params.disputeID,\\n _params.round,\\n leftoverPnkReward,\\n leftoverFeeReward,\\n round.feeToken\\n );\\n }\\n }\\n }\\n\\n /// @dev Executes a specified dispute's ruling.\\n /// @param _disputeID The ID of the dispute.\\n function executeRuling(uint256 _disputeID) external {\\n Dispute storage dispute = disputes[_disputeID];\\n if (dispute.period != Period.execution) revert NotExecutionPeriod();\\n if (dispute.ruled) revert RulingAlreadyExecuted();\\n\\n (uint256 winningChoice, , ) = currentRuling(_disputeID);\\n dispute.ruled = true;\\n emit Ruling(dispute.arbitrated, _disputeID, winningChoice);\\n dispute.arbitrated.rule(_disputeID, winningChoice);\\n }\\n\\n // ************************************* //\\n // * Public Views * //\\n // ************************************* //\\n\\n /// @dev Compute the cost of arbitration denominated in ETH.\\n /// It is recommended not to increase it often, as it can be highly time and gas consuming for the arbitrated contracts to cope with fee augmentation.\\n /// @param _extraData Additional info about the dispute. We use it to pass the ID of the dispute's court (first 32 bytes), the minimum number of jurors required (next 32 bytes) and the ID of the specific dispute kit (last 32 bytes).\\n /// @return cost The arbitration cost in ETH.\\n function arbitrationCost(bytes memory _extraData) public view override returns (uint256 cost) {\\n (uint96 courtID, uint256 minJurors, ) = _extraDataToCourtIDMinJurorsDisputeKit(_extraData);\\n cost = courts[courtID].feeForJuror * minJurors;\\n }\\n\\n /// @dev Compute the cost of arbitration denominated in `_feeToken`.\\n /// It is recommended not to increase it often, as it can be highly time and gas consuming for the arbitrated contracts to cope with fee augmentation.\\n /// @param _extraData Additional info about the dispute. We use it to pass the ID of the dispute's court (first 32 bytes), the minimum number of jurors required (next 32 bytes) and the ID of the specific dispute kit (last 32 bytes).\\n /// @param _feeToken The ERC20 token used to pay fees.\\n /// @return cost The arbitration cost in `_feeToken`.\\n function arbitrationCost(bytes calldata _extraData, IERC20 _feeToken) public view override returns (uint256 cost) {\\n cost = convertEthToTokenAmount(_feeToken, arbitrationCost(_extraData));\\n }\\n\\n /// @dev Gets the cost of appealing a specified dispute.\\n /// @param _disputeID The ID of the dispute.\\n /// @return cost The appeal cost.\\n function appealCost(uint256 _disputeID) public view returns (uint256 cost) {\\n Dispute storage dispute = disputes[_disputeID];\\n Round storage round = dispute.rounds[dispute.rounds.length - 1];\\n Court storage court = courts[dispute.courtID];\\n if (round.nbVotes >= court.jurorsForCourtJump) {\\n // Jump to parent court.\\n if (dispute.courtID == GENERAL_COURT) {\\n // TODO: Handle the forking when appealed in General court.\\n cost = NON_PAYABLE_AMOUNT; // Get the cost of the parent court.\\n } else {\\n cost = courts[court.parent].feeForJuror * ((round.nbVotes * 2) + 1);\\n }\\n } else {\\n // Stay in current court.\\n cost = court.feeForJuror * ((round.nbVotes * 2) + 1);\\n }\\n }\\n\\n /// @dev Gets the start and the end of a specified dispute's current appeal period.\\n /// @param _disputeID The ID of the dispute.\\n /// @return start The start of the appeal period.\\n /// @return end The end of the appeal period.\\n function appealPeriod(uint256 _disputeID) public view returns (uint256 start, uint256 end) {\\n Dispute storage dispute = disputes[_disputeID];\\n if (dispute.period == Period.appeal) {\\n start = dispute.lastPeriodChange;\\n end = dispute.lastPeriodChange + courts[dispute.courtID].timesPerPeriod[uint256(Period.appeal)];\\n } else {\\n start = 0;\\n end = 0;\\n }\\n }\\n\\n /// @dev Gets the current ruling of a specified dispute.\\n /// @param _disputeID The ID of the dispute.\\n /// @return ruling The current ruling.\\n /// @return tied Whether it's a tie or not.\\n /// @return overridden Whether the ruling was overridden by appeal funding or not.\\n function currentRuling(uint256 _disputeID) public view returns (uint256 ruling, bool tied, bool overridden) {\\n Dispute storage dispute = disputes[_disputeID];\\n Round storage round = dispute.rounds[dispute.rounds.length - 1];\\n IDisputeKit disputeKit = disputeKits[round.disputeKitID];\\n (ruling, tied, overridden) = disputeKit.currentRuling(_disputeID);\\n }\\n\\n function getRoundInfo(uint256 _disputeID, uint256 _round) external view returns (Round memory) {\\n return disputes[_disputeID].rounds[_round];\\n }\\n\\n function getNumberOfRounds(uint256 _disputeID) external view returns (uint256) {\\n return disputes[_disputeID].rounds.length;\\n }\\n\\n function isSupported(uint96 _courtID, uint256 _disputeKitID) external view returns (bool) {\\n return courts[_courtID].supportedDisputeKits[_disputeKitID];\\n }\\n\\n /// @dev Gets the timesPerPeriod array for a given court.\\n /// @param _courtID The ID of the court to get the times from.\\n /// @return timesPerPeriod The timesPerPeriod array for the given court.\\n function getTimesPerPeriod(uint96 _courtID) external view returns (uint256[4] memory timesPerPeriod) {\\n timesPerPeriod = courts[_courtID].timesPerPeriod;\\n }\\n\\n // ************************************* //\\n // * Public Views for Dispute Kits * //\\n // ************************************* //\\n\\n /// @dev Gets the number of votes permitted for the specified dispute in the latest round.\\n /// @param _disputeID The ID of the dispute.\\n function getNumberOfVotes(uint256 _disputeID) external view returns (uint256) {\\n Dispute storage dispute = disputes[_disputeID];\\n return dispute.rounds[dispute.rounds.length - 1].nbVotes;\\n }\\n\\n /// @dev Returns true if the dispute kit will be switched to a parent DK.\\n /// @param _disputeID The ID of the dispute.\\n /// @return Whether DK will be switched or not.\\n function isDisputeKitJumping(uint256 _disputeID) external view returns (bool) {\\n Dispute storage dispute = disputes[_disputeID];\\n Round storage round = dispute.rounds[dispute.rounds.length - 1];\\n Court storage court = courts[dispute.courtID];\\n\\n if (round.nbVotes < court.jurorsForCourtJump) {\\n return false;\\n }\\n\\n // Jump if the parent court doesn't support the current DK.\\n return !courts[court.parent].supportedDisputeKits[round.disputeKitID];\\n }\\n\\n function getDisputeKitsLength() external view returns (uint256) {\\n return disputeKits.length;\\n }\\n\\n function convertEthToTokenAmount(IERC20 _toToken, uint256 _amountInEth) public view returns (uint256) {\\n return (_amountInEth * 10 ** currencyRates[_toToken].rateDecimals) / currencyRates[_toToken].rateInEth;\\n }\\n\\n // ************************************* //\\n // * Internal * //\\n // ************************************* //\\n\\n /// @dev Toggles the dispute kit support for a given court.\\n /// @param _courtID The ID of the court to toggle the support for.\\n /// @param _disputeKitID The ID of the dispute kit to toggle the support for.\\n /// @param _enable Whether to enable or disable the support. Note that classic dispute kit should always be enabled.\\n function _enableDisputeKit(uint96 _courtID, uint256 _disputeKitID, bool _enable) internal {\\n courts[_courtID].supportedDisputeKits[_disputeKitID] = _enable;\\n emit DisputeKitEnabled(_courtID, _disputeKitID, _enable);\\n }\\n\\n /// @dev If called only once then set _onError to Revert, otherwise set it to Return\\n /// @param _account The account to set the stake for.\\n /// @param _courtID The ID of the court to set the stake for.\\n /// @param _newStake The new stake.\\n /// @param _alreadyTransferred Whether the PNKs were already transferred to/from the staking contract.\\n /// @param _onError Whether to revert or return false on error.\\n /// @return Whether the stake was successfully set or not.\\n function _setStake(\\n address _account,\\n uint96 _courtID,\\n uint256 _newStake,\\n bool _alreadyTransferred,\\n OnError _onError\\n ) internal returns (bool) {\\n if (_courtID == FORKING_COURT || _courtID > courts.length) {\\n _stakingFailed(_onError, StakingResult.CannotStakeInThisCourt); // Staking directly into the forking court is not allowed.\\n return false;\\n }\\n if (_newStake != 0 && _newStake < courts[_courtID].minStake) {\\n _stakingFailed(_onError, StakingResult.CannotStakeLessThanMinStake); // Staking less than the minimum stake is not allowed.\\n return false;\\n }\\n (uint256 pnkDeposit, uint256 pnkWithdrawal, StakingResult stakingResult) = sortitionModule.setStake(\\n _account,\\n _courtID,\\n _newStake,\\n _alreadyTransferred\\n );\\n if (stakingResult != StakingResult.Successful) {\\n _stakingFailed(_onError, stakingResult);\\n return false;\\n }\\n if (pnkDeposit > 0) {\\n if (!pinakion.safeTransferFrom(_account, address(this), pnkDeposit)) {\\n _stakingFailed(_onError, StakingResult.StakingTransferFailed);\\n return false;\\n }\\n }\\n if (pnkWithdrawal > 0) {\\n if (!pinakion.safeTransfer(_account, pnkWithdrawal)) {\\n _stakingFailed(_onError, StakingResult.UnstakingTransferFailed);\\n return false;\\n }\\n }\\n return true;\\n }\\n\\n /// @dev It may revert depending on the _onError parameter.\\n function _stakingFailed(OnError _onError, StakingResult _result) internal pure virtual {\\n if (_onError == OnError.Return) return;\\n if (_result == StakingResult.StakingTransferFailed) revert StakingTransferFailed();\\n if (_result == StakingResult.UnstakingTransferFailed) revert UnstakingTransferFailed();\\n if (_result == StakingResult.CannotStakeInMoreCourts) revert StakingInTooManyCourts();\\n if (_result == StakingResult.CannotStakeInThisCourt) revert StakingNotPossibeInThisCourt();\\n if (_result == StakingResult.CannotStakeLessThanMinStake) revert StakingLessThanCourtMinStake();\\n }\\n\\n /// @dev Gets a court ID, the minimum number of jurors and an ID of a dispute kit from a specified extra data bytes array.\\n /// Note that if extradata contains an incorrect value then this value will be switched to default.\\n /// @param _extraData The extra data bytes array. The first 32 bytes are the court ID, the next are the minimum number of jurors and the last are the dispute kit ID.\\n /// @return courtID The court ID.\\n /// @return minJurors The minimum number of jurors required.\\n /// @return disputeKitID The ID of the dispute kit.\\n function _extraDataToCourtIDMinJurorsDisputeKit(\\n bytes memory _extraData\\n ) internal view returns (uint96 courtID, uint256 minJurors, uint256 disputeKitID) {\\n // Note that if the extradata doesn't contain 32 bytes for the dispute kit ID it'll return the default 0 index.\\n if (_extraData.length >= 64) {\\n assembly {\\n // solium-disable-line security/no-inline-assembly\\n courtID := mload(add(_extraData, 0x20))\\n minJurors := mload(add(_extraData, 0x40))\\n disputeKitID := mload(add(_extraData, 0x60))\\n }\\n if (courtID == FORKING_COURT || courtID >= courts.length) {\\n courtID = GENERAL_COURT;\\n }\\n if (minJurors == 0) {\\n minJurors = DEFAULT_NB_OF_JURORS;\\n }\\n if (disputeKitID == NULL_DISPUTE_KIT || disputeKitID >= disputeKits.length) {\\n disputeKitID = DISPUTE_KIT_CLASSIC; // 0 index is not used.\\n }\\n } else {\\n courtID = GENERAL_COURT;\\n minJurors = DEFAULT_NB_OF_JURORS;\\n disputeKitID = DISPUTE_KIT_CLASSIC;\\n }\\n }\\n\\n // ************************************* //\\n // * Errors * //\\n // ************************************* //\\n\\n error GovernorOnly();\\n error InstructorOnly();\\n error GovernorOrInstructorOnly();\\n error DisputeKitOnly();\\n error SortitionModuleOnly();\\n error UnsuccessfulCall();\\n error InvalidDisputKitParent();\\n error DepthLevelMax();\\n error MinStakeLowerThanParentCourt();\\n error UnsupportedDisputeKit();\\n error InvalidForkingCourtAsParent();\\n error WrongDisputeKitIndex();\\n error CannotDisableClassicDK();\\n error ArraysLengthMismatch();\\n error StakingInTooManyCourts();\\n error StakingNotPossibeInThisCourt();\\n error StakingLessThanCourtMinStake();\\n error StakingTransferFailed();\\n error UnstakingTransferFailed();\\n error ArbitrationFeesNotEnough();\\n error DisputeKitNotSupportedByCourt();\\n error MustSupportDisputeKitClassic();\\n error TokenNotAccepted();\\n error EvidenceNotPassedAndNotAppeal();\\n error DisputeStillDrawing();\\n error CommitPeriodNotPassed();\\n error VotePeriodNotPassed();\\n error AppealPeriodNotPassed();\\n error NotEvidencePeriod();\\n error AppealFeesNotEnough();\\n error DisputeNotAppealable();\\n error NotExecutionPeriod();\\n error RulingAlreadyExecuted();\\n error DisputePeriodIsFinal();\\n error TransferFailed();\\n error AllJurorsDrawn();\\n error NoJurorDrawn();\\n}\\n\",\"keccak256\":\"0xd636c2294d15110a20dcf97d67f2989e14233cd1de353032807ad44a8e828e49\",\"license\":\"MIT\"},\"src/libraries/Constants.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n// Courts\\nuint96 constant FORKING_COURT = 0; // Index of the forking court.\\nuint96 constant GENERAL_COURT = 1; // Index of the default (general) court.\\n\\n// Dispute Kits\\nuint256 constant NULL_DISPUTE_KIT = 0; // Null pattern to indicate a top-level DK which has no parent.\\nuint256 constant DISPUTE_KIT_CLASSIC = 1; // Index of the default DK. 0 index is skipped.\\n\\n// Sortition Module\\nuint256 constant MAX_STAKE_PATHS = 4; // The maximum number of stake paths a juror can have.\\nuint256 constant DEFAULT_K = 6; // Default number of children per node.\\n\\n// Defaults\\nuint256 constant DEFAULT_NB_OF_JURORS = 3; // The default number of jurors in a dispute.\\nIERC20 constant NATIVE_CURRENCY = IERC20(address(0)); // The native currency, such as ETH on Arbitrum, Optimism and Ethereum L1.\\n\\nenum OnError {\\n Revert,\\n Return\\n}\\n\\nenum StakingResult {\\n Successful,\\n StakingTransferFailed,\\n UnstakingTransferFailed,\\n CannotStakeInMoreCourts,\\n CannotStakeInThisCourt,\\n CannotStakeLessThanMinStake,\\n CannotStakeMoreThanMaxStakePerJuror,\\n CannotStakeMoreThanMaxTotalStaked\\n}\\n\",\"keccak256\":\"0x486016fb74cc91439c2ec918e97a79190ab4eed223987d516986fff8eaeecfbf\",\"license\":\"MIT\"},\"src/libraries/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// Adapted from https://github.com/OpenZeppelin/openzeppelin-contracts/blob/a7a94c77463acea95d979aae1580fb0ddc3b6a1e/contracts/token/ERC20/utils/SafeERC20.sol\\n\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/// @title SafeERC20\\n/// @dev Wrappers around ERC20 operations that throw on failure (when the token\\n/// contract returns false). Tokens that return no value (and instead revert or\\n/// throw on failure) are also supported, non-reverting calls are assumed to be\\n/// successful.\\n/// To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n/// which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\nlibrary SafeERC20 {\\n /// @dev Increases the allowance granted to `spender` by the caller.\\n /// @param _token Token to transfer.\\n /// @param _spender The address which will spend the funds.\\n /// @param _addedValue The amount of tokens to increase the allowance by.\\n function increaseAllowance(IERC20 _token, address _spender, uint256 _addedValue) internal returns (bool) {\\n _token.approve(_spender, _token.allowance(address(this), _spender) + _addedValue);\\n return true;\\n }\\n\\n /// @dev Calls transfer() without reverting.\\n /// @param _token Token to transfer.\\n /// @param _to Recepient address.\\n /// @param _value Amount transferred.\\n /// @return Whether transfer succeeded or not.\\n function safeTransfer(IERC20 _token, address _to, uint256 _value) internal returns (bool) {\\n (bool success, bytes memory data) = address(_token).call(abi.encodeCall(IERC20.transfer, (_to, _value)));\\n return (success && (data.length == 0 || abi.decode(data, (bool))));\\n }\\n\\n /// @dev Calls transferFrom() without reverting.\\n /// @param _token Token to transfer.\\n /// @param _from Sender address.\\n /// @param _to Recepient address.\\n /// @param _value Amount transferred.\\n /// @return Whether transfer succeeded or not.\\n function safeTransferFrom(IERC20 _token, address _from, address _to, uint256 _value) internal returns (bool) {\\n (bool success, bytes memory data) = address(_token).call(\\n abi.encodeCall(IERC20.transferFrom, (_from, _to, _value))\\n );\\n return (success && (data.length == 0 || abi.decode(data, (bool))));\\n }\\n}\\n\",\"keccak256\":\"0x3e39adb9cdd9f86b0defc8f6e1223533d86f82c804e186193f729c32c10161b1\",\"license\":\"MIT\"},\"src/proxy/Initializable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol) \\n\\npragma solidity 0.8.24;\\n\\n/**\\n * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed\\n * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an\\n * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer\\n * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.\\n *\\n * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be\\n * reused. This mechanism prevents re-execution of each \\\"step\\\" but allows the creation of new initialization steps in\\n * case an upgrade adds a module that needs to be initialized.\\n *\\n * For example:\\n *\\n * ```solidity\\n * contract MyToken is ERC20Upgradeable {\\n * function initialize() initializer public {\\n * __ERC20_init(\\\"MyToken\\\", \\\"MTK\\\");\\n * }\\n * }\\n *\\n * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {\\n * function initializeV2() reinitializer(2) public {\\n * __ERC20Permit_init(\\\"MyToken\\\");\\n * }\\n * }\\n * ```\\n *\\n * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as\\n * possible by providing the encoded function call as the `_data` argument to the proxy constructor\\n *\\n * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure\\n * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.\\n *\\n * [CAUTION]\\n * ====\\n * Avoid leaving a contract uninitialized.\\n *\\n * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation\\n * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke\\n * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:\\n *\\n * ```\\n * /// @custom:oz-upgrades-unsafe-allow constructor\\n * constructor() {\\n * _disableInitializers();\\n * }\\n * ```\\n */\\nabstract contract Initializable {\\n /**\\n * @dev Storage of the initializable contract.\\n *\\n * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions\\n * when using with upgradeable contracts.\\n *\\n * @custom:storage-location erc7201:openzeppelin.storage.Initializable\\n */\\n struct InitializableStorage {\\n /**\\n * @dev Indicates that the contract has been initialized.\\n */\\n uint64 _initialized;\\n /**\\n * @dev Indicates that the contract is in the process of being initialized.\\n */\\n bool _initializing;\\n }\\n\\n // keccak256(abi.encode(uint256(keccak256(\\\"openzeppelin.storage.Initializable\\\")) - 1))\\n bytes32 private constant _INITIALIZABLE_STORAGE =\\n 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0e;\\n\\n /**\\n * @dev The contract is already initialized.\\n */\\n error AlreadyInitialized();\\n\\n /**\\n * @dev The contract is not initializing.\\n */\\n error NotInitializing();\\n\\n /**\\n * @dev Triggered when the contract has been initialized or reinitialized.\\n */\\n event Initialized(uint64 version);\\n\\n /**\\n * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,\\n * `onlyInitializing` functions can be used to initialize parent contracts.\\n *\\n * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a\\n * constructor.\\n *\\n * Emits an {Initialized} event.\\n */\\n modifier initializer() {\\n // solhint-disable-next-line var-name-mixedcase\\n InitializableStorage storage $ = _getInitializableStorage();\\n\\n bool isTopLevelCall = !$._initializing;\\n uint64 initialized = $._initialized;\\n if (!(isTopLevelCall && initialized < 1) && !(address(this).code.length == 0 && initialized == 1)) {\\n revert AlreadyInitialized();\\n }\\n $._initialized = 1;\\n if (isTopLevelCall) {\\n $._initializing = true;\\n }\\n _;\\n if (isTopLevelCall) {\\n $._initializing = false;\\n emit Initialized(1);\\n }\\n }\\n\\n /**\\n * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the\\n * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be\\n * used to initialize parent contracts.\\n *\\n * A reinitializer may be used after the original initialization step. This is essential to configure modules that\\n * are added through upgrades and that require initialization.\\n *\\n * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`\\n * cannot be nested. If one is invoked in the context of another, execution will revert.\\n *\\n * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in\\n * a contract, executing them in the right order is up to the developer or operator.\\n *\\n * WARNING: setting the version to 255 will prevent any future reinitialization.\\n *\\n * Emits an {Initialized} event.\\n */\\n modifier reinitializer(uint64 version) {\\n // solhint-disable-next-line var-name-mixedcase\\n InitializableStorage storage $ = _getInitializableStorage();\\n\\n if ($._initializing || $._initialized >= version) {\\n revert AlreadyInitialized();\\n }\\n $._initialized = version;\\n $._initializing = true;\\n _;\\n $._initializing = false;\\n emit Initialized(version);\\n }\\n\\n /**\\n * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the\\n * {initializer} and {reinitializer} modifiers, directly or indirectly.\\n */\\n modifier onlyInitializing() {\\n _checkInitializing();\\n _;\\n }\\n\\n /**\\n * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.\\n */\\n function _checkInitializing() internal view virtual {\\n if (!_isInitializing()) {\\n revert NotInitializing();\\n }\\n }\\n\\n /**\\n * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.\\n * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized\\n * to any version. It is recommended to use this to lock implementation contracts that are designed to be called\\n * through proxies.\\n *\\n * Emits an {Initialized} event the first time it is successfully executed.\\n */\\n function _disableInitializers() internal virtual {\\n // solhint-disable-next-line var-name-mixedcase\\n InitializableStorage storage $ = _getInitializableStorage();\\n\\n if ($._initializing) {\\n revert AlreadyInitialized();\\n }\\n if ($._initialized != type(uint64).max) {\\n $._initialized = type(uint64).max;\\n emit Initialized(type(uint64).max);\\n }\\n }\\n\\n /**\\n * @dev Returns the highest version that has been initialized. See {reinitializer}.\\n */\\n function _getInitializedVersion() internal view returns (uint64) {\\n return _getInitializableStorage()._initialized;\\n }\\n\\n /**\\n * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.\\n */\\n function _isInitializing() internal view returns (bool) {\\n return _getInitializableStorage()._initializing;\\n }\\n\\n /**\\n * @dev Returns a pointer to the storage namespace.\\n */\\n // solhint-disable-next-line var-name-mixedcase\\n function _getInitializableStorage() private pure returns (InitializableStorage storage $) {\\n assembly {\\n $.slot := _INITIALIZABLE_STORAGE\\n }\\n }\\n}\\n\",\"keccak256\":\"0x560ea64115636ecd6b3596248817125551c038ce1648019fde3cbe02d9759a30\",\"license\":\"MIT\"},\"src/proxy/UUPSProxiable.sol\":{\"content\":\"//SPDX-License-Identifier: MIT\\n// Adapted from \\n\\n/**\\n * @authors: [@malatrax]\\n * @reviewers: []\\n * @auditors: []\\n * @bounties: []\\n * @deployments: []\\n */\\npragma solidity 0.8.24;\\n\\n/**\\n * @title UUPS Proxiable\\n * @author Simon Malatrait \\n * @dev This contract implements an upgradeability mechanism designed for UUPS proxies.\\n * The functions included here can perform an upgrade of an UUPS Proxy, when this contract is set as the implementation behind such a proxy.\\n *\\n * IMPORTANT: A UUPS proxy requires its upgradeability functions to be in the implementation as opposed to the transparent proxy.\\n * This means that if the proxy is upgraded to an implementation that does not support this interface, it will no longer be upgradeable.\\n *\\n * A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is\\n * reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing\\n * `UUPSProxiable` with a custom implementation of upgrades.\\n *\\n * The `_authorizeUpgrade` function must be overridden to include access restriction to the upgrade mechanism.\\n */\\nabstract contract UUPSProxiable {\\n // ************************************* //\\n // * Event * //\\n // ************************************* //\\n\\n /**\\n * Emitted when the `implementation` has been successfully upgraded.\\n * @param newImplementation Address of the new implementation the proxy is now forwarding calls to.\\n */\\n event Upgraded(address indexed newImplementation);\\n\\n // ************************************* //\\n // * Error * //\\n // ************************************* //\\n\\n /**\\n * @dev The call is from an unauthorized context.\\n */\\n error UUPSUnauthorizedCallContext();\\n\\n /**\\n * @dev The storage `slot` is unsupported as a UUID.\\n */\\n error UUPSUnsupportedProxiableUUID(bytes32 slot);\\n\\n /// The `implementation` is not UUPS-compliant\\n error InvalidImplementation(address implementation);\\n\\n /// Failed Delegated call\\n error FailedDelegateCall();\\n\\n // ************************************* //\\n // * Storage * //\\n // ************************************* //\\n\\n /**\\n * @dev Storage slot with the address of the current implementation.\\n * This is the keccak-256 hash of \\\"eip1967.proxy.implementation\\\" subtracted by 1, and is\\n * validated in the constructor.\\n * NOTE: bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1)\\n */\\n bytes32 private constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\\n\\n /**\\n * @dev Storage variable of the proxiable contract address.\\n * It is used to check whether or not the current call is from the proxy.\\n */\\n address private immutable __self = address(this);\\n\\n // ************************************* //\\n // * Governance * //\\n // ************************************* //\\n\\n /**\\n * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract.\\n * @dev Called by {upgradeToAndCall}.\\n */\\n function _authorizeUpgrade(address newImplementation) internal virtual;\\n\\n // ************************************* //\\n // * State Modifiers * //\\n // ************************************* //\\n\\n /**\\n * @dev Upgrade mechanism including access control and UUPS-compliance.\\n * @param newImplementation Address of the new implementation contract.\\n * @param data Data used in a delegate call to `newImplementation` if non-empty. This will typically be an encoded\\n * function call, and allows initializing the storage of the proxy like a Solidity constructor.\\n *\\n * @dev Reverts if the execution is not performed via delegatecall or the execution\\n * context is not of a proxy with an ERC1967-compliant implementation pointing to self.\\n */\\n function upgradeToAndCall(address newImplementation, bytes memory data) public payable virtual {\\n _authorizeUpgrade(newImplementation);\\n\\n /* Check that the execution is being performed through a delegatecall call and that the execution context is\\n a proxy contract with an implementation (as defined in ERC1967) pointing to self. */\\n if (address(this) == __self || _getImplementation() != __self) {\\n revert UUPSUnauthorizedCallContext();\\n }\\n\\n try UUPSProxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {\\n if (slot != IMPLEMENTATION_SLOT) {\\n revert UUPSUnsupportedProxiableUUID(slot);\\n }\\n // Store the new implementation address to the implementation storage slot.\\n assembly {\\n sstore(IMPLEMENTATION_SLOT, newImplementation)\\n }\\n emit Upgraded(newImplementation);\\n\\n if (data.length != 0) {\\n // The return data is not checked (checking, in case of success, that the newImplementation code is non-empty if the return data is empty) because the authorized callee is trusted.\\n (bool success, ) = newImplementation.delegatecall(data);\\n if (!success) {\\n revert FailedDelegateCall();\\n }\\n }\\n } catch {\\n revert InvalidImplementation(newImplementation);\\n }\\n }\\n\\n // ************************************* //\\n // * Public Views * //\\n // ************************************* //\\n\\n /**\\n * @dev Implementation of the ERC1822 `proxiableUUID` function. This returns the storage slot used by the\\n * implementation. It is used to validate the implementation's compatibility when performing an upgrade.\\n *\\n * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks\\n * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this\\n * function revert if invoked through a proxy. This is guaranteed by the if statement.\\n */\\n function proxiableUUID() external view virtual returns (bytes32) {\\n if (address(this) != __self) {\\n // Must not be called through delegatecall\\n revert UUPSUnauthorizedCallContext();\\n }\\n return IMPLEMENTATION_SLOT;\\n }\\n\\n // ************************************* //\\n // * Internal Views * //\\n // ************************************* //\\n\\n function _getImplementation() internal view returns (address implementation) {\\n assembly {\\n implementation := sload(IMPLEMENTATION_SLOT)\\n }\\n }\\n}\\n\",\"keccak256\":\"0x5956855046cdda7aa45f44e379ef45323af7266c44c817d1266d8b32d52b0e22\",\"license\":\"MIT\"}},\"version\":1}",
- "bytecode": "0x60a0604052306080523480156200001557600080fd5b506200002062000026565b620000d9565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0e805468010000000000000000900460ff1615620000765760405162dc149f60e41b815260040160405180910390fd5b80546001600160401b0390811614620000d65780546001600160401b0319166001600160401b0390811782556040519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50565b60805161566962000103600039600081816115e10152818161160a015261180101526156696000f3fe60806040526004361061027c5760003560e01c80638a9bb02a1161014f578063d07368bd116100c1578063f6506db41161007a578063f6506db414610867578063f7434ea914610887578063fbb519e7146108a7578063fbf405b0146108c7578063fc6f8f16146108e7578063fe524c391461090757600080fd5b8063d07368bd146107b2578063d4d1d76a146107d2578063d874514b146107e7578063d98493f614610807578063e399d29b14610827578063e4c0aaf41461084757600080fd5b8063b702a87911610113578063b702a8791461070c578063c13517e11461072c578063c258bb191461073f578063c35699021461075f578063c71f425314610772578063cf0c38f81461079257600080fd5b80638a9bb02a1461064a5780638bb0487514610677578063acdbf51d14610697578063afe15cfb146106b7578063b0049637146106ec57600080fd5b80632e1daf2f116101f357806371ae413d116101ac57806371ae413d1461058a578063751accd0146105aa5780637717a6e8146105ca5780637934c0be146105ea57806382d022371461060a57806386541b241461062a57600080fd5b80632e1daf2f146104c45780633cfd1184146104e45780634f1ef2861461051157806352d1902d14610524578063564a565d1461053957806359ec827e1461056a57600080fd5b8063115d537611610245578063115d5376146103885780631860592b146103a857806319b81529146103d65780631c3db16d146104065780631f5a0dd2146104435780632d29a47b146104a457600080fd5b8062f5822c146102815780630219da79146102a357806309cfdc9c1461031b5780630b7414bc1461033b5780630c340a241461035b575b600080fd5b34801561028d57600080fd5b506102a161029c366004614846565b610927565b005b3480156102af57600080fd5b506102ee6102be366004614846565b60086020526000908152604090205460ff808216916001600160401b0361010082041691600160481b9091041683565b6040805193151584526001600160401b03909216602084015260ff16908201526060015b60405180910390f35b34801561032757600080fd5b506102a1610336366004614846565b610974565b34801561034757600080fd5b506102a161035636600461494e565b6109da565b34801561036757600080fd5b5060005461037b906001600160a01b031681565b60405161031291906149af565b34801561039457600080fd5b506102a16103a33660046149c3565b610b11565b3480156103b457600080fd5b506103c86103c33660046149dc565b611048565b604051908152602001610312565b3480156103e257600080fd5b506103f66103f13660046149c3565b6110a2565b6040519015158152602001610312565b34801561041257600080fd5b506104266104213660046149c3565b61119b565b604080519384529115156020840152151590820152606001610312565b34801561044f57600080fd5b5061046361045e3660046149c3565b61129c565b604080516001600160601b0390981688529515156020880152948601939093526060850191909152608084015260a0830152151560c082015260e001610312565b3480156104b057600080fd5b506102a16104bf366004614a08565b6112fb565b3480156104d057600080fd5b5060045461037b906001600160a01b031681565b3480156104f057600080fd5b506105046104ff366004614a34565b611563565b6040516103129190614a72565b6102a161051f366004614aef565b6115cd565b34801561053057600080fd5b506103c86117f4565b34801561054557600080fd5b506105596105543660046149c3565b611852565b604051610312959493929190614b76565b34801561057657600080fd5b506103c86105853660046149c3565b6118ae565b34801561059657600080fd5b5060015461037b906001600160a01b031681565b3480156105b657600080fd5b506102a16105c5366004614bb5565b611a03565b3480156105d657600080fd5b506102a16105e5366004614c0d565b611aad565b3480156105f657600080fd5b506102a1610605366004614c29565b611abb565b34801561061657600080fd5b506102a1610625366004614c62565b611b3a565b34801561063657600080fd5b506102a1610645366004614d21565b611bf7565b34801561065657600080fd5b5061066a610665366004614d8f565b611dd4565b6040516103129190614df6565b34801561068357600080fd5b506102a16106923660046149c3565b611f60565b3480156106a357600080fd5b5061037b6106b23660046149c3565b6120c4565b3480156106c357600080fd5b506106d76106d23660046149c3565b6120ee565b60408051928352602083019190915201610312565b3480156106f857600080fd5b506102a1610707366004614846565b61219a565b34801561071857600080fd5b506102a1610727366004614e9b565b6121e7565b6103c861073a366004614ec0565b6125fa565b34801561074b57600080fd5b506102a161075a366004614846565b612632565b6102a161076d366004614ef0565b61267f565b34801561077e57600080fd5b506103c861078d3660046149c3565b612b53565b34801561079e57600080fd5b5060035461037b906001600160a01b031681565b3480156107be57600080fd5b506102a16107cd366004614846565b612bbb565b3480156107de57600080fd5b506006546103c8565b3480156107f357600080fd5b506102a1610802366004614f29565b612c64565b34801561081357600080fd5b506103c861082236600461500a565b612f62565b34801561083357600080fd5b506102a1610842366004615055565b612faf565b34801561085357600080fd5b506102a1610862366004614846565b61329f565b34801561087357600080fd5b506103c8610882366004615110565b6132ec565b34801561089357600080fd5b506103c86108a2366004615176565b6133d2565b3480156108b357600080fd5b506102a16108c23660046151aa565b61341e565b3480156108d357600080fd5b5060025461037b906001600160a01b031681565b3480156108f357600080fd5b506103c86109023660046149c3565b61345e565b34801561091357600080fd5b506103f6610922366004614c0d565b61348d565b6000546001600160a01b031633146109525760405163c383977560e01b815260040160405180910390fd5b600280546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b0316331480159061099a57506001546001600160a01b03163314155b156109b857604051633244d29960e21b815260040160405180910390fd5b600180546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b03163314610a055760405163c383977560e01b815260040160405180910390fd5b60005b8251811015610b0b578115610aa457828181518110610a2957610a296151fb565b602002602001015160001480610a5c57506006548351849083908110610a5157610a516151fb565b602002602001015110155b15610a7a57604051633d58a98960e11b815260040160405180910390fd5b610a9f84848381518110610a9057610a906151fb565b602002602001015160016134d5565b610b03565b6001838281518110610ab857610ab86151fb565b602002602001015103610ade576040516356d111fd60e11b815260040160405180910390fd5b610b0384848381518110610af457610af46151fb565b602002602001015160006134d5565b600101610a08565b50505050565b600060078281548110610b2657610b266151fb565b600091825260208220600490910201805460058054929450916001600160601b03909116908110610b5957610b596151fb565b6000918252602082206003850154600c909202019250610b7b90600190615227565b90506000836003018281548110610b9457610b946151fb565b600091825260208220600b909102019150600185015460ff166004811115610bbe57610bbe614b3e565b03610c995781158015610c0d57506001840154600684019060ff166004811115610bea57610bea614b3e565b60048110610bfa57610bfa6151fb565b01546002850154610c0b9042615227565b105b15610c2b57604051633e9727df60e01b815260040160405180910390fd5b6003810154600682015414610c53576040516309e4486b60e41b815260040160405180910390fd5b8254600160601b900460ff16610c6a576002610c6d565b60015b60018086018054909160ff1990911690836004811115610c8f57610c8f614b3e565b0217905550610ffa565b60018085015460ff166004811115610cb357610cb3614b3e565b03610dc3576001840154600684019060ff166004811115610cd657610cd6614b3e565b60048110610ce657610ce66151fb565b01546002850154610cf79042615227565b108015610d8e57506006816000015481548110610d1657610d166151fb565b600091825260209091200154604051630baa64d160e01b8152600481018790526001600160a01b0390911690630baa64d190602401602060405180830381865afa158015610d68573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d8c919061523a565b155b15610dac57604051634dfa578560e11b815260040160405180910390fd5b6001808501805460029260ff199091169083610c8f565b6002600185015460ff166004811115610dde57610dde614b3e565b03610f2c576001840154600684019060ff166004811115610e0157610e01614b3e565b60048110610e1157610e116151fb565b01546002850154610e229042615227565b108015610eb957506006816000015481548110610e4157610e416151fb565b6000918252602090912001546040516336a66c7560e11b8152600481018790526001600160a01b0390911690636d4cd8ea90602401602060405180830381865afa158015610e93573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610eb7919061523a565b155b15610ed757604051631988dead60e31b815260040160405180910390fd5b600184018054600360ff199091161790558354604051600160601b9091046001600160a01b03169086907fa5d41b970d849372be1da1481ffd78d162bfe57a7aa2fe4e5fb73481fa5ac24f90600090a3610ffa565b6003600185015460ff166004811115610f4757610f47614b3e565b03610fc1576001840154600684019060ff166004811115610f6a57610f6a614b3e565b60048110610f7a57610f7a6151fb565b01546002850154610f8b9042615227565b1015610faa57604051632f4dfd8760e01b815260040160405180910390fd5b6001808501805460049260ff199091169083610c8f565b6004600185015460ff166004811115610fdc57610fdc614b3e565b03610ffa576040516307f38c8f60e11b815260040160405180910390fd5b426002850155600184015460405186917f4e6f5cf43b95303e86aee81683df63992061723a829ee012db21dad388756b91916110399160ff1690615257565b60405180910390a25050505050565b6001600160a01b03821660009081526008602052604081205461010081046001600160401b03169061108590600160481b900460ff16600a615349565b61108f9084615358565b6110999190615385565b90505b92915050565b600080600783815481106110b8576110b86151fb565b60009182526020822060036004909202019081018054919350906110de90600190615227565b815481106110ee576110ee6151fb565b600091825260208220845460058054600b909402909201945090916001600160601b03909116908110611123576111236151fb565b90600052602060002090600c0201905080600501548260030154101561114e57506000949350505050565b80546005805490916001600160601b031690811061116e5761116e6151fb565b6000918252602080832094548352600a600c9092029094010190925250604090205460ff16159392505050565b600080600080600785815481106111b4576111b46151fb565b60009182526020822060036004909202019081018054919350906111da90600190615227565b815481106111ea576111ea6151fb565b90600052602060002090600b0201905060006006826000015481548110611213576112136151fb565b600091825260209091200154604051631c3db16d60e01b8152600481018990526001600160a01b0390911691508190631c3db16d90602401606060405180830381865afa158015611268573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061128c9190615399565b9199909850909650945050505050565b600581815481106112ac57600080fd5b60009182526020909120600c9091020180546002820154600383015460048401546005850154600b909501546001600160601b038516965060ff600160601b9095048516959394929391921687565b60008060078581548110611311576113116151fb565b600091825260209091206004918202019150600182015460ff16600481111561133c5761133c614b3e565b1461135a57604051638794ce4b60e01b815260040160405180910390fd5b80600301848154811061136f5761136f6151fb565b6000918252602082206004600b9092020190810154909350915061139384836153d1565b60058401546006850154600286015492935090916000906113b5908390615385565b905060008660010154905060008060068960000154815481106113da576113da6151fb565b60009182526020909120015460405163368efae360e21b8152600481018e9052602481018d90526001600160a01b039091169150819063da3beb8c90604401602060405180830381865afa158015611436573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061145a91906153e4565b915050806000036114765783861115611471578395505b611496565b611481846002615358565b86111561149657611493846002615358565b95505b60048801869055865b8681101561154257848110156114f8576114f16040518061010001604052808e81526020018d81526020018481526020018781526020018681526020018581526020018881526020018381525061355d565b955061153a565b61153a6040518061010001604052808e81526020018d815260200184815260200187815260200186815260200185815260200188815260200183815250613a2e565b60010161149f565b508488600501541461155657600588018590555b5050505050505050505050565b61156b614786565b6005826001600160601b031681548110611587576115876151fb565b6000918252602090912060408051608081019182905292600c029091016006019060049082845b8154815260200190600101908083116115ae5750505050509050919050565b6115d682613f70565b306001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016148061165457507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166116486000805160206156148339815191525490565b6001600160a01b031614155b156116725760405163703e46dd60e11b815260040160405180910390fd5b816001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa9250505080156116cc575060408051601f3d908101601f191682019092526116c9918101906153e4565b60015b6116f45781604051630c76093760e01b81526004016116eb91906149af565b60405180910390fd5b600080516020615614833981519152811461172557604051632a87526960e21b8152600481018290526024016116eb565b6000805160206156148339815191528390556040516001600160a01b038416907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a28151156117ee576000836001600160a01b03168360405161178c9190615421565b600060405180830381855af49150503d80600081146117c7576040519150601f19603f3d011682016040523d82523d6000602084013e6117cc565b606091505b5050905080610b0b576040516339b21b5d60e11b815260040160405180910390fd5b505b5050565b6000306001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461183f5760405163703e46dd60e11b815260040160405180910390fd5b5060008051602061561483398151915290565b6007818154811061186257600080fd5b60009182526020909120600490910201805460018201546002909201546001600160601b0382169350600160601b9091046001600160a01b03169160ff80821692610100909204169085565b600080600783815481106118c4576118c46151fb565b60009182526020822060036004909202019081018054919350906118ea90600190615227565b815481106118fa576118fa6151fb565b600091825260208220845460058054600b909402909201945090916001600160601b0390911690811061192f5761192f6151fb565b90600052602060002090600c0201905080600501548260030154106119ce5782546001600160601b031660001901611970576001600160ff1b0393506119fb565b6003820154611980906002615358565b61198b9060016153d1565b81546005805490916001600160601b03169081106119ab576119ab6151fb565b90600052602060002090600c0201600401546119c79190615358565b93506119fb565b60038201546119de906002615358565b6119e99060016153d1565b81600401546119f89190615358565b93505b505050919050565b6000546001600160a01b03163314611a2e5760405163c383977560e01b815260040160405180910390fd5b6000836001600160a01b03168383604051611a499190615421565b60006040518083038185875af1925050503d8060008114611a86576040519150601f19603f3d011682016040523d82523d6000602084013e611a8b565b606091505b5050905080610b0b576040516322092f2f60e11b815260040160405180910390fd5b6117ee338383600080613f9e565b6000546001600160a01b03163314611ae65760405163c383977560e01b815260040160405180910390fd5b6001600160a01b038216600081815260086020526040808220805460ff191685151590811790915590519092917f541615e167511d757a7067a700eb54431b256bb458dfdce0ac58bf2ed0aefd4491a35050565b6000546001600160a01b03163314611b655760405163c383977560e01b815260040160405180910390fd5b6001600160a01b038316600081815260086020908152604091829020805469ffffffffffffffffff0019166101006001600160401b03881690810260ff60481b191691909117600160481b60ff8816908102919091179092558351908152918201527fe6996b7f03e9bd02228b99d3d946932e3197f505f60542c4cfbc919441d8a4e6910160405180910390a2505050565b6000546001600160a01b03163314611c225760405163c383977560e01b815260040160405180910390fd5b60006005886001600160601b031681548110611c4057611c406151fb565b90600052602060002090600c0201905060016001600160601b0316886001600160601b031614158015611ca2575080546005805488926001600160601b0316908110611c8e57611c8e6151fb565b90600052602060002090600c020160020154115b15611cc057604051639717078960e01b815260040160405180910390fd5b60005b6001820154811015611d3b57866005836001018381548110611ce757611ce76151fb565b906000526020600020015481548110611d0257611d026151fb565b90600052602060002090600c0201600201541015611d3357604051639717078960e01b815260040160405180910390fd5b600101611cc3565b5060028101869055805460ff60601b1916600160601b8815150217815560038101859055600480820185905560058201849055611d7e90600683019084906147a4565b50876001600160601b03167f709b1f5fda58af9a4f52dacd1ec404840a8148455700cce155a2bd8cf127ef1a888888888888604051611dc29695949392919061543d565b60405180910390a25050505050505050565b611e3a60405180610160016040528060008152602001600081526020016000815260200160008152602001600081526020016000815260200160608152602001600081526020016000815260200160006001600160a01b03168152602001600081525090565b60078381548110611e4d57611e4d6151fb565b90600052602060002090600402016003018281548110611e6f57611e6f6151fb565b90600052602060002090600b02016040518061016001604052908160008201548152602001600182015481526020016002820154815260200160038201548152602001600482015481526020016005820154815260200160068201805480602002602001604051908101604052809291908181526020018280548015611f1e57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611f00575b5050509183525050600782015460208201526008820154604082015260098201546001600160a01b03166060820152600a909101546080909101529392505050565b600060078281548110611f7557611f756151fb565b600091825260209091206004918202019150600182015460ff166004811115611fa057611fa0614b3e565b14611fbe57604051638794ce4b60e01b815260040160405180910390fd5b6001810154610100900460ff1615611fe95760405163c977f8d360e01b815260040160405180910390fd5b6000611ff48361119b565b505060018301805461010061ff001990911617905582546040518281529192508491600160601b9091046001600160a01b0316907f394027a5fa6e098a1191094d1719d6929b9abc535fcc0c8f448d6a4e756222769060200160405180910390a3815460405163188d362b60e11b81526004810185905260248101839052600160601b9091046001600160a01b03169063311a6c5690604401600060405180830381600087803b1580156120a757600080fd5b505af11580156120bb573d6000803e3d6000fd5b50505050505050565b600681815481106120d457600080fd5b6000918252602090912001546001600160a01b0316905081565b600080600060078481548110612106576121066151fb565b6000918252602090912060049091020190506003600182015460ff16600481111561213357612133614b3e565b0361218b576002810154815460058054929550916001600160601b03909116908110612161576121616151fb565b600091825260209091206009600c909202010154600282015461218491906153d1565b9150612194565b60009250600091505b50915091565b6000546001600160a01b031633146121c55760405163c383977560e01b815260040160405180910390fd5b600480546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b0316331480159061220d57506001546001600160a01b03163314155b1561222b57604051633244d29960e21b815260040160405180910390fd5b600060078381548110612240576122406151fb565b906000526020600020906004020190506000600182600301805490506122669190615227565b9050600082600301828154811061227f5761227f6151fb565b600091825260208220600b909102019150600184015460ff1660048111156122a9576122a9614b3e565b146122c757604051638285c4ef60e01b815260040160405180910390fd5b60038101546006820154106122ef57604051634df06de360e01b815260040160405180910390fd5b60048054604051633c694c4160e21b81526001600160a01b039091169163f1a531049161231e918891016149af565b600060405180830381600087803b15801561233857600080fd5b505af115801561234c573d6000803e3d6000fd5b5050505060006006826000015481548110612369576123696151fb565b6000918252602082200154600a8401546001600160a01b0390911692506123919060016153d1565b60405163695c01ad60e11b815260048101899052602481018290529091506000906001600160a01b0384169063d2b8035a906044016020604051808303816000875af11580156123e5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124099190615470565b90506001600160a01b03811661243257604051632e38b8f760e11b815260040160405180910390fd5b6004805460018601546040516310f0b12f60e11b81526001600160a01b03909216926321e1625e9261246892869290910161548d565b600060405180830381600087803b15801561248257600080fd5b505af1158015612496573d6000803e3d6000fd5b50505060068501546040518a92506001600160a01b038416917f6119cf536152c11e0a9a6c22f3953ce4ecc93ee54fa72ffa326ffabded21509b916124e3918a8252602082015260400190565b60405180910390a36006840180546001810182556000828152602090200180546001600160a01b0319166001600160a01b038416179055600385015490540361258a5760048054604051632e96bc2360e11b81529182018a9052602482018790526001600160a01b031690635d2d784690604401600060405180830381600087803b15801561257157600080fd5b505af1158015612585573d6000803e3d6000fd5b505050505b50600a8301555060048054604051633c694c4160e21b81526001600160a01b039091169163f1a53104916125c191600091016149af565b600060405180830381600087803b1580156125db57600080fd5b505af11580156125ef573d6000803e3d6000fd5b505050505050505050565b6000612605826133d2565b34101561262557604051630e3360f160e21b815260040160405180910390fd5b6110998383600034614158565b6000546001600160a01b0316331461265d5760405163c383977560e01b815260040160405180910390fd5b600380546001600160a01b0319166001600160a01b0392909216919091179055565b612688836118ae565b3410156126a857604051633191f8f160e01b815260040160405180910390fd5b6000600784815481106126bd576126bd6151fb565b6000918252602090912060049091020190506003600182015460ff1660048111156126ea576126ea614b3e565b14612708576040516337cdefcb60e21b815260040160405180910390fd5b6003810180546000919061271e90600190615227565b8154811061272e5761272e6151fb565b90600052602060002090600b020190506006816000015481548110612755576127556151fb565b6000918252602090912001546001600160a01b031633146127895760405163065f245f60e01b815260040160405180910390fd5b8154815460038401805460018101825560009182526020909120600580546001600160601b0390951694600b90930290910191849081106127cc576127cc6151fb565b90600052602060002090600c0201600501548460030154106128d5576005836001600160601b031681548110612804576128046151fb565b60009182526020909120600c9091020154600580546001600160601b0390921694509084908110612837576128376151fb565b60009182526020808320858452600a600c90930201919091019052604090205460ff1661286357600191505b84546001600160601b038481169116146128d557845460038601546001600160601b039091169061289690600190615227565b6040516001600160601b03861681528a907f736e3f52761298c8c0823e1ebf482ed3c5ecb304f743d2d91a7c006e8e8d7a1f9060200160405180910390a45b84546001600160601b0319166001600160601b038416908117865560018601805460ff1916905542600287015560058054600092908110612918576129186151fb565b90600052602060002090600c020190508060040154346129389190615385565b8260030181905550612710816003015482600201546129579190615358565b6129619190615385565b60018084019190915534600284015583835560045460038801546001600160a01b039091169163d09f392d918c9161299891615227565b6040516001600160e01b031960e085901b16815260048101929092526024820152604401600060405180830381600087803b1580156129d657600080fd5b505af11580156129ea573d6000803e3d6000fd5b505086548454149150612ad090505784546003870154612a0c90600190615227565b83546040519081528b907fcbe7939a71f0b369c7471d760a0a99b60b7bb010ee0406cba8a46679d1ea77569060200160405180910390a46006826000015481548110612a5a57612a5a6151fb565b60009182526020909120015460038301546040516302dbb79560e61b81526001600160a01b039092169163b6ede54091612a9d918d918d918d91906004016154a6565b600060405180830381600087803b158015612ab757600080fd5b505af1158015612acb573d6000803e3d6000fd5b505050505b8554604051600160601b9091046001600160a01b0316908a907f9c9b64db9e130f48381bf697abf638e73117dbfbfd7a4484f2da3ba188f4187d90600090a3887f4e6f5cf43b95303e86aee81683df63992061723a829ee012db21dad388756b916000604051612b409190615257565b60405180910390a2505050505050505050565b60008060078381548110612b6957612b696151fb565b906000526020600020906004020190508060030160018260030180549050612b919190615227565b81548110612ba157612ba16151fb565b90600052602060002090600b020160030154915050919050565b6000546001600160a01b03163314612be65760405163c383977560e01b815260040160405180910390fd5b6006805460018101825560009182527ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f810180546001600160a01b0319166001600160a01b0385169081179091556040519192909183917f44063d258760b98116d53815adbc906a56b3563e540148cc0fc2457f83b5eeb291a35050565b6000546001600160a01b03163314612c8f5760405163c383977560e01b815260040160405180910390fd5b856005896001600160601b031681548110612cac57612cac6151fb565b90600052602060002090600c0201600201541115612cdd57604051639717078960e01b815260040160405180910390fd5b8051600003612cff5760405163402585f560e01b815260040160405180910390fd5b6001600160601b038816612d2657604051631ef4f64960e01b815260040160405180910390fd5b60058054600181018255600091825290600c82027f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db001905b8351811015612e1557838181518110612d7957612d796151fb565b602002602001015160001480612dac57506006548451859083908110612da157612da16151fb565b602002602001015110155b15612dca57604051633d58a98960e11b815260040160405180910390fd5b600182600a016000868481518110612de457612de46151fb565b6020908102919091018101518252810191909152604001600020805460ff1916911515919091179055600101612d5e565b5060016000908152600a8201602052604090205460ff16612e49576040516306351b3d60e31b815260040160405180910390fd5b80546001600160601b0319166001600160601b038b161781556040805160008152602081019182905251612e819160018401916147e2565b50805460ff60601b1916600160601b8a1515021781556002810188905560038101879055600480820187905560058201869055612ec490600683019086906147a4565b5060058a6001600160601b031681548110612ee157612ee16151fb565b600091825260208083206001600c909302018201805492830181558352909120018290556040516001600160601b038b169083907f3475f0ed7216dd7d453db663a1c3024e4f36cc925521d54edb9d13e022cbee3d90612f4e908d908d908d908d908d908d908d906154ef565b60405180910390a350505050505050505050565b6000612fa7826103c386868080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506133d292505050565b949350505050565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0e805460019190600160401b900460ff1680612ff8575080546001600160401b03808416911610155b156130155760405162dc149f60e41b815260040160405180910390fd5b805468ffffffffffffffffff19166001600160401b03831617600160401b178155600080546001600160a01b03808e166001600160a01b0319928316178355600180548e8316908416178155600280548e8416908516178155600380548e8516908616179055600480548985169086161790556006805481875291820190557ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d40018054928c1692909316821790925560405190927f44063d258760b98116d53815adbc906a56b3563e540148cc0fc2457f83b5eeb291a360058054600082815260028201909255600c6001909101027f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db0810180546001600160601b031916815560408051938452602084019081905292519092613174927f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db101916147e2565b50805460ff60601b1916600160601b8815150217815585516002820155602086015160038201556040860151600480830191909155606087015160058301556131c390600683019087906147a4565b50805486516020808901516040808b015160608c0151825160008082529581019093526001600160601b03909616956001957f3475f0ed7216dd7d453db663a1c3024e4f36cc925521d54edb9d13e022cbee3d958f959194919392918e915060405161323597969594939291906154ef565b60405180910390a361324a60018060016134d5565b50805460ff60401b191681556040516001600160401b03831681527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15050505050505050505050565b6000546001600160a01b031633146132ca5760405163c383977560e01b815260040160405180910390fd5b600080546001600160a01b0319166001600160a01b0392909216919091179055565b6001600160a01b03821660009081526008602052604081205460ff166133255760405163e51cf7bf60e01b815260040160405180910390fd5b613330858585612f62565b82101561335057604051630e3360f160e21b815260040160405180910390fd5b6133656001600160a01b03841633308561443f565b613382576040516312171d8360e31b815260040160405180910390fd5b6133c68686868080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508892508791506141589050565b90505b95945050505050565b60008060006133e08461451b565b5091509150806005836001600160601b031681548110613402576134026151fb565b90600052602060002090600c020160040154612fa79190615358565b6004546001600160a01b0316331461344957604051639d6cab9960e01b815260040160405180910390fd5b613457848484846001613f9e565b5050505050565b600060078281548110613473576134736151fb565b600091825260209091206003600490920201015492915050565b60006005836001600160601b0316815481106134ab576134ab6151fb565b60009182526020808320948352600c91909102909301600a0190925250604090205460ff16919050565b806005846001600160601b0316815481106134f2576134f26151fb565b60009182526020808320868452600c92909202909101600a0190526040808220805460ff19169315159390931790925590518215159184916001600160601b038716917fb47629acdf64971062d40984f77d3dee212d735b11e3e8c7a4222d9f0572cc7991a4505050565b6000806007836000015181548110613577576135776151fb565b906000526020600020906004020190506000816003018460200151815481106135a2576135a26151fb565b90600052602060002090600b02019050600060068260000154815481106135cb576135cb6151fb565b60009182526020808320919091015487519188015160e089015160808a015160a08b01516040516333ac937b60e11b8152600481019690965260248601939093526044850191909152606484015260848301526001600160a01b03169250829063675926f69060a401602060405180830381865afa158015613651573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061367591906153e4565b905061271081111561368657506127105b60006127106136958382615227565b85600101546136a49190615358565b6136ae9190615385565b9050808760c0018181516136c291906153d1565b90525060e08701516006850180546000929081106136e2576136e26151fb565b6000918252602090912001546004805460405163965af6c760e01b81526001600160a01b03938416945092169163965af6c79161372391859187910161548d565b600060405180830381600087803b15801561373d57600080fd5b505af1158015613751573d6000803e3d6000fd5b505060048054604051633c85b79360e21b81526001600160a01b03909116935063f216de4c925061378691859187910161548d565b600060405180830381600087803b1580156137a057600080fd5b505af11580156137b4573d6000803e3d6000fd5b50505050602088015188516001600160a01b0383167f8975b837fe0d18616c65abb8b843726a32b552ee4feca009944fa658bbb282e7866137f48761556e565b60098b01546040516138169392916000916001600160a01b039091169061558a565b60405180910390a48751602089015160e08a015160405163ba66fde760e01b81526004810193909352602483019190915260448201526001600160a01b0385169063ba66fde790606401602060405180830381865afa15801561387d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138a1919061523a565b613907576004805460405163b5d69e9960e01b81526001600160a01b039091169163b5d69e99916138d4918591016149af565b600060405180830381600087803b1580156138ee57600080fd5b505af1158015613902573d6000803e3d6000fd5b505050505b600188606001516139189190615227565b8860e0015114801561392c57506040880151155b15613a1d5760098501546001600160a01b0316613975576000805460028701546040516001600160a01b039092169281156108fc029290818181858888f193505050505061399c565b6000546002860154600987015461399a926001600160a01b03918216929116906145a2565b505b60005460c08901516002546139bf926001600160a01b03918216929116906145a2565b506020880151885160c08a0151600288015460098901546040517f6cecfd3ec56289ccb16e30eb194f9a87dfdc12630b9abbc31fc69af5a0b0eaf493613a1493909290916001600160a01b03909116906155ae565b60405180910390a35b50505060c090940151949350505050565b60006007826000015181548110613a4757613a476151fb565b90600052602060002090600402019050600081600301836020015181548110613a7257613a726151fb565b90600052602060002090600b0201905060006006826000015481548110613a9b57613a9b6151fb565b6000918252602080832090910154865191870151606088015160e08901516001600160a01b039093169550859363675926f693909291613ada916155cd565b60808a015160a08b01516040516001600160e01b031960e088901b1681526004810195909552602485019390935260448401919091526064830152608482015260a401602060405180830381865afa158015613b3a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b5e91906153e4565b9050612710811115613b6f57506127105b60008360060186606001518760e00151613b8991906155cd565b81548110613b9957613b996151fb565b600091825260208220015460018601546001600160a01b03909116925061271090613bc5908590615358565b613bcf9190615385565b6004805460405163965af6c760e01b81529293506001600160a01b03169163965af6c791613c0191869186910161548d565b600060405180830381600087803b158015613c1b57600080fd5b505af1158015613c2f573d6000803e3d6000fd5b505060048054604051636624192f60e01b81526001600160a01b039091169350636624192f9250613c62918691016149af565b602060405180830381865afa158015613c7f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ca3919061523a565b613cc057600254613cbe906001600160a01b031683836145a2565b505b60006127108489604001518a60c00151613cda9190615385565b613ce49190615358565b613cee9190615385565b905080866008016000828254613d0491906153d1565b925050819055506000612710858a604001518960020154613d259190615385565b613d2f9190615358565b613d399190615385565b905080876007016000828254613d4f91906153d1565b9091555050600254613d6b906001600160a01b031685846145a2565b5060098701546001600160a01b0316613da9576040516001600160a01b0385169082156108fc029083906000818181858888f1935050505050613dc4565b6009870154613dc2906001600160a01b031685836145a2565b505b6020890151895160098901546040516001600160a01b03888116927f8975b837fe0d18616c65abb8b843726a32b552ee4feca009944fa658bbb282e792613e14928c928a928a929091169061558a565b60405180910390a4600189606001516002613e2f9190615358565b613e399190615227565b8960e00151036125ef57600087600801548a60c00151613e599190615227565b9050600088600701548960020154613e719190615227565b905081151580613e8057508015155b15611556578115613eaa57600054600254613ea8916001600160a01b039182169116846145a2565b505b8015613f115760098901546001600160a01b0316613ef057600080546040516001600160a01b039091169183156108fc02918491818181858888f1935050505050613f11565b60005460098a0154613f0f916001600160a01b039182169116836145a2565b505b60208b01518b5160098b01546040517f6cecfd3ec56289ccb16e30eb194f9a87dfdc12630b9abbc31fc69af5a0b0eaf491613f5b91879187916001600160a01b03909116906155ae565b60405180910390a35050505050505050505050565b6000546001600160a01b03163314613f9b5760405163c383977560e01b815260040160405180910390fd5b50565b60006001600160601b0385161580613fc057506005546001600160601b038616115b15613fd857613fd082600461466f565b5060006133c9565b831580159061401357506005856001600160601b031681548110613ffe57613ffe6151fb565b90600052602060002090600c02016002015484105b1561402357613fd082600561466f565b60048054604051630a5861b960e41b81526001600160a01b03898116938201939093526001600160601b03881660248201526044810187905285151560648201526000928392839291169063a5861b90906084016060604051808303816000875af1158015614096573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140ba91906155e1565b9194509250905060008160078111156140d5576140d5614b3e565b146140f0576140e4858261466f565b600093505050506133c9565b821561411d5760025461410e906001600160a01b03168a308661443f565b61411d576140e485600161466f565b81156141495760025461413a906001600160a01b03168a846145a2565b614149576140e485600261466f565b50600198975050505050505050565b60008060006141668661451b565b92505091506005826001600160601b031681548110614187576141876151fb565b60009182526020808320848452600a600c90930201919091019052604090205460ff166141c75760405163b34eb75d60e01b815260040160405180910390fd5b600780546001810182556000918252600160601b33026001600160601b03851617600482027fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c6888101918255427fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c68a909101556006805492965090929184908110614252576142526151fb565b6000918252602082200154600580546001600160a01b039092169350906001600160601b038716908110614288576142886151fb565b60009182526020808320600387018054600181018255908552918420600c909302019350600b0201906001600160a01b038a16156142d3576142ce8a8460040154611048565b6142d9565b82600401545b90506142e5818a615385565b60038084019190915586835583015460028401546127109161430691615358565b6143109190615385565b6001830155600282018990556009820180546001600160a01b0319166001600160a01b038c8116919091179091556004805460405163d09f392d60e01b81529182018b9052600060248301529091169063d09f392d90604401600060405180830381600087803b15801561438357600080fd5b505af1158015614397573d6000803e3d6000fd5b50505050836001600160a01b031663b6ede540898e8e86600301546040518563ffffffff1660e01b81526004016143d194939291906154a6565b600060405180830381600087803b1580156143eb57600080fd5b505af11580156143ff573d6000803e3d6000fd5b50506040513392508a91507f141dfc18aa6a56fc816f44f0e9e2f1ebc92b15ab167770e17db5b084c10ed99590600090a350505050505050949350505050565b6040516001600160a01b038481166024830152838116604483015260648201839052600091829182919088169060840160408051601f198184030181529181526020820180516001600160e01b03166323b872dd60e01b179052516144a49190615421565b6000604051808303816000865af19150503d80600081146144e1576040519150601f19603f3d011682016040523d82523d6000602084013e6144e6565b606091505b5091509150818015614510575080511580614510575080806020019051810190614510919061523a565b979650505050505050565b60008060006040845110614590575050506020810151604082015160608301516001600160601b038316158061455c57506005546001600160601b03841610155b1561456657600192505b8160000361457357600391505b80158061458257506006548110155b1561458b575060015b61459b565b506001915060039050815b9193909250565b6000806000856001600160a01b031685856040516024016145c492919061548d565b60408051601f198184030181529181526020820180516001600160e01b031663a9059cbb60e01b179052516145f99190615421565b6000604051808303816000865af19150503d8060008114614636576040519150601f19603f3d011682016040523d82523d6000602084013e61463b565b606091505b5091509150818015614665575080511580614665575080806020019051810190614665919061523a565b9695505050505050565b600182600181111561468357614683614b3e565b0361468c575050565b60018160078111156146a0576146a0614b3e565b036146be57604051630f323ed960e11b815260040160405180910390fd5b60028160078111156146d2576146d2614b3e565b036146f05760405163e45e13a360e01b815260040160405180910390fd5b600381600781111561470457614704614b3e565b0361472257604051631d91d0ed60e31b815260040160405180910390fd5b600481600781111561473657614736614b3e565b03614754576040516321f1774b60e11b815260040160405180910390fd5b600581600781111561476857614768614b3e565b036117f057604051630caac6b360e31b815260040160405180910390fd5b60405180608001604052806004906020820280368337509192915050565b82600481019282156147d2579160200282015b828111156147d25782518255916020019190600101906147b7565b506147de92915061481c565b5090565b8280548282559060005260206000209081019282156147d257916020028201828111156147d25782518255916020019190600101906147b7565b5b808211156147de576000815560010161481d565b6001600160a01b0381168114613f9b57600080fd5b60006020828403121561485857600080fd5b813561486381614831565b9392505050565b80356001600160601b038116811461488157600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b03811182821017156148c4576148c4614886565b604052919050565b600082601f8301126148dd57600080fd5b813560206001600160401b038211156148f8576148f8614886565b8160051b61490782820161489c565b928352848101820192828101908785111561492157600080fd5b83870192505b8483101561451057823582529183019190830190614927565b8015158114613f9b57600080fd5b60008060006060848603121561496357600080fd5b61496c8461486a565b925060208401356001600160401b0381111561498757600080fd5b614993868287016148cc565b92505060408401356149a481614940565b809150509250925092565b6001600160a01b0391909116815260200190565b6000602082840312156149d557600080fd5b5035919050565b600080604083850312156149ef57600080fd5b82356149fa81614831565b946020939093013593505050565b600080600060608486031215614a1d57600080fd5b505081359360208301359350604090920135919050565b600060208284031215614a4657600080fd5b6110998261486a565b8060005b6004811015610b0b578151845260209384019390910190600101614a53565b6080810161109c8284614a4f565b600082601f830112614a9157600080fd5b81356001600160401b03811115614aaa57614aaa614886565b614abd601f8201601f191660200161489c565b818152846020838601011115614ad257600080fd5b816020850160208301376000918101602001919091529392505050565b60008060408385031215614b0257600080fd5b8235614b0d81614831565b915060208301356001600160401b03811115614b2857600080fd5b614b3485828601614a80565b9150509250929050565b634e487b7160e01b600052602160045260246000fd5b60058110614b7257634e487b7160e01b600052602160045260246000fd5b9052565b6001600160601b03861681526001600160a01b038516602082015260a08101614ba26040830186614b54565b9215156060820152608001529392505050565b600080600060608486031215614bca57600080fd5b8335614bd581614831565b92506020840135915060408401356001600160401b03811115614bf757600080fd5b614c0386828701614a80565b9150509250925092565b60008060408385031215614c2057600080fd5b6149fa8361486a565b60008060408385031215614c3c57600080fd5b8235614c4781614831565b91506020830135614c5781614940565b809150509250929050565b600080600060608486031215614c7757600080fd5b8335614c8281614831565b925060208401356001600160401b0381168114614c9e57600080fd5b9150604084013560ff811681146149a457600080fd5b600082601f830112614cc557600080fd5b604051608081018181106001600160401b0382111715614ce757614ce7614886565b604052806080840185811115614cfc57600080fd5b845b81811015614d16578035835260209283019201614cfe565b509195945050505050565b6000806000806000806000610140888a031215614d3d57600080fd5b614d468861486a565b96506020880135614d5681614940565b955060408801359450606088013593506080880135925060a08801359150614d818960c08a01614cb4565b905092959891949750929550565b60008060408385031215614da257600080fd5b50508035926020909101359150565b60008151808452602080850194506020840160005b83811015614deb5781516001600160a01b031687529582019590820190600101614dc6565b509495945050505050565b6020815281516020820152602082015160408201526040820151606082015260608201516080820152608082015160a082015260a082015160c0820152600060c08301516101608060e0850152614e51610180850183614db1565b60e08601516101008681019190915286015161012080870191909152860151909250610140614e8a818701836001600160a01b03169052565b959095015193019290925250919050565b60008060408385031215614eae57600080fd5b823591506020830135614c5781614831565b60008060408385031215614ed357600080fd5b8235915060208301356001600160401b03811115614b2857600080fd5b600080600060608486031215614f0557600080fd5b833592506020840135915060408401356001600160401b03811115614bf757600080fd5b600080600080600080600080610160898b031215614f4657600080fd5b614f4f8961486a565b97506020890135614f5f81614940565b965060408901359550606089013594506080890135935060a08901359250614f8a8a60c08b01614cb4565b91506101408901356001600160401b03811115614fa657600080fd5b614fb28b828c016148cc565b9150509295985092959890939650565b60008083601f840112614fd457600080fd5b5081356001600160401b03811115614feb57600080fd5b60208301915083602082850101111561500357600080fd5b9250929050565b60008060006040848603121561501f57600080fd5b83356001600160401b0381111561503557600080fd5b61504186828701614fc2565b90945092505060208401356149a481614831565b60008060008060008060008060006101e08a8c03121561507457600080fd5b893561507f81614831565b985060208a013561508f81614831565b975060408a013561509f81614831565b965060608a01356150af81614831565b955060808a01356150bf81614831565b945060a08a01356150cf81614940565b93506150de8b60c08c01614cb4565b92506150ee8b6101408c01614cb4565b91506101c08a01356150ff81614831565b809150509295985092959850929598565b60008060008060006080868803121561512857600080fd5b8535945060208601356001600160401b0381111561514557600080fd5b61515188828901614fc2565b909550935050604086013561516581614831565b949793965091946060013592915050565b60006020828403121561518857600080fd5b81356001600160401b0381111561519e57600080fd5b612fa784828501614a80565b600080600080608085870312156151c057600080fd5b84356151cb81614831565b93506151d96020860161486a565b92506040850135915060608501356151f081614940565b939692955090935050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b8181038181111561109c5761109c615211565b60006020828403121561524c57600080fd5b815161486381614940565b6020810161109c8284614b54565b600181815b808511156152a057816000190482111561528657615286615211565b8085161561529357918102915b93841c939080029061526a565b509250929050565b6000826152b75750600161109c565b816152c45750600061109c565b81600181146152da57600281146152e457615300565b600191505061109c565b60ff8411156152f5576152f5615211565b50506001821b61109c565b5060208310610133831016604e8410600b8410161715615323575081810a61109c565b61532d8383615265565b806000190482111561534157615341615211565b029392505050565b600061109960ff8416836152a8565b808202811582820484141761109c5761109c615211565b634e487b7160e01b600052601260045260246000fd5b6000826153945761539461536f565b500490565b6000806000606084860312156153ae57600080fd5b8351925060208401516153c081614940565b60408501519092506149a481614940565b8082018082111561109c5761109c615211565b6000602082840312156153f657600080fd5b5051919050565b60005b83811015615418578181015183820152602001615400565b50506000910152565b600082516154338184602087016153fd565b9190910192915050565b600061012082019050871515825286602083015285604083015284606083015283608083015261451060a0830184614a4f565b60006020828403121561548257600080fd5b815161486381614831565b6001600160a01b03929092168252602082015260400190565b84815283602082015260806040820152600083518060808401526154d18160a08501602088016153fd565b606083019390935250601f91909101601f19160160a0019392505050565b60006101408083018a1515845260208a602086015289604086015288606086015287608086015261552360a0860188614a4f565b610120850192909252845190819052610160840191602086019160005b8181101561555c57835185529382019392820192600101615540565b50929c9b505050505050505050505050565b6000600160ff1b820161558357615583615211565b5060000390565b938452602084019290925260408301526001600160a01b0316606082015260800190565b92835260208301919091526001600160a01b0316604082015260600190565b6000826155dc576155dc61536f565b500690565b6000806000606084860312156155f657600080fd5b83519250602084015191506040840151600881106149a457600080fdfe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbca264697066735822122088332e4bd463fd5a2a31ab980f2b2ead694ff8b8a10a33684171a45128537f0a64736f6c63430008180033",
- "deployedBytecode": "0x60806040526004361061027c5760003560e01c80638a9bb02a1161014f578063d07368bd116100c1578063f6506db41161007a578063f6506db414610867578063f7434ea914610887578063fbb519e7146108a7578063fbf405b0146108c7578063fc6f8f16146108e7578063fe524c391461090757600080fd5b8063d07368bd146107b2578063d4d1d76a146107d2578063d874514b146107e7578063d98493f614610807578063e399d29b14610827578063e4c0aaf41461084757600080fd5b8063b702a87911610113578063b702a8791461070c578063c13517e11461072c578063c258bb191461073f578063c35699021461075f578063c71f425314610772578063cf0c38f81461079257600080fd5b80638a9bb02a1461064a5780638bb0487514610677578063acdbf51d14610697578063afe15cfb146106b7578063b0049637146106ec57600080fd5b80632e1daf2f116101f357806371ae413d116101ac57806371ae413d1461058a578063751accd0146105aa5780637717a6e8146105ca5780637934c0be146105ea57806382d022371461060a57806386541b241461062a57600080fd5b80632e1daf2f146104c45780633cfd1184146104e45780634f1ef2861461051157806352d1902d14610524578063564a565d1461053957806359ec827e1461056a57600080fd5b8063115d537611610245578063115d5376146103885780631860592b146103a857806319b81529146103d65780631c3db16d146104065780631f5a0dd2146104435780632d29a47b146104a457600080fd5b8062f5822c146102815780630219da79146102a357806309cfdc9c1461031b5780630b7414bc1461033b5780630c340a241461035b575b600080fd5b34801561028d57600080fd5b506102a161029c366004614846565b610927565b005b3480156102af57600080fd5b506102ee6102be366004614846565b60086020526000908152604090205460ff808216916001600160401b0361010082041691600160481b9091041683565b6040805193151584526001600160401b03909216602084015260ff16908201526060015b60405180910390f35b34801561032757600080fd5b506102a1610336366004614846565b610974565b34801561034757600080fd5b506102a161035636600461494e565b6109da565b34801561036757600080fd5b5060005461037b906001600160a01b031681565b60405161031291906149af565b34801561039457600080fd5b506102a16103a33660046149c3565b610b11565b3480156103b457600080fd5b506103c86103c33660046149dc565b611048565b604051908152602001610312565b3480156103e257600080fd5b506103f66103f13660046149c3565b6110a2565b6040519015158152602001610312565b34801561041257600080fd5b506104266104213660046149c3565b61119b565b604080519384529115156020840152151590820152606001610312565b34801561044f57600080fd5b5061046361045e3660046149c3565b61129c565b604080516001600160601b0390981688529515156020880152948601939093526060850191909152608084015260a0830152151560c082015260e001610312565b3480156104b057600080fd5b506102a16104bf366004614a08565b6112fb565b3480156104d057600080fd5b5060045461037b906001600160a01b031681565b3480156104f057600080fd5b506105046104ff366004614a34565b611563565b6040516103129190614a72565b6102a161051f366004614aef565b6115cd565b34801561053057600080fd5b506103c86117f4565b34801561054557600080fd5b506105596105543660046149c3565b611852565b604051610312959493929190614b76565b34801561057657600080fd5b506103c86105853660046149c3565b6118ae565b34801561059657600080fd5b5060015461037b906001600160a01b031681565b3480156105b657600080fd5b506102a16105c5366004614bb5565b611a03565b3480156105d657600080fd5b506102a16105e5366004614c0d565b611aad565b3480156105f657600080fd5b506102a1610605366004614c29565b611abb565b34801561061657600080fd5b506102a1610625366004614c62565b611b3a565b34801561063657600080fd5b506102a1610645366004614d21565b611bf7565b34801561065657600080fd5b5061066a610665366004614d8f565b611dd4565b6040516103129190614df6565b34801561068357600080fd5b506102a16106923660046149c3565b611f60565b3480156106a357600080fd5b5061037b6106b23660046149c3565b6120c4565b3480156106c357600080fd5b506106d76106d23660046149c3565b6120ee565b60408051928352602083019190915201610312565b3480156106f857600080fd5b506102a1610707366004614846565b61219a565b34801561071857600080fd5b506102a1610727366004614e9b565b6121e7565b6103c861073a366004614ec0565b6125fa565b34801561074b57600080fd5b506102a161075a366004614846565b612632565b6102a161076d366004614ef0565b61267f565b34801561077e57600080fd5b506103c861078d3660046149c3565b612b53565b34801561079e57600080fd5b5060035461037b906001600160a01b031681565b3480156107be57600080fd5b506102a16107cd366004614846565b612bbb565b3480156107de57600080fd5b506006546103c8565b3480156107f357600080fd5b506102a1610802366004614f29565b612c64565b34801561081357600080fd5b506103c861082236600461500a565b612f62565b34801561083357600080fd5b506102a1610842366004615055565b612faf565b34801561085357600080fd5b506102a1610862366004614846565b61329f565b34801561087357600080fd5b506103c8610882366004615110565b6132ec565b34801561089357600080fd5b506103c86108a2366004615176565b6133d2565b3480156108b357600080fd5b506102a16108c23660046151aa565b61341e565b3480156108d357600080fd5b5060025461037b906001600160a01b031681565b3480156108f357600080fd5b506103c86109023660046149c3565b61345e565b34801561091357600080fd5b506103f6610922366004614c0d565b61348d565b6000546001600160a01b031633146109525760405163c383977560e01b815260040160405180910390fd5b600280546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b0316331480159061099a57506001546001600160a01b03163314155b156109b857604051633244d29960e21b815260040160405180910390fd5b600180546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b03163314610a055760405163c383977560e01b815260040160405180910390fd5b60005b8251811015610b0b578115610aa457828181518110610a2957610a296151fb565b602002602001015160001480610a5c57506006548351849083908110610a5157610a516151fb565b602002602001015110155b15610a7a57604051633d58a98960e11b815260040160405180910390fd5b610a9f84848381518110610a9057610a906151fb565b602002602001015160016134d5565b610b03565b6001838281518110610ab857610ab86151fb565b602002602001015103610ade576040516356d111fd60e11b815260040160405180910390fd5b610b0384848381518110610af457610af46151fb565b602002602001015160006134d5565b600101610a08565b50505050565b600060078281548110610b2657610b266151fb565b600091825260208220600490910201805460058054929450916001600160601b03909116908110610b5957610b596151fb565b6000918252602082206003850154600c909202019250610b7b90600190615227565b90506000836003018281548110610b9457610b946151fb565b600091825260208220600b909102019150600185015460ff166004811115610bbe57610bbe614b3e565b03610c995781158015610c0d57506001840154600684019060ff166004811115610bea57610bea614b3e565b60048110610bfa57610bfa6151fb565b01546002850154610c0b9042615227565b105b15610c2b57604051633e9727df60e01b815260040160405180910390fd5b6003810154600682015414610c53576040516309e4486b60e41b815260040160405180910390fd5b8254600160601b900460ff16610c6a576002610c6d565b60015b60018086018054909160ff1990911690836004811115610c8f57610c8f614b3e565b0217905550610ffa565b60018085015460ff166004811115610cb357610cb3614b3e565b03610dc3576001840154600684019060ff166004811115610cd657610cd6614b3e565b60048110610ce657610ce66151fb565b01546002850154610cf79042615227565b108015610d8e57506006816000015481548110610d1657610d166151fb565b600091825260209091200154604051630baa64d160e01b8152600481018790526001600160a01b0390911690630baa64d190602401602060405180830381865afa158015610d68573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d8c919061523a565b155b15610dac57604051634dfa578560e11b815260040160405180910390fd5b6001808501805460029260ff199091169083610c8f565b6002600185015460ff166004811115610dde57610dde614b3e565b03610f2c576001840154600684019060ff166004811115610e0157610e01614b3e565b60048110610e1157610e116151fb565b01546002850154610e229042615227565b108015610eb957506006816000015481548110610e4157610e416151fb565b6000918252602090912001546040516336a66c7560e11b8152600481018790526001600160a01b0390911690636d4cd8ea90602401602060405180830381865afa158015610e93573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610eb7919061523a565b155b15610ed757604051631988dead60e31b815260040160405180910390fd5b600184018054600360ff199091161790558354604051600160601b9091046001600160a01b03169086907fa5d41b970d849372be1da1481ffd78d162bfe57a7aa2fe4e5fb73481fa5ac24f90600090a3610ffa565b6003600185015460ff166004811115610f4757610f47614b3e565b03610fc1576001840154600684019060ff166004811115610f6a57610f6a614b3e565b60048110610f7a57610f7a6151fb565b01546002850154610f8b9042615227565b1015610faa57604051632f4dfd8760e01b815260040160405180910390fd5b6001808501805460049260ff199091169083610c8f565b6004600185015460ff166004811115610fdc57610fdc614b3e565b03610ffa576040516307f38c8f60e11b815260040160405180910390fd5b426002850155600184015460405186917f4e6f5cf43b95303e86aee81683df63992061723a829ee012db21dad388756b91916110399160ff1690615257565b60405180910390a25050505050565b6001600160a01b03821660009081526008602052604081205461010081046001600160401b03169061108590600160481b900460ff16600a615349565b61108f9084615358565b6110999190615385565b90505b92915050565b600080600783815481106110b8576110b86151fb565b60009182526020822060036004909202019081018054919350906110de90600190615227565b815481106110ee576110ee6151fb565b600091825260208220845460058054600b909402909201945090916001600160601b03909116908110611123576111236151fb565b90600052602060002090600c0201905080600501548260030154101561114e57506000949350505050565b80546005805490916001600160601b031690811061116e5761116e6151fb565b6000918252602080832094548352600a600c9092029094010190925250604090205460ff16159392505050565b600080600080600785815481106111b4576111b46151fb565b60009182526020822060036004909202019081018054919350906111da90600190615227565b815481106111ea576111ea6151fb565b90600052602060002090600b0201905060006006826000015481548110611213576112136151fb565b600091825260209091200154604051631c3db16d60e01b8152600481018990526001600160a01b0390911691508190631c3db16d90602401606060405180830381865afa158015611268573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061128c9190615399565b9199909850909650945050505050565b600581815481106112ac57600080fd5b60009182526020909120600c9091020180546002820154600383015460048401546005850154600b909501546001600160601b038516965060ff600160601b9095048516959394929391921687565b60008060078581548110611311576113116151fb565b600091825260209091206004918202019150600182015460ff16600481111561133c5761133c614b3e565b1461135a57604051638794ce4b60e01b815260040160405180910390fd5b80600301848154811061136f5761136f6151fb565b6000918252602082206004600b9092020190810154909350915061139384836153d1565b60058401546006850154600286015492935090916000906113b5908390615385565b905060008660010154905060008060068960000154815481106113da576113da6151fb565b60009182526020909120015460405163368efae360e21b8152600481018e9052602481018d90526001600160a01b039091169150819063da3beb8c90604401602060405180830381865afa158015611436573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061145a91906153e4565b915050806000036114765783861115611471578395505b611496565b611481846002615358565b86111561149657611493846002615358565b95505b60048801869055865b8681101561154257848110156114f8576114f16040518061010001604052808e81526020018d81526020018481526020018781526020018681526020018581526020018881526020018381525061355d565b955061153a565b61153a6040518061010001604052808e81526020018d815260200184815260200187815260200186815260200185815260200188815260200183815250613a2e565b60010161149f565b508488600501541461155657600588018590555b5050505050505050505050565b61156b614786565b6005826001600160601b031681548110611587576115876151fb565b6000918252602090912060408051608081019182905292600c029091016006019060049082845b8154815260200190600101908083116115ae5750505050509050919050565b6115d682613f70565b306001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016148061165457507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166116486000805160206156148339815191525490565b6001600160a01b031614155b156116725760405163703e46dd60e11b815260040160405180910390fd5b816001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa9250505080156116cc575060408051601f3d908101601f191682019092526116c9918101906153e4565b60015b6116f45781604051630c76093760e01b81526004016116eb91906149af565b60405180910390fd5b600080516020615614833981519152811461172557604051632a87526960e21b8152600481018290526024016116eb565b6000805160206156148339815191528390556040516001600160a01b038416907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a28151156117ee576000836001600160a01b03168360405161178c9190615421565b600060405180830381855af49150503d80600081146117c7576040519150601f19603f3d011682016040523d82523d6000602084013e6117cc565b606091505b5050905080610b0b576040516339b21b5d60e11b815260040160405180910390fd5b505b5050565b6000306001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461183f5760405163703e46dd60e11b815260040160405180910390fd5b5060008051602061561483398151915290565b6007818154811061186257600080fd5b60009182526020909120600490910201805460018201546002909201546001600160601b0382169350600160601b9091046001600160a01b03169160ff80821692610100909204169085565b600080600783815481106118c4576118c46151fb565b60009182526020822060036004909202019081018054919350906118ea90600190615227565b815481106118fa576118fa6151fb565b600091825260208220845460058054600b909402909201945090916001600160601b0390911690811061192f5761192f6151fb565b90600052602060002090600c0201905080600501548260030154106119ce5782546001600160601b031660001901611970576001600160ff1b0393506119fb565b6003820154611980906002615358565b61198b9060016153d1565b81546005805490916001600160601b03169081106119ab576119ab6151fb565b90600052602060002090600c0201600401546119c79190615358565b93506119fb565b60038201546119de906002615358565b6119e99060016153d1565b81600401546119f89190615358565b93505b505050919050565b6000546001600160a01b03163314611a2e5760405163c383977560e01b815260040160405180910390fd5b6000836001600160a01b03168383604051611a499190615421565b60006040518083038185875af1925050503d8060008114611a86576040519150601f19603f3d011682016040523d82523d6000602084013e611a8b565b606091505b5050905080610b0b576040516322092f2f60e11b815260040160405180910390fd5b6117ee338383600080613f9e565b6000546001600160a01b03163314611ae65760405163c383977560e01b815260040160405180910390fd5b6001600160a01b038216600081815260086020526040808220805460ff191685151590811790915590519092917f541615e167511d757a7067a700eb54431b256bb458dfdce0ac58bf2ed0aefd4491a35050565b6000546001600160a01b03163314611b655760405163c383977560e01b815260040160405180910390fd5b6001600160a01b038316600081815260086020908152604091829020805469ffffffffffffffffff0019166101006001600160401b03881690810260ff60481b191691909117600160481b60ff8816908102919091179092558351908152918201527fe6996b7f03e9bd02228b99d3d946932e3197f505f60542c4cfbc919441d8a4e6910160405180910390a2505050565b6000546001600160a01b03163314611c225760405163c383977560e01b815260040160405180910390fd5b60006005886001600160601b031681548110611c4057611c406151fb565b90600052602060002090600c0201905060016001600160601b0316886001600160601b031614158015611ca2575080546005805488926001600160601b0316908110611c8e57611c8e6151fb565b90600052602060002090600c020160020154115b15611cc057604051639717078960e01b815260040160405180910390fd5b60005b6001820154811015611d3b57866005836001018381548110611ce757611ce76151fb565b906000526020600020015481548110611d0257611d026151fb565b90600052602060002090600c0201600201541015611d3357604051639717078960e01b815260040160405180910390fd5b600101611cc3565b5060028101869055805460ff60601b1916600160601b8815150217815560038101859055600480820185905560058201849055611d7e90600683019084906147a4565b50876001600160601b03167f709b1f5fda58af9a4f52dacd1ec404840a8148455700cce155a2bd8cf127ef1a888888888888604051611dc29695949392919061543d565b60405180910390a25050505050505050565b611e3a60405180610160016040528060008152602001600081526020016000815260200160008152602001600081526020016000815260200160608152602001600081526020016000815260200160006001600160a01b03168152602001600081525090565b60078381548110611e4d57611e4d6151fb565b90600052602060002090600402016003018281548110611e6f57611e6f6151fb565b90600052602060002090600b02016040518061016001604052908160008201548152602001600182015481526020016002820154815260200160038201548152602001600482015481526020016005820154815260200160068201805480602002602001604051908101604052809291908181526020018280548015611f1e57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611f00575b5050509183525050600782015460208201526008820154604082015260098201546001600160a01b03166060820152600a909101546080909101529392505050565b600060078281548110611f7557611f756151fb565b600091825260209091206004918202019150600182015460ff166004811115611fa057611fa0614b3e565b14611fbe57604051638794ce4b60e01b815260040160405180910390fd5b6001810154610100900460ff1615611fe95760405163c977f8d360e01b815260040160405180910390fd5b6000611ff48361119b565b505060018301805461010061ff001990911617905582546040518281529192508491600160601b9091046001600160a01b0316907f394027a5fa6e098a1191094d1719d6929b9abc535fcc0c8f448d6a4e756222769060200160405180910390a3815460405163188d362b60e11b81526004810185905260248101839052600160601b9091046001600160a01b03169063311a6c5690604401600060405180830381600087803b1580156120a757600080fd5b505af11580156120bb573d6000803e3d6000fd5b50505050505050565b600681815481106120d457600080fd5b6000918252602090912001546001600160a01b0316905081565b600080600060078481548110612106576121066151fb565b6000918252602090912060049091020190506003600182015460ff16600481111561213357612133614b3e565b0361218b576002810154815460058054929550916001600160601b03909116908110612161576121616151fb565b600091825260209091206009600c909202010154600282015461218491906153d1565b9150612194565b60009250600091505b50915091565b6000546001600160a01b031633146121c55760405163c383977560e01b815260040160405180910390fd5b600480546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b0316331480159061220d57506001546001600160a01b03163314155b1561222b57604051633244d29960e21b815260040160405180910390fd5b600060078381548110612240576122406151fb565b906000526020600020906004020190506000600182600301805490506122669190615227565b9050600082600301828154811061227f5761227f6151fb565b600091825260208220600b909102019150600184015460ff1660048111156122a9576122a9614b3e565b146122c757604051638285c4ef60e01b815260040160405180910390fd5b60038101546006820154106122ef57604051634df06de360e01b815260040160405180910390fd5b60048054604051633c694c4160e21b81526001600160a01b039091169163f1a531049161231e918891016149af565b600060405180830381600087803b15801561233857600080fd5b505af115801561234c573d6000803e3d6000fd5b5050505060006006826000015481548110612369576123696151fb565b6000918252602082200154600a8401546001600160a01b0390911692506123919060016153d1565b60405163695c01ad60e11b815260048101899052602481018290529091506000906001600160a01b0384169063d2b8035a906044016020604051808303816000875af11580156123e5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124099190615470565b90506001600160a01b03811661243257604051632e38b8f760e11b815260040160405180910390fd5b6004805460018601546040516310f0b12f60e11b81526001600160a01b03909216926321e1625e9261246892869290910161548d565b600060405180830381600087803b15801561248257600080fd5b505af1158015612496573d6000803e3d6000fd5b50505060068501546040518a92506001600160a01b038416917f6119cf536152c11e0a9a6c22f3953ce4ecc93ee54fa72ffa326ffabded21509b916124e3918a8252602082015260400190565b60405180910390a36006840180546001810182556000828152602090200180546001600160a01b0319166001600160a01b038416179055600385015490540361258a5760048054604051632e96bc2360e11b81529182018a9052602482018790526001600160a01b031690635d2d784690604401600060405180830381600087803b15801561257157600080fd5b505af1158015612585573d6000803e3d6000fd5b505050505b50600a8301555060048054604051633c694c4160e21b81526001600160a01b039091169163f1a53104916125c191600091016149af565b600060405180830381600087803b1580156125db57600080fd5b505af11580156125ef573d6000803e3d6000fd5b505050505050505050565b6000612605826133d2565b34101561262557604051630e3360f160e21b815260040160405180910390fd5b6110998383600034614158565b6000546001600160a01b0316331461265d5760405163c383977560e01b815260040160405180910390fd5b600380546001600160a01b0319166001600160a01b0392909216919091179055565b612688836118ae565b3410156126a857604051633191f8f160e01b815260040160405180910390fd5b6000600784815481106126bd576126bd6151fb565b6000918252602090912060049091020190506003600182015460ff1660048111156126ea576126ea614b3e565b14612708576040516337cdefcb60e21b815260040160405180910390fd5b6003810180546000919061271e90600190615227565b8154811061272e5761272e6151fb565b90600052602060002090600b020190506006816000015481548110612755576127556151fb565b6000918252602090912001546001600160a01b031633146127895760405163065f245f60e01b815260040160405180910390fd5b8154815460038401805460018101825560009182526020909120600580546001600160601b0390951694600b90930290910191849081106127cc576127cc6151fb565b90600052602060002090600c0201600501548460030154106128d5576005836001600160601b031681548110612804576128046151fb565b60009182526020909120600c9091020154600580546001600160601b0390921694509084908110612837576128376151fb565b60009182526020808320858452600a600c90930201919091019052604090205460ff1661286357600191505b84546001600160601b038481169116146128d557845460038601546001600160601b039091169061289690600190615227565b6040516001600160601b03861681528a907f736e3f52761298c8c0823e1ebf482ed3c5ecb304f743d2d91a7c006e8e8d7a1f9060200160405180910390a45b84546001600160601b0319166001600160601b038416908117865560018601805460ff1916905542600287015560058054600092908110612918576129186151fb565b90600052602060002090600c020190508060040154346129389190615385565b8260030181905550612710816003015482600201546129579190615358565b6129619190615385565b60018084019190915534600284015583835560045460038801546001600160a01b039091169163d09f392d918c9161299891615227565b6040516001600160e01b031960e085901b16815260048101929092526024820152604401600060405180830381600087803b1580156129d657600080fd5b505af11580156129ea573d6000803e3d6000fd5b505086548454149150612ad090505784546003870154612a0c90600190615227565b83546040519081528b907fcbe7939a71f0b369c7471d760a0a99b60b7bb010ee0406cba8a46679d1ea77569060200160405180910390a46006826000015481548110612a5a57612a5a6151fb565b60009182526020909120015460038301546040516302dbb79560e61b81526001600160a01b039092169163b6ede54091612a9d918d918d918d91906004016154a6565b600060405180830381600087803b158015612ab757600080fd5b505af1158015612acb573d6000803e3d6000fd5b505050505b8554604051600160601b9091046001600160a01b0316908a907f9c9b64db9e130f48381bf697abf638e73117dbfbfd7a4484f2da3ba188f4187d90600090a3887f4e6f5cf43b95303e86aee81683df63992061723a829ee012db21dad388756b916000604051612b409190615257565b60405180910390a2505050505050505050565b60008060078381548110612b6957612b696151fb565b906000526020600020906004020190508060030160018260030180549050612b919190615227565b81548110612ba157612ba16151fb565b90600052602060002090600b020160030154915050919050565b6000546001600160a01b03163314612be65760405163c383977560e01b815260040160405180910390fd5b6006805460018101825560009182527ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f810180546001600160a01b0319166001600160a01b0385169081179091556040519192909183917f44063d258760b98116d53815adbc906a56b3563e540148cc0fc2457f83b5eeb291a35050565b6000546001600160a01b03163314612c8f5760405163c383977560e01b815260040160405180910390fd5b856005896001600160601b031681548110612cac57612cac6151fb565b90600052602060002090600c0201600201541115612cdd57604051639717078960e01b815260040160405180910390fd5b8051600003612cff5760405163402585f560e01b815260040160405180910390fd5b6001600160601b038816612d2657604051631ef4f64960e01b815260040160405180910390fd5b60058054600181018255600091825290600c82027f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db001905b8351811015612e1557838181518110612d7957612d796151fb565b602002602001015160001480612dac57506006548451859083908110612da157612da16151fb565b602002602001015110155b15612dca57604051633d58a98960e11b815260040160405180910390fd5b600182600a016000868481518110612de457612de46151fb565b6020908102919091018101518252810191909152604001600020805460ff1916911515919091179055600101612d5e565b5060016000908152600a8201602052604090205460ff16612e49576040516306351b3d60e31b815260040160405180910390fd5b80546001600160601b0319166001600160601b038b161781556040805160008152602081019182905251612e819160018401916147e2565b50805460ff60601b1916600160601b8a1515021781556002810188905560038101879055600480820187905560058201869055612ec490600683019086906147a4565b5060058a6001600160601b031681548110612ee157612ee16151fb565b600091825260208083206001600c909302018201805492830181558352909120018290556040516001600160601b038b169083907f3475f0ed7216dd7d453db663a1c3024e4f36cc925521d54edb9d13e022cbee3d90612f4e908d908d908d908d908d908d908d906154ef565b60405180910390a350505050505050505050565b6000612fa7826103c386868080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506133d292505050565b949350505050565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0e805460019190600160401b900460ff1680612ff8575080546001600160401b03808416911610155b156130155760405162dc149f60e41b815260040160405180910390fd5b805468ffffffffffffffffff19166001600160401b03831617600160401b178155600080546001600160a01b03808e166001600160a01b0319928316178355600180548e8316908416178155600280548e8416908516178155600380548e8516908616179055600480548985169086161790556006805481875291820190557ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d40018054928c1692909316821790925560405190927f44063d258760b98116d53815adbc906a56b3563e540148cc0fc2457f83b5eeb291a360058054600082815260028201909255600c6001909101027f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db0810180546001600160601b031916815560408051938452602084019081905292519092613174927f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db101916147e2565b50805460ff60601b1916600160601b8815150217815585516002820155602086015160038201556040860151600480830191909155606087015160058301556131c390600683019087906147a4565b50805486516020808901516040808b015160608c0151825160008082529581019093526001600160601b03909616956001957f3475f0ed7216dd7d453db663a1c3024e4f36cc925521d54edb9d13e022cbee3d958f959194919392918e915060405161323597969594939291906154ef565b60405180910390a361324a60018060016134d5565b50805460ff60401b191681556040516001600160401b03831681527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15050505050505050505050565b6000546001600160a01b031633146132ca5760405163c383977560e01b815260040160405180910390fd5b600080546001600160a01b0319166001600160a01b0392909216919091179055565b6001600160a01b03821660009081526008602052604081205460ff166133255760405163e51cf7bf60e01b815260040160405180910390fd5b613330858585612f62565b82101561335057604051630e3360f160e21b815260040160405180910390fd5b6133656001600160a01b03841633308561443f565b613382576040516312171d8360e31b815260040160405180910390fd5b6133c68686868080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508892508791506141589050565b90505b95945050505050565b60008060006133e08461451b565b5091509150806005836001600160601b031681548110613402576134026151fb565b90600052602060002090600c020160040154612fa79190615358565b6004546001600160a01b0316331461344957604051639d6cab9960e01b815260040160405180910390fd5b613457848484846001613f9e565b5050505050565b600060078281548110613473576134736151fb565b600091825260209091206003600490920201015492915050565b60006005836001600160601b0316815481106134ab576134ab6151fb565b60009182526020808320948352600c91909102909301600a0190925250604090205460ff16919050565b806005846001600160601b0316815481106134f2576134f26151fb565b60009182526020808320868452600c92909202909101600a0190526040808220805460ff19169315159390931790925590518215159184916001600160601b038716917fb47629acdf64971062d40984f77d3dee212d735b11e3e8c7a4222d9f0572cc7991a4505050565b6000806007836000015181548110613577576135776151fb565b906000526020600020906004020190506000816003018460200151815481106135a2576135a26151fb565b90600052602060002090600b02019050600060068260000154815481106135cb576135cb6151fb565b60009182526020808320919091015487519188015160e089015160808a015160a08b01516040516333ac937b60e11b8152600481019690965260248601939093526044850191909152606484015260848301526001600160a01b03169250829063675926f69060a401602060405180830381865afa158015613651573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061367591906153e4565b905061271081111561368657506127105b60006127106136958382615227565b85600101546136a49190615358565b6136ae9190615385565b9050808760c0018181516136c291906153d1565b90525060e08701516006850180546000929081106136e2576136e26151fb565b6000918252602090912001546004805460405163965af6c760e01b81526001600160a01b03938416945092169163965af6c79161372391859187910161548d565b600060405180830381600087803b15801561373d57600080fd5b505af1158015613751573d6000803e3d6000fd5b505060048054604051633c85b79360e21b81526001600160a01b03909116935063f216de4c925061378691859187910161548d565b600060405180830381600087803b1580156137a057600080fd5b505af11580156137b4573d6000803e3d6000fd5b50505050602088015188516001600160a01b0383167f8975b837fe0d18616c65abb8b843726a32b552ee4feca009944fa658bbb282e7866137f48761556e565b60098b01546040516138169392916000916001600160a01b039091169061558a565b60405180910390a48751602089015160e08a015160405163ba66fde760e01b81526004810193909352602483019190915260448201526001600160a01b0385169063ba66fde790606401602060405180830381865afa15801561387d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138a1919061523a565b613907576004805460405163b5d69e9960e01b81526001600160a01b039091169163b5d69e99916138d4918591016149af565b600060405180830381600087803b1580156138ee57600080fd5b505af1158015613902573d6000803e3d6000fd5b505050505b600188606001516139189190615227565b8860e0015114801561392c57506040880151155b15613a1d5760098501546001600160a01b0316613975576000805460028701546040516001600160a01b039092169281156108fc029290818181858888f193505050505061399c565b6000546002860154600987015461399a926001600160a01b03918216929116906145a2565b505b60005460c08901516002546139bf926001600160a01b03918216929116906145a2565b506020880151885160c08a0151600288015460098901546040517f6cecfd3ec56289ccb16e30eb194f9a87dfdc12630b9abbc31fc69af5a0b0eaf493613a1493909290916001600160a01b03909116906155ae565b60405180910390a35b50505060c090940151949350505050565b60006007826000015181548110613a4757613a476151fb565b90600052602060002090600402019050600081600301836020015181548110613a7257613a726151fb565b90600052602060002090600b0201905060006006826000015481548110613a9b57613a9b6151fb565b6000918252602080832090910154865191870151606088015160e08901516001600160a01b039093169550859363675926f693909291613ada916155cd565b60808a015160a08b01516040516001600160e01b031960e088901b1681526004810195909552602485019390935260448401919091526064830152608482015260a401602060405180830381865afa158015613b3a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b5e91906153e4565b9050612710811115613b6f57506127105b60008360060186606001518760e00151613b8991906155cd565b81548110613b9957613b996151fb565b600091825260208220015460018601546001600160a01b03909116925061271090613bc5908590615358565b613bcf9190615385565b6004805460405163965af6c760e01b81529293506001600160a01b03169163965af6c791613c0191869186910161548d565b600060405180830381600087803b158015613c1b57600080fd5b505af1158015613c2f573d6000803e3d6000fd5b505060048054604051636624192f60e01b81526001600160a01b039091169350636624192f9250613c62918691016149af565b602060405180830381865afa158015613c7f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ca3919061523a565b613cc057600254613cbe906001600160a01b031683836145a2565b505b60006127108489604001518a60c00151613cda9190615385565b613ce49190615358565b613cee9190615385565b905080866008016000828254613d0491906153d1565b925050819055506000612710858a604001518960020154613d259190615385565b613d2f9190615358565b613d399190615385565b905080876007016000828254613d4f91906153d1565b9091555050600254613d6b906001600160a01b031685846145a2565b5060098701546001600160a01b0316613da9576040516001600160a01b0385169082156108fc029083906000818181858888f1935050505050613dc4565b6009870154613dc2906001600160a01b031685836145a2565b505b6020890151895160098901546040516001600160a01b03888116927f8975b837fe0d18616c65abb8b843726a32b552ee4feca009944fa658bbb282e792613e14928c928a928a929091169061558a565b60405180910390a4600189606001516002613e2f9190615358565b613e399190615227565b8960e00151036125ef57600087600801548a60c00151613e599190615227565b9050600088600701548960020154613e719190615227565b905081151580613e8057508015155b15611556578115613eaa57600054600254613ea8916001600160a01b039182169116846145a2565b505b8015613f115760098901546001600160a01b0316613ef057600080546040516001600160a01b039091169183156108fc02918491818181858888f1935050505050613f11565b60005460098a0154613f0f916001600160a01b039182169116836145a2565b505b60208b01518b5160098b01546040517f6cecfd3ec56289ccb16e30eb194f9a87dfdc12630b9abbc31fc69af5a0b0eaf491613f5b91879187916001600160a01b03909116906155ae565b60405180910390a35050505050505050505050565b6000546001600160a01b03163314613f9b5760405163c383977560e01b815260040160405180910390fd5b50565b60006001600160601b0385161580613fc057506005546001600160601b038616115b15613fd857613fd082600461466f565b5060006133c9565b831580159061401357506005856001600160601b031681548110613ffe57613ffe6151fb565b90600052602060002090600c02016002015484105b1561402357613fd082600561466f565b60048054604051630a5861b960e41b81526001600160a01b03898116938201939093526001600160601b03881660248201526044810187905285151560648201526000928392839291169063a5861b90906084016060604051808303816000875af1158015614096573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140ba91906155e1565b9194509250905060008160078111156140d5576140d5614b3e565b146140f0576140e4858261466f565b600093505050506133c9565b821561411d5760025461410e906001600160a01b03168a308661443f565b61411d576140e485600161466f565b81156141495760025461413a906001600160a01b03168a846145a2565b614149576140e485600261466f565b50600198975050505050505050565b60008060006141668661451b565b92505091506005826001600160601b031681548110614187576141876151fb565b60009182526020808320848452600a600c90930201919091019052604090205460ff166141c75760405163b34eb75d60e01b815260040160405180910390fd5b600780546001810182556000918252600160601b33026001600160601b03851617600482027fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c6888101918255427fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c68a909101556006805492965090929184908110614252576142526151fb565b6000918252602082200154600580546001600160a01b039092169350906001600160601b038716908110614288576142886151fb565b60009182526020808320600387018054600181018255908552918420600c909302019350600b0201906001600160a01b038a16156142d3576142ce8a8460040154611048565b6142d9565b82600401545b90506142e5818a615385565b60038084019190915586835583015460028401546127109161430691615358565b6143109190615385565b6001830155600282018990556009820180546001600160a01b0319166001600160a01b038c8116919091179091556004805460405163d09f392d60e01b81529182018b9052600060248301529091169063d09f392d90604401600060405180830381600087803b15801561438357600080fd5b505af1158015614397573d6000803e3d6000fd5b50505050836001600160a01b031663b6ede540898e8e86600301546040518563ffffffff1660e01b81526004016143d194939291906154a6565b600060405180830381600087803b1580156143eb57600080fd5b505af11580156143ff573d6000803e3d6000fd5b50506040513392508a91507f141dfc18aa6a56fc816f44f0e9e2f1ebc92b15ab167770e17db5b084c10ed99590600090a350505050505050949350505050565b6040516001600160a01b038481166024830152838116604483015260648201839052600091829182919088169060840160408051601f198184030181529181526020820180516001600160e01b03166323b872dd60e01b179052516144a49190615421565b6000604051808303816000865af19150503d80600081146144e1576040519150601f19603f3d011682016040523d82523d6000602084013e6144e6565b606091505b5091509150818015614510575080511580614510575080806020019051810190614510919061523a565b979650505050505050565b60008060006040845110614590575050506020810151604082015160608301516001600160601b038316158061455c57506005546001600160601b03841610155b1561456657600192505b8160000361457357600391505b80158061458257506006548110155b1561458b575060015b61459b565b506001915060039050815b9193909250565b6000806000856001600160a01b031685856040516024016145c492919061548d565b60408051601f198184030181529181526020820180516001600160e01b031663a9059cbb60e01b179052516145f99190615421565b6000604051808303816000865af19150503d8060008114614636576040519150601f19603f3d011682016040523d82523d6000602084013e61463b565b606091505b5091509150818015614665575080511580614665575080806020019051810190614665919061523a565b9695505050505050565b600182600181111561468357614683614b3e565b0361468c575050565b60018160078111156146a0576146a0614b3e565b036146be57604051630f323ed960e11b815260040160405180910390fd5b60028160078111156146d2576146d2614b3e565b036146f05760405163e45e13a360e01b815260040160405180910390fd5b600381600781111561470457614704614b3e565b0361472257604051631d91d0ed60e31b815260040160405180910390fd5b600481600781111561473657614736614b3e565b03614754576040516321f1774b60e11b815260040160405180910390fd5b600581600781111561476857614768614b3e565b036117f057604051630caac6b360e31b815260040160405180910390fd5b60405180608001604052806004906020820280368337509192915050565b82600481019282156147d2579160200282015b828111156147d25782518255916020019190600101906147b7565b506147de92915061481c565b5090565b8280548282559060005260206000209081019282156147d257916020028201828111156147d25782518255916020019190600101906147b7565b5b808211156147de576000815560010161481d565b6001600160a01b0381168114613f9b57600080fd5b60006020828403121561485857600080fd5b813561486381614831565b9392505050565b80356001600160601b038116811461488157600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b03811182821017156148c4576148c4614886565b604052919050565b600082601f8301126148dd57600080fd5b813560206001600160401b038211156148f8576148f8614886565b8160051b61490782820161489c565b928352848101820192828101908785111561492157600080fd5b83870192505b8483101561451057823582529183019190830190614927565b8015158114613f9b57600080fd5b60008060006060848603121561496357600080fd5b61496c8461486a565b925060208401356001600160401b0381111561498757600080fd5b614993868287016148cc565b92505060408401356149a481614940565b809150509250925092565b6001600160a01b0391909116815260200190565b6000602082840312156149d557600080fd5b5035919050565b600080604083850312156149ef57600080fd5b82356149fa81614831565b946020939093013593505050565b600080600060608486031215614a1d57600080fd5b505081359360208301359350604090920135919050565b600060208284031215614a4657600080fd5b6110998261486a565b8060005b6004811015610b0b578151845260209384019390910190600101614a53565b6080810161109c8284614a4f565b600082601f830112614a9157600080fd5b81356001600160401b03811115614aaa57614aaa614886565b614abd601f8201601f191660200161489c565b818152846020838601011115614ad257600080fd5b816020850160208301376000918101602001919091529392505050565b60008060408385031215614b0257600080fd5b8235614b0d81614831565b915060208301356001600160401b03811115614b2857600080fd5b614b3485828601614a80565b9150509250929050565b634e487b7160e01b600052602160045260246000fd5b60058110614b7257634e487b7160e01b600052602160045260246000fd5b9052565b6001600160601b03861681526001600160a01b038516602082015260a08101614ba26040830186614b54565b9215156060820152608001529392505050565b600080600060608486031215614bca57600080fd5b8335614bd581614831565b92506020840135915060408401356001600160401b03811115614bf757600080fd5b614c0386828701614a80565b9150509250925092565b60008060408385031215614c2057600080fd5b6149fa8361486a565b60008060408385031215614c3c57600080fd5b8235614c4781614831565b91506020830135614c5781614940565b809150509250929050565b600080600060608486031215614c7757600080fd5b8335614c8281614831565b925060208401356001600160401b0381168114614c9e57600080fd5b9150604084013560ff811681146149a457600080fd5b600082601f830112614cc557600080fd5b604051608081018181106001600160401b0382111715614ce757614ce7614886565b604052806080840185811115614cfc57600080fd5b845b81811015614d16578035835260209283019201614cfe565b509195945050505050565b6000806000806000806000610140888a031215614d3d57600080fd5b614d468861486a565b96506020880135614d5681614940565b955060408801359450606088013593506080880135925060a08801359150614d818960c08a01614cb4565b905092959891949750929550565b60008060408385031215614da257600080fd5b50508035926020909101359150565b60008151808452602080850194506020840160005b83811015614deb5781516001600160a01b031687529582019590820190600101614dc6565b509495945050505050565b6020815281516020820152602082015160408201526040820151606082015260608201516080820152608082015160a082015260a082015160c0820152600060c08301516101608060e0850152614e51610180850183614db1565b60e08601516101008681019190915286015161012080870191909152860151909250610140614e8a818701836001600160a01b03169052565b959095015193019290925250919050565b60008060408385031215614eae57600080fd5b823591506020830135614c5781614831565b60008060408385031215614ed357600080fd5b8235915060208301356001600160401b03811115614b2857600080fd5b600080600060608486031215614f0557600080fd5b833592506020840135915060408401356001600160401b03811115614bf757600080fd5b600080600080600080600080610160898b031215614f4657600080fd5b614f4f8961486a565b97506020890135614f5f81614940565b965060408901359550606089013594506080890135935060a08901359250614f8a8a60c08b01614cb4565b91506101408901356001600160401b03811115614fa657600080fd5b614fb28b828c016148cc565b9150509295985092959890939650565b60008083601f840112614fd457600080fd5b5081356001600160401b03811115614feb57600080fd5b60208301915083602082850101111561500357600080fd5b9250929050565b60008060006040848603121561501f57600080fd5b83356001600160401b0381111561503557600080fd5b61504186828701614fc2565b90945092505060208401356149a481614831565b60008060008060008060008060006101e08a8c03121561507457600080fd5b893561507f81614831565b985060208a013561508f81614831565b975060408a013561509f81614831565b965060608a01356150af81614831565b955060808a01356150bf81614831565b945060a08a01356150cf81614940565b93506150de8b60c08c01614cb4565b92506150ee8b6101408c01614cb4565b91506101c08a01356150ff81614831565b809150509295985092959850929598565b60008060008060006080868803121561512857600080fd5b8535945060208601356001600160401b0381111561514557600080fd5b61515188828901614fc2565b909550935050604086013561516581614831565b949793965091946060013592915050565b60006020828403121561518857600080fd5b81356001600160401b0381111561519e57600080fd5b612fa784828501614a80565b600080600080608085870312156151c057600080fd5b84356151cb81614831565b93506151d96020860161486a565b92506040850135915060608501356151f081614940565b939692955090935050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b8181038181111561109c5761109c615211565b60006020828403121561524c57600080fd5b815161486381614940565b6020810161109c8284614b54565b600181815b808511156152a057816000190482111561528657615286615211565b8085161561529357918102915b93841c939080029061526a565b509250929050565b6000826152b75750600161109c565b816152c45750600061109c565b81600181146152da57600281146152e457615300565b600191505061109c565b60ff8411156152f5576152f5615211565b50506001821b61109c565b5060208310610133831016604e8410600b8410161715615323575081810a61109c565b61532d8383615265565b806000190482111561534157615341615211565b029392505050565b600061109960ff8416836152a8565b808202811582820484141761109c5761109c615211565b634e487b7160e01b600052601260045260246000fd5b6000826153945761539461536f565b500490565b6000806000606084860312156153ae57600080fd5b8351925060208401516153c081614940565b60408501519092506149a481614940565b8082018082111561109c5761109c615211565b6000602082840312156153f657600080fd5b5051919050565b60005b83811015615418578181015183820152602001615400565b50506000910152565b600082516154338184602087016153fd565b9190910192915050565b600061012082019050871515825286602083015285604083015284606083015283608083015261451060a0830184614a4f565b60006020828403121561548257600080fd5b815161486381614831565b6001600160a01b03929092168252602082015260400190565b84815283602082015260806040820152600083518060808401526154d18160a08501602088016153fd565b606083019390935250601f91909101601f19160160a0019392505050565b60006101408083018a1515845260208a602086015289604086015288606086015287608086015261552360a0860188614a4f565b610120850192909252845190819052610160840191602086019160005b8181101561555c57835185529382019392820192600101615540565b50929c9b505050505050505050505050565b6000600160ff1b820161558357615583615211565b5060000390565b938452602084019290925260408301526001600160a01b0316606082015260800190565b92835260208301919091526001600160a01b0316604082015260600190565b6000826155dc576155dc61536f565b500690565b6000806000606084860312156155f657600080fd5b83519250602084015191506040840151600881106149a457600080fdfe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbca264697066735822122088332e4bd463fd5a2a31ab980f2b2ead694ff8b8a10a33684171a45128537f0a64736f6c63430008180033",
+ "solcInputHash": "d547d738900bce1310e91a5d1adfc179",
+ "metadata": "{\"compiler\":{\"version\":\"0.8.30+commit.73712a01\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"AllJurorsDrawn\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"AlreadyInitialized\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"AppealFeesNotEnough\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"AppealPeriodNotPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ArbitrationFeesNotEnough\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CannotDisableClassicDK\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CommitPeriodNotPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputeKitNotSupportedByCourt\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputeKitOnly\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputeNotAppealable\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputePeriodIsFinal\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputeStillDrawing\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"EvidenceNotPassedAndNotAppeal\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedDelegateCall\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InstructorOnly\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidDisputKitParent\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidForkingCourtAsParent\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"implementation\",\"type\":\"address\"}],\"name\":\"InvalidImplementation\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MinStakeLowerThanParentCourt\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MustSupportDisputeKitClassic\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NoJurorDrawn\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotEvidencePeriod\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotExecutionPeriod\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotInitializing\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OwnerOnly\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OwnerOrInstructorOnly\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RulingAlreadyExecuted\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SortitionModuleOnly\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"StakingInTooManyCourts\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"StakingLessThanCourtMinStake\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"StakingNotPossibleInThisCourt\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"StakingTransferFailed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"StakingZeroWhenNoStake\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TokenNotAccepted\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TransferFailed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UUPSUnauthorizedCallContext\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"slot\",\"type\":\"bytes32\"}],\"name\":\"UUPSUnsupportedProxiableUUID\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnstakingTransferFailed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnsuccessfulCall\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnsupportedDisputeKit\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"VotePeriodNotPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"WrongDisputeKitIndex\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"contract IERC20\",\"name\":\"_token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"bool\",\"name\":\"_accepted\",\"type\":\"bool\"}],\"name\":\"AcceptedFeeToken\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_disputeID\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"contract IArbitrableV2\",\"name\":\"_arbitrable\",\"type\":\"address\"}],\"name\":\"AppealDecision\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_disputeID\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"contract IArbitrableV2\",\"name\":\"_arbitrable\",\"type\":\"address\"}],\"name\":\"AppealPossible\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint96\",\"name\":\"_courtID\",\"type\":\"uint96\"},{\"indexed\":true,\"internalType\":\"uint96\",\"name\":\"_parent\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"_hiddenVotes\",\"type\":\"bool\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_minStake\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_alpha\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_feeForJuror\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_jurorsForCourtJump\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256[4]\",\"name\":\"_timesPerPeriod\",\"type\":\"uint256[4]\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"_supportedDisputeKits\",\"type\":\"uint256[]\"}],\"name\":\"CourtCreated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_disputeID\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_roundID\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint96\",\"name\":\"_fromCourtID\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"_toCourtID\",\"type\":\"uint96\"}],\"name\":\"CourtJump\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint96\",\"name\":\"_courtID\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"_hiddenVotes\",\"type\":\"bool\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_minStake\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_alpha\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_feeForJuror\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_jurorsForCourtJump\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256[4]\",\"name\":\"_timesPerPeriod\",\"type\":\"uint256[4]\"}],\"name\":\"CourtModified\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_disputeID\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"contract IArbitrableV2\",\"name\":\"_arbitrable\",\"type\":\"address\"}],\"name\":\"DisputeCreation\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_disputeKitID\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"contract IDisputeKit\",\"name\":\"_disputeKitAddress\",\"type\":\"address\"}],\"name\":\"DisputeKitCreated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint96\",\"name\":\"_courtID\",\"type\":\"uint96\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_disputeKitID\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"bool\",\"name\":\"_enable\",\"type\":\"bool\"}],\"name\":\"DisputeKitEnabled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_disputeID\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_roundID\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_fromDisputeKitID\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_toDisputeKitID\",\"type\":\"uint256\"}],\"name\":\"DisputeKitJump\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_disputeID\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_roundID\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_voteID\",\"type\":\"uint256\"}],\"name\":\"Draw\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"version\",\"type\":\"uint64\"}],\"name\":\"Initialized\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_disputeID\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_roundID\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_degreeOfCoherencyPnk\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_degreeOfCoherencyFee\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"_amountPnk\",\"type\":\"int256\"},{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"_amountFee\",\"type\":\"int256\"},{\"indexed\":false,\"internalType\":\"contract IERC20\",\"name\":\"_feeToken\",\"type\":\"address\"}],\"name\":\"JurorRewardPenalty\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_disputeID\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_roundID\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amountPnk\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amountFee\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"contract IERC20\",\"name\":\"_feeToken\",\"type\":\"address\"}],\"name\":\"LeftoverRewardSent\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"contract IERC20\",\"name\":\"_feeToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"_rateInEth\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"_rateDecimals\",\"type\":\"uint8\"}],\"name\":\"NewCurrencyRate\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_disputeID\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"enum KlerosCoreUniversity.Period\",\"name\":\"_period\",\"type\":\"uint8\"}],\"name\":\"NewPeriod\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"contract IArbitrableV2\",\"name\":\"_arbitrable\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_disputeID\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_ruling\",\"type\":\"uint256\"}],\"name\":\"Ruling\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newImplementation\",\"type\":\"address\"}],\"name\":\"Upgraded\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"contract IDisputeKit\",\"name\":\"_disputeKitAddress\",\"type\":\"address\"}],\"name\":\"addNewDisputeKit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_disputeID\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_numberOfChoices\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"_extraData\",\"type\":\"bytes\"}],\"name\":\"appeal\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_disputeID\",\"type\":\"uint256\"}],\"name\":\"appealCost\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"cost\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_disputeID\",\"type\":\"uint256\"}],\"name\":\"appealPeriod\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"start\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"end\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_extraData\",\"type\":\"bytes\"},{\"internalType\":\"contract IERC20\",\"name\":\"_feeToken\",\"type\":\"address\"}],\"name\":\"arbitrationCost\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"cost\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_extraData\",\"type\":\"bytes\"}],\"name\":\"arbitrationCost\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"cost\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract IERC20\",\"name\":\"_feeToken\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"_accepted\",\"type\":\"bool\"}],\"name\":\"changeAcceptedFeeTokens\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint96\",\"name\":\"_courtID\",\"type\":\"uint96\"},{\"internalType\":\"bool\",\"name\":\"_hiddenVotes\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"_minStake\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_alpha\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_feeForJuror\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_jurorsForCourtJump\",\"type\":\"uint256\"},{\"internalType\":\"uint256[4]\",\"name\":\"_timesPerPeriod\",\"type\":\"uint256[4]\"}],\"name\":\"changeCourtParameters\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract IERC20\",\"name\":\"_feeToken\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"_rateInEth\",\"type\":\"uint64\"},{\"internalType\":\"uint8\",\"name\":\"_rateDecimals\",\"type\":\"uint8\"}],\"name\":\"changeCurrencyRates\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_instructor\",\"type\":\"address\"}],\"name\":\"changeInstructor\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_jurorProsecutionModule\",\"type\":\"address\"}],\"name\":\"changeJurorProsecutionModule\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address payable\",\"name\":\"_owner\",\"type\":\"address\"}],\"name\":\"changeOwner\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract IERC20\",\"name\":\"_pinakion\",\"type\":\"address\"}],\"name\":\"changePinakion\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract ISortitionModuleUniversity\",\"name\":\"_sortitionModule\",\"type\":\"address\"}],\"name\":\"changeSortitionModule\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract IERC20\",\"name\":\"_toToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amountInEth\",\"type\":\"uint256\"}],\"name\":\"convertEthToTokenAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"courts\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"parent\",\"type\":\"uint96\"},{\"internalType\":\"bool\",\"name\":\"hiddenVotes\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"minStake\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"alpha\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"feeForJuror\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"jurorsForCourtJump\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint96\",\"name\":\"_parent\",\"type\":\"uint96\"},{\"internalType\":\"bool\",\"name\":\"_hiddenVotes\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"_minStake\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_alpha\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_feeForJuror\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_jurorsForCourtJump\",\"type\":\"uint256\"},{\"internalType\":\"uint256[4]\",\"name\":\"_timesPerPeriod\",\"type\":\"uint256[4]\"},{\"internalType\":\"uint256[]\",\"name\":\"_supportedDisputeKits\",\"type\":\"uint256[]\"}],\"name\":\"createCourt\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_numberOfChoices\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"_extraData\",\"type\":\"bytes\"}],\"name\":\"createDispute\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"disputeID\",\"type\":\"uint256\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_numberOfChoices\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"_extraData\",\"type\":\"bytes\"},{\"internalType\":\"contract IERC20\",\"name\":\"_feeToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_feeAmount\",\"type\":\"uint256\"}],\"name\":\"createDispute\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"disputeID\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract IERC20\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"currencyRates\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"feePaymentAccepted\",\"type\":\"bool\"},{\"internalType\":\"uint64\",\"name\":\"rateInEth\",\"type\":\"uint64\"},{\"internalType\":\"uint8\",\"name\":\"rateDecimals\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_disputeID\",\"type\":\"uint256\"}],\"name\":\"currentRuling\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"ruling\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"tied\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"overridden\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"disputeKits\",\"outputs\":[{\"internalType\":\"contract IDisputeKit\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"disputes\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"courtID\",\"type\":\"uint96\"},{\"internalType\":\"contract IArbitrableV2\",\"name\":\"arbitrated\",\"type\":\"address\"},{\"internalType\":\"enum KlerosCoreUniversity.Period\",\"name\":\"period\",\"type\":\"uint8\"},{\"internalType\":\"bool\",\"name\":\"ruled\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"lastPeriodChange\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_disputeID\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_juror\",\"type\":\"address\"}],\"name\":\"draw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint96\",\"name\":\"_courtID\",\"type\":\"uint96\"},{\"internalType\":\"uint256[]\",\"name\":\"_disputeKitIDs\",\"type\":\"uint256[]\"},{\"internalType\":\"bool\",\"name\":\"_enable\",\"type\":\"bool\"}],\"name\":\"enableDisputeKits\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_disputeID\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_round\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_iterations\",\"type\":\"uint256\"}],\"name\":\"execute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_destination\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"executeOwnerProposal\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_disputeID\",\"type\":\"uint256\"}],\"name\":\"executeRuling\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getDisputeKitsLength\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_disputeID\",\"type\":\"uint256\"}],\"name\":\"getNumberOfRounds\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_disputeID\",\"type\":\"uint256\"}],\"name\":\"getNumberOfVotes\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_disputeID\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_round\",\"type\":\"uint256\"}],\"name\":\"getPnkAtStakePerJuror\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_disputeID\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_round\",\"type\":\"uint256\"}],\"name\":\"getRoundInfo\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"disputeKitID\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"pnkAtStakePerJuror\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"totalFeesForJurors\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nbVotes\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repartitions\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"pnkPenalties\",\"type\":\"uint256\"},{\"internalType\":\"address[]\",\"name\":\"drawnJurors\",\"type\":\"address[]\"},{\"internalType\":\"uint96[]\",\"name\":\"drawnJurorFromCourtIDs\",\"type\":\"uint96[]\"},{\"internalType\":\"uint256\",\"name\":\"sumFeeRewardPaid\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"sumPnkRewardPaid\",\"type\":\"uint256\"},{\"internalType\":\"contract IERC20\",\"name\":\"feeToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"drawIterations\",\"type\":\"uint256\"},{\"internalType\":\"uint256[10]\",\"name\":\"__gap\",\"type\":\"uint256[10]\"}],\"internalType\":\"struct KlerosCoreUniversity.Round\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint96\",\"name\":\"_courtID\",\"type\":\"uint96\"}],\"name\":\"getTimesPerPeriod\",\"outputs\":[{\"internalType\":\"uint256[4]\",\"name\":\"timesPerPeriod\",\"type\":\"uint256[4]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_instructor\",\"type\":\"address\"},{\"internalType\":\"contract IERC20\",\"name\":\"_pinakion\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_jurorProsecutionModule\",\"type\":\"address\"},{\"internalType\":\"contract IDisputeKit\",\"name\":\"_disputeKit\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"_hiddenVotes\",\"type\":\"bool\"},{\"internalType\":\"uint256[4]\",\"name\":\"_courtParameters\",\"type\":\"uint256[4]\"},{\"internalType\":\"uint256[4]\",\"name\":\"_timesPerPeriod\",\"type\":\"uint256[4]\"},{\"internalType\":\"contract ISortitionModuleUniversity\",\"name\":\"_sortitionModuleAddress\",\"type\":\"address\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"instructor\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_disputeID\",\"type\":\"uint256\"}],\"name\":\"isDisputeKitJumping\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint96\",\"name\":\"_courtID\",\"type\":\"uint96\"},{\"internalType\":\"uint256\",\"name\":\"_disputeKitID\",\"type\":\"uint256\"}],\"name\":\"isSupported\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"jurorProsecutionModule\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_disputeID\",\"type\":\"uint256\"}],\"name\":\"passPeriod\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pinakion\",\"outputs\":[{\"internalType\":\"contract IERC20\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"proxiableUUID\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint96\",\"name\":\"_courtID\",\"type\":\"uint96\"},{\"internalType\":\"uint256\",\"name\":\"_newStake\",\"type\":\"uint256\"}],\"name\":\"setStake\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_account\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"_courtID\",\"type\":\"uint96\"},{\"internalType\":\"uint256\",\"name\":\"_newStake\",\"type\":\"uint256\"}],\"name\":\"setStakeBySortitionModule\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"sortitionModule\",\"outputs\":[{\"internalType\":\"contract ISortitionModuleUniversity\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_account\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"transferBySortitionModule\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newImplementation\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"upgradeToAndCall\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"version\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"errors\":{\"AlreadyInitialized()\":[{\"details\":\"The contract is already initialized.\"}],\"NotInitializing()\":[{\"details\":\"The contract is not initializing.\"}]},\"events\":{\"AcceptedFeeToken(address,bool)\":{\"params\":{\"_accepted\":\"Whether the token is accepted or not.\",\"_token\":\"The ERC20 token.\"}},\"DisputeCreation(uint256,address)\":{\"params\":{\"_arbitrable\":\"The contract which created the dispute.\",\"_disputeID\":\"The identifier of the dispute in the Arbitrator contract.\"}},\"Initialized(uint64)\":{\"details\":\"Triggered when the contract has been initialized or reinitialized.\"},\"NewCurrencyRate(address,uint64,uint8)\":{\"params\":{\"_feeToken\":\"The ERC20 token.\",\"_rateDecimals\":\"The new decimals of the fee token rate.\",\"_rateInEth\":\"The new rate of the fee token in ETH.\"}},\"Ruling(address,uint256,uint256)\":{\"params\":{\"_arbitrable\":\"The arbitrable receiving the ruling.\",\"_disputeID\":\"The identifier of the dispute in the Arbitrator contract.\",\"_ruling\":\"The ruling which was given.\"}},\"Upgraded(address)\":{\"params\":{\"newImplementation\":\"Address of the new implementation the proxy is now forwarding calls to.\"}}},\"kind\":\"dev\",\"methods\":{\"addNewDisputeKit(address)\":{\"params\":{\"_disputeKitAddress\":\"The address of the dispute kit contract.\"}},\"appeal(uint256,uint256,bytes)\":{\"details\":\"Access restricted to the Dispute Kit for this `disputeID`.\",\"params\":{\"_disputeID\":\"The ID of the dispute.\",\"_extraData\":\"Extradata for the dispute. Can be required during court jump.\",\"_numberOfChoices\":\"Number of choices for the dispute. Can be required during court jump.\"}},\"appealCost(uint256)\":{\"params\":{\"_disputeID\":\"The ID of the dispute.\"},\"returns\":{\"cost\":\"The appeal cost.\"}},\"appealPeriod(uint256)\":{\"params\":{\"_disputeID\":\"The ID of the dispute.\"},\"returns\":{\"end\":\"The end of the appeal period.\",\"start\":\"The start of the appeal period.\"}},\"arbitrationCost(bytes)\":{\"details\":\"It is recommended not to increase it often, as it can be highly time and gas consuming for the arbitrated contracts to cope with fee augmentation.\",\"params\":{\"_extraData\":\"Additional info about the dispute. We use it to pass the ID of the dispute's court (first 32 bytes), the minimum number of jurors required (next 32 bytes) and the ID of the specific dispute kit (last 32 bytes).\"},\"returns\":{\"cost\":\"The arbitration cost in ETH.\"}},\"arbitrationCost(bytes,address)\":{\"details\":\"It is recommended not to increase it often, as it can be highly time and gas consuming for the arbitrated contracts to cope with fee augmentation.\",\"params\":{\"_extraData\":\"Additional info about the dispute. We use it to pass the ID of the dispute's court (first 32 bytes), the minimum number of jurors required (next 32 bytes) and the ID of the specific dispute kit (last 32 bytes).\",\"_feeToken\":\"The ERC20 token used to pay fees.\"},\"returns\":{\"cost\":\"The arbitration cost in `_feeToken`.\"}},\"changeAcceptedFeeTokens(address,bool)\":{\"params\":{\"_accepted\":\"Whether the token is supported or not as a method of fee payment.\",\"_feeToken\":\"The fee token.\"}},\"changeCurrencyRates(address,uint64,uint8)\":{\"params\":{\"_feeToken\":\"The fee token.\",\"_rateDecimals\":\"The new decimals of the fee token rate.\",\"_rateInEth\":\"The new rate of the fee token in ETH.\"}},\"changeInstructor(address)\":{\"params\":{\"_instructor\":\"The new value for the `instructor` storage variable.\"}},\"changeJurorProsecutionModule(address)\":{\"params\":{\"_jurorProsecutionModule\":\"The new value for the `jurorProsecutionModule` storage variable.\"}},\"changeOwner(address)\":{\"params\":{\"_owner\":\"The new value for the `owner` storage variable.\"}},\"changePinakion(address)\":{\"params\":{\"_pinakion\":\"The new value for the `pinakion` storage variable.\"}},\"changeSortitionModule(address)\":{\"params\":{\"_sortitionModule\":\"The new value for the `sortitionModule` storage variable.\"}},\"constructor\":{\"custom:oz-upgrades-unsafe-allow\":\"constructor\"},\"createCourt(uint96,bool,uint256,uint256,uint256,uint256,uint256[4],uint256[])\":{\"params\":{\"_alpha\":\"The `alpha` property value of the court.\",\"_feeForJuror\":\"The `feeForJuror` property value of the court.\",\"_hiddenVotes\":\"The `hiddenVotes` property value of the court.\",\"_jurorsForCourtJump\":\"The `jurorsForCourtJump` property value of the court.\",\"_minStake\":\"The `minStake` property value of the court.\",\"_parent\":\"The `parent` property value of the court.\",\"_supportedDisputeKits\":\"Indexes of dispute kits that this court will support.\",\"_timesPerPeriod\":\"The `timesPerPeriod` property value of the court.\"}},\"createDispute(uint256,bytes)\":{\"details\":\"Must be called by the arbitrable contract and pay at least `arbitrationCost(_extraData)` in ETH.\",\"params\":{\"_extraData\":\"Additional info about the dispute. We use it to pass the ID of the dispute's court (first 32 bytes), the minimum number of jurors required (next 32 bytes) and the ID of the specific dispute kit (last 32 bytes).\",\"_numberOfChoices\":\"The number of choices the arbitrator can choose from in this dispute.\"},\"returns\":{\"disputeID\":\"The identifier of the dispute created.\"}},\"createDispute(uint256,bytes,address,uint256)\":{\"details\":\"Must be called by the arbitrable contract and pay at least `arbitrationCost(_extraData)` in the supported ERC20 token.\",\"params\":{\"_extraData\":\"Additional info about the dispute. We use it to pass the ID of the dispute's court (first 32 bytes), the minimum number of jurors required (next 32 bytes) and the ID of the specific dispute kit (last 32 bytes).\",\"_feeAmount\":\"Amount of the ERC20 token used to pay fees.\",\"_feeToken\":\"The ERC20 token used to pay fees.\",\"_numberOfChoices\":\"The number of choices the arbitrator can choose from in this dispute.\"},\"returns\":{\"disputeID\":\"The identifier of the dispute created.\"}},\"currentRuling(uint256)\":{\"params\":{\"_disputeID\":\"The ID of the dispute.\"},\"returns\":{\"overridden\":\"Whether the ruling was overridden by appeal funding or not.\",\"ruling\":\"The current ruling.\",\"tied\":\"Whether it's a tie or not.\"}},\"draw(uint256,address)\":{\"params\":{\"_disputeID\":\"The ID of the dispute.\",\"_juror\":\"The address of the juror to draw.\"}},\"enableDisputeKits(uint96,uint256[],bool)\":{\"params\":{\"_courtID\":\"The ID of the court.\",\"_disputeKitIDs\":\"The IDs of dispute kits which support should be added/removed.\",\"_enable\":\"Whether add or remove the dispute kits from the court.\"}},\"execute(uint256,uint256,uint256)\":{\"params\":{\"_disputeID\":\"The ID of the dispute.\",\"_iterations\":\"The number of iterations to run.\",\"_round\":\"The appeal round.\"}},\"executeOwnerProposal(address,uint256,bytes)\":{\"params\":{\"_amount\":\"The value sent with the call.\",\"_data\":\"The data sent with the call.\",\"_destination\":\"The destination of the call.\"}},\"executeRuling(uint256)\":{\"params\":{\"_disputeID\":\"The ID of the dispute.\"}},\"getNumberOfRounds(uint256)\":{\"params\":{\"_disputeID\":\"The ID of the dispute.\"},\"returns\":{\"_0\":\"The number of rounds.\"}},\"getNumberOfVotes(uint256)\":{\"params\":{\"_disputeID\":\"The ID of the dispute.\"}},\"getPnkAtStakePerJuror(uint256,uint256)\":{\"params\":{\"_disputeID\":\"The ID of the dispute.\",\"_round\":\"The round to get the info for.\"},\"returns\":{\"_0\":\"pnkAtStakePerJuror The PNK at stake per juror.\"}},\"getRoundInfo(uint256,uint256)\":{\"details\":\"This function must not be called from a non-view function because it returns a dynamic array which might be very large, theoretically exceeding the block gas limit.\",\"params\":{\"_disputeID\":\"The ID of the dispute.\",\"_round\":\"The round to get the info for.\"},\"returns\":{\"_0\":\"round The round info.\"}},\"getTimesPerPeriod(uint96)\":{\"params\":{\"_courtID\":\"The ID of the court to get the times from.\"},\"returns\":{\"timesPerPeriod\":\"The timesPerPeriod array for the given court.\"}},\"initialize(address,address,address,address,address,bool,uint256[4],uint256[4],address)\":{\"params\":{\"_courtParameters\":\"Numeric parameters of General court (minStake, alpha, feeForJuror and jurorsForCourtJump respectively).\",\"_disputeKit\":\"The address of the default dispute kit.\",\"_hiddenVotes\":\"The `hiddenVotes` property value of the general court.\",\"_instructor\":\"The address of the instructor.\",\"_jurorProsecutionModule\":\"The address of the juror prosecution module.\",\"_owner\":\"The owner's address.\",\"_pinakion\":\"The address of the token contract.\",\"_sortitionModuleAddress\":\"The sortition module responsible for sortition of the jurors.\",\"_timesPerPeriod\":\"The `timesPerPeriod` property value of the general court.\"}},\"isDisputeKitJumping(uint256)\":{\"params\":{\"_disputeID\":\"The ID of the dispute.\"},\"returns\":{\"_0\":\"Whether DK will be switched or not.\"}},\"isSupported(uint96,uint256)\":{\"params\":{\"_courtID\":\"The ID of the court to check the support for.\",\"_disputeKitID\":\"The ID of the dispute kit to check the support for.\"},\"returns\":{\"_0\":\"Whether the dispute kit is supported or not.\"}},\"passPeriod(uint256)\":{\"params\":{\"_disputeID\":\"The ID of the dispute.\"}},\"proxiableUUID()\":{\"details\":\"IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this function revert if invoked through a proxy. This is guaranteed by the if statement.\"},\"setStake(uint96,uint256)\":{\"params\":{\"_courtID\":\"The ID of the court.\",\"_newStake\":\"The new stake. Note that the existing delayed stake will be nullified as non-relevant.\"}},\"setStakeBySortitionModule(address,uint96,uint256)\":{\"params\":{\"_account\":\"The account whose stake is being set.\",\"_courtID\":\"The ID of the court.\",\"_newStake\":\"The new stake.\"}},\"transferBySortitionModule(address,uint256)\":{\"params\":{\"_account\":\"The account of the juror whose PNK to transfer.\",\"_amount\":\"The amount to transfer.\"}},\"upgradeToAndCall(address,bytes)\":{\"details\":\"Reverts if the execution is not performed via delegatecall or the execution context is not of a proxy with an ERC1967-compliant implementation pointing to self.\",\"params\":{\"data\":\"Data used in a delegate call to `newImplementation` if non-empty. This will typically be an encoded function call, and allows initializing the storage of the proxy like a Solidity constructor.\",\"newImplementation\":\"Address of the new implementation contract.\"}}},\"stateVariables\":{\"version\":{\"return\":\"Version string.\",\"returns\":{\"_0\":\"Version string.\"}}},\"title\":\"KlerosCoreUniversity\",\"version\":1},\"userdoc\":{\"errors\":{\"FailedDelegateCall()\":[{\"notice\":\"Failed Delegated call\"}],\"InvalidImplementation(address)\":[{\"notice\":\"The `implementation` is not UUPS-compliant\"}],\"UUPSUnauthorizedCallContext()\":[{\"notice\":\"The call is from an unauthorized context.\"}],\"UUPSUnsupportedProxiableUUID(bytes32)\":[{\"notice\":\"The storage `slot` is unsupported as a UUID.\"}]},\"events\":{\"AcceptedFeeToken(address,bool)\":{\"notice\":\"To be emitted when an ERC20 token is added or removed as a method to pay fees.\"},\"DisputeCreation(uint256,address)\":{\"notice\":\"To be emitted when a dispute is created.\"},\"NewCurrencyRate(address,uint64,uint8)\":{\"notice\":\"To be emitted when the fee for a particular ERC20 token is updated.\"},\"Ruling(address,uint256,uint256)\":{\"notice\":\"To be raised when a ruling is given.\"},\"Upgraded(address)\":{\"notice\":\"Emitted when the `implementation` has been successfully upgraded.\"}},\"kind\":\"user\",\"methods\":{\"addNewDisputeKit(address)\":{\"notice\":\"Add a new supported dispute kit module to the court.\"},\"appeal(uint256,uint256,bytes)\":{\"notice\":\"Appeals the ruling of a specified dispute.\"},\"appealCost(uint256)\":{\"notice\":\"Gets the cost of appealing a specified dispute.\"},\"appealPeriod(uint256)\":{\"notice\":\"Gets the start and the end of a specified dispute's current appeal period.\"},\"arbitrationCost(bytes)\":{\"notice\":\"Compute the cost of arbitration denominated in the native currency, typically ETH.\"},\"arbitrationCost(bytes,address)\":{\"notice\":\"Compute the cost of arbitration denominated in `_feeToken`.\"},\"changeAcceptedFeeTokens(address,bool)\":{\"notice\":\"Changes the supported fee tokens.\"},\"changeCurrencyRates(address,uint64,uint8)\":{\"notice\":\"Changes the currency rate of a fee token.\"},\"changeInstructor(address)\":{\"notice\":\"Changes the `instructor` storage variable.\"},\"changeJurorProsecutionModule(address)\":{\"notice\":\"Changes the `jurorProsecutionModule` storage variable.\"},\"changeOwner(address)\":{\"notice\":\"Changes the `owner` storage variable.\"},\"changePinakion(address)\":{\"notice\":\"Changes the `pinakion` storage variable.\"},\"changeSortitionModule(address)\":{\"notice\":\"Changes the `_sortitionModule` storage variable. Note that the new module should be initialized for all courts.\"},\"createCourt(uint96,bool,uint256,uint256,uint256,uint256,uint256[4],uint256[])\":{\"notice\":\"Creates a court under a specified parent court.\"},\"createDispute(uint256,bytes)\":{\"notice\":\"Create a dispute and pay for the fees in the native currency, typically ETH.\"},\"createDispute(uint256,bytes,address,uint256)\":{\"notice\":\"Create a dispute and pay for the fees in a supported ERC20 token.\"},\"currentRuling(uint256)\":{\"notice\":\"Gets the current ruling of a specified dispute.\"},\"draw(uint256,address)\":{\"notice\":\"Draws one juror for the dispute until the number votes paid for is reached.\"},\"enableDisputeKits(uint96,uint256[],bool)\":{\"notice\":\"Adds/removes court's support for specified dispute kits.\"},\"execute(uint256,uint256,uint256)\":{\"notice\":\"Distribute the PNKs at stake and the dispute fees for the specific round of the dispute. Can be called in parts.\"},\"executeOwnerProposal(address,uint256,bytes)\":{\"notice\":\"Allows the owner to call anything on behalf of the contract.\"},\"executeRuling(uint256)\":{\"notice\":\"Executes a specified dispute's ruling.\"},\"getNumberOfRounds(uint256)\":{\"notice\":\"Gets the number of rounds for a specified dispute.\"},\"getNumberOfVotes(uint256)\":{\"notice\":\"Gets the number of votes permitted for the specified dispute in the latest round.\"},\"getPnkAtStakePerJuror(uint256,uint256)\":{\"notice\":\"Gets the PNK at stake per juror for a specified dispute and round.\"},\"getRoundInfo(uint256,uint256)\":{\"notice\":\"Gets the round info for a specified dispute and round.\"},\"getTimesPerPeriod(uint96)\":{\"notice\":\"Gets the timesPerPeriod array for a given court.\"},\"initialize(address,address,address,address,address,bool,uint256[4],uint256[4],address)\":{\"notice\":\"Initializer (constructor equivalent for upgradable contracts).\"},\"isDisputeKitJumping(uint256)\":{\"notice\":\"Returns true if the dispute kit will be switched to a parent DK.\"},\"isSupported(uint96,uint256)\":{\"notice\":\"Checks if a given dispute kit is supported by a given court.\"},\"passPeriod(uint256)\":{\"notice\":\"Passes the period of a specified dispute.\"},\"proxiableUUID()\":{\"notice\":\"Implementation of the ERC1822 `proxiableUUID` function. This returns the storage slot used by the implementation. It is used to validate the implementation's compatibility when performing an upgrade.\"},\"setStake(uint96,uint256)\":{\"notice\":\"Sets the caller's stake in a court.\"},\"setStakeBySortitionModule(address,uint96,uint256)\":{\"notice\":\"Sets the stake of a specified account in a court, typically to apply a delayed stake or unstake inactive jurors.\"},\"transferBySortitionModule(address,uint256)\":{\"notice\":\"Transfers PNK to the juror by SortitionModule.\"},\"upgradeToAndCall(address,bytes)\":{\"notice\":\"Upgrade mechanism including access control and UUPS-compliance.\"},\"version()\":{\"notice\":\"Returns the version of the implementation.\"}},\"notice\":\"Core arbitrator contract for educational purposes.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/arbitration/university/KlerosCoreUniversity.sol\":\"KlerosCoreUniversity\"},\"evmVersion\":\"cancun\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000},\"remappings\":[],\"viaIR\":true},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity >=0.4.16;\\n\\n/**\\n * @dev Interface of the ERC-20 standard as defined in the ERC.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n\\n /**\\n * @dev Returns the value of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the value of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 value) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\\n * caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 value) external returns (bool);\\n\\n /**\\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\\n * allowance mechanism. `value` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(address from, address to, uint256 value) external returns (bool);\\n}\\n\",\"keccak256\":\"0x74ed01eb66b923d0d0cfe3be84604ac04b76482a55f9dd655e1ef4d367f95bc2\",\"license\":\"MIT\"},\"src/arbitration/interfaces/IArbitrableV2.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity >=0.8.0 <0.9.0;\\n\\nimport \\\"./IArbitratorV2.sol\\\";\\n\\n/// @title IArbitrableV2\\n/// @notice Arbitrable interface.\\n/// @dev When developing arbitrable contracts, we need to:\\n/// - Define the action taken when a ruling is received by the contract.\\n/// - Allow dispute creation which calls `arbitrator.createDispute{value: _fee}(_choices,_extraData)`.\\ninterface IArbitrableV2 {\\n // ************************************* //\\n // * Events * //\\n // ************************************* //\\n\\n /// @notice To be emitted when a dispute is created to link the correct template to the disputeID.\\n /// @param _arbitrator The arbitrator of the contract.\\n /// @param _arbitratorDisputeID The identifier of the dispute in the Arbitrator contract.\\n /// @param _externalDisputeID An identifier created outside Kleros by the protocol requesting arbitration.\\n /// @param _templateId The identifier of the dispute template.\\n event DisputeRequest(\\n IArbitratorV2 indexed _arbitrator,\\n uint256 indexed _arbitratorDisputeID,\\n uint256 _externalDisputeID,\\n uint256 _templateId\\n );\\n\\n /// @notice To be raised when a ruling is given.\\n /// @param _arbitrator The arbitrator giving the ruling.\\n /// @param _disputeID The identifier of the dispute in the Arbitrator contract.\\n /// @param _ruling The ruling which was given.\\n event Ruling(IArbitratorV2 indexed _arbitrator, uint256 indexed _disputeID, uint256 _ruling);\\n\\n // ************************************* //\\n // * State Modifiers * //\\n // ************************************* //\\n\\n /// @notice Give a ruling for a dispute.\\n ///\\n /// @dev This is a callback function for the arbitrator to provide the ruling to this contract.\\n /// Only the arbitrator must be allowed to call this function.\\n /// Ruling 0 is reserved for \\\"Not able/wanting to make a decision\\\".\\n ///\\n /// @param _disputeID The identifier of the dispute in the Arbitrator contract.\\n /// @param _ruling Ruling given by the arbitrator.\\n function rule(uint256 _disputeID, uint256 _ruling) external;\\n}\\n\",\"keccak256\":\"0x3afa29a93847399c8705103350b69bb70706b2075ca41b39d523b007e69e23db\",\"license\":\"MIT\"},\"src/arbitration/interfaces/IArbitratorV2.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity >=0.8.0 <0.9.0;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"./IArbitrableV2.sol\\\";\\n\\n/// @title Arbitrator\\n/// @notice Arbitrator interface for the Kleros V2 protocol.\\n/// @dev Unlike the ERC-792 this standard is not concerned with appeals, so each arbitrator can implement an appeal system that suits it the most.\\ninterface IArbitratorV2 {\\n // ************************************* //\\n // * Events * //\\n // ************************************* //\\n\\n /// @notice To be emitted when a dispute is created.\\n /// @param _disputeID The identifier of the dispute in the Arbitrator contract.\\n /// @param _arbitrable The contract which created the dispute.\\n event DisputeCreation(uint256 indexed _disputeID, IArbitrableV2 indexed _arbitrable);\\n\\n /// @notice To be raised when a ruling is given.\\n /// @param _arbitrable The arbitrable receiving the ruling.\\n /// @param _disputeID The identifier of the dispute in the Arbitrator contract.\\n /// @param _ruling The ruling which was given.\\n event Ruling(IArbitrableV2 indexed _arbitrable, uint256 indexed _disputeID, uint256 _ruling);\\n\\n /// @notice To be emitted when an ERC20 token is added or removed as a method to pay fees.\\n /// @param _token The ERC20 token.\\n /// @param _accepted Whether the token is accepted or not.\\n event AcceptedFeeToken(IERC20 indexed _token, bool indexed _accepted);\\n\\n /// @notice To be emitted when the fee for a particular ERC20 token is updated.\\n /// @param _feeToken The ERC20 token.\\n /// @param _rateInEth The new rate of the fee token in ETH.\\n /// @param _rateDecimals The new decimals of the fee token rate.\\n event NewCurrencyRate(IERC20 indexed _feeToken, uint64 _rateInEth, uint8 _rateDecimals);\\n\\n // ************************************* //\\n // * State Modifiers * //\\n // ************************************* //\\n\\n /// @notice Create a dispute and pay for the fees in the native currency, typically ETH.\\n /// @dev Must be called by the arbitrable contract and pay at least `arbitrationCost(_extraData)` in ETH.\\n /// @param _numberOfChoices The number of choices the arbitrator can choose from in this dispute.\\n /// @param _extraData Additional info about the dispute. We use it to pass the ID of the dispute's court (first 32 bytes), the minimum number of jurors required (next 32 bytes) and the ID of the specific dispute kit (last 32 bytes).\\n /// @return disputeID The identifier of the dispute created.\\n function createDispute(\\n uint256 _numberOfChoices,\\n bytes calldata _extraData\\n ) external payable returns (uint256 disputeID);\\n\\n /// @notice Create a dispute and pay for the fees in a supported ERC20 token.\\n /// @dev Must be called by the arbitrable contract and pay at least `arbitrationCost(_extraData)` in the supported ERC20 token.\\n /// @param _numberOfChoices The number of choices the arbitrator can choose from in this dispute.\\n /// @param _extraData Additional info about the dispute. We use it to pass the ID of the dispute's court (first 32 bytes), the minimum number of jurors required (next 32 bytes) and the ID of the specific dispute kit (last 32 bytes).\\n /// @param _feeToken The ERC20 token used to pay fees.\\n /// @param _feeAmount Amount of the ERC20 token used to pay fees.\\n /// @return disputeID The identifier of the dispute created.\\n function createDispute(\\n uint256 _numberOfChoices,\\n bytes calldata _extraData,\\n IERC20 _feeToken,\\n uint256 _feeAmount\\n ) external returns (uint256 disputeID);\\n\\n // ************************************* //\\n // * Public Views * //\\n // ************************************* //\\n\\n /// @notice Compute the cost of arbitration denominated in the native currency, typically ETH.\\n /// @dev It is recommended not to increase it often, as it can be highly time and gas consuming for the arbitrated contracts to cope with fee augmentation.\\n /// @param _extraData Additional info about the dispute. We use it to pass the ID of the dispute's court (first 32 bytes), the minimum number of jurors required (next 32 bytes) and the ID of the specific dispute kit (last 32 bytes).\\n /// @return cost The arbitration cost in ETH.\\n function arbitrationCost(bytes calldata _extraData) external view returns (uint256 cost);\\n\\n /// @notice Compute the cost of arbitration denominated in `_feeToken`.\\n /// @dev It is recommended not to increase it often, as it can be highly time and gas consuming for the arbitrated contracts to cope with fee augmentation.\\n /// @param _extraData Additional info about the dispute. We use it to pass the ID of the dispute's court (first 32 bytes), the minimum number of jurors required (next 32 bytes) and the ID of the specific dispute kit (last 32 bytes).\\n /// @param _feeToken The ERC20 token used to pay fees.\\n /// @return cost The arbitration cost in `_feeToken`.\\n function arbitrationCost(bytes calldata _extraData, IERC20 _feeToken) external view returns (uint256 cost);\\n\\n /// @notice Gets the current ruling of a specified dispute.\\n /// @param _disputeID The ID of the dispute.\\n /// @return ruling The current ruling.\\n /// @return tied Whether it's a tie or not.\\n /// @return overridden Whether the ruling was overridden by appeal funding or not.\\n function currentRuling(uint256 _disputeID) external view returns (uint256 ruling, bool tied, bool overridden);\\n}\\n\",\"keccak256\":\"0x65ba87c5309cd6e6562e569f79778ca423c9be7b0a44b9407e5bd2bdf8fdc3b0\",\"license\":\"MIT\"},\"src/arbitration/interfaces/IDisputeKit.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity >=0.8.0 <0.9.0;\\n\\nimport \\\"./IArbitratorV2.sol\\\";\\n\\n/// @title IDisputeKit\\n/// @notice An abstraction of the Dispute Kits intended for interfacing with KlerosCore.\\n/// @dev It does not intend to abstract the interactions with the user (such as voting or appeal funding) to allow for implementation-specific parameters.\\ninterface IDisputeKit {\\n // ************************************ //\\n // * Events * //\\n // ************************************ //\\n\\n /// @notice Emitted when casting a vote to provide the justification of juror's choice.\\n /// @param _coreDisputeID The identifier of the dispute in the Arbitrator contract.\\n /// @param _juror Address of the juror.\\n /// @param _voteIDs The identifiers of the votes in the dispute.\\n /// @param _choice The choice juror voted for.\\n /// @param _justification Justification of the choice.\\n event VoteCast(\\n uint256 indexed _coreDisputeID,\\n address indexed _juror,\\n uint256[] _voteIDs,\\n uint256 indexed _choice,\\n string _justification\\n );\\n\\n // ************************************* //\\n // * State Modifiers * //\\n // ************************************* //\\n\\n /// @notice Creates a local dispute and maps it to the dispute ID in the Core contract.\\n /// @dev Access restricted to Kleros Core only.\\n /// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.\\n /// @param _numberOfChoices Number of choices of the dispute\\n /// @param _extraData Additional info about the dispute, for possible use in future dispute kits.\\n /// @param _nbVotes Maximal number of votes this dispute can get. Added for future-proofing.\\n function createDispute(\\n uint256 _coreDisputeID,\\n uint256 _numberOfChoices,\\n bytes calldata _extraData,\\n uint256 _nbVotes\\n ) external;\\n\\n /// @notice Draws the juror from the sortition tree. The drawn address is picked up by Kleros Core.\\n /// @dev Access restricted to Kleros Core only.\\n /// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.\\n /// @param _nonce Nonce.\\n /// @return drawnAddress The drawn address.\\n function draw(\\n uint256 _coreDisputeID,\\n uint256 _nonce\\n ) external returns (address drawnAddress, uint96 fromSubcourtID);\\n\\n // ************************************* //\\n // * Public Views * //\\n // ************************************* //\\n\\n /// @notice Gets the current ruling of a specified dispute.\\n /// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.\\n /// @return ruling The current ruling.\\n /// @return tied Whether it's a tie or not.\\n /// @return overridden Whether the ruling was overridden by appeal funding or not.\\n function currentRuling(uint256 _coreDisputeID) external view returns (uint256 ruling, bool tied, bool overridden);\\n\\n /// @notice Gets the degree of coherence of a particular voter.\\n /// @dev This function is called by Kleros Core in order to determine the amount of the reward.\\n /// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.\\n /// @param _coreRoundID The ID of the round in Kleros Core, not in the Dispute Kit.\\n /// @param _voteID The ID of the vote.\\n /// @param _feePerJuror The fee per juror.\\n /// @param _pnkAtStakePerJuror The PNK at stake per juror.\\n /// @return pnkCoherence The degree of coherence in basis points for the dispute PNK reward.\\n /// @return feeCoherence The degree of coherence in basis points for the dispute fee reward.\\n function getDegreeOfCoherenceReward(\\n uint256 _coreDisputeID,\\n uint256 _coreRoundID,\\n uint256 _voteID,\\n uint256 _feePerJuror,\\n uint256 _pnkAtStakePerJuror\\n ) external view returns (uint256 pnkCoherence, uint256 feeCoherence);\\n\\n /// @notice Gets the degree of coherence of a particular voter.\\n /// @dev This function is called by Kleros Core in order to determine the amount of the penalty.\\n /// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.\\n /// @param _coreRoundID The ID of the round in Kleros Core, not in the Dispute Kit.\\n /// @param _voteID The ID of the vote.\\n /// @param _feePerJuror The fee per juror.\\n /// @param _pnkAtStakePerJuror The PNK at stake per juror.\\n /// @return pnkCoherence The degree of coherence in basis points for the dispute PNK reward.\\n function getDegreeOfCoherencePenalty(\\n uint256 _coreDisputeID,\\n uint256 _coreRoundID,\\n uint256 _voteID,\\n uint256 _feePerJuror,\\n uint256 _pnkAtStakePerJuror\\n ) external view returns (uint256 pnkCoherence);\\n\\n /// @notice Gets the number of jurors who are eligible to a reward in this round.\\n /// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.\\n /// @param _coreRoundID The ID of the round in Kleros Core, not in the Dispute Kit.\\n /// @return The number of coherent jurors.\\n function getCoherentCount(uint256 _coreDisputeID, uint256 _coreRoundID) external view returns (uint256);\\n\\n /// @notice Returns true if all of the jurors have cast their commits for the last round.\\n /// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.\\n /// @return Whether all of the jurors have cast their commits for the last round.\\n function areCommitsAllCast(uint256 _coreDisputeID) external view returns (bool);\\n\\n /// @notice Returns true if all of the jurors have cast their votes for the last round.\\n /// @dev This function is to be called directly by the core contract and is not for off-chain usage.\\n /// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.\\n /// @return Whether all of the jurors have cast their votes for the last round.\\n function areVotesAllCast(uint256 _coreDisputeID) external view returns (bool);\\n\\n /// @notice Returns true if the appeal funding is finished prematurely (e.g. when losing side didn't fund).\\n /// @dev This function is to be called directly by the core contract and is not for off-chain usage.\\n /// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.\\n /// @return Whether the appeal funding is finished.\\n function isAppealFunded(uint256 _coreDisputeID) external view returns (bool);\\n\\n /// @dev Returns true if the dispute is jumping to a parent court.\\n /// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.\\n /// @return Whether the dispute is jumping to a parent court or not.\\n function earlyCourtJump(uint256 _coreDisputeID) external view returns (bool);\\n\\n /// @notice Returns the number of votes after the appeal.\\n /// @param _previousDisputeKit The previous Dispute Kit.\\n /// @param _currentNbVotes The number of votes before the appeal.\\n /// @return The number of votes after the appeal.\\n function getNbVotesAfterAppeal(\\n IDisputeKit _previousDisputeKit,\\n uint256 _currentNbVotes\\n ) external view returns (uint256);\\n\\n /// @notice Returns the dispute kit ID to be used after court jump by Kleros Core.\\n /// @return The ID of the dispute kit in Kleros Core disputeKits array.\\n function getJumpDisputeKitID() external view returns (uint256);\\n\\n /// @notice Returns true if the specified voter was active in this round.\\n /// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.\\n /// @param _coreRoundID The ID of the round in Kleros Core, not in the Dispute Kit.\\n /// @param _voteID The ID of the voter.\\n /// @return Whether the voter was active or not.\\n function isVoteActive(uint256 _coreDisputeID, uint256 _coreRoundID, uint256 _voteID) external view returns (bool);\\n\\n /// @notice Returns the info of the specified round in the core contract.\\n /// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.\\n /// @param _coreRoundID The ID of the round in Kleros Core, not in the Dispute Kit.\\n /// @param _choice The choice to query.\\n /// @return winningChoice The winning choice of this round.\\n /// @return tied Whether it's a tie or not.\\n /// @return totalVoted Number of jurors who cast the vote already.\\n /// @return totalCommited Number of jurors who cast the commit already (only relevant for hidden votes).\\n /// @return nbVoters Total number of voters in this round.\\n /// @return choiceCount Number of votes cast for the queried choice.\\n function getRoundInfo(\\n uint256 _coreDisputeID,\\n uint256 _coreRoundID,\\n uint256 _choice\\n )\\n external\\n view\\n returns (\\n uint256 winningChoice,\\n bool tied,\\n uint256 totalVoted,\\n uint256 totalCommited,\\n uint256 nbVoters,\\n uint256 choiceCount\\n );\\n\\n /// @notice Returns the vote information for a given vote ID.\\n /// @param _coreDisputeID The ID of the dispute in Kleros Core.\\n /// @param _coreRoundID The ID of the round in Kleros Core.\\n /// @param _voteID The ID of the vote.\\n /// @return account The address of the juror who cast the vote.\\n /// @return commit The commit of the vote.\\n /// @return choice The choice that got the vote.\\n /// @return voted Whether the vote was cast or not.\\n function getVoteInfo(\\n uint256 _coreDisputeID,\\n uint256 _coreRoundID,\\n uint256 _voteID\\n ) external view returns (address account, bytes32 commit, uint256 choice, bool voted);\\n}\\n\",\"keccak256\":\"0x1f12d2574dffd9bf83cf33a54aa4abbbfa4203251a0f962edd8e5c3b370408bc\",\"license\":\"MIT\"},\"src/arbitration/interfaces/ISortitionModule.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity >=0.8.0 <0.9.0;\\n\\nimport \\\"../../libraries/Constants.sol\\\";\\n\\n/// @title ISortitionModule\\n/// @notice Interface for the SortitionModule contract.\\ninterface ISortitionModule {\\n // ************************************* //\\n // * Enums * //\\n // ************************************* //\\n\\n enum Phase {\\n staking, // Stake sum trees can be updated. Pass after `minStakingTime` passes and there is at least one dispute without jurors.\\n generating, // Waiting for a random number. Pass as soon as it is ready.\\n drawing // Jurors can be drawn. Pass after all disputes have jurors or `maxDrawingTime` passes.\\n }\\n\\n // ************************************* //\\n // * Events * //\\n // ************************************* //\\n\\n /// @notice Emitted when the phase is changed.\\n /// @param _phase The new phase.\\n event NewPhase(Phase _phase);\\n\\n // ************************************* //\\n // * State Modifiers * //\\n // ************************************* //\\n\\n /// @notice Passes the phase.\\n function passPhase() external;\\n\\n /// @notice Executes the next delayed stakes.\\n /// @param _iterations The number of delayed stakes to execute.\\n function executeDelayedStakes(uint256 _iterations) external;\\n\\n /// @notice Create a sortition sum tree at the specified key.\\n /// @param _courtID The ID of the court.\\n /// @param _extraData Extra data that contains the number of children each node in the tree should have.\\n function createTree(uint96 _courtID, bytes memory _extraData) external;\\n\\n /// @notice Validate the specified juror's new stake for a court.\\n /// @dev No state changes should be made when returning stakingResult != Successful, otherwise delayed stakes might break invariants.\\n /// @param _account The address of the juror.\\n /// @param _courtID The ID of the court.\\n /// @param _newStake The new stake.\\n /// @param _noDelay True if the stake change should not be delayed.\\n /// @return pnkDeposit The amount of PNK to be deposited.\\n /// @return pnkWithdrawal The amount of PNK to be withdrawn.\\n /// @return stakingResult The result of the staking operation.\\n function validateStake(\\n address _account,\\n uint96 _courtID,\\n uint256 _newStake,\\n bool _noDelay\\n ) external returns (uint256 pnkDeposit, uint256 pnkWithdrawal, StakingResult stakingResult);\\n\\n /// @notice Update the state of the stakes, called by KC at the end of setStake flow.\\n ///\\n /// @dev `O(n + p * log_k(j))` where\\n /// `n` is the number of courts the juror has staked in,\\n /// `p` is the depth of the court tree,\\n /// `k` is the minimum number of children per node of one of these courts' sortition sum tree,\\n /// and `j` is the maximum number of jurors that ever staked in one of these courts simultaneously.\\n ///\\n /// @param _account The address of the juror.\\n /// @param _courtID The ID of the court.\\n /// @param _pnkDeposit The amount of PNK to be deposited.\\n /// @param _pnkWithdrawal The amount of PNK to be withdrawn.\\n /// @param _newStake The new stake.\\n function setStake(\\n address _account,\\n uint96 _courtID,\\n uint256 _pnkDeposit,\\n uint256 _pnkWithdrawal,\\n uint256 _newStake\\n ) external;\\n\\n /// @notice Update the state of the stakes with a PNK reward deposit, called by KC during rewards execution.\\n ///\\n /// @dev `O(n + p * log_k(j))` where\\n /// `n` is the number of courts the juror has staked in,\\n /// `p` is the depth of the court tree,\\n /// `k` is the minimum number of children per node of one of these courts' sortition sum tree,\\n /// and `j` is the maximum number of jurors that ever staked in one of these courts simultaneously.\\n ///\\n /// @param _account The address of the juror.\\n /// @param _courtID The ID of the court.\\n /// @param _penalty The amount of PNK to be deducted.\\n /// @return pnkBalance The updated total PNK balance of the juror, including the penalty.\\n /// @return newCourtStake The updated stake of the juror in the court.\\n /// @return availablePenalty The amount of PNK that was actually deducted.\\n function setStakePenalty(\\n address _account,\\n uint96 _courtID,\\n uint256 _penalty\\n ) external returns (uint256 pnkBalance, uint256 newCourtStake, uint256 availablePenalty);\\n\\n /// @notice Update the state of the stakes with a PNK reward deposit, called by KC during rewards execution.\\n ///\\n /// @dev `O(n + p * log_k(j))` where\\n /// `O(n + p * log_k(j))` where\\n /// `n` is the number of courts the juror has staked in,\\n /// `p` is the depth of the court tree,\\n /// `k` is the minimum number of children per node of one of these courts' sortition sum tree,\\n /// and `j` is the maximum number of jurors that ever staked in one of these courts simultaneously.\\n ///\\n /// @param _account The address of the juror.\\n /// @param _courtID The ID of the court.\\n /// @param _reward The amount of PNK to be deposited as a reward.\\n /// @return success True if the reward was added successfully.\\n function setStakeReward(address _account, uint96 _courtID, uint256 _reward) external returns (bool success);\\n\\n /// @notice Unstakes the inactive juror from all courts.\\n ///\\n /// @dev `O(n * (p * log_k(j)) )` where\\n /// `O(n * (p * log_k(j)) )` where\\n /// `n` is the number of courts the juror has staked in,\\n /// `p` is the depth of the court tree,\\n /// `k` is the minimum number of children per node of one of these courts' sortition sum tree,\\n /// and `j` is the maximum number of jurors that ever staked in one of these courts simultaneously.\\n ///\\n /// @param _account The juror to unstake.\\n function forcedUnstakeAllCourts(address _account) external;\\n\\n /// @notice Unstakes the inactive juror from a specific court.\\n ///\\n /// @dev `O(n * (p * log_k(j)) )` where\\n /// `n` is the number of courts the juror has staked in,\\n /// `p` is the depth of the court tree,\\n /// `k` is the minimum number of children per node of one of these courts' sortition sum tree,\\n /// and `j` is the maximum number of jurors that ever staked in one of these courts simultaneously.\\n ///\\n /// @param _account The juror to unstake.\\n /// @param _courtID The ID of the court.\\n function forcedUnstake(address _account, uint96 _courtID) external;\\n\\n /// @notice Locks the tokens of the drawn juror.\\n /// @param _account The address of the juror.\\n /// @param _relativeAmount The amount to lock.\\n function lockStake(address _account, uint256 _relativeAmount) external;\\n\\n /// @notice Unlocks the tokens of the drawn juror.\\n /// @param _account The address of the juror.\\n /// @param _relativeAmount The amount to unlock.\\n function unlockStake(address _account, uint256 _relativeAmount) external;\\n\\n /// @notice Triggers the state changes after dispute creation.\\n /// @param _disputeID The ID of the dispute.\\n /// @param _roundID The ID of the round.\\n function createDisputeHook(uint256 _disputeID, uint256 _roundID) external;\\n\\n /// @notice Triggers the state changes after drawing.\\n /// @param _disputeID The ID of the dispute.\\n /// @param _roundID The ID of the round.\\n function postDrawHook(uint256 _disputeID, uint256 _roundID) external;\\n\\n /// @notice Gives back the locked PNKs in case the juror fully unstaked earlier.\\n ///\\n /// @dev that since locked and staked PNK are async it is possible for the juror to have positive staked PNK balance\\n /// while having 0 stake in courts and 0 locked tokens (eg. when the juror fully unstaked during dispute and later got his tokens unlocked).\\n /// In this case the juror can use this function to withdraw the leftover tokens.\\n /// Also note that if the juror has some leftover PNK while not fully unstaked he'll have to manually unstake from all courts to trigger this function.\\n ///\\n /// @param _account The juror whose PNK to withdraw.\\n function withdrawLeftoverPNK(address _account) external;\\n\\n // ************************************* //\\n // * Public Views * //\\n // ************************************* //\\n\\n /// @notice Draw an ID from a tree using a number.\\n ///\\n /// @dev that this function reverts if the sum of all values in the tree is 0.\\n /// `O(k * log_k(n))` where\\n /// `k` is the maximum number of children per node in the tree,\\n /// and `n` is the maximum number of nodes ever appended.\\n ///\\n /// @param _courtID The ID of the court.\\n /// @param _coreDisputeID Index of the dispute in Kleros Core.\\n /// @param _nonce Nonce to hash with random number.\\n /// @return drawnAddress The drawn address.\\n function draw(\\n uint96 _courtID,\\n uint256 _coreDisputeID,\\n uint256 _nonce\\n ) external view returns (address drawnAddress, uint96 fromSubcourtID);\\n\\n /// @notice Gets the balance of a juror in a court.\\n /// @param _juror The address of the juror.\\n /// @param _courtID The ID of the court.\\n /// @return totalStakedPnk The total amount of tokens staked including locked tokens and penalty deductions. Equivalent to the effective stake in the General court.\\n /// @return totalLocked The total amount of tokens locked in disputes.\\n /// @return stakedInCourt The amount of tokens staked in the specified court including locked tokens and penalty deductions.\\n /// @return nbCourts The number of courts the juror has directly staked in.\\n function getJurorBalance(\\n address _juror,\\n uint96 _courtID\\n ) external view returns (uint256 totalStakedPnk, uint256 totalLocked, uint256 stakedInCourt, uint256 nbCourts);\\n\\n /// @notice Gets the court identifiers where a specific `_juror` has staked.\\n /// @param _juror The address of the juror.\\n function getJurorCourtIDs(address _juror) external view returns (uint96[] memory);\\n\\n /// @notice Checks if the juror is staked in any court.\\n /// @param _juror The address of the juror.\\n /// @return Whether the juror is staked or not.\\n function isJurorStaked(address _juror) external view returns (bool);\\n\\n /// @notice Checks if the juror has any leftover PNK in the contract.\\n /// @param _juror The address of the juror.\\n /// @return Whether the juror has leftover PNK.\\n function getJurorLeftoverPNK(address _juror) external view returns (uint256);\\n}\\n\",\"keccak256\":\"0x3eeff4281ddf3c731c6503094bbbcc80d8015e3a60a27c8cadadfffdf1bf5437\",\"license\":\"MIT\"},\"src/arbitration/university/ISortitionModuleUniversity.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.24;\\n\\nimport {ISortitionModule} from \\\"../interfaces/ISortitionModule.sol\\\";\\n\\ninterface ISortitionModuleUniversity is ISortitionModule {\\n function setTransientJuror(address _juror) external;\\n}\\n\",\"keccak256\":\"0x57478726f4dd824eca06d8b5349395b5b37756f7988d3fffb6fdae4d0f4164ee\",\"license\":\"MIT\"},\"src/arbitration/university/KlerosCoreUniversity.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.24;\\n\\nimport {IArbitrableV2, IArbitratorV2} from \\\"../interfaces/IArbitratorV2.sol\\\";\\nimport {IDisputeKit} from \\\"../interfaces/IDisputeKit.sol\\\";\\nimport {ISortitionModuleUniversity} from \\\"./ISortitionModuleUniversity.sol\\\";\\nimport {SafeERC20, IERC20} from \\\"../../libraries/SafeERC20.sol\\\";\\nimport {UUPSProxiable} from \\\"../../proxy/UUPSProxiable.sol\\\";\\nimport {Initializable} from \\\"../../proxy/Initializable.sol\\\";\\nimport \\\"../../libraries/Constants.sol\\\";\\n\\n/// @title KlerosCoreUniversity\\n/// @notice Core arbitrator contract for educational purposes.\\ncontract KlerosCoreUniversity is IArbitratorV2, UUPSProxiable, Initializable {\\n using SafeERC20 for IERC20;\\n\\n string public constant override version = \\\"2.0.0\\\";\\n\\n // ************************************* //\\n // * Enums / Structs * //\\n // ************************************* //\\n\\n enum Period {\\n evidence, // Evidence can be submitted. This is also when drawing has to take place.\\n commit, // Jurors commit a hashed vote. This is skipped for courts without hidden votes.\\n vote, // Jurors reveal/cast their vote depending on whether the court has hidden votes or not.\\n appeal, // The dispute can be appealed.\\n execution // Tokens are redistributed and the ruling is executed.\\n }\\n\\n struct Court {\\n uint96 parent; // The parent court.\\n bool hiddenVotes; // Whether to use commit and reveal or not.\\n uint256[] children; // List of child courts.\\n uint256 minStake; // Minimum PNKs needed to stake in the court.\\n uint256 alpha; // Basis point of PNKs that are lost when incoherent.\\n uint256 feeForJuror; // Arbitration fee paid per juror.\\n uint256 jurorsForCourtJump; // The appeal after the one that reaches this number of jurors will go to the parent court if any.\\n uint256[4] timesPerPeriod; // The time allotted to each dispute period in the form `timesPerPeriod[period]`.\\n mapping(uint256 disputeKitId => bool) supportedDisputeKits; // True if DK with this ID is supported by the court. Note that each court must support classic dispute kit.\\n uint256[10] __gap; // Reserved slots for future upgrades.\\n }\\n\\n struct Dispute {\\n uint96 courtID; // The ID of the court the dispute is in.\\n IArbitrableV2 arbitrated; // The arbitrable contract.\\n Period period; // The current period of the dispute.\\n bool ruled; // True if the ruling has been executed, false otherwise.\\n uint256 lastPeriodChange; // The last time the period was changed.\\n Round[] rounds;\\n uint256[10] __gap; // Reserved slots for future upgrades.\\n }\\n\\n struct Round {\\n uint256 disputeKitID; // Index of the dispute kit in the array.\\n uint256 pnkAtStakePerJuror; // The amount of PNKs at stake for each juror in this round.\\n uint256 totalFeesForJurors; // The total juror fees paid in this round.\\n uint256 nbVotes; // The total number of votes the dispute can possibly have in the current round. Former votes[_round].length.\\n uint256 repartitions; // A counter of reward repartitions made in this round.\\n uint256 pnkPenalties; // The amount of PNKs collected from penalties in this round.\\n address[] drawnJurors; // Addresses of the jurors that were drawn in this round.\\n uint96[] drawnJurorFromCourtIDs; // The courtIDs where the juror was drawn from, possibly their stake in a subcourt.\\n uint256 sumFeeRewardPaid; // Total sum of arbitration fees paid to coherent jurors as a reward in this round.\\n uint256 sumPnkRewardPaid; // Total sum of PNK paid to coherent jurors as a reward in this round.\\n IERC20 feeToken; // The token used for paying fees in this round.\\n uint256 drawIterations; // The number of iterations passed drawing the jurors for this round.\\n uint256[10] __gap; // Reserved slots for future upgrades.\\n }\\n\\n // Workaround \\\"stack too deep\\\" errors\\n struct ExecuteParams {\\n uint256 disputeID; // The ID of the dispute to execute.\\n uint256 round; // The round to execute.\\n uint256 coherentCount; // The number of coherent votes in the round.\\n uint256 numberOfVotesInRound; // The number of votes in the round.\\n uint256 feePerJurorInRound; // The fee per juror in the round.\\n uint256 pnkAtStakePerJurorInRound; // The amount of PNKs at stake for each juror in the round.\\n uint256 pnkPenaltiesInRound; // The amount of PNKs collected from penalties in the round.\\n uint256 repartition; // The index of the repartition to execute.\\n }\\n\\n struct CurrencyRate {\\n bool feePaymentAccepted;\\n uint64 rateInEth;\\n uint8 rateDecimals;\\n }\\n\\n // ************************************* //\\n // * Storage * //\\n // ************************************* //\\n\\n uint256 private constant NON_PAYABLE_AMOUNT = (2 ** 256 - 2) / 2; // An amount higher than the supply of ETH.\\n\\n address public owner; // The owner of the contract.\\n address public instructor; // The instructor who is allowed to choose the jurors.\\n IERC20 public pinakion; // The Pinakion token contract.\\n address public jurorProsecutionModule; // The module for juror's prosecution.\\n ISortitionModuleUniversity public sortitionModule; // Sortition module for drawing.\\n Court[] public courts; // The courts.\\n IDisputeKit[] public disputeKits; // Array of dispute kits.\\n Dispute[] public disputes; // The disputes.\\n mapping(IERC20 => CurrencyRate) public currencyRates; // The price of each token in ETH.\\n\\n // ************************************* //\\n // * Events * //\\n // ************************************* //\\n\\n event NewPeriod(uint256 indexed _disputeID, Period _period);\\n event AppealPossible(uint256 indexed _disputeID, IArbitrableV2 indexed _arbitrable);\\n event AppealDecision(uint256 indexed _disputeID, IArbitrableV2 indexed _arbitrable);\\n event Draw(address indexed _address, uint256 indexed _disputeID, uint256 _roundID, uint256 _voteID);\\n event CourtCreated(\\n uint96 indexed _courtID,\\n uint96 indexed _parent,\\n bool _hiddenVotes,\\n uint256 _minStake,\\n uint256 _alpha,\\n uint256 _feeForJuror,\\n uint256 _jurorsForCourtJump,\\n uint256[4] _timesPerPeriod,\\n uint256[] _supportedDisputeKits\\n );\\n event CourtModified(\\n uint96 indexed _courtID,\\n bool _hiddenVotes,\\n uint256 _minStake,\\n uint256 _alpha,\\n uint256 _feeForJuror,\\n uint256 _jurorsForCourtJump,\\n uint256[4] _timesPerPeriod\\n );\\n event DisputeKitCreated(uint256 indexed _disputeKitID, IDisputeKit indexed _disputeKitAddress);\\n event DisputeKitEnabled(uint96 indexed _courtID, uint256 indexed _disputeKitID, bool indexed _enable);\\n event CourtJump(\\n uint256 indexed _disputeID,\\n uint256 indexed _roundID,\\n uint96 indexed _fromCourtID,\\n uint96 _toCourtID\\n );\\n event DisputeKitJump(\\n uint256 indexed _disputeID,\\n uint256 indexed _roundID,\\n uint256 indexed _fromDisputeKitID,\\n uint256 _toDisputeKitID\\n );\\n event JurorRewardPenalty(\\n address indexed _account,\\n uint256 indexed _disputeID,\\n uint256 indexed _roundID,\\n uint256 _degreeOfCoherencyPnk,\\n uint256 _degreeOfCoherencyFee,\\n int256 _amountPnk,\\n int256 _amountFee,\\n IERC20 _feeToken\\n );\\n event LeftoverRewardSent(\\n uint256 indexed _disputeID,\\n uint256 indexed _roundID,\\n uint256 _amountPnk,\\n uint256 _amountFee,\\n IERC20 _feeToken\\n );\\n\\n // ************************************* //\\n // * Function Modifiers * //\\n // ************************************* //\\n\\n modifier onlyByOwner() {\\n if (owner != msg.sender) revert OwnerOnly();\\n _;\\n }\\n\\n modifier onlyByInstructor() {\\n if (instructor != msg.sender) revert InstructorOnly();\\n _;\\n }\\n\\n modifier onlyByOwnerOrInstructor() {\\n if (msg.sender != owner && msg.sender != instructor) revert OwnerOrInstructorOnly();\\n _;\\n }\\n\\n // ************************************* //\\n // * Constructor * //\\n // ************************************* //\\n\\n /// @custom:oz-upgrades-unsafe-allow constructor\\n constructor() {\\n _disableInitializers();\\n }\\n\\n /// @notice Initializer (constructor equivalent for upgradable contracts).\\n /// @param _owner The owner's address.\\n /// @param _instructor The address of the instructor.\\n /// @param _pinakion The address of the token contract.\\n /// @param _jurorProsecutionModule The address of the juror prosecution module.\\n /// @param _disputeKit The address of the default dispute kit.\\n /// @param _hiddenVotes The `hiddenVotes` property value of the general court.\\n /// @param _courtParameters Numeric parameters of General court (minStake, alpha, feeForJuror and jurorsForCourtJump respectively).\\n /// @param _timesPerPeriod The `timesPerPeriod` property value of the general court.\\n /// @param _sortitionModuleAddress The sortition module responsible for sortition of the jurors.\\n function initialize(\\n address _owner,\\n address _instructor,\\n IERC20 _pinakion,\\n address _jurorProsecutionModule,\\n IDisputeKit _disputeKit,\\n bool _hiddenVotes,\\n uint256[4] memory _courtParameters,\\n uint256[4] memory _timesPerPeriod,\\n ISortitionModuleUniversity _sortitionModuleAddress\\n ) external initializer {\\n owner = _owner;\\n instructor = _instructor;\\n pinakion = _pinakion;\\n jurorProsecutionModule = _jurorProsecutionModule;\\n sortitionModule = _sortitionModuleAddress;\\n\\n // NULL_DISPUTE_KIT: an empty element at index 0 to indicate when a dispute kit is not supported.\\n disputeKits.push();\\n\\n // DISPUTE_KIT_CLASSIC\\n disputeKits.push(_disputeKit);\\n\\n emit DisputeKitCreated(DISPUTE_KIT_CLASSIC, _disputeKit);\\n\\n // FORKING_COURT\\n // TODO: Fill the properties for the Forking court, emit CourtCreated.\\n courts.push();\\n\\n // GENERAL_COURT\\n Court storage court = courts.push();\\n court.parent = FORKING_COURT;\\n court.children = new uint256[](0);\\n court.hiddenVotes = _hiddenVotes;\\n court.minStake = _courtParameters[0];\\n court.alpha = _courtParameters[1];\\n court.feeForJuror = _courtParameters[2];\\n court.jurorsForCourtJump = _courtParameters[3];\\n court.timesPerPeriod = _timesPerPeriod;\\n\\n emit CourtCreated(\\n GENERAL_COURT,\\n court.parent,\\n _hiddenVotes,\\n _courtParameters[0],\\n _courtParameters[1],\\n _courtParameters[2],\\n _courtParameters[3],\\n _timesPerPeriod,\\n new uint256[](0)\\n );\\n _enableDisputeKit(GENERAL_COURT, DISPUTE_KIT_CLASSIC, true);\\n }\\n\\n // ************************************* //\\n // * Governance * //\\n // ************************************* //\\n\\n /* @dev Access Control to perform implementation upgrades (UUPS Proxiable)\\n * @dev Only the owner can perform upgrades (`onlyByOwner`)\\n */\\n function _authorizeUpgrade(address) internal view override onlyByOwner {\\n // NOP\\n }\\n\\n /// @notice Allows the owner to call anything on behalf of the contract.\\n /// @param _destination The destination of the call.\\n /// @param _amount The value sent with the call.\\n /// @param _data The data sent with the call.\\n function executeOwnerProposal(address _destination, uint256 _amount, bytes memory _data) external onlyByOwner {\\n (bool success, ) = _destination.call{value: _amount}(_data);\\n if (!success) revert UnsuccessfulCall();\\n }\\n\\n /// @notice Changes the `owner` storage variable.\\n /// @param _owner The new value for the `owner` storage variable.\\n function changeOwner(address payable _owner) external onlyByOwner {\\n owner = _owner;\\n }\\n\\n /// @notice Changes the `instructor` storage variable.\\n /// @param _instructor The new value for the `instructor` storage variable.\\n function changeInstructor(address _instructor) external onlyByOwnerOrInstructor {\\n instructor = _instructor;\\n }\\n\\n /// @notice Changes the `pinakion` storage variable.\\n /// @param _pinakion The new value for the `pinakion` storage variable.\\n function changePinakion(IERC20 _pinakion) external onlyByOwner {\\n pinakion = _pinakion;\\n }\\n\\n /// @notice Changes the `jurorProsecutionModule` storage variable.\\n /// @param _jurorProsecutionModule The new value for the `jurorProsecutionModule` storage variable.\\n function changeJurorProsecutionModule(address _jurorProsecutionModule) external onlyByOwner {\\n jurorProsecutionModule = _jurorProsecutionModule;\\n }\\n\\n /// @notice Changes the `_sortitionModule` storage variable.\\n /// Note that the new module should be initialized for all courts.\\n /// @param _sortitionModule The new value for the `sortitionModule` storage variable.\\n function changeSortitionModule(ISortitionModuleUniversity _sortitionModule) external onlyByOwner {\\n sortitionModule = _sortitionModule;\\n }\\n\\n /// @notice Add a new supported dispute kit module to the court.\\n /// @param _disputeKitAddress The address of the dispute kit contract.\\n function addNewDisputeKit(IDisputeKit _disputeKitAddress) external onlyByOwner {\\n uint256 disputeKitID = disputeKits.length;\\n disputeKits.push(_disputeKitAddress);\\n emit DisputeKitCreated(disputeKitID, _disputeKitAddress);\\n }\\n\\n /// @notice Creates a court under a specified parent court.\\n /// @param _parent The `parent` property value of the court.\\n /// @param _hiddenVotes The `hiddenVotes` property value of the court.\\n /// @param _minStake The `minStake` property value of the court.\\n /// @param _alpha The `alpha` property value of the court.\\n /// @param _feeForJuror The `feeForJuror` property value of the court.\\n /// @param _jurorsForCourtJump The `jurorsForCourtJump` property value of the court.\\n /// @param _timesPerPeriod The `timesPerPeriod` property value of the court.\\n /// @param _supportedDisputeKits Indexes of dispute kits that this court will support.\\n function createCourt(\\n uint96 _parent,\\n bool _hiddenVotes,\\n uint256 _minStake,\\n uint256 _alpha,\\n uint256 _feeForJuror,\\n uint256 _jurorsForCourtJump,\\n uint256[4] memory _timesPerPeriod,\\n uint256[] memory _supportedDisputeKits\\n ) external onlyByOwner {\\n if (courts[_parent].minStake > _minStake) revert MinStakeLowerThanParentCourt();\\n if (_supportedDisputeKits.length == 0) revert UnsupportedDisputeKit();\\n if (_parent == FORKING_COURT) revert InvalidForkingCourtAsParent();\\n\\n uint256 courtID = courts.length;\\n Court storage court = courts.push();\\n\\n for (uint256 i = 0; i < _supportedDisputeKits.length; i++) {\\n if (_supportedDisputeKits[i] == 0 || _supportedDisputeKits[i] >= disputeKits.length) {\\n revert WrongDisputeKitIndex();\\n }\\n court.supportedDisputeKits[_supportedDisputeKits[i]] = true;\\n }\\n // Check that Classic DK support was added.\\n if (!court.supportedDisputeKits[DISPUTE_KIT_CLASSIC]) revert MustSupportDisputeKitClassic();\\n\\n court.parent = _parent;\\n court.children = new uint256[](0);\\n court.hiddenVotes = _hiddenVotes;\\n court.minStake = _minStake;\\n court.alpha = _alpha;\\n court.feeForJuror = _feeForJuror;\\n court.jurorsForCourtJump = _jurorsForCourtJump;\\n court.timesPerPeriod = _timesPerPeriod;\\n\\n // Update the parent.\\n courts[_parent].children.push(courtID);\\n emit CourtCreated(\\n uint96(courtID),\\n _parent,\\n _hiddenVotes,\\n _minStake,\\n _alpha,\\n _feeForJuror,\\n _jurorsForCourtJump,\\n _timesPerPeriod,\\n _supportedDisputeKits\\n );\\n }\\n\\n function changeCourtParameters(\\n uint96 _courtID,\\n bool _hiddenVotes,\\n uint256 _minStake,\\n uint256 _alpha,\\n uint256 _feeForJuror,\\n uint256 _jurorsForCourtJump,\\n uint256[4] memory _timesPerPeriod\\n ) external onlyByOwner {\\n Court storage court = courts[_courtID];\\n if (_courtID != GENERAL_COURT && courts[court.parent].minStake > _minStake) {\\n revert MinStakeLowerThanParentCourt();\\n }\\n for (uint256 i = 0; i < court.children.length; i++) {\\n if (courts[court.children[i]].minStake < _minStake) {\\n revert MinStakeLowerThanParentCourt();\\n }\\n }\\n court.minStake = _minStake;\\n court.hiddenVotes = _hiddenVotes;\\n court.alpha = _alpha;\\n court.feeForJuror = _feeForJuror;\\n court.jurorsForCourtJump = _jurorsForCourtJump;\\n court.timesPerPeriod = _timesPerPeriod;\\n emit CourtModified(\\n _courtID,\\n _hiddenVotes,\\n _minStake,\\n _alpha,\\n _feeForJuror,\\n _jurorsForCourtJump,\\n _timesPerPeriod\\n );\\n }\\n\\n /// @notice Adds/removes court's support for specified dispute kits.\\n /// @param _courtID The ID of the court.\\n /// @param _disputeKitIDs The IDs of dispute kits which support should be added/removed.\\n /// @param _enable Whether add or remove the dispute kits from the court.\\n function enableDisputeKits(uint96 _courtID, uint256[] memory _disputeKitIDs, bool _enable) external onlyByOwner {\\n for (uint256 i = 0; i < _disputeKitIDs.length; i++) {\\n if (_enable) {\\n if (_disputeKitIDs[i] == 0 || _disputeKitIDs[i] >= disputeKits.length) {\\n revert WrongDisputeKitIndex();\\n }\\n _enableDisputeKit(_courtID, _disputeKitIDs[i], true);\\n } else {\\n // Classic dispute kit must be supported by all courts.\\n if (_disputeKitIDs[i] == DISPUTE_KIT_CLASSIC) {\\n revert CannotDisableClassicDK();\\n }\\n _enableDisputeKit(_courtID, _disputeKitIDs[i], false);\\n }\\n }\\n }\\n\\n /// @notice Changes the supported fee tokens.\\n /// @param _feeToken The fee token.\\n /// @param _accepted Whether the token is supported or not as a method of fee payment.\\n function changeAcceptedFeeTokens(IERC20 _feeToken, bool _accepted) external onlyByOwner {\\n currencyRates[_feeToken].feePaymentAccepted = _accepted;\\n emit AcceptedFeeToken(_feeToken, _accepted);\\n }\\n\\n /// @notice Changes the currency rate of a fee token.\\n /// @param _feeToken The fee token.\\n /// @param _rateInEth The new rate of the fee token in ETH.\\n /// @param _rateDecimals The new decimals of the fee token rate.\\n function changeCurrencyRates(IERC20 _feeToken, uint64 _rateInEth, uint8 _rateDecimals) external onlyByOwner {\\n currencyRates[_feeToken].rateInEth = _rateInEth;\\n currencyRates[_feeToken].rateDecimals = _rateDecimals;\\n emit NewCurrencyRate(_feeToken, _rateInEth, _rateDecimals);\\n }\\n\\n // ************************************* //\\n // * State Modifiers * //\\n // ************************************* //\\n\\n /// @notice Sets the caller's stake in a court.\\n /// @param _courtID The ID of the court.\\n /// @param _newStake The new stake.\\n /// Note that the existing delayed stake will be nullified as non-relevant.\\n function setStake(uint96 _courtID, uint256 _newStake) external {\\n _setStake(msg.sender, _courtID, _newStake, false, OnError.Revert);\\n }\\n\\n /// @notice Sets the stake of a specified account in a court, typically to apply a delayed stake or unstake inactive jurors.\\n /// @param _account The account whose stake is being set.\\n /// @param _courtID The ID of the court.\\n /// @param _newStake The new stake.\\n function setStakeBySortitionModule(address _account, uint96 _courtID, uint256 _newStake) external {\\n if (msg.sender != address(sortitionModule)) revert SortitionModuleOnly();\\n _setStake(_account, _courtID, _newStake, true, OnError.Return);\\n }\\n\\n /// @notice Transfers PNK to the juror by SortitionModule.\\n /// @param _account The account of the juror whose PNK to transfer.\\n /// @param _amount The amount to transfer.\\n function transferBySortitionModule(address _account, uint256 _amount) external {\\n if (msg.sender != address(sortitionModule)) revert SortitionModuleOnly();\\n // Note eligibility is checked in SortitionModule.\\n pinakion.safeTransfer(_account, _amount);\\n }\\n\\n /// @inheritdoc IArbitratorV2\\n function createDispute(\\n uint256 _numberOfChoices,\\n bytes memory _extraData\\n ) external payable override returns (uint256 disputeID) {\\n if (msg.value < arbitrationCost(_extraData)) revert ArbitrationFeesNotEnough();\\n\\n return _createDispute(_numberOfChoices, _extraData, NATIVE_CURRENCY, msg.value);\\n }\\n\\n /// @inheritdoc IArbitratorV2\\n function createDispute(\\n uint256 _numberOfChoices,\\n bytes calldata _extraData,\\n IERC20 _feeToken,\\n uint256 _feeAmount\\n ) external override returns (uint256 disputeID) {\\n if (!currencyRates[_feeToken].feePaymentAccepted) revert TokenNotAccepted();\\n if (_feeAmount < arbitrationCost(_extraData, _feeToken)) revert ArbitrationFeesNotEnough();\\n\\n if (!_feeToken.safeTransferFrom(msg.sender, address(this), _feeAmount)) revert TransferFailed();\\n return _createDispute(_numberOfChoices, _extraData, _feeToken, _feeAmount);\\n }\\n\\n function _createDispute(\\n uint256 _numberOfChoices,\\n bytes memory _extraData,\\n IERC20 _feeToken,\\n uint256 _feeAmount\\n ) internal returns (uint256 disputeID) {\\n (uint96 courtID, , uint256 disputeKitID) = _extraDataToCourtIDMinJurorsDisputeKit(_extraData);\\n if (!courts[courtID].supportedDisputeKits[disputeKitID]) revert DisputeKitNotSupportedByCourt();\\n\\n disputeID = disputes.length;\\n Dispute storage dispute = disputes.push();\\n dispute.courtID = courtID;\\n dispute.arbitrated = IArbitrableV2(msg.sender);\\n dispute.lastPeriodChange = block.timestamp;\\n\\n IDisputeKit disputeKit = disputeKits[disputeKitID];\\n Court storage court = courts[courtID];\\n Round storage round = dispute.rounds.push();\\n\\n // Obtain the feeForJuror in the same currency as the _feeAmount\\n uint256 feeForJuror = (_feeToken == NATIVE_CURRENCY)\\n ? court.feeForJuror\\n : convertEthToTokenAmount(_feeToken, court.feeForJuror);\\n round.nbVotes = _feeAmount / feeForJuror;\\n round.disputeKitID = disputeKitID;\\n round.pnkAtStakePerJuror = (court.minStake * court.alpha) / ONE_BASIS_POINT;\\n round.totalFeesForJurors = _feeAmount;\\n round.feeToken = IERC20(_feeToken);\\n\\n sortitionModule.createDisputeHook(disputeID, 0); // Default round ID.\\n\\n disputeKit.createDispute(disputeID, _numberOfChoices, _extraData, round.nbVotes);\\n emit DisputeCreation(disputeID, IArbitrableV2(msg.sender));\\n }\\n\\n /// @notice Passes the period of a specified dispute.\\n /// @param _disputeID The ID of the dispute.\\n function passPeriod(uint256 _disputeID) external {\\n Dispute storage dispute = disputes[_disputeID];\\n Court storage court = courts[dispute.courtID];\\n\\n uint256 currentRound = dispute.rounds.length - 1;\\n Round storage round = dispute.rounds[currentRound];\\n if (dispute.period == Period.evidence) {\\n if (\\n currentRound == 0 &&\\n block.timestamp - dispute.lastPeriodChange < court.timesPerPeriod[uint256(dispute.period)]\\n ) {\\n revert EvidenceNotPassedAndNotAppeal();\\n }\\n if (round.drawnJurors.length != round.nbVotes) revert DisputeStillDrawing();\\n dispute.period = court.hiddenVotes ? Period.commit : Period.vote;\\n } else if (dispute.period == Period.commit) {\\n if (\\n block.timestamp - dispute.lastPeriodChange < court.timesPerPeriod[uint256(dispute.period)] &&\\n !disputeKits[round.disputeKitID].areCommitsAllCast(_disputeID)\\n ) {\\n revert CommitPeriodNotPassed();\\n }\\n dispute.period = Period.vote;\\n } else if (dispute.period == Period.vote) {\\n if (\\n block.timestamp - dispute.lastPeriodChange < court.timesPerPeriod[uint256(dispute.period)] &&\\n !disputeKits[round.disputeKitID].areVotesAllCast(_disputeID)\\n ) {\\n revert VotePeriodNotPassed();\\n }\\n dispute.period = Period.appeal;\\n emit AppealPossible(_disputeID, dispute.arbitrated);\\n } else if (dispute.period == Period.appeal) {\\n if (\\n block.timestamp - dispute.lastPeriodChange < court.timesPerPeriod[uint256(dispute.period)] &&\\n !disputeKits[round.disputeKitID].isAppealFunded(_disputeID)\\n ) {\\n revert AppealPeriodNotPassed();\\n }\\n dispute.period = Period.execution;\\n } else if (dispute.period == Period.execution) {\\n revert DisputePeriodIsFinal();\\n }\\n\\n dispute.lastPeriodChange = block.timestamp;\\n emit NewPeriod(_disputeID, dispute.period);\\n }\\n\\n /// @notice Draws one juror for the dispute until the number votes paid for is reached.\\n /// @param _disputeID The ID of the dispute.\\n /// @param _juror The address of the juror to draw.\\n function draw(uint256 _disputeID, address _juror) external onlyByOwnerOrInstructor {\\n Dispute storage dispute = disputes[_disputeID];\\n uint256 currentRound = dispute.rounds.length - 1;\\n Round storage round = dispute.rounds[currentRound];\\n if (dispute.period != Period.evidence) revert NotEvidencePeriod();\\n if (round.drawnJurors.length >= round.nbVotes) revert AllJurorsDrawn();\\n\\n sortitionModule.setTransientJuror(_juror);\\n {\\n IDisputeKit disputeKit = disputeKits[round.disputeKitID];\\n uint256 iteration = round.drawIterations + 1;\\n (address drawnAddress, uint96 fromSubcourtID) = disputeKit.draw(_disputeID, iteration);\\n if (drawnAddress == address(0)) {\\n revert NoJurorDrawn();\\n }\\n sortitionModule.lockStake(drawnAddress, round.pnkAtStakePerJuror);\\n emit Draw(drawnAddress, _disputeID, currentRound, round.drawnJurors.length);\\n round.drawnJurors.push(drawnAddress);\\n round.drawnJurorFromCourtIDs.push(fromSubcourtID != 0 ? fromSubcourtID : dispute.courtID);\\n if (round.drawnJurors.length == round.nbVotes) {\\n sortitionModule.postDrawHook(_disputeID, currentRound);\\n }\\n round.drawIterations = iteration;\\n }\\n sortitionModule.setTransientJuror(address(0));\\n }\\n\\n /// @notice Appeals the ruling of a specified dispute.\\n /// @dev Access restricted to the Dispute Kit for this `disputeID`.\\n /// @param _disputeID The ID of the dispute.\\n /// @param _numberOfChoices Number of choices for the dispute. Can be required during court jump.\\n /// @param _extraData Extradata for the dispute. Can be required during court jump.\\n function appeal(uint256 _disputeID, uint256 _numberOfChoices, bytes memory _extraData) external payable {\\n if (msg.value < appealCost(_disputeID)) revert AppealFeesNotEnough();\\n\\n Dispute storage dispute = disputes[_disputeID];\\n if (dispute.period != Period.appeal) revert DisputeNotAppealable();\\n\\n Round storage round = dispute.rounds[dispute.rounds.length - 1];\\n if (msg.sender != address(disputeKits[round.disputeKitID])) revert DisputeKitOnly();\\n\\n uint96 newCourtID = dispute.courtID;\\n uint256 newDisputeKitID = round.disputeKitID;\\n\\n // Warning: the extra round must be created before calling disputeKit.createDispute()\\n Round storage extraRound = dispute.rounds.push();\\n\\n if (round.nbVotes >= courts[newCourtID].jurorsForCourtJump) {\\n // Jump to parent court.\\n newCourtID = courts[newCourtID].parent;\\n\\n if (!courts[newCourtID].supportedDisputeKits[newDisputeKitID]) {\\n // Switch to classic dispute kit if parent court doesn't support the current one.\\n newDisputeKitID = DISPUTE_KIT_CLASSIC;\\n }\\n\\n if (newCourtID != dispute.courtID) {\\n emit CourtJump(_disputeID, dispute.rounds.length - 1, dispute.courtID, newCourtID);\\n }\\n }\\n\\n dispute.courtID = newCourtID;\\n dispute.period = Period.evidence;\\n dispute.lastPeriodChange = block.timestamp;\\n\\n Court storage court = courts[newCourtID];\\n extraRound.nbVotes = msg.value / court.feeForJuror; // As many votes that can be afforded by the provided funds.\\n extraRound.pnkAtStakePerJuror = (court.minStake * court.alpha) / ONE_BASIS_POINT;\\n extraRound.totalFeesForJurors = msg.value;\\n extraRound.disputeKitID = newDisputeKitID;\\n\\n sortitionModule.createDisputeHook(_disputeID, dispute.rounds.length - 1);\\n\\n // Dispute kit was changed, so create a dispute in the new DK contract.\\n if (extraRound.disputeKitID != round.disputeKitID) {\\n emit DisputeKitJump(_disputeID, dispute.rounds.length - 1, round.disputeKitID, extraRound.disputeKitID);\\n disputeKits[extraRound.disputeKitID].createDispute(\\n _disputeID,\\n _numberOfChoices,\\n _extraData,\\n extraRound.nbVotes\\n );\\n }\\n\\n emit AppealDecision(_disputeID, dispute.arbitrated);\\n emit NewPeriod(_disputeID, Period.evidence);\\n }\\n\\n /// @notice Distribute the PNKs at stake and the dispute fees for the specific round of the dispute. Can be called in parts.\\n /// @param _disputeID The ID of the dispute.\\n /// @param _round The appeal round.\\n /// @param _iterations The number of iterations to run.\\n function execute(uint256 _disputeID, uint256 _round, uint256 _iterations) external {\\n Round storage round;\\n {\\n Dispute storage dispute = disputes[_disputeID];\\n if (dispute.period != Period.execution) revert NotExecutionPeriod();\\n\\n round = dispute.rounds[_round];\\n } // stack too deep workaround\\n\\n uint256 start = round.repartitions;\\n uint256 end = round.repartitions + _iterations;\\n\\n uint256 pnkPenaltiesInRound = round.pnkPenalties; // Keep in memory to save gas.\\n uint256 numberOfVotesInRound = round.drawnJurors.length;\\n uint256 feePerJurorInRound = round.totalFeesForJurors / numberOfVotesInRound;\\n uint256 pnkAtStakePerJurorInRound = round.pnkAtStakePerJuror;\\n uint256 coherentCount;\\n {\\n IDisputeKit disputeKit = disputeKits[round.disputeKitID];\\n coherentCount = disputeKit.getCoherentCount(_disputeID, _round); // Total number of jurors that are eligible to a reward in this round.\\n } // stack too deep workaround\\n\\n if (coherentCount == 0) {\\n // We loop over the votes once as there are no rewards because it is not a tie and no one in this round is coherent with the final outcome.\\n if (end > numberOfVotesInRound) end = numberOfVotesInRound;\\n } else {\\n // We loop over the votes twice, first to collect the PNK penalties, and second to distribute them as rewards along with arbitration fees.\\n if (end > numberOfVotesInRound * 2) end = numberOfVotesInRound * 2;\\n }\\n round.repartitions = end;\\n\\n for (uint256 i = start; i < end; i++) {\\n if (i < numberOfVotesInRound) {\\n pnkPenaltiesInRound = _executePenalties(\\n ExecuteParams({\\n disputeID: _disputeID,\\n round: _round,\\n coherentCount: coherentCount,\\n numberOfVotesInRound: numberOfVotesInRound,\\n feePerJurorInRound: feePerJurorInRound,\\n pnkAtStakePerJurorInRound: pnkAtStakePerJurorInRound,\\n pnkPenaltiesInRound: pnkPenaltiesInRound,\\n repartition: i\\n })\\n );\\n } else {\\n _executeRewards(\\n ExecuteParams({\\n disputeID: _disputeID,\\n round: _round,\\n coherentCount: coherentCount,\\n numberOfVotesInRound: numberOfVotesInRound,\\n feePerJurorInRound: feePerJurorInRound,\\n pnkAtStakePerJurorInRound: pnkAtStakePerJurorInRound,\\n pnkPenaltiesInRound: pnkPenaltiesInRound,\\n repartition: i\\n })\\n );\\n }\\n }\\n if (round.pnkPenalties != pnkPenaltiesInRound) {\\n round.pnkPenalties = pnkPenaltiesInRound; // Reentrancy risk: breaks Check-Effect-Interact\\n }\\n }\\n\\n /// @notice Distribute the PNKs at stake and the dispute fees for the specific round of the dispute, penalties only.\\n /// @param _params The parameters for the execution, see `ExecuteParams`.\\n /// @return pnkPenaltiesInRoundCache The updated penalties in round cache.\\n function _executePenalties(ExecuteParams memory _params) internal returns (uint256) {\\n Dispute storage dispute = disputes[_params.disputeID];\\n Round storage round = dispute.rounds[_params.round];\\n IDisputeKit disputeKit = disputeKits[round.disputeKitID];\\n\\n // [0, 1] value that determines how coherent the juror was in this round, in basis points.\\n uint256 coherence = disputeKit.getDegreeOfCoherencePenalty(\\n _params.disputeID,\\n _params.round,\\n _params.repartition,\\n _params.feePerJurorInRound,\\n _params.pnkAtStakePerJurorInRound\\n );\\n\\n // Guard against degree exceeding 1, though it should be ensured by the dispute kit.\\n if (coherence > ONE_BASIS_POINT) {\\n coherence = ONE_BASIS_POINT;\\n }\\n\\n // Fully coherent jurors won't be penalized.\\n uint256 penalty = (round.pnkAtStakePerJuror * (ONE_BASIS_POINT - coherence)) / ONE_BASIS_POINT;\\n\\n // Unlock the PNKs affected by the penalty\\n address account = round.drawnJurors[_params.repartition];\\n sortitionModule.unlockStake(account, penalty);\\n\\n // Apply the penalty to the staked PNKs.\\n uint96 penalizedInCourtID = round.drawnJurorFromCourtIDs[_params.repartition];\\n (uint256 pnkBalance, uint256 newCourtStake, uint256 availablePenalty) = sortitionModule.setStakePenalty(\\n account,\\n penalizedInCourtID,\\n penalty\\n );\\n _params.pnkPenaltiesInRound += availablePenalty;\\n emit JurorRewardPenalty(\\n account,\\n _params.disputeID,\\n _params.round,\\n coherence,\\n coherence,\\n -int256(availablePenalty),\\n 0,\\n round.feeToken\\n );\\n\\n if (pnkBalance == 0 || !disputeKit.isVoteActive(_params.disputeID, _params.round, _params.repartition)) {\\n // The juror is inactive or their balance is can't cover penalties anymore, unstake them from all courts.\\n sortitionModule.forcedUnstakeAllCourts(account);\\n } else if (newCourtStake < courts[penalizedInCourtID].minStake) {\\n // The juror's balance fell below the court minStake, unstake them from the court.\\n sortitionModule.forcedUnstake(account, penalizedInCourtID);\\n }\\n\\n if (_params.repartition == _params.numberOfVotesInRound - 1 && _params.coherentCount == 0) {\\n // No one was coherent, send the rewards to the owner.\\n if (round.feeToken == NATIVE_CURRENCY) {\\n // The dispute fees were paid in ETH\\n payable(owner).send(round.totalFeesForJurors);\\n } else {\\n // The dispute fees were paid in ERC20\\n round.feeToken.safeTransfer(owner, round.totalFeesForJurors);\\n }\\n pinakion.safeTransfer(owner, _params.pnkPenaltiesInRound);\\n emit LeftoverRewardSent(\\n _params.disputeID,\\n _params.round,\\n _params.pnkPenaltiesInRound,\\n round.totalFeesForJurors,\\n round.feeToken\\n );\\n }\\n return _params.pnkPenaltiesInRound;\\n }\\n\\n /// @notice Distribute the PNKs at stake and the dispute fees for the specific round of the dispute, rewards only.\\n /// @param _params The parameters for the execution, see `ExecuteParams`.\\n function _executeRewards(ExecuteParams memory _params) internal {\\n Dispute storage dispute = disputes[_params.disputeID];\\n Round storage round = dispute.rounds[_params.round];\\n IDisputeKit disputeKit = disputeKits[round.disputeKitID];\\n\\n // [0, 1] value that determines how coherent the juror was in this round, in basis points.\\n (uint256 pnkCoherence, uint256 feeCoherence) = disputeKit.getDegreeOfCoherenceReward(\\n _params.disputeID,\\n _params.round,\\n _params.repartition % _params.numberOfVotesInRound,\\n _params.feePerJurorInRound,\\n _params.pnkAtStakePerJurorInRound\\n );\\n\\n // Guard against degree exceeding 1, though it should be ensured by the dispute kit.\\n if (pnkCoherence > ONE_BASIS_POINT) {\\n pnkCoherence = ONE_BASIS_POINT;\\n }\\n if (feeCoherence > ONE_BASIS_POINT) {\\n feeCoherence = ONE_BASIS_POINT;\\n }\\n\\n address account = round.drawnJurors[_params.repartition % _params.numberOfVotesInRound];\\n uint256 pnkLocked = (round.pnkAtStakePerJuror * pnkCoherence) / ONE_BASIS_POINT;\\n\\n // Release the rest of the PNKs of the juror for this round.\\n sortitionModule.unlockStake(account, pnkLocked);\\n\\n // Compute the rewards\\n uint256 pnkReward = ((_params.pnkPenaltiesInRound / _params.coherentCount) * pnkCoherence) / ONE_BASIS_POINT; /// forge-lint: disable-line(divide-before-multiply)\\n round.sumPnkRewardPaid += pnkReward;\\n uint256 feeReward = ((round.totalFeesForJurors / _params.coherentCount) * feeCoherence) / ONE_BASIS_POINT; /// forge-lint: disable-line(divide-before-multiply)\\n round.sumFeeRewardPaid += feeReward;\\n\\n // Transfer the fee reward\\n if (round.feeToken == NATIVE_CURRENCY) {\\n // The dispute fees were paid in ETH\\n payable(account).send(feeReward);\\n } else {\\n // The dispute fees were paid in ERC20\\n round.feeToken.safeTransfer(account, feeReward);\\n }\\n\\n // Stake the PNK reward if possible, by-passes delayed stakes and other checks usually done by validateStake()\\n if (!sortitionModule.setStakeReward(account, dispute.courtID, pnkReward)) {\\n pinakion.safeTransfer(account, pnkReward);\\n }\\n\\n emit JurorRewardPenalty(\\n account,\\n _params.disputeID,\\n _params.round,\\n pnkCoherence,\\n feeCoherence,\\n int256(pnkReward),\\n int256(feeReward),\\n round.feeToken\\n );\\n\\n // Transfer any residual rewards to the owner. It may happen due to partial coherence of the jurors.\\n if (_params.repartition == _params.numberOfVotesInRound * 2 - 1) {\\n uint256 leftoverPnkReward = _params.pnkPenaltiesInRound - round.sumPnkRewardPaid;\\n uint256 leftoverFeeReward = round.totalFeesForJurors - round.sumFeeRewardPaid;\\n if (leftoverPnkReward != 0 || leftoverFeeReward != 0) {\\n if (leftoverPnkReward != 0) {\\n pinakion.safeTransfer(owner, leftoverPnkReward);\\n }\\n if (leftoverFeeReward != 0) {\\n if (round.feeToken == NATIVE_CURRENCY) {\\n // The dispute fees were paid in ETH\\n payable(owner).send(leftoverFeeReward);\\n } else {\\n // The dispute fees were paid in ERC20\\n round.feeToken.safeTransfer(owner, leftoverFeeReward);\\n }\\n }\\n emit LeftoverRewardSent(\\n _params.disputeID,\\n _params.round,\\n leftoverPnkReward,\\n leftoverFeeReward,\\n round.feeToken\\n );\\n }\\n }\\n }\\n\\n /// @notice Executes a specified dispute's ruling.\\n /// @param _disputeID The ID of the dispute.\\n function executeRuling(uint256 _disputeID) external {\\n Dispute storage dispute = disputes[_disputeID];\\n if (dispute.period != Period.execution) revert NotExecutionPeriod();\\n if (dispute.ruled) revert RulingAlreadyExecuted();\\n\\n (uint256 winningChoice, , ) = currentRuling(_disputeID);\\n dispute.ruled = true;\\n emit Ruling(dispute.arbitrated, _disputeID, winningChoice);\\n dispute.arbitrated.rule(_disputeID, winningChoice);\\n }\\n\\n // ************************************* //\\n // * Public Views * //\\n // ************************************* //\\n\\n /// @inheritdoc IArbitratorV2\\n function arbitrationCost(bytes memory _extraData) public view override returns (uint256 cost) {\\n (uint96 courtID, uint256 minJurors, ) = _extraDataToCourtIDMinJurorsDisputeKit(_extraData);\\n cost = courts[courtID].feeForJuror * minJurors;\\n }\\n\\n /// @inheritdoc IArbitratorV2\\n function arbitrationCost(bytes calldata _extraData, IERC20 _feeToken) public view override returns (uint256 cost) {\\n cost = convertEthToTokenAmount(_feeToken, arbitrationCost(_extraData));\\n }\\n\\n /// @notice Gets the cost of appealing a specified dispute.\\n /// @param _disputeID The ID of the dispute.\\n /// @return cost The appeal cost.\\n function appealCost(uint256 _disputeID) public view returns (uint256 cost) {\\n Dispute storage dispute = disputes[_disputeID];\\n Round storage round = dispute.rounds[dispute.rounds.length - 1];\\n Court storage court = courts[dispute.courtID];\\n if (round.nbVotes >= court.jurorsForCourtJump) {\\n // Jump to parent court.\\n if (dispute.courtID == GENERAL_COURT) {\\n // TODO: Handle the forking when appealed in General court.\\n cost = NON_PAYABLE_AMOUNT; // Get the cost of the parent court.\\n } else {\\n cost = courts[court.parent].feeForJuror * ((round.nbVotes * 2) + 1);\\n }\\n } else {\\n // Stay in current court.\\n cost = court.feeForJuror * ((round.nbVotes * 2) + 1);\\n }\\n }\\n\\n /// @notice Gets the start and the end of a specified dispute's current appeal period.\\n /// @param _disputeID The ID of the dispute.\\n /// @return start The start of the appeal period.\\n /// @return end The end of the appeal period.\\n function appealPeriod(uint256 _disputeID) public view returns (uint256 start, uint256 end) {\\n Dispute storage dispute = disputes[_disputeID];\\n if (dispute.period == Period.appeal) {\\n start = dispute.lastPeriodChange;\\n end = dispute.lastPeriodChange + courts[dispute.courtID].timesPerPeriod[uint256(Period.appeal)];\\n } else {\\n start = 0;\\n end = 0;\\n }\\n }\\n\\n /// @inheritdoc IArbitratorV2\\n function currentRuling(uint256 _disputeID) public view returns (uint256 ruling, bool tied, bool overridden) {\\n Dispute storage dispute = disputes[_disputeID];\\n Round storage round = dispute.rounds[dispute.rounds.length - 1];\\n IDisputeKit disputeKit = disputeKits[round.disputeKitID];\\n (ruling, tied, overridden) = disputeKit.currentRuling(_disputeID);\\n }\\n\\n /// @notice Gets the round info for a specified dispute and round.\\n /// @dev This function must not be called from a non-view function because it returns a dynamic array which might be very large, theoretically exceeding the block gas limit.\\n /// @param _disputeID The ID of the dispute.\\n /// @param _round The round to get the info for.\\n /// @return round The round info.\\n function getRoundInfo(uint256 _disputeID, uint256 _round) external view returns (Round memory) {\\n return disputes[_disputeID].rounds[_round];\\n }\\n\\n /// @notice Gets the PNK at stake per juror for a specified dispute and round.\\n /// @param _disputeID The ID of the dispute.\\n /// @param _round The round to get the info for.\\n /// @return pnkAtStakePerJuror The PNK at stake per juror.\\n function getPnkAtStakePerJuror(uint256 _disputeID, uint256 _round) external view returns (uint256) {\\n return disputes[_disputeID].rounds[_round].pnkAtStakePerJuror;\\n }\\n\\n /// @notice Gets the number of rounds for a specified dispute.\\n /// @param _disputeID The ID of the dispute.\\n /// @return The number of rounds.\\n function getNumberOfRounds(uint256 _disputeID) external view returns (uint256) {\\n return disputes[_disputeID].rounds.length;\\n }\\n\\n /// @notice Checks if a given dispute kit is supported by a given court.\\n /// @param _courtID The ID of the court to check the support for.\\n /// @param _disputeKitID The ID of the dispute kit to check the support for.\\n /// @return Whether the dispute kit is supported or not.\\n function isSupported(uint96 _courtID, uint256 _disputeKitID) external view returns (bool) {\\n return courts[_courtID].supportedDisputeKits[_disputeKitID];\\n }\\n\\n /// @notice Gets the timesPerPeriod array for a given court.\\n /// @param _courtID The ID of the court to get the times from.\\n /// @return timesPerPeriod The timesPerPeriod array for the given court.\\n function getTimesPerPeriod(uint96 _courtID) external view returns (uint256[4] memory timesPerPeriod) {\\n timesPerPeriod = courts[_courtID].timesPerPeriod;\\n }\\n\\n // ************************************* //\\n // * Public Views for Dispute Kits * //\\n // ************************************* //\\n\\n /// @notice Gets the number of votes permitted for the specified dispute in the latest round.\\n /// @param _disputeID The ID of the dispute.\\n function getNumberOfVotes(uint256 _disputeID) external view returns (uint256) {\\n Dispute storage dispute = disputes[_disputeID];\\n return dispute.rounds[dispute.rounds.length - 1].nbVotes;\\n }\\n\\n /// @notice Returns true if the dispute kit will be switched to a parent DK.\\n /// @param _disputeID The ID of the dispute.\\n /// @return Whether DK will be switched or not.\\n function isDisputeKitJumping(uint256 _disputeID) external view returns (bool) {\\n Dispute storage dispute = disputes[_disputeID];\\n Round storage round = dispute.rounds[dispute.rounds.length - 1];\\n Court storage court = courts[dispute.courtID];\\n\\n if (round.nbVotes < court.jurorsForCourtJump) {\\n return false;\\n }\\n\\n // Jump if the parent court doesn't support the current DK.\\n return !courts[court.parent].supportedDisputeKits[round.disputeKitID];\\n }\\n\\n function getDisputeKitsLength() external view returns (uint256) {\\n return disputeKits.length;\\n }\\n\\n function convertEthToTokenAmount(IERC20 _toToken, uint256 _amountInEth) public view returns (uint256) {\\n return (_amountInEth * 10 ** currencyRates[_toToken].rateDecimals) / currencyRates[_toToken].rateInEth;\\n }\\n\\n // ************************************* //\\n // * Internal * //\\n // ************************************* //\\n\\n /// @notice Toggles the dispute kit support for a given court.\\n /// @param _courtID The ID of the court to toggle the support for.\\n /// @param _disputeKitID The ID of the dispute kit to toggle the support for.\\n /// @param _enable Whether to enable or disable the support. Note that classic dispute kit should always be enabled.\\n function _enableDisputeKit(uint96 _courtID, uint256 _disputeKitID, bool _enable) internal {\\n courts[_courtID].supportedDisputeKits[_disputeKitID] = _enable;\\n emit DisputeKitEnabled(_courtID, _disputeKitID, _enable);\\n }\\n\\n /// @notice If called only once then set _onError to Revert, otherwise set it to Return\\n /// @param _account The account to set the stake for.\\n /// @param _courtID The ID of the court to set the stake for.\\n /// @param _newStake The new stake.\\n /// @param _noDelay True if the stake change should not be delayed.\\n /// @param _onError Whether to revert or return false on error.\\n /// @return Whether the stake was successfully set or not.\\n function _setStake(\\n address _account,\\n uint96 _courtID,\\n uint256 _newStake,\\n bool _noDelay,\\n OnError _onError\\n ) internal returns (bool) {\\n if (_courtID == FORKING_COURT || _courtID >= courts.length) {\\n _stakingFailed(_onError, StakingResult.CannotStakeInThisCourt); // Staking directly into the forking court is not allowed.\\n return false;\\n }\\n if (_newStake != 0 && _newStake < courts[_courtID].minStake) {\\n _stakingFailed(_onError, StakingResult.CannotStakeLessThanMinStake); // Staking less than the minimum stake is not allowed.\\n return false;\\n }\\n (uint256 pnkDeposit, uint256 pnkWithdrawal, StakingResult stakingResult) = sortitionModule.validateStake(\\n _account,\\n _courtID,\\n _newStake,\\n _noDelay\\n );\\n if (stakingResult != StakingResult.Successful) {\\n _stakingFailed(_onError, stakingResult);\\n return false;\\n }\\n if (pnkDeposit > 0) {\\n if (!pinakion.safeTransferFrom(_account, address(this), pnkDeposit)) {\\n _stakingFailed(_onError, StakingResult.StakingTransferFailed);\\n return false;\\n }\\n }\\n if (pnkWithdrawal > 0) {\\n if (!pinakion.safeTransfer(_account, pnkWithdrawal)) {\\n _stakingFailed(_onError, StakingResult.UnstakingTransferFailed);\\n return false;\\n }\\n }\\n sortitionModule.setStake(_account, _courtID, pnkDeposit, pnkWithdrawal, _newStake);\\n\\n return true;\\n }\\n\\n /// @notice It may revert depending on the _onError parameter.\\n function _stakingFailed(OnError _onError, StakingResult _result) internal pure virtual {\\n if (_onError == OnError.Return) return;\\n if (_result == StakingResult.StakingTransferFailed) revert StakingTransferFailed();\\n if (_result == StakingResult.UnstakingTransferFailed) revert UnstakingTransferFailed();\\n if (_result == StakingResult.CannotStakeInMoreCourts) revert StakingInTooManyCourts();\\n if (_result == StakingResult.CannotStakeInThisCourt) revert StakingNotPossibleInThisCourt();\\n if (_result == StakingResult.CannotStakeLessThanMinStake) revert StakingLessThanCourtMinStake();\\n if (_result == StakingResult.CannotStakeZeroWhenNoStake) revert StakingZeroWhenNoStake();\\n }\\n\\n /// @notice Gets a court ID, the minimum number of jurors and an ID of a dispute kit from a specified extra data bytes array.\\n /// @dev If `_extraData` contains an incorrect value then this value will be switched to default.\\n /// @param _extraData The extra data bytes array. The first 32 bytes are the court ID, the next are the minimum number of jurors and the last are the dispute kit ID.\\n /// @return courtID The court ID.\\n /// @return minJurors The minimum number of jurors required.\\n /// @return disputeKitID The ID of the dispute kit.\\n function _extraDataToCourtIDMinJurorsDisputeKit(\\n bytes memory _extraData\\n ) internal view returns (uint96 courtID, uint256 minJurors, uint256 disputeKitID) {\\n // Note that if the extradata doesn't contain 32 bytes for the dispute kit ID it'll return the default 0 index.\\n if (_extraData.length >= 64) {\\n assembly {\\n // solium-disable-line security/no-inline-assembly\\n courtID := mload(add(_extraData, 0x20))\\n minJurors := mload(add(_extraData, 0x40))\\n disputeKitID := mload(add(_extraData, 0x60))\\n }\\n if (courtID == FORKING_COURT || courtID >= courts.length) {\\n courtID = GENERAL_COURT;\\n }\\n if (minJurors == 0) {\\n minJurors = DEFAULT_NB_OF_JURORS;\\n }\\n if (disputeKitID == NULL_DISPUTE_KIT || disputeKitID >= disputeKits.length) {\\n disputeKitID = DISPUTE_KIT_CLASSIC; // 0 index is not used.\\n }\\n } else {\\n courtID = GENERAL_COURT;\\n minJurors = DEFAULT_NB_OF_JURORS;\\n disputeKitID = DISPUTE_KIT_CLASSIC;\\n }\\n }\\n\\n // ************************************* //\\n // * Errors * //\\n // ************************************* //\\n\\n error OwnerOnly();\\n error InstructorOnly();\\n error OwnerOrInstructorOnly();\\n error DisputeKitOnly();\\n error SortitionModuleOnly();\\n error UnsuccessfulCall();\\n error InvalidDisputKitParent();\\n error MinStakeLowerThanParentCourt();\\n error UnsupportedDisputeKit();\\n error InvalidForkingCourtAsParent();\\n error WrongDisputeKitIndex();\\n error CannotDisableClassicDK();\\n error StakingInTooManyCourts();\\n error StakingNotPossibleInThisCourt();\\n error StakingLessThanCourtMinStake();\\n error StakingTransferFailed();\\n error UnstakingTransferFailed();\\n error ArbitrationFeesNotEnough();\\n error DisputeKitNotSupportedByCourt();\\n error MustSupportDisputeKitClassic();\\n error TokenNotAccepted();\\n error EvidenceNotPassedAndNotAppeal();\\n error DisputeStillDrawing();\\n error CommitPeriodNotPassed();\\n error VotePeriodNotPassed();\\n error AppealPeriodNotPassed();\\n error NotEvidencePeriod();\\n error AppealFeesNotEnough();\\n error DisputeNotAppealable();\\n error NotExecutionPeriod();\\n error RulingAlreadyExecuted();\\n error DisputePeriodIsFinal();\\n error TransferFailed();\\n error AllJurorsDrawn();\\n error NoJurorDrawn();\\n error StakingZeroWhenNoStake();\\n}\\n\",\"keccak256\":\"0x6a0daf9a8720b0618dc69c8b29794fad12f5477d4ec96c778c7c140150b8214d\",\"license\":\"MIT\"},\"src/libraries/Constants.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n// Courts\\nuint96 constant FORKING_COURT = 0; // Index of the forking court.\\nuint96 constant GENERAL_COURT = 1; // Index of the default (general) court.\\n\\n// Dispute Kits\\nuint256 constant NULL_DISPUTE_KIT = 0; // Null pattern to indicate a top-level DK which has no parent.\\nuint256 constant DISPUTE_KIT_CLASSIC = 1; // Index of the default DK. 0 index is skipped.\\n\\n// Sortition Module\\nuint256 constant MAX_STAKE_PATHS = 4; // The maximum number of stake paths a juror can have.\\nuint256 constant DEFAULT_K = 6; // Default number of children per node.\\n\\n// Defaults\\nuint256 constant DEFAULT_NB_OF_JURORS = 3; // The default number of jurors in a dispute.\\nIERC20 constant NATIVE_CURRENCY = IERC20(address(0)); // The native currency, such as ETH on Arbitrum, Optimism and Ethereum L1.\\n\\n// Units\\nuint256 constant ONE_BASIS_POINT = 10000;\\n\\nenum OnError {\\n Revert,\\n Return\\n}\\n\\nenum StakingResult {\\n Successful,\\n Delayed,\\n StakingTransferFailed,\\n UnstakingTransferFailed,\\n CannotStakeInMoreCourts,\\n CannotStakeInThisCourt,\\n CannotStakeLessThanMinStake,\\n CannotStakeMoreThanMaxStakePerJuror,\\n CannotStakeMoreThanMaxTotalStaked,\\n CannotStakeZeroWhenNoStake\\n}\\n\",\"keccak256\":\"0xb8c96c842259ca1384e8450dfb214f0fcd604829c84293dd3f8981f3421b66c9\",\"license\":\"MIT\"},\"src/libraries/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// Adapted from https://github.com/OpenZeppelin/openzeppelin-contracts/blob/a7a94c77463acea95d979aae1580fb0ddc3b6a1e/contracts/token/ERC20/utils/SafeERC20.sol\\n\\npragma solidity ^0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/// @title SafeERC20\\n///\\n/// @notice Wrappers around ERC20 operations\\n///\\n/// @dev Throws on failure (when the token contract returns false).\\n/// Tokens that return no value (and instead revert or throw on failure) are also supported.\\n/// Non-reverting calls are assumed to be successful.\\n/// To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n/// which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\nlibrary SafeERC20 {\\n /// @notice Increases the allowance granted to `spender` by the caller.\\n /// @param _token Token to transfer.\\n /// @param _spender The address which will spend the funds.\\n /// @param _addedValue The amount of tokens to increase the allowance by.\\n function increaseAllowance(IERC20 _token, address _spender, uint256 _addedValue) internal returns (bool) {\\n _token.approve(_spender, _token.allowance(address(this), _spender) + _addedValue);\\n return true;\\n }\\n\\n /// @notice Calls transfer() without reverting.\\n /// @param _token Token to transfer.\\n /// @param _to Recipient address.\\n /// @param _value Amount transferred.\\n /// @return Whether transfer succeeded or not.\\n function safeTransfer(IERC20 _token, address _to, uint256 _value) internal returns (bool) {\\n (bool success, bytes memory data) = address(_token).call(abi.encodeCall(IERC20.transfer, (_to, _value)));\\n return (success && (data.length == 0 || abi.decode(data, (bool))));\\n }\\n\\n /// @notice Calls transferFrom() without reverting.\\n /// @param _token Token to transfer.\\n /// @param _from Sender address.\\n /// @param _to Recipient address.\\n /// @param _value Amount transferred.\\n /// @return Whether transfer succeeded or not.\\n function safeTransferFrom(IERC20 _token, address _from, address _to, uint256 _value) internal returns (bool) {\\n (bool success, bytes memory data) = address(_token).call(\\n abi.encodeCall(IERC20.transferFrom, (_from, _to, _value))\\n );\\n return (success && (data.length == 0 || abi.decode(data, (bool))));\\n }\\n}\\n\",\"keccak256\":\"0x36b92f984484f9dfd63a40ccb1c1e23cde0085db36ec8adb7afe7e98ef667bd7\",\"license\":\"MIT\"},\"src/proxy/Initializable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol) \\n\\npragma solidity ^0.8.24;\\n\\n/**\\n * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed\\n * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an\\n * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer\\n * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.\\n *\\n * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be\\n * reused. This mechanism prevents re-execution of each \\\"step\\\" but allows the creation of new initialization steps in\\n * case an upgrade adds a module that needs to be initialized.\\n *\\n * For example:\\n *\\n * ```solidity\\n * contract MyToken is ERC20Upgradeable {\\n * function initialize() initializer public {\\n * __ERC20_init(\\\"MyToken\\\", \\\"MTK\\\");\\n * }\\n * }\\n *\\n * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {\\n * function initializeV2() reinitializer(2) public {\\n * __ERC20Permit_init(\\\"MyToken\\\");\\n * }\\n * }\\n * ```\\n *\\n * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as\\n * possible by providing the encoded function call as the `_data` argument to the proxy constructor\\n *\\n * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure\\n * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.\\n *\\n * [CAUTION]\\n * ====\\n * Avoid leaving a contract uninitialized.\\n *\\n * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation\\n * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke\\n * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:\\n *\\n * ```\\n * /// @custom:oz-upgrades-unsafe-allow constructor\\n * constructor() {\\n * _disableInitializers();\\n * }\\n * ```\\n */\\nabstract contract Initializable {\\n /**\\n * @dev Storage of the initializable contract.\\n *\\n * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions\\n * when using with upgradeable contracts.\\n *\\n * @custom:storage-location erc7201:openzeppelin.storage.Initializable\\n */\\n struct InitializableStorage {\\n /**\\n * @dev Indicates that the contract has been initialized.\\n */\\n uint64 _initialized;\\n /**\\n * @dev Indicates that the contract is in the process of being initialized.\\n */\\n bool _initializing;\\n }\\n\\n // keccak256(abi.encode(uint256(keccak256(\\\"openzeppelin.storage.Initializable\\\")) - 1))\\n bytes32 private constant _INITIALIZABLE_STORAGE =\\n 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0e;\\n\\n /**\\n * @dev The contract is already initialized.\\n */\\n error AlreadyInitialized();\\n\\n /**\\n * @dev The contract is not initializing.\\n */\\n error NotInitializing();\\n\\n /**\\n * @dev Triggered when the contract has been initialized or reinitialized.\\n */\\n event Initialized(uint64 version);\\n\\n /**\\n * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,\\n * `onlyInitializing` functions can be used to initialize parent contracts.\\n *\\n * Similar to `initializer()`, except that functions marked with `initializer` can be nested in the context of a\\n * constructor.\\n *\\n * Emits an {Initialized} event.\\n */\\n modifier initializer() {\\n // solhint-disable-next-line var-name-mixedcase\\n InitializableStorage storage $ = _getInitializableStorage();\\n\\n bool isTopLevelCall = !$._initializing;\\n uint64 initialized = $._initialized;\\n if (!(isTopLevelCall && initialized < 1) && !(address(this).code.length == 0 && initialized == 1)) {\\n revert AlreadyInitialized();\\n }\\n $._initialized = 1;\\n if (isTopLevelCall) {\\n $._initializing = true;\\n }\\n _;\\n if (isTopLevelCall) {\\n $._initializing = false;\\n emit Initialized(1);\\n }\\n }\\n\\n /**\\n * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the\\n * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be\\n * used to initialize parent contracts.\\n *\\n * A reinitializer may be used after the original initialization step. This is essential to configure modules that\\n * are added through upgrades and that require initialization.\\n *\\n * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`\\n * cannot be nested. If one is invoked in the context of another, execution will revert.\\n *\\n * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in\\n * a contract, executing them in the right order is up to the developer or operator.\\n *\\n * WARNING: setting the version to 255 will prevent any future reinitialization.\\n *\\n * Emits an {Initialized} event.\\n */\\n modifier reinitializer(uint64 version) {\\n // solhint-disable-next-line var-name-mixedcase\\n InitializableStorage storage $ = _getInitializableStorage();\\n\\n if ($._initializing || $._initialized >= version) {\\n revert AlreadyInitialized();\\n }\\n $._initialized = version;\\n $._initializing = true;\\n _;\\n $._initializing = false;\\n emit Initialized(version);\\n }\\n\\n /**\\n * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the\\n * {initializer} and {reinitializer} modifiers, directly or indirectly.\\n */\\n modifier onlyInitializing() {\\n _checkInitializing();\\n _;\\n }\\n\\n /**\\n * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.\\n */\\n function _checkInitializing() internal view virtual {\\n if (!_isInitializing()) {\\n revert NotInitializing();\\n }\\n }\\n\\n /**\\n * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.\\n * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized\\n * to any version. It is recommended to use this to lock implementation contracts that are designed to be called\\n * through proxies.\\n *\\n * Emits an {Initialized} event the first time it is successfully executed.\\n */\\n function _disableInitializers() internal virtual {\\n // solhint-disable-next-line var-name-mixedcase\\n InitializableStorage storage $ = _getInitializableStorage();\\n\\n if ($._initializing) {\\n revert AlreadyInitialized();\\n }\\n if ($._initialized != type(uint64).max) {\\n $._initialized = type(uint64).max;\\n emit Initialized(type(uint64).max);\\n }\\n }\\n\\n /**\\n * @dev Returns the highest version that has been initialized. See {reinitializer}.\\n */\\n function _getInitializedVersion() internal view returns (uint64) {\\n return _getInitializableStorage()._initialized;\\n }\\n\\n /**\\n * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.\\n */\\n function _isInitializing() internal view returns (bool) {\\n return _getInitializableStorage()._initializing;\\n }\\n\\n /**\\n * @dev Returns a pointer to the storage namespace.\\n */\\n // solhint-disable-next-line var-name-mixedcase\\n function _getInitializableStorage() private pure returns (InitializableStorage storage $) {\\n assembly {\\n $.slot := _INITIALIZABLE_STORAGE\\n }\\n }\\n}\\n\",\"keccak256\":\"0xdad09e5f773fa6940dbd8c28480f602a7eaa3c70d3da9d06df140187cbf5dad4\",\"license\":\"MIT\"},\"src/proxy/UUPSProxiable.sol\":{\"content\":\"//SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.24;\\n\\n/// @title UUPS Proxiable\\n/// @author Simon Malatrait \\n/// @notice This contract implements an upgradeability mechanism designed for UUPS proxies.\\n///\\n/// @dev Adapted from \\n/// The functions included here can perform an upgrade of an UUPS Proxy, when this contract is set as the implementation behind such a proxy.\\n///\\n/// IMPORTANT: A UUPS proxy requires its upgradeability functions to be in the implementation as opposed to the transparent proxy.\\n/// This means that if the proxy is upgraded to an implementation that does not support this interface, it will no longer be upgradeable.\\n///\\n/// A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is\\n/// reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing\\n/// `UUPSProxiable` with a custom implementation of upgrades.\\n///\\n/// The `_authorizeUpgrade` function must be overridden to include access restriction to the upgrade mechanism.\\nabstract contract UUPSProxiable {\\n // ************************************* //\\n // * Event * //\\n // ************************************* //\\n\\n /// @notice Emitted when the `implementation` has been successfully upgraded.\\n /// @param newImplementation Address of the new implementation the proxy is now forwarding calls to.\\n event Upgraded(address indexed newImplementation);\\n\\n // ************************************* //\\n // * Error * //\\n // ************************************* //\\n\\n /// @notice The call is from an unauthorized context.\\n error UUPSUnauthorizedCallContext();\\n\\n /// @notice The storage `slot` is unsupported as a UUID.\\n error UUPSUnsupportedProxiableUUID(bytes32 slot);\\n\\n /// @notice The `implementation` is not UUPS-compliant\\n error InvalidImplementation(address implementation);\\n\\n /// Failed Delegated call\\n error FailedDelegateCall();\\n\\n // ************************************* //\\n // * Storage * //\\n // ************************************* //\\n\\n /// @dev Storage slot with the address of the current implementation.\\n /// @dev This is the keccak-256 hash of \\\"eip1967.proxy.implementation\\\" subtracted by 1, and is\\n /// @dev validated in the constructor.\\n /// @dev NOTE: bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1)\\n bytes32 private constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\\n\\n /// @dev Storage variable of the proxiable contract address.\\n /// @dev It is used to check whether or not the current call is from the proxy.\\n /// @custom:oz-upgrades-unsafe-allow state-variable-immutable\\n address private immutable __self = address(this);\\n\\n // ************************************* //\\n // * Governance * //\\n // ************************************* //\\n\\n /// @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract.\\n /// @dev Called by {upgradeToAndCall}.\\n function _authorizeUpgrade(address newImplementation) internal virtual;\\n\\n // ************************************* //\\n // * State Modifiers * //\\n // ************************************* //\\n\\n /// @notice Upgrade mechanism including access control and UUPS-compliance.\\n /// @param newImplementation Address of the new implementation contract.\\n /// @param data Data used in a delegate call to `newImplementation` if non-empty. This will typically be an encoded\\n /// function call, and allows initializing the storage of the proxy like a Solidity constructor.\\n /// @dev Reverts if the execution is not performed via delegatecall or the execution\\n /// context is not of a proxy with an ERC1967-compliant implementation pointing to self.\\n function upgradeToAndCall(address newImplementation, bytes memory data) public payable virtual {\\n _authorizeUpgrade(newImplementation);\\n\\n // Check that the execution is being performed through a delegatecall call and that the execution context is\\n // a proxy contract with an implementation (as defined in ERC1967) pointing to self.\\n if (address(this) == __self || _getImplementation() != __self) {\\n revert UUPSUnauthorizedCallContext();\\n }\\n\\n try UUPSProxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {\\n if (slot != IMPLEMENTATION_SLOT) {\\n revert UUPSUnsupportedProxiableUUID(slot);\\n }\\n // Store the new implementation address to the implementation storage slot.\\n assembly {\\n sstore(IMPLEMENTATION_SLOT, newImplementation)\\n }\\n emit Upgraded(newImplementation);\\n\\n if (data.length != 0) {\\n // The return data is not checked (checking, in case of success, that the newImplementation code is non-empty if the return data is empty) because the authorized callee is trusted.\\n /// @custom:oz-upgrades-unsafe-allow delegatecall\\n (bool success, ) = newImplementation.delegatecall(data);\\n if (!success) {\\n revert FailedDelegateCall();\\n }\\n }\\n } catch {\\n revert InvalidImplementation(newImplementation);\\n }\\n }\\n\\n // ************************************* //\\n // * Public Views * //\\n // ************************************* //\\n\\n /// @notice Implementation of the ERC1822 `proxiableUUID` function. This returns the storage slot used by the\\n /// implementation. It is used to validate the implementation's compatibility when performing an upgrade.\\n ///\\n /// @dev IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks\\n /// bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this\\n /// function revert if invoked through a proxy. This is guaranteed by the if statement.\\n function proxiableUUID() external view virtual returns (bytes32) {\\n if (address(this) != __self) {\\n // Must not be called through delegatecall\\n revert UUPSUnauthorizedCallContext();\\n }\\n return IMPLEMENTATION_SLOT;\\n }\\n\\n /// @notice Returns the version of the implementation.\\n /// @return Version string.\\n function version() external view virtual returns (string memory);\\n\\n // ************************************* //\\n // * Internal Views * //\\n // ************************************* //\\n\\n function _getImplementation() internal view returns (address implementation) {\\n assembly {\\n implementation := sload(IMPLEMENTATION_SLOT)\\n }\\n }\\n}\\n\",\"keccak256\":\"0xa369061748e8a7b02873d597d4c78a2a09328111f04a97428b1c209e82cf5414\",\"license\":\"MIT\"}},\"version\":1}",
+ "bytecode": "0x60a080604052346100c157306080525f5160206156465f395f51905f525460ff8160401c166100b3576002600160401b03196001600160401b03821601610060575b60405161558090816100c682396080518181816112b001526114de0152f35b6001600160401b0319166001600160401b039081175f5160206156465f395f51905f525581527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a15f80610041565b62dc149f60e41b5f5260045ffd5b5f80fdfe60806040526004361015610011575f80fd5b5f3560e01c8062f5822c146103235780630219da791461031e5780630761c14d1461031957806309cfdc9c146103145780630b7414bc1461030f578063115d53761461030a5780631860592b1461030557806319b81529146103005780631c3db16d146102fb5780631f5a0dd2146102f65780632d29a47b146102f15780632e1daf2f146102ec5780633cfd1184146102e757806342c37fa3146102e25780634f1ef286146102dd57806352d1902d146102d857806354fd4d50146102d3578063564a565d146102ce57806359ec827e146102c95780636a8c9194146102c457806371ae413d146102bf5780637717a6e8146102ba5780637934c0be146102b557806382d02237146102b057806386541b24146102ab57806386cdecef146102a65780638a9bb02a146102a15780638bb048751461029c5780638da5cb5b14610297578063a6f9dae114610292578063acdbf51d1461028d578063afe15cfb14610288578063b004963714610283578063b702a8791461027e578063c13517e114610279578063c258bb1914610274578063c35699021461026f578063c71f42531461026a578063cf0c38f814610265578063d07368bd14610260578063d4d1d76a1461025b578063d874514b14610256578063d98493f614610251578063e399d29b1461024c578063f6506db414610247578063f7434ea914610242578063fbf405b01461023d578063fc6f8f16146102385763fe524c3914610233575f80fd5b6131a5565b613185565b61315f565b613129565b613016565b612f55565b612ef8565b612c27565b612c0a565b612b9f565b612b79565b612b39565b6126f9565b6126ad565b61242e565b612017565b611fcb565b611f48565b611eef565b611e76565b611e51565b611d02565b611c54565b611ab6565b61193d565b61180d565b611784565b61175a565b611734565b61169e565b611680565b6115fd565b611552565b6114c4565b611266565b6111af565b611134565b6110d7565b610e80565b610e00565b610d96565b610d6e565b610d3b565b610750565b61061c565b610493565b610421565b6103b1565b61033d565b6001600160a01b0381160361033957565b5f80fd5b346103395760203660031901126103395760043561035a81610328565b6001600160a01b035f54163303610389576001600160a01b03166001600160a01b031960025416176002555f80f35b7f596dcdb8000000000000000000000000000000000000000000000000000000005f5260045ffd5b34610339576020366003190112610339576001600160a01b036004356103d681610328565b165f526008602052606060405f205460ff604051918181161515835267ffffffffffffffff8160081c16602084015260481c166040820152f35b6001600160601b0381160361033957565b346103395760603660031901126103395760043561043e81610328565b60243561044a81610410565b604435906001600160a01b0360045416330361046b5761046992613fb0565b005b7f9d6cab99000000000000000000000000000000000000000000000000000000005f5260045ffd5b34610339576020366003190112610339576004356104b081610328565b6001600160a01b035f54163314158061050e575b6104e6576001600160a01b03166001600160a01b031960015416176001555f80f35b7ff10d23b5000000000000000000000000000000000000000000000000000000005f5260045ffd5b506001600160a01b03600154163314156104c4565b634e487b7160e01b5f52604160045260245ffd5b6101a0810190811067ffffffffffffffff82111761055457604052565b610523565b90601f8019910116810190811067ffffffffffffffff82111761055457604052565b6040519061058b61010083610559565b565b6040519061058b6101a083610559565b67ffffffffffffffff81116105545760051b60200190565b9080601f830112156103395781356105cc8161059d565b926105da6040519485610559565b81845260208085019260051b82010192831161033957602001905b8282106106025750505090565b81358152602091820191016105f5565b8015150361033957565b346103395760603660031901126103395760043561063981610410565b60243567ffffffffffffffff8111610339576106599036906004016105b5565b6044359061066682610612565b6001600160a01b035f54163303610389575f5b81518110156104695782156106fa5761069281836131ec565b511580156106e4575b6106bc57806106b66106af600193856131ec565b51866143e8565b01610679565b7f7ab15312000000000000000000000000000000000000000000000000000000005f5260045ffd5b506106ef81836131ec565b51600654111561069b565b600161070682846131ec565b5114610728578061072361071c600193856131ec565b5186614397565b6106b6565b7fada223fa000000000000000000000000000000000000000000000000000000005f5260045ffd5b346103395760203660031901126103395760043561076d816115b1565b5061078761078282546001600160601b031690565b610ddf565b509060038101916107a261079b8454613214565b809461323f565b5060018301936107b3855460ff1690565b6107bc816115e1565b806108d857501580610896575b61086e57600360068201549101540361084657547f4e6f5cf43b95303e86aee81683df63992061723a829ee012db21dad388756b91926108379261082b9260601c60ff161561083c5761081e60015b83613287565b6002429101555460ff1690565b6040519182918261329f565b0390a2005b61081e6002610818565b7f9e4486b0000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f3e9727df000000000000000000000000000000000000000000000000000000005f5260045ffd5b506108a5600284015442613232565b6108d26108c86108b6875460ff1690565b6108bf816115e1565b60068601613258565b90549060031b1c90565b116107c9565b90506108e9819594959392936115e1565b60018103610a5057506109246108c8610906600287015442613232565b926006610914875460ff1690565b9161091e836115e1565b01613258565b119081610993575b5061096b57805460ff191660021781557f4e6f5cf43b95303e86aee81683df63992061723a829ee012db21dad388756b91916108379161082b9161081e565b7f9bf4af0a000000000000000000000000000000000000000000000000000000005f5260045ffd5b6109c491506109a56109b89154611ec2565b90546001600160a01b039160031b1c1690565b6001600160a01b031690565b602060405180927f0baa64d10000000000000000000000000000000000000000000000000000000082528180610a0289600483019190602083019252565b03915afa908115610a4b575f91610a1c575b50155f61092c565b610a3e915060203d602011610a44575b610a368183610559565b810190613267565b5f610a14565b503d610a2c565b61327c565b610a59816115e1565b60028103610ba75750610a766108c8610906600287015442613232565b119081610b1e575b50610af657805460ff191660031781557f4e6f5cf43b95303e86aee81683df63992061723a829ee012db21dad388756b91916108379161082b916001600160a01b03610acb825460601c90565b16867fa5d41b970d849372be1da1481ffd78d162bfe57a7aa2fe4e5fb73481fa5ac24f5f80a361081e565b7fcc46f568000000000000000000000000000000000000000000000000000000005f5260045ffd5b610b3091506109a56109b89154611ec2565b602060405180927f6d4cd8ea0000000000000000000000000000000000000000000000000000000082528180610b6e89600483019190602083019252565b03915afa908115610a4b575f91610b88575b50155f610a7e565b610ba1915060203d602011610a4457610a368183610559565b5f610b80565b610bb0816115e1565b60038103610cd1576108c8610bd9916006610bcf600289015442613232565b9461091e836115e1565b119081610c48575b50610c2057805460ff191660041781557f4e6f5cf43b95303e86aee81683df63992061723a829ee012db21dad388756b91916108379161082b9161081e565b7f2f4dfd87000000000000000000000000000000000000000000000000000000005f5260045ffd5b610c5a91506109a56109b89154611ec2565b602060405180927f0855bbe90000000000000000000000000000000000000000000000000000000082528180610c9889600483019190602083019252565b03915afa908115610a4b575f91610cb2575b50155f610be1565b610ccb915060203d602011610a4457610a368183610559565b5f610caa565b905060049150610ce0816115e1565b14610d135761082b610837917f4e6f5cf43b95303e86aee81683df63992061723a829ee012db21dad388756b919361081e565b7f0fe7191e000000000000000000000000000000000000000000000000000000005f5260045ffd5b34610339576040366003190112610339576020610d66600435610d5d81610328565b602435906132fb565b604051908152f35b34610339576020366003190112610339576020610d8c600435613353565b6040519015158152f35b34610339576020366003190112610339576060610db46004356133f9565b906040519283521515602083015215156040820152f35b634e487b7160e01b5f52603260045260245ffd5b600554811015610dfb5760055f52601560205f20910201905f90565b610dcb565b346103395760203660031901126103395760043560055481101561033957610e2790610ddf565b508054600282015460038301546004840154600590940154604080516001600160601b0386168152606095861c60ff16151560208201529081019390935292820152608081019290925260a08201528060c081015b0390f35b3461033957606036600319011261033957600435604435602435610ea3836115b1565b506004610eb4600183015460ff1690565b610ebd816115e1565b036110a557816003610ecf920161323f565b50906004820193610ee2855494856134e1565b926005810194855496600683015490610eff8260028601546132ec565b92610f156109b86109a560018801549754611ec2565b6040517fda3beb8c00000000000000000000000000000000000000000000000000000000815260048101889052602481018990529290602090849060449082905afa928315610a4b575f93611074575b50826110455783891161103c575b9780979695949392985b55965b868810610f9657898981815403610f9357005b55005b9091929394959698828a105f14610ff657610fe7600191610fb561057b565b908882528960208301528460408301528560608301528660808301528760a083015260c08201528b60e0820152614a40565b995b0196959493929190610f80565b9860019061103761100561057b565b8881528960208201528460408201528560608201528660808201528760a08201528c60c08201528260e08201526144aa565b610fe9565b97508297610f73565b61104e846132af565b8911611063575b978097969594939298610f7d565b975061106e836132af565b97611055565b61109791935060203d60201161109e575b61108f8183610559565b8101906134ee565b915f610f65565b503d611085565b7f8794ce4b000000000000000000000000000000000000000000000000000000005f5260045ffd5b5f91031261033957565b34610339575f3660031901126103395760206001600160a01b0360045416604051908152f35b905f905b6004821061110e57505050565b6020806001928551815201930191019091611101565b60808101929161058b91906110fd565b346103395760203660031901126103395761116b60043561115481610410565b60806040516111638282610559565b369037610ddf565b50604051906006015f825b6004821061119957610e7c8461118d608082610559565b60405191829182611124565b6001602081928554815201930191019091611176565b34610339576040366003190112610339576004356111cc81610328565b6024356001600160a01b0360045416330361046b57610469916001600160a01b036002541661500d565b67ffffffffffffffff811161055457601f01601f191660200190565b92919261121e826111f6565b9161122c6040519384610559565b829481845281830111610339578281602093845f960137010152565b9080601f830112156103395781602061126393359101611212565b90565b60403660031901126103395760043561127e81610328565b60243567ffffffffffffffff81116103395761129e903690600401611248565b6112a66150a2565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016803014908115611489575b50611461576001600160a01b0382166040517f52d1902d000000000000000000000000000000000000000000000000000000008152602081600481855afa5f9181611440575b5061135b577f0c760937000000000000000000000000000000000000000000000000000000005f526001600160a01b03841660045260245ffd5b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc81036114155750827f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a28051806113d357005b5f926020849301905af46113e56134fd565b50156113ed57005b7f736436ba000000000000000000000000000000000000000000000000000000005f5260045ffd5b7faa1d49a4000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b61145a91925060203d60201161109e5761108f8183610559565b905f611321565b7fe07c8dba000000000000000000000000000000000000000000000000000000005f5260045ffd5b90506114bc7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b14155f6112db565b34610339575f366003190112610339576001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001630036114615760206040517f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8152f35b805180835260209291819084018484015e5f828201840152601f01601f1916010190565b34610339575f36600319011261033957610e7c604051611573604082610559565b600581527f322e302e30000000000000000000000000000000000000000000000000000000602082015260405191829160208352602083019061152e565b600754811015610dfb5760075f52600e60205f20910201905f90565b634e487b7160e01b5f52602160045260245ffd5b600511156115eb57565b6115cd565b9060058210156115eb5752565b34610339576020366003190112610339576004356007548110156103395761162660ff916115b1565b508054600260018301549201546040519384936001600160a01b0360a08601946001600160601b0380821616875260601c16602086015261166c604086018383166115f0565b60081c161515606084015260808301520390f35b34610339576020366003190112610339576020610d6660043561352c565b34610339576060366003190112610339576004356116bb81610328565b60243560443567ffffffffffffffff8111610339576116de903690600401611248565b6001600160a01b035f54163303610389575f928392602083519301915af16117046134fd565b501561170c57005b7f44125e5e000000000000000000000000000000000000000000000000000000005f5260045ffd5b34610339575f3660031901126103395760206001600160a01b0360015416604051908152f35b346103395760403660031901126103395761046960043561177a81610410565b6024359033614203565b34610339576040366003190112610339576004356117a181610328565b602435906117ae82610612565b6001600160a01b035f54163303610389576001600160a01b031690815f52600860205260405f2060ff1981541660ff831515161790551515907f541615e167511d757a7067a700eb54431b256bb458dfdce0ac58bf2ed0aefd445f80a3005b346103395760603660031901126103395760043561182a81610328565b6024359067ffffffffffffffff821682036103395760443560ff81168103610339576001600160a01b035f54163303610389576001600160a01b03919091165f81815260086020818152604092839020805469ffffffffffffffffff0019169287901b68ffffffffffffffff001692909217604886901b69ff0000000000000000001617909155815167ffffffffffffffff909516855260ff90931692840192909252917fe6996b7f03e9bd02228b99d3d946932e3197f505f60542c4cfbc919441d8a4e69181908101610837565b8060e312156103395760405190611911608083610559565b8190610144116103395760c4905b610144821061192d57505090565b813581526020918201910161191f565b34610339576101403660031901126103395760043561195b81610410565b60243561196781610612565b6044359060643560a43560843561197d366118f9565b926001600160a01b035f54163303610389576001600160601b036119a088610ddf565b50971696600188141580611a95575b611a6d575f600182018054915b828110611a4a57600284018a905583546cff000000000000000000000000191689151560601b6cff000000000000000000000000161784558a7f709b1f5fda58af9a4f52dacd1ec404840a8148455700cce155a2bd8cf127ef1a8b8b6108378c8c8c8c611a3e8460068f846003820155856004820155866005820155016135fa565b6040519687968761361e565b896002611a5d6107826108c88587611eda565b50015410611a6d576001016119bc565b7f97170789000000000000000000000000000000000000000000000000000000005f5260045ffd5b50866002611aad61078284546001600160601b031690565b500154116119af565b346103395760403660031901126103395760206001611ae56024356003611ade6004356115b1565b500161323f565b500154604051908152f35b90602080835192838152019201905f5b818110611b0d5750505090565b82516001600160a01b0316845260209384019390920191600101611b00565b90602080835192838152019201905f5b818110611b495750505090565b82516001600160601b0316845260209384019390920191600101611b3c565b905f905b600a8210611b7957505050565b6020806001928551815201930191019091611b6c565b611263906020815282516020820152602083015160408201526040830151606082015260608301516080820152608083015160a082015260a083015160c08201526101a0610180611c0b611bf460c08701516102c060e08701526102e0860190611af0565b60e0870151858203601f1901610100870152611b2c565b94610100810151610120850152610120810151610140850152611c406101408201516101608601906001600160a01b03169052565b610160810151828501520151910190611b68565b3461033957604036600319011261033957610e7c611cf6611cf06004356003611ade60243592604051611c8681610537565b5f81525f60208201525f60408201525f60608201525f60808201525f60a0820152606060c0820152606060e08201525f6101008201525f6101208201525f6101408201525f6101608201526101806101409160405192611ce68185610559565b36843701526115b1565b5061379b565b60405191829182611b8f565b3461033957602036600319011261033957600435611d1f816115b1565b5090600182019182546004611d348260ff1690565b611d3d816115e1565b036110a55760081c60ff16611e2957611d78611dbd91611d71611d5f856133f9565b5050865461ff00191661010017909655565b5460601c90565b60405184815283906001600160a01b038316907f394027a5fa6e098a1191094d1719d6929b9abc535fcc0c8f448d6a4e7562227690602090a36001600160a01b031690565b91823b15610339576040517f311a6c5600000000000000000000000000000000000000000000000000000000815260048101929092526024820152905f908290818381604481015b03925af18015610a4b57611e1557005b80611e235f61046993610559565b806110cd565b7fc977f8d3000000000000000000000000000000000000000000000000000000005f5260045ffd5b34610339575f3660031901126103395760206001600160a01b035f5416604051908152f35b3461033957602036600319011261033957600435611e9381610328565b5f5490336001600160a01b03831603610389576001600160a01b036001600160a01b031991169116175f555f80f35b600654811015610dfb5760065f5260205f2001905f90565b8054821015610dfb575f5260205f2001905f90565b3461033957602036600319011261033957600435600654811015610339576001600160a01b0360209160065f527ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f015416604051908152f35b3461033957602036600319011261033957611f646004356115b1565b5060ff60018201541660058110156115eb57600303611fc357611fb0611faa6108c86006611fa06001600160601b036002870154965416610ddf565b5001600301905f90565b826134e1565b905b604080519182526020820192909252f35b505f80611fb2565b3461033957602036600319011261033957600435611fe881610328565b6001600160a01b035f54163303610389576001600160a01b03166001600160a01b031960045416176004555f80f35b346103395760403660031901126103395760243560043561203782610328565b6001600160a01b035f541633141580612419575b6104e657612058816115b1565b5090600382019061207361206c8354613214565b809361323f565b5093612083600185015460ff1690565b61208c816115e1565b6123f157600685018054916003870192835411156123c9576120b96109b86004546001600160a01b031690565b803b1561033957604051633c694c4160e21b81526001600160a01b039290921660048301525f908290602490829084905af18015610a4b576123b5575b506121666121076109a58854611ec2565b96600b810196604061211989546134d3565b809a885f6001600160a01b0385518099819682957fd2b8035a0000000000000000000000000000000000000000000000000000000084526004840160209093929193604081019481520152565b0393165af18015610a4b575f935f91612380575b506001600160a01b038416918215612358576121a16109b86004546001600160a01b031690565b600185015490803b15610339576040517f21e1625e0000000000000000000000000000000000000000000000000000000081526001600160a01b038816600482015260248101929092525f908290604490829084905af1958615610a4b578960079561224b9361226399612344575b508954604080518f815260208101929092527f6119cf536152c11e0a9a6c22f3953ce4ecc93ee54fa72ffa326ffabded21509b91a38761387e565b6001600160601b038216156123325750915b016138e0565b549054146122af575b5050556122846109b86004546001600160a01b031690565b803b15610339575f6040518092633c694c4160e21b8252818381611e0560048201905f602083019252565b6122c46109b86004546001600160a01b031690565b91823b15610339576040517f5d2d784600000000000000000000000000000000000000000000000000000000815260048101929092526024820152905f908290604490829084905af18015610a4b5761231e575b8061226c565b80611e235f61232c93610559565b5f612318565b546001600160601b031690509161225d565b80611e235f61235293610559565b5f612210565b7f5c7171ee000000000000000000000000000000000000000000000000000000005f5260045ffd5b90506123a591935060403d6040116123ae575b61239d8183610559565b810190613859565b9290925f61217a565b503d612393565b80611e235f6123c393610559565b5f6120f6565b7f4df06de3000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f8285c4ef000000000000000000000000000000000000000000000000000000005f5260045ffd5b506001600160a01b036001541633141561204b565b60403660031901126103395760043560243567ffffffffffffffff81116103395761245d903690600401611248565b9061246782613f61565b34106126855761247682615331565b90506124a96124a561249e83600a61248f879897610ddf565b5001905f5260205260405f2090565b5460ff1690565b1590565b61265d57600754926125675f600a6124bf6150b5565b503360601b6bffffffffffffffffffffffff19166001600160601b03861617815542600282015561254061253861250e60036125066125006109a58c611ec2565b99610ddf565b50940161391b565b509261251e6004820154346132ec565b9860038501998a55845560036002820154910154906132c5565b612710900490565b600182015534600282015501906001600160a01b03166001600160a01b0319825416179055565b61257c6109b86004546001600160a01b031690565b90813b156103395760405163d09f392d60e01b8152600481018690525f6024820181905290928390604490829084905af1918215610a4b576001600160a01b0392612649575b5016905490803b15610339576125f3945f8094604051978895869485936302dbb79560e61b85528a6004860161393c565b03925af1918215610a4b57602092612635575b5033817f141dfc18aa6a56fc816f44f0e9e2f1ebc92b15ab167770e17db5b084c10ed9955f80a3604051908152f35b80611e235f61264393610559565b5f612606565b80611e235f61265793610559565b5f6125c2565b7fb34eb75d000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f38cd83c4000000000000000000000000000000000000000000000000000000005f5260045ffd5b34610339576020366003190112610339576004356126ca81610328565b6001600160a01b035f54163303610389576001600160a01b03166001600160a01b031960035416176003555f80f35b60603660031901126103395760043560243560443567ffffffffffffffff81116103395761272b903690600401611248565b6127348361352c565b3410612b1157612743836115b1565b5091600183016003612756825460ff1690565b61275f816115e1565b03612ae9576003840161277b6127758254613214565b8261323f565b509081546127916109b86109b86109a584611ec2565b3303612ac15786546001600160601b031681946127ad8461391b565b5092600386015460056127bf85610ddf565b50015411156129fa575b5088546bffffffffffffffffffffffff19166001600160601b03831617895561280691906127fb90805460ff19169055565b4260028a0155610ddf565b509361283461253861281c6004880154346132ec565b966003850197885560036002820154910154906132c5565b600183015534600283015581556128566109b86004546001600160a01b031690565b6128608354613214565b90803b156103395760405163d09f392d60e01b8152600481018b905260248101929092525f908290604490829084905af18015610a4b576129e6575b5054915490818303612915575b877f4e6f5cf43b95303e86aee81683df63992061723a829ee012db21dad388756b916001600160a01b036128de8a5460601c90565b1660405190837f9c9b64db9e130f48381bf697abf638e73117dbfbfd7a4484f2da3ba188f4187d5f80a35f81528060208101610837565b61295d926109b89261292a6109a59354613214565b6040518381528b907fcbe7939a71f0b369c7471d760a0a99b60b7bb010ee0406cba8a46679d1ea775690602090a4611ec2565b905490803b156103395761298c935f8094604051968795869485936302dbb79560e61b85528c6004860161393c565b03925af18015610a4b577f4e6f5cf43b95303e86aee81683df63992061723a829ee012db21dad388756b91926001600160a01b03926128de926129d2575b8194816128a9565b80611e235f6129e093610559565b5f6129ca565b80611e235f6129f493610559565b5f61289c565b916124a561249e612a1e612a10612a2a94610ddf565b50546001600160601b031690565b94600a61248f87610ddf565b612ab8575b906127fb61280692612a488b546001600160601b031690565b6001600160601b0381166001600160601b03851603612a6b575b509192506127c9565b612a758754613214565b6040516001600160601b03868116825292909216918e907f736e3f52761298c8c0823e1ebf482ed3c5ecb304f743d2d91a7c006e8e8d7a1f90602090a45f612a62565b60019550612a2f565b7f065f245f000000000000000000000000000000000000000000000000000000005f5260045ffd5b7fdf37bf2c000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f3191f8f1000000000000000000000000000000000000000000000000000000005f5260045ffd5b34610339576020366003190112610339576003612b576004356115b1565b500180545f198101908111612b7457611ae560039160209361323f565b613200565b34610339575f3660031901126103395760206001600160a01b0360035416604051908152f35b3461033957602036600319011261033957600435612bbc81610328565b6001600160a01b035f54163303610389576001600160a01b0360065491612be281613963565b16907f44063d258760b98116d53815adbc906a56b3563e540148cc0fc2457f83b5eeb25f80a3005b34610339575f366003190112610339576020600654604051908152f35b346103395761016036600319011261033957600435612c4581610410565b602435612c5181610612565b604435606435906084359260a43591612c69366118f9565b956101443567ffffffffffffffff811161033957612c8b9036906004016105b5565b966001600160a01b035f5416330361038957826002612ca984610ddf565b50015411611a6d57875115612ea2576001600160601b038216948515612e7a5760059796975491612cd86139cb565b50915f98600a8401995b8c51811015612d54578c81612cf781836131ec565b5115918215612d3d575b50506106bc5780612d37612d2a8f612d1d8f91956001966131ec565b515f5260205260405f2090565b805460ff19166001179055565b01612ce2565b612d4792506131ec565b516006541115818e612d01565b50908b92918b612d726124a561249e8e60015f5260205260405f2090565b612e52577f550ff678017abc294b4786a99a046628d5a1eac07be0f1ea7e89543f13576ee698612e3f886001612e388c8f8a6001600160601b039f8e612e4d9f61078294612ddb600694612e1a93906001600160601b03166001600160601b0319825416179055565b612dee612de66139fd565b8a8501613a18565b82546cff000000000000000000000000191690151560601b6cff00000000000000000000000016178255565b8960028201558a60038201558b60048201558c6005820155016135fa565b5001613a96565b604051988998169a88613aca565b0390a3005b7f31a8d9e8000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f1ef4f649000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f402585f5000000000000000000000000000000000000000000000000000000005f5260045ffd5b9181601f840112156103395782359167ffffffffffffffff8311610339576020838186019501011161033957565b346103395760403660031901126103395760043567ffffffffffffffff811161033957610d66612f4a612f4f612f346020943690600401612eca565b929060243593612f4385610328565b3691611212565b613f61565b906132fb565b34610339576101e036600319011261033957600435612f7381610328565b60243590612f8082610328565b604435612f8c81610328565b606435612f9881610328565b608435612fa481610328565b60a43590612fb182610612565b612fba366118f9565b923661016312156103395760405194612fd4608087610559565b8597366101c41161033957610144985b6101c48a10613006575061046998506101c4359761300189610328565b613b38565b893581526020998a019901612fe4565b346103395760803660031901126103395760043560243567ffffffffffffffff81116103395761304a903690600401612eca565b9160443561305781610328565b606435916001600160a01b0382165f52600860205261307d6124a560405f205460ff1690565b61310157613098613092612f4a368888611212565b836132fb565b8310612685576130ad6124a5843033866152d4565b6130d9576130c36130c994610e7c963691611212565b906150e7565b6040519081529081906020820190565b7f90b8ec18000000000000000000000000000000000000000000000000000000005f5260045ffd5b7fe51cf7bf000000000000000000000000000000000000000000000000000000005f5260045ffd5b346103395760203660031901126103395760043567ffffffffffffffff811161033957610d66612f4a6020923690600401611248565b34610339575f3660031901126103395760206001600160a01b0360025416604051908152f35b346103395760203660031901126103395760206003611ae56004356115b1565b3461033957604036600319011261033957600a6004356131c481610410565b6131d060243591610ddf565b50905f5201602052602060ff60405f2054166040519015158152f35b8051821015610dfb5760209160051b010190565b634e487b7160e01b5f52601160045260245ffd5b5f19810191908211612b7457565b61271003906127108211612b7457565b91908203918211612b7457565b8054821015610dfb575f52601660205f20910201905f90565b6004821015610dfb5701905f90565b90816020910312610339575161126381610612565b6040513d5f823e3d90fd5b9060058110156115eb5760ff80198354169116179055565b60208101929161058b91906115f0565b908160011b9180830460021490151715612b7457565b81810292918115918404141715612b7457565b634e487b7160e01b5f52601260045260245ffd5b81156132f6570490565b6132d8565b6001600160a01b031690815f52600860205260ff60405f205460481c1690604d8211612b745761332e91600a0a906132c5565b905f52600860205267ffffffffffffffff60405f205460081c169081156132f6570490565b61335c906115b1565b506003810180545f198101908111612b74576133836001600160601b039161338c9361323f565b50925416610ddf565b509060038101546005830154116133c9576133b26001600160601b03600a935416610ddf565b5090545f520160205260ff60405f20541615151590565b50505f90565b9081606091031261033957805191604060208301516133ed81610612565b92015161126381610612565b6003613404826115b1565b500180545f19810192908311612b745761344c6001600160a01b036134386134316134859660609661323f565b5054611ec2565b90549060031b1c166001600160a01b031690565b60405180809581947f1c3db16d000000000000000000000000000000000000000000000000000000008352600483019190602083019252565b03915afa908115610a4b575f915f915f916134a1575b50909192565b9150506134c6915060603d6060116134cc575b6134be8183610559565b8101906133cf565b5f61349b565b503d6134b4565b9060018201809211612b7457565b91908201809211612b7457565b90816020910312610339575190565b3d15613527573d9061350e826111f6565b9161351c6040519384610559565b82523d5f602084013e565b606090565b613535906115b1565b5061355f6135506003830161354a8154613214565b9061323f565b5091546001600160601b031690565b600361356a82610ddf565b50920154600583015490919082106135e5576001600160601b03166001036135b25750507f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90565b6135df6135da60046135d161078261126396546001600160601b031690565b500154926132af565b6134d3565b906132c5565b506135df6135da6004611263940154926132af565b905f5b6004811061360a57505050565b6001906020835193019281850155016135fd565b919360a09361058b969298979561012085019915158552602085015260408401526060830152608082015201906110fd565b90604051918281549182825260208201905f5260205f20925f5b81811061367f57505061058b92500383610559565b84546001600160a01b031683526001948501948794506020909301920161366a565b604051815480825290929183906136bf60208301915f5260205f2090565b925f905b80600183011061371a5761058b945491818110613700575b106136e9575b500383610559565b60601c6001600160601b031681526020015f6136e1565b6001600160601b03831684529260019060200193016136db565b91600291935060406001916137588754613745836001600160601b0383166001600160601b03169052565b60601c6001600160601b03166020830152565b0194019201859293916136c3565b60405191905f835b600a82106137855750505061058b61014083610559565b600160208192855481520193019101909161376e565b90613851600c6137a961058d565b938054855260018101546020860152600281015460408601526003810154606086015260048101546080860152600581015460a08601526137ec60068201613650565b60c08601526137fd600782016136a1565b60e08601526008810154610100860152600981015461012086015261384061382f600a8301546001600160a01b031690565b6001600160a01b0316610140870152565b600b81015461016086015201613766565b610180830152565b9190826040910312610339576020825161387281610328565b92015161126381610410565b90815491600160401b83101561055457826138a191600161058b95018155611eda565b9091906001600160a01b038084549260031b9316831b921b1916179055565b9190918054831015610dfb575f52600c600160205f2084821c0193160290565b8054600160401b811015610554576138fd916001820181556138c0565b6001600160601b0380839493549260031b9316831b921b1916179055565b8054600160401b811015610554576139389160018201815561323f565b9091565b94939260609261395e928752602087015260806040870152608086019061152e565b930152565b60065490600160401b8210156105545760018201600655600654821015610dfb5760065f527ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f90910180546001600160a01b0319166001600160a01b03909216919091179055565b600554600160401b8110156105545760018101600555600554811015610dfb5760055f52601560205f20910201905f90565b60405190613a0c602083610559565b5f808352366020840137565b81519167ffffffffffffffff831161055457600160401b8311610554578154838355808410613a70575b50602001905f5260205f205f5b838110613a5c5750505050565b600190602084519401938184015501613a4f565b825f528360205f2091820191015b818110613a8b5750613a42565b5f8155600101613a7e565b8054600160401b81101561055457613ab391600182018155611eda565b819291549060031b91821b915f19901b1916179055565b929461016094602096613b0194989398610140870199151587528887015260408601526060850152608084015260a08301906110fd565b6101406101208201528451809452019201905f5b818110613b225750505090565b8251845260209384019390920191600101613b15565b96949290979593917ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0e5498613b84613b7660ff8c60401c1615151590565b9a67ffffffffffffffff1690565b8a80613d37575b159081613d0f575b50613ce757613bfd988a613bf4600167ffffffffffffffff197ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0e5416177ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0e55565b613c8757613d79565b613c0357565b613c5868ff0000000000000000197ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0e54167ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0e55565b604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a1565b613ce2600160401b68ff0000000000000000197ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0e5416177ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0e55565b613d79565b7f0dc149f0000000000000000000000000000000000000000000000000000000005f5260045ffd5b303b15915081613d22575b50155f613b93565b6001915067ffffffffffffffff16145f613d1a565b50600167ffffffffffffffff821610613b8b565b600654600160401b8110156105545760018101600655600654811015610dfb5760065f5260205f2001905f90565b93613e516001600160601b039699613e35613f5696613e1960019c97613dfd6001600160a01b0398613de17f550ff678017abc294b4786a99a046628d5a1eac07be0f1ea7e89543f13576ee69f9d6001600160a01b03166001600160a01b03195f5416175f55565b6001600160a01b03166001600160a01b03196001541617600155565b6001600160a01b03166001600160a01b03196002541617600255565b6001600160a01b03166001600160a01b03196003541617600355565b6001600160a01b03166001600160a01b03196004541617600455565b613e59613d4b565b5050613e6481613963565b16867f44063d258760b98116d53815adbc906a56b3563e540148cc0fc2457f83b5eeb25f80a3613e926139cb565b5050613e9c6139cb565b5080546bffffffffffffffffffffffff1916815590613ec4613ebc6139fd565b888401613a18565b81546cff000000000000000000000000191688151560601b6cff0000000000000000000000001617825583516002830155602084018051600384015591604085018051600483015590613f36606087019182516005820155613f2985600683016135fa565b546001600160601b031690565b955193519151905191613f476139fd565b94604051988998169b88613aca565b0390a361058b61443c565b613f7a6004613f7261126393615331565b509290610ddf565b5001546132c5565b908160609103126103395780519160406020830151920151600a8110156103395790565b600a11156115eb57565b906001600160601b03811680159081156141f6575b506141e957821515806141d3575b6141c657613fec6109b86004546001600160a01b031690565b60405163c70ba3b960e01b81526001600160a01b03841660048201526001600160601b038316602482015260448101859052600160648201529390606090859060849082905f905af1918215610a4b575f925f955f9161418d575b5061405181613fa6565b8061417c575082614147575b84614110575b6140786109b86004546001600160a01b031690565b91823b15610339576040517faac03ad20000000000000000000000000000000000000000000000000000000081526001600160a01b0390951660048601526001600160601b039091166024850152604484019290925260648301939093526084820152905f90829081838160a4810103925af18015610a4b576140fc575b50600190565b80611e235f61410a93610559565b5f6140f6565b61412f6124a5868661412a6002546001600160a01b031690565b61500d565b156140635750505050506141436001615422565b5f90565b6141686124a5846141606002546001600160a01b031690565b8730916152d4565b1561405d5750505050506141436001615402565b935050505061414391506001615442565b919350506141b491945060603d6060116141bf575b6141ac8183610559565b810190613f82565b94919290945f614047565b503d6141a2565b50505061414360016153e2565b5060026141df82610ddf565b5001548310613fd3565b50505061414360016153c2565b905060055411155f613fc5565b906001600160601b038116801590811561438a575b5061437e5782151580614368575b61435c5761423f6109b86004546001600160a01b031690565b60405163c70ba3b960e01b81526001600160a01b03841660048201526001600160601b0383166024820152604481018590525f60648201819052909491606091869160849183915af1918215610a4b575f925f955f91614333575b506142a481613fa6565b806143235750826142f7575b846142ca576140786109b86004546001600160a01b031690565b6142e46124a5868661412a6002546001600160a01b031690565b156140635750505050506141435f615422565b6143106124a5846141606002546001600160a01b031690565b156142b05750505050506141435f615402565b935050505061414391505f615442565b9193505061435191945060603d6060116141bf576141ac8183610559565b94919290945f61429a565b5050506141435f6153e2565b50600261437482610ddf565b5001548310614226565b5050506141435f6153c2565b905060055411155f614218565b906001600160601b035f92600a6143ad82610ddf565b508486520160205260408420805460ff19169055167fb47629acdf64971062d40984f77d3dee212d735b11e3e8c7a4222d9f0572cc798380a4565b906001600160601b03600192600a6143ff82610ddf565b50845f520160205260405f208460ff19825416179055167fb47629acdf64971062d40984f77d3dee212d735b11e3e8c7a4222d9f0572cc795f80a4565b600a6144486001610ddf565b5060015f520160205260405f20600160ff19825416179055600180807fb47629acdf64971062d40984f77d3dee212d735b11e3e8c7a4222d9f0572cc795f80a4565b81156132f6570690565b9190826040910312610339576020825192015190565b6144b481516115b1565b50906144c760208201516003840161323f565b50916144d96109b86109a58554611ec2565b9060408351926020850151906144f860e087015160608801519061448a565b608087015160a088015185517f9d61ab6e00000000000000000000000000000000000000000000000000000000815260048101989098526024880194909452604487019190915260648601526084850191909152839060a49082905afa8015610a4b575f925f916149c4575b50918261271082116149ba575b612710106149b0575b61459c6109a561459360e087015160608801519061448a565b60068801611eda565b926145ae6125388360018901546132c5565b936145c46109b86004546001600160a01b031690565b803b156103395760405163965af6c760e01b81526001600160a01b038316600482015260248101969096525f908690604490829084905af1908115610a4b576002956147279261499c575b5060208861465f6125388661463a8c61463f6125388c61463a604060c08601519501948551906132ec565b6132c5565b9c866146508f6009819a01546134e1565b600982015501549051906132ec565b9661466e8860088d01546134e1565b60088c0155600a8b01546001600160a01b031688858261498d575090505f8115614984575b5f80809381936001600160a01b038a1690f1505b6146cd6146bf6109b86004546001600160a01b031690565b91546001600160601b031690565b5f6040518097819582947f664bffc300000000000000000000000000000000000000000000000000000000845289600485016001600160601b036040929594936001600160a01b0360608401971683521660208201520152565b03925af1918215610a4b577fa90d30adac7f21a7def444f0fe0a60bdf16d7e8415973dd09bf869db8f94d58e936001600160a01b03936147bf925f91614965575b5015614948575b88519660208a01519861478c600a8d01546001600160a01b031690565b60408051998a5260208a01949094529288015260608701526001600160a01b0316608086015291169290819060a0820190565b0390a460e08101516147dc6147d760608401516132af565b613214565b146147e5575050565b6147f860c0820151600984015490613232565b61480b6002840154600885015490613232565b8115918215809361493f575b614823575b5050505050565b7f6cecfd3ec56289ccb16e30eb194f9a87dfdc12630b9abbc31fc69af5a0b0eaf492614913575b81801580156148a9575b505061489c614874600a602087519701519701546001600160a01b031690565b604051938493849160409194936001600160a01b039160608501968552602085015216910152565b0390a35f8080808061481c565b600a8701546001600160a01b0316806148f557505f80809381936148da6109b86109b885546001600160a01b031690565b9083906148ec575bf1505b815f614854565b506108fc6148e2565b5f5461490d9392506001600160a01b03165b9061500d565b506148e5565b614939816149296002546001600160a01b031690565b5f546001600160a01b0316614907565b5061484a565b50811515614817565b61495f888461412a6002546001600160a01b031690565b5061476f565b61497e915060203d602011610a4457610a368183610559565b5f614768565b506108fc614693565b6149969261500d565b506146a7565b80611e235f6149aa93610559565b5f61460f565b612710925061457a565b6127109150614571565b90506149e991925060403d6040116149f2575b6149e18183610559565b810190614494565b9190915f614564565b503d6149d7565b90816060910312610339578051916040602083015192015190565b7f80000000000000000000000000000000000000000000000000000000000000008114612b74575f0390565b614a4a81516115b1565b50614a5e602083019160038351910161323f565b5090614a706109b86109a58454611ec2565b8351825160e086018051608088015160a08901516040517f149a5dc0000000000000000000000000000000000000000000000000000000008152600481019690965260248601949094526044850191909152606484015260848301919091529094919060208660a481855afa958615610a4b575f96614fec575b506127108611614fe2575b614b0961253860018701546135df89613222565b614b1a6109a5835160068901611eda565b614b2f6109b86004546001600160a01b031690565b803b156103395760405163965af6c760e01b81526001600160a01b038316600482015260248101849052905f908290604490829084905af18015610a4b57614fce575b505f6060614c0e614b9d614b8a875160078d016138c0565b90546001600160601b039160031b1c1690565b94614bb36109b86004546001600160a01b031690565b906040519485809481937f771a27cb0000000000000000000000000000000000000000000000000000000083528a8a600485016001600160601b036040929594936001600160a01b0360608401971683521660208201520152565b03925af1948515610a4b5788955f905f935f91614f97575b508960c08a019c8d614c398482516134e1565b90527fa90d30adac7f21a7def444f0fe0a60bdf16d7e8415973dd09bf869db8f94d58e600a614c6b8d51945195614a14565b9b019a614c7f8c546001600160a01b031690565b6040805185815260208101959095528401919091525f60608401526001600160a01b03908116608084015288169160a090a415908115614f13575b5015614e6357509050614cd86109b86004546001600160a01b031690565b803b15610339576040517faa9ebfb70000000000000000000000000000000000000000000000000000000081526001600160a01b039290921660048301525f908290602490829084905af18015610a4b57614e4f575b505b51614d3e6060840151613214565b1480614e43575b614d52575b505050505190565b7f6cecfd3ec56289ccb16e30eb194f9a87dfdc12630b9abbc31fc69af5a0b0eaf491614d8582546001600160a01b031690565b6001600160a01b038116614e1d57505f808080614daf6109b86109b883546001600160a01b031690565b60028a015490828215614e14575bf1505b614de8614dd56002546001600160a01b031690565b5f546001600160a01b031688519161500d565b5051925193614e086148746002885193015493546001600160a01b031690565b0390a35f808080614d4a565b506108fc614dbd565b614e3d90614e325f546001600160a01b031690565b60028801549161500d565b50614dc0565b50604082015115614d45565b80611e235f614e5d93610559565b5f614d2e565b6002614e6e84610ddf565b50015411614e7e575b5050614d30565b614e936109b86004546001600160a01b031690565b91823b15610339576040517f9d5608670000000000000000000000000000000000000000000000000000000081526001600160a01b039290921660048301526001600160601b03166024820152905f908290604490829084905af18015610a4b57614eff575b80614e77565b80611e235f614f0d93610559565b5f614ef9565b8751895187516040517fba66fde70000000000000000000000000000000000000000000000000000000081526004810193909352602483019190915260448201529150602090829060649082905afa908115610a4b575f91614f78575b50155f614cba565b614f91915060203d602011610a4457610a368183610559565b5f614f70565b915050614fbd91925060603d606011614fc7575b614fb58183610559565b8101906149f9565b929190925f614c26565b503d614fab565b80611e235f614fdc93610559565b5f614b72565b6127109550614af5565b61500691965060203d60201161109e5761108f8183610559565b945f614aea565b6040517fa9059cbb00000000000000000000000000000000000000000000000000000000602082019081526001600160a01b0393841660248301526044808301959095529381525f9384939091849190615068606482610559565b5193165af16150756134fd565b8161507e575090565b805180159250821561508f57505090565b6112639250602080918301019101613267565b6001600160a01b035f5416330361038957565b600754600160401b8110156105545760018101600755600754811015610dfb5760075f52600e60205f20910201905f90565b90919392936150f583615331565b92905061510d6124a561249e85600a61248f87610ddf565b61265d576151d290600a600754986151236150b5565b503360601b6bffffffffffffffffffffffff19166001600160601b038716178155426002820155906151ac612538615173600361516b6151656109a58d611ec2565b9a610ddf565b50950161391b565b50936001600160a01b0387166152be5761519260048201545b856132ec565b99600386019a8b55855560036002820154910154906132c5565b6001830155600282015501906001600160a01b03166001600160a01b0319825416179055565b6151e76109b86004546001600160a01b031690565b90813b156103395760405163d09f392d60e01b8152600481018890525f6024820181905290928390604490829084905af1918215610a4b576001600160a01b03926152aa575b5016905490803b156103395761525e935f8094604051968795869485936302dbb79560e61b85528c6004860161393c565b03925af18015610a4b57615296575b5033827f141dfc18aa6a56fc816f44f0e9e2f1ebc92b15ab167770e17db5b084c10ed9955f80a3565b80611e235f6152a493610559565b5f61526d565b80611e235f6152b893610559565b5f61522d565b6151926152cf6004830154896132fb565b61518c565b905f6001600160a01b03819594829582604051928160208501977f23b872dd000000000000000000000000000000000000000000000000000000008952166024850152166044830152606482015260648152615068608482610559565b80516040116153ac5760208101519160606040830151920151906001600160601b038416801590811561539f575b50615396575b821561538d575b81158015615381575b61537b57565b60019150565b50600654821015615375565b6003925061536c565b60019350615365565b905060055411155f61535f565b50600190600390600190565b600211156115eb57565b6001906153ce816153b8565b1461058b57637c84af5160e01b5f5260045ffd5b6001906153ee816153b8565b1461058b57630caac6b360e31b5f5260045ffd5b60019061540e816153b8565b1461058b57630f323ed960e11b5f5260045ffd5b60019061542e816153b8565b1461058b5763e45e13a360e01b5f5260045ffd5b60019061544e816153b8565b146155475761545c81613fa6565b600281146155385761546d81613fa6565b600381146155295761547e81613fa6565b600481146155015761548f81613fa6565b600581146154f2576154a081613fa6565b600681146154e357806154b4600992613fa6565b146154bb57565b7ff95e58bc000000000000000000000000000000000000000000000000000000005f5260045ffd5b630caac6b360e31b5f5260045ffd5b637c84af5160e01b5f5260045ffd5b7fec8e8768000000000000000000000000000000000000000000000000000000005f5260045ffd5b63e45e13a360e01b5f5260045ffd5b630f323ed960e11b5f5260045ffd5b5056fea26469706673582212209d8693ceca011df52e9dd63f6056bbcd764f392dc1976d1654c7a6599b67d72c64736f6c634300081e0033f0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0e",
+ "deployedBytecode": "0x60806040526004361015610011575f80fd5b5f3560e01c8062f5822c146103235780630219da791461031e5780630761c14d1461031957806309cfdc9c146103145780630b7414bc1461030f578063115d53761461030a5780631860592b1461030557806319b81529146103005780631c3db16d146102fb5780631f5a0dd2146102f65780632d29a47b146102f15780632e1daf2f146102ec5780633cfd1184146102e757806342c37fa3146102e25780634f1ef286146102dd57806352d1902d146102d857806354fd4d50146102d3578063564a565d146102ce57806359ec827e146102c95780636a8c9194146102c457806371ae413d146102bf5780637717a6e8146102ba5780637934c0be146102b557806382d02237146102b057806386541b24146102ab57806386cdecef146102a65780638a9bb02a146102a15780638bb048751461029c5780638da5cb5b14610297578063a6f9dae114610292578063acdbf51d1461028d578063afe15cfb14610288578063b004963714610283578063b702a8791461027e578063c13517e114610279578063c258bb1914610274578063c35699021461026f578063c71f42531461026a578063cf0c38f814610265578063d07368bd14610260578063d4d1d76a1461025b578063d874514b14610256578063d98493f614610251578063e399d29b1461024c578063f6506db414610247578063f7434ea914610242578063fbf405b01461023d578063fc6f8f16146102385763fe524c3914610233575f80fd5b6131a5565b613185565b61315f565b613129565b613016565b612f55565b612ef8565b612c27565b612c0a565b612b9f565b612b79565b612b39565b6126f9565b6126ad565b61242e565b612017565b611fcb565b611f48565b611eef565b611e76565b611e51565b611d02565b611c54565b611ab6565b61193d565b61180d565b611784565b61175a565b611734565b61169e565b611680565b6115fd565b611552565b6114c4565b611266565b6111af565b611134565b6110d7565b610e80565b610e00565b610d96565b610d6e565b610d3b565b610750565b61061c565b610493565b610421565b6103b1565b61033d565b6001600160a01b0381160361033957565b5f80fd5b346103395760203660031901126103395760043561035a81610328565b6001600160a01b035f54163303610389576001600160a01b03166001600160a01b031960025416176002555f80f35b7f596dcdb8000000000000000000000000000000000000000000000000000000005f5260045ffd5b34610339576020366003190112610339576001600160a01b036004356103d681610328565b165f526008602052606060405f205460ff604051918181161515835267ffffffffffffffff8160081c16602084015260481c166040820152f35b6001600160601b0381160361033957565b346103395760603660031901126103395760043561043e81610328565b60243561044a81610410565b604435906001600160a01b0360045416330361046b5761046992613fb0565b005b7f9d6cab99000000000000000000000000000000000000000000000000000000005f5260045ffd5b34610339576020366003190112610339576004356104b081610328565b6001600160a01b035f54163314158061050e575b6104e6576001600160a01b03166001600160a01b031960015416176001555f80f35b7ff10d23b5000000000000000000000000000000000000000000000000000000005f5260045ffd5b506001600160a01b03600154163314156104c4565b634e487b7160e01b5f52604160045260245ffd5b6101a0810190811067ffffffffffffffff82111761055457604052565b610523565b90601f8019910116810190811067ffffffffffffffff82111761055457604052565b6040519061058b61010083610559565b565b6040519061058b6101a083610559565b67ffffffffffffffff81116105545760051b60200190565b9080601f830112156103395781356105cc8161059d565b926105da6040519485610559565b81845260208085019260051b82010192831161033957602001905b8282106106025750505090565b81358152602091820191016105f5565b8015150361033957565b346103395760603660031901126103395760043561063981610410565b60243567ffffffffffffffff8111610339576106599036906004016105b5565b6044359061066682610612565b6001600160a01b035f54163303610389575f5b81518110156104695782156106fa5761069281836131ec565b511580156106e4575b6106bc57806106b66106af600193856131ec565b51866143e8565b01610679565b7f7ab15312000000000000000000000000000000000000000000000000000000005f5260045ffd5b506106ef81836131ec565b51600654111561069b565b600161070682846131ec565b5114610728578061072361071c600193856131ec565b5186614397565b6106b6565b7fada223fa000000000000000000000000000000000000000000000000000000005f5260045ffd5b346103395760203660031901126103395760043561076d816115b1565b5061078761078282546001600160601b031690565b610ddf565b509060038101916107a261079b8454613214565b809461323f565b5060018301936107b3855460ff1690565b6107bc816115e1565b806108d857501580610896575b61086e57600360068201549101540361084657547f4e6f5cf43b95303e86aee81683df63992061723a829ee012db21dad388756b91926108379261082b9260601c60ff161561083c5761081e60015b83613287565b6002429101555460ff1690565b6040519182918261329f565b0390a2005b61081e6002610818565b7f9e4486b0000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f3e9727df000000000000000000000000000000000000000000000000000000005f5260045ffd5b506108a5600284015442613232565b6108d26108c86108b6875460ff1690565b6108bf816115e1565b60068601613258565b90549060031b1c90565b116107c9565b90506108e9819594959392936115e1565b60018103610a5057506109246108c8610906600287015442613232565b926006610914875460ff1690565b9161091e836115e1565b01613258565b119081610993575b5061096b57805460ff191660021781557f4e6f5cf43b95303e86aee81683df63992061723a829ee012db21dad388756b91916108379161082b9161081e565b7f9bf4af0a000000000000000000000000000000000000000000000000000000005f5260045ffd5b6109c491506109a56109b89154611ec2565b90546001600160a01b039160031b1c1690565b6001600160a01b031690565b602060405180927f0baa64d10000000000000000000000000000000000000000000000000000000082528180610a0289600483019190602083019252565b03915afa908115610a4b575f91610a1c575b50155f61092c565b610a3e915060203d602011610a44575b610a368183610559565b810190613267565b5f610a14565b503d610a2c565b61327c565b610a59816115e1565b60028103610ba75750610a766108c8610906600287015442613232565b119081610b1e575b50610af657805460ff191660031781557f4e6f5cf43b95303e86aee81683df63992061723a829ee012db21dad388756b91916108379161082b916001600160a01b03610acb825460601c90565b16867fa5d41b970d849372be1da1481ffd78d162bfe57a7aa2fe4e5fb73481fa5ac24f5f80a361081e565b7fcc46f568000000000000000000000000000000000000000000000000000000005f5260045ffd5b610b3091506109a56109b89154611ec2565b602060405180927f6d4cd8ea0000000000000000000000000000000000000000000000000000000082528180610b6e89600483019190602083019252565b03915afa908115610a4b575f91610b88575b50155f610a7e565b610ba1915060203d602011610a4457610a368183610559565b5f610b80565b610bb0816115e1565b60038103610cd1576108c8610bd9916006610bcf600289015442613232565b9461091e836115e1565b119081610c48575b50610c2057805460ff191660041781557f4e6f5cf43b95303e86aee81683df63992061723a829ee012db21dad388756b91916108379161082b9161081e565b7f2f4dfd87000000000000000000000000000000000000000000000000000000005f5260045ffd5b610c5a91506109a56109b89154611ec2565b602060405180927f0855bbe90000000000000000000000000000000000000000000000000000000082528180610c9889600483019190602083019252565b03915afa908115610a4b575f91610cb2575b50155f610be1565b610ccb915060203d602011610a4457610a368183610559565b5f610caa565b905060049150610ce0816115e1565b14610d135761082b610837917f4e6f5cf43b95303e86aee81683df63992061723a829ee012db21dad388756b919361081e565b7f0fe7191e000000000000000000000000000000000000000000000000000000005f5260045ffd5b34610339576040366003190112610339576020610d66600435610d5d81610328565b602435906132fb565b604051908152f35b34610339576020366003190112610339576020610d8c600435613353565b6040519015158152f35b34610339576020366003190112610339576060610db46004356133f9565b906040519283521515602083015215156040820152f35b634e487b7160e01b5f52603260045260245ffd5b600554811015610dfb5760055f52601560205f20910201905f90565b610dcb565b346103395760203660031901126103395760043560055481101561033957610e2790610ddf565b508054600282015460038301546004840154600590940154604080516001600160601b0386168152606095861c60ff16151560208201529081019390935292820152608081019290925260a08201528060c081015b0390f35b3461033957606036600319011261033957600435604435602435610ea3836115b1565b506004610eb4600183015460ff1690565b610ebd816115e1565b036110a557816003610ecf920161323f565b50906004820193610ee2855494856134e1565b926005810194855496600683015490610eff8260028601546132ec565b92610f156109b86109a560018801549754611ec2565b6040517fda3beb8c00000000000000000000000000000000000000000000000000000000815260048101889052602481018990529290602090849060449082905afa928315610a4b575f93611074575b50826110455783891161103c575b9780979695949392985b55965b868810610f9657898981815403610f9357005b55005b9091929394959698828a105f14610ff657610fe7600191610fb561057b565b908882528960208301528460408301528560608301528660808301528760a083015260c08201528b60e0820152614a40565b995b0196959493929190610f80565b9860019061103761100561057b565b8881528960208201528460408201528560608201528660808201528760a08201528c60c08201528260e08201526144aa565b610fe9565b97508297610f73565b61104e846132af565b8911611063575b978097969594939298610f7d565b975061106e836132af565b97611055565b61109791935060203d60201161109e575b61108f8183610559565b8101906134ee565b915f610f65565b503d611085565b7f8794ce4b000000000000000000000000000000000000000000000000000000005f5260045ffd5b5f91031261033957565b34610339575f3660031901126103395760206001600160a01b0360045416604051908152f35b905f905b6004821061110e57505050565b6020806001928551815201930191019091611101565b60808101929161058b91906110fd565b346103395760203660031901126103395761116b60043561115481610410565b60806040516111638282610559565b369037610ddf565b50604051906006015f825b6004821061119957610e7c8461118d608082610559565b60405191829182611124565b6001602081928554815201930191019091611176565b34610339576040366003190112610339576004356111cc81610328565b6024356001600160a01b0360045416330361046b57610469916001600160a01b036002541661500d565b67ffffffffffffffff811161055457601f01601f191660200190565b92919261121e826111f6565b9161122c6040519384610559565b829481845281830111610339578281602093845f960137010152565b9080601f830112156103395781602061126393359101611212565b90565b60403660031901126103395760043561127e81610328565b60243567ffffffffffffffff81116103395761129e903690600401611248565b6112a66150a2565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016803014908115611489575b50611461576001600160a01b0382166040517f52d1902d000000000000000000000000000000000000000000000000000000008152602081600481855afa5f9181611440575b5061135b577f0c760937000000000000000000000000000000000000000000000000000000005f526001600160a01b03841660045260245ffd5b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc81036114155750827f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a28051806113d357005b5f926020849301905af46113e56134fd565b50156113ed57005b7f736436ba000000000000000000000000000000000000000000000000000000005f5260045ffd5b7faa1d49a4000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b61145a91925060203d60201161109e5761108f8183610559565b905f611321565b7fe07c8dba000000000000000000000000000000000000000000000000000000005f5260045ffd5b90506114bc7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b14155f6112db565b34610339575f366003190112610339576001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001630036114615760206040517f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8152f35b805180835260209291819084018484015e5f828201840152601f01601f1916010190565b34610339575f36600319011261033957610e7c604051611573604082610559565b600581527f322e302e30000000000000000000000000000000000000000000000000000000602082015260405191829160208352602083019061152e565b600754811015610dfb5760075f52600e60205f20910201905f90565b634e487b7160e01b5f52602160045260245ffd5b600511156115eb57565b6115cd565b9060058210156115eb5752565b34610339576020366003190112610339576004356007548110156103395761162660ff916115b1565b508054600260018301549201546040519384936001600160a01b0360a08601946001600160601b0380821616875260601c16602086015261166c604086018383166115f0565b60081c161515606084015260808301520390f35b34610339576020366003190112610339576020610d6660043561352c565b34610339576060366003190112610339576004356116bb81610328565b60243560443567ffffffffffffffff8111610339576116de903690600401611248565b6001600160a01b035f54163303610389575f928392602083519301915af16117046134fd565b501561170c57005b7f44125e5e000000000000000000000000000000000000000000000000000000005f5260045ffd5b34610339575f3660031901126103395760206001600160a01b0360015416604051908152f35b346103395760403660031901126103395761046960043561177a81610410565b6024359033614203565b34610339576040366003190112610339576004356117a181610328565b602435906117ae82610612565b6001600160a01b035f54163303610389576001600160a01b031690815f52600860205260405f2060ff1981541660ff831515161790551515907f541615e167511d757a7067a700eb54431b256bb458dfdce0ac58bf2ed0aefd445f80a3005b346103395760603660031901126103395760043561182a81610328565b6024359067ffffffffffffffff821682036103395760443560ff81168103610339576001600160a01b035f54163303610389576001600160a01b03919091165f81815260086020818152604092839020805469ffffffffffffffffff0019169287901b68ffffffffffffffff001692909217604886901b69ff0000000000000000001617909155815167ffffffffffffffff909516855260ff90931692840192909252917fe6996b7f03e9bd02228b99d3d946932e3197f505f60542c4cfbc919441d8a4e69181908101610837565b8060e312156103395760405190611911608083610559565b8190610144116103395760c4905b610144821061192d57505090565b813581526020918201910161191f565b34610339576101403660031901126103395760043561195b81610410565b60243561196781610612565b6044359060643560a43560843561197d366118f9565b926001600160a01b035f54163303610389576001600160601b036119a088610ddf565b50971696600188141580611a95575b611a6d575f600182018054915b828110611a4a57600284018a905583546cff000000000000000000000000191689151560601b6cff000000000000000000000000161784558a7f709b1f5fda58af9a4f52dacd1ec404840a8148455700cce155a2bd8cf127ef1a8b8b6108378c8c8c8c611a3e8460068f846003820155856004820155866005820155016135fa565b6040519687968761361e565b896002611a5d6107826108c88587611eda565b50015410611a6d576001016119bc565b7f97170789000000000000000000000000000000000000000000000000000000005f5260045ffd5b50866002611aad61078284546001600160601b031690565b500154116119af565b346103395760403660031901126103395760206001611ae56024356003611ade6004356115b1565b500161323f565b500154604051908152f35b90602080835192838152019201905f5b818110611b0d5750505090565b82516001600160a01b0316845260209384019390920191600101611b00565b90602080835192838152019201905f5b818110611b495750505090565b82516001600160601b0316845260209384019390920191600101611b3c565b905f905b600a8210611b7957505050565b6020806001928551815201930191019091611b6c565b611263906020815282516020820152602083015160408201526040830151606082015260608301516080820152608083015160a082015260a083015160c08201526101a0610180611c0b611bf460c08701516102c060e08701526102e0860190611af0565b60e0870151858203601f1901610100870152611b2c565b94610100810151610120850152610120810151610140850152611c406101408201516101608601906001600160a01b03169052565b610160810151828501520151910190611b68565b3461033957604036600319011261033957610e7c611cf6611cf06004356003611ade60243592604051611c8681610537565b5f81525f60208201525f60408201525f60608201525f60808201525f60a0820152606060c0820152606060e08201525f6101008201525f6101208201525f6101408201525f6101608201526101806101409160405192611ce68185610559565b36843701526115b1565b5061379b565b60405191829182611b8f565b3461033957602036600319011261033957600435611d1f816115b1565b5090600182019182546004611d348260ff1690565b611d3d816115e1565b036110a55760081c60ff16611e2957611d78611dbd91611d71611d5f856133f9565b5050865461ff00191661010017909655565b5460601c90565b60405184815283906001600160a01b038316907f394027a5fa6e098a1191094d1719d6929b9abc535fcc0c8f448d6a4e7562227690602090a36001600160a01b031690565b91823b15610339576040517f311a6c5600000000000000000000000000000000000000000000000000000000815260048101929092526024820152905f908290818381604481015b03925af18015610a4b57611e1557005b80611e235f61046993610559565b806110cd565b7fc977f8d3000000000000000000000000000000000000000000000000000000005f5260045ffd5b34610339575f3660031901126103395760206001600160a01b035f5416604051908152f35b3461033957602036600319011261033957600435611e9381610328565b5f5490336001600160a01b03831603610389576001600160a01b036001600160a01b031991169116175f555f80f35b600654811015610dfb5760065f5260205f2001905f90565b8054821015610dfb575f5260205f2001905f90565b3461033957602036600319011261033957600435600654811015610339576001600160a01b0360209160065f527ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f015416604051908152f35b3461033957602036600319011261033957611f646004356115b1565b5060ff60018201541660058110156115eb57600303611fc357611fb0611faa6108c86006611fa06001600160601b036002870154965416610ddf565b5001600301905f90565b826134e1565b905b604080519182526020820192909252f35b505f80611fb2565b3461033957602036600319011261033957600435611fe881610328565b6001600160a01b035f54163303610389576001600160a01b03166001600160a01b031960045416176004555f80f35b346103395760403660031901126103395760243560043561203782610328565b6001600160a01b035f541633141580612419575b6104e657612058816115b1565b5090600382019061207361206c8354613214565b809361323f565b5093612083600185015460ff1690565b61208c816115e1565b6123f157600685018054916003870192835411156123c9576120b96109b86004546001600160a01b031690565b803b1561033957604051633c694c4160e21b81526001600160a01b039290921660048301525f908290602490829084905af18015610a4b576123b5575b506121666121076109a58854611ec2565b96600b810196604061211989546134d3565b809a885f6001600160a01b0385518099819682957fd2b8035a0000000000000000000000000000000000000000000000000000000084526004840160209093929193604081019481520152565b0393165af18015610a4b575f935f91612380575b506001600160a01b038416918215612358576121a16109b86004546001600160a01b031690565b600185015490803b15610339576040517f21e1625e0000000000000000000000000000000000000000000000000000000081526001600160a01b038816600482015260248101929092525f908290604490829084905af1958615610a4b578960079561224b9361226399612344575b508954604080518f815260208101929092527f6119cf536152c11e0a9a6c22f3953ce4ecc93ee54fa72ffa326ffabded21509b91a38761387e565b6001600160601b038216156123325750915b016138e0565b549054146122af575b5050556122846109b86004546001600160a01b031690565b803b15610339575f6040518092633c694c4160e21b8252818381611e0560048201905f602083019252565b6122c46109b86004546001600160a01b031690565b91823b15610339576040517f5d2d784600000000000000000000000000000000000000000000000000000000815260048101929092526024820152905f908290604490829084905af18015610a4b5761231e575b8061226c565b80611e235f61232c93610559565b5f612318565b546001600160601b031690509161225d565b80611e235f61235293610559565b5f612210565b7f5c7171ee000000000000000000000000000000000000000000000000000000005f5260045ffd5b90506123a591935060403d6040116123ae575b61239d8183610559565b810190613859565b9290925f61217a565b503d612393565b80611e235f6123c393610559565b5f6120f6565b7f4df06de3000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f8285c4ef000000000000000000000000000000000000000000000000000000005f5260045ffd5b506001600160a01b036001541633141561204b565b60403660031901126103395760043560243567ffffffffffffffff81116103395761245d903690600401611248565b9061246782613f61565b34106126855761247682615331565b90506124a96124a561249e83600a61248f879897610ddf565b5001905f5260205260405f2090565b5460ff1690565b1590565b61265d57600754926125675f600a6124bf6150b5565b503360601b6bffffffffffffffffffffffff19166001600160601b03861617815542600282015561254061253861250e60036125066125006109a58c611ec2565b99610ddf565b50940161391b565b509261251e6004820154346132ec565b9860038501998a55845560036002820154910154906132c5565b612710900490565b600182015534600282015501906001600160a01b03166001600160a01b0319825416179055565b61257c6109b86004546001600160a01b031690565b90813b156103395760405163d09f392d60e01b8152600481018690525f6024820181905290928390604490829084905af1918215610a4b576001600160a01b0392612649575b5016905490803b15610339576125f3945f8094604051978895869485936302dbb79560e61b85528a6004860161393c565b03925af1918215610a4b57602092612635575b5033817f141dfc18aa6a56fc816f44f0e9e2f1ebc92b15ab167770e17db5b084c10ed9955f80a3604051908152f35b80611e235f61264393610559565b5f612606565b80611e235f61265793610559565b5f6125c2565b7fb34eb75d000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f38cd83c4000000000000000000000000000000000000000000000000000000005f5260045ffd5b34610339576020366003190112610339576004356126ca81610328565b6001600160a01b035f54163303610389576001600160a01b03166001600160a01b031960035416176003555f80f35b60603660031901126103395760043560243560443567ffffffffffffffff81116103395761272b903690600401611248565b6127348361352c565b3410612b1157612743836115b1565b5091600183016003612756825460ff1690565b61275f816115e1565b03612ae9576003840161277b6127758254613214565b8261323f565b509081546127916109b86109b86109a584611ec2565b3303612ac15786546001600160601b031681946127ad8461391b565b5092600386015460056127bf85610ddf565b50015411156129fa575b5088546bffffffffffffffffffffffff19166001600160601b03831617895561280691906127fb90805460ff19169055565b4260028a0155610ddf565b509361283461253861281c6004880154346132ec565b966003850197885560036002820154910154906132c5565b600183015534600283015581556128566109b86004546001600160a01b031690565b6128608354613214565b90803b156103395760405163d09f392d60e01b8152600481018b905260248101929092525f908290604490829084905af18015610a4b576129e6575b5054915490818303612915575b877f4e6f5cf43b95303e86aee81683df63992061723a829ee012db21dad388756b916001600160a01b036128de8a5460601c90565b1660405190837f9c9b64db9e130f48381bf697abf638e73117dbfbfd7a4484f2da3ba188f4187d5f80a35f81528060208101610837565b61295d926109b89261292a6109a59354613214565b6040518381528b907fcbe7939a71f0b369c7471d760a0a99b60b7bb010ee0406cba8a46679d1ea775690602090a4611ec2565b905490803b156103395761298c935f8094604051968795869485936302dbb79560e61b85528c6004860161393c565b03925af18015610a4b577f4e6f5cf43b95303e86aee81683df63992061723a829ee012db21dad388756b91926001600160a01b03926128de926129d2575b8194816128a9565b80611e235f6129e093610559565b5f6129ca565b80611e235f6129f493610559565b5f61289c565b916124a561249e612a1e612a10612a2a94610ddf565b50546001600160601b031690565b94600a61248f87610ddf565b612ab8575b906127fb61280692612a488b546001600160601b031690565b6001600160601b0381166001600160601b03851603612a6b575b509192506127c9565b612a758754613214565b6040516001600160601b03868116825292909216918e907f736e3f52761298c8c0823e1ebf482ed3c5ecb304f743d2d91a7c006e8e8d7a1f90602090a45f612a62565b60019550612a2f565b7f065f245f000000000000000000000000000000000000000000000000000000005f5260045ffd5b7fdf37bf2c000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f3191f8f1000000000000000000000000000000000000000000000000000000005f5260045ffd5b34610339576020366003190112610339576003612b576004356115b1565b500180545f198101908111612b7457611ae560039160209361323f565b613200565b34610339575f3660031901126103395760206001600160a01b0360035416604051908152f35b3461033957602036600319011261033957600435612bbc81610328565b6001600160a01b035f54163303610389576001600160a01b0360065491612be281613963565b16907f44063d258760b98116d53815adbc906a56b3563e540148cc0fc2457f83b5eeb25f80a3005b34610339575f366003190112610339576020600654604051908152f35b346103395761016036600319011261033957600435612c4581610410565b602435612c5181610612565b604435606435906084359260a43591612c69366118f9565b956101443567ffffffffffffffff811161033957612c8b9036906004016105b5565b966001600160a01b035f5416330361038957826002612ca984610ddf565b50015411611a6d57875115612ea2576001600160601b038216948515612e7a5760059796975491612cd86139cb565b50915f98600a8401995b8c51811015612d54578c81612cf781836131ec565b5115918215612d3d575b50506106bc5780612d37612d2a8f612d1d8f91956001966131ec565b515f5260205260405f2090565b805460ff19166001179055565b01612ce2565b612d4792506131ec565b516006541115818e612d01565b50908b92918b612d726124a561249e8e60015f5260205260405f2090565b612e52577f550ff678017abc294b4786a99a046628d5a1eac07be0f1ea7e89543f13576ee698612e3f886001612e388c8f8a6001600160601b039f8e612e4d9f61078294612ddb600694612e1a93906001600160601b03166001600160601b0319825416179055565b612dee612de66139fd565b8a8501613a18565b82546cff000000000000000000000000191690151560601b6cff00000000000000000000000016178255565b8960028201558a60038201558b60048201558c6005820155016135fa565b5001613a96565b604051988998169a88613aca565b0390a3005b7f31a8d9e8000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f1ef4f649000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f402585f5000000000000000000000000000000000000000000000000000000005f5260045ffd5b9181601f840112156103395782359167ffffffffffffffff8311610339576020838186019501011161033957565b346103395760403660031901126103395760043567ffffffffffffffff811161033957610d66612f4a612f4f612f346020943690600401612eca565b929060243593612f4385610328565b3691611212565b613f61565b906132fb565b34610339576101e036600319011261033957600435612f7381610328565b60243590612f8082610328565b604435612f8c81610328565b606435612f9881610328565b608435612fa481610328565b60a43590612fb182610612565b612fba366118f9565b923661016312156103395760405194612fd4608087610559565b8597366101c41161033957610144985b6101c48a10613006575061046998506101c4359761300189610328565b613b38565b893581526020998a019901612fe4565b346103395760803660031901126103395760043560243567ffffffffffffffff81116103395761304a903690600401612eca565b9160443561305781610328565b606435916001600160a01b0382165f52600860205261307d6124a560405f205460ff1690565b61310157613098613092612f4a368888611212565b836132fb565b8310612685576130ad6124a5843033866152d4565b6130d9576130c36130c994610e7c963691611212565b906150e7565b6040519081529081906020820190565b7f90b8ec18000000000000000000000000000000000000000000000000000000005f5260045ffd5b7fe51cf7bf000000000000000000000000000000000000000000000000000000005f5260045ffd5b346103395760203660031901126103395760043567ffffffffffffffff811161033957610d66612f4a6020923690600401611248565b34610339575f3660031901126103395760206001600160a01b0360025416604051908152f35b346103395760203660031901126103395760206003611ae56004356115b1565b3461033957604036600319011261033957600a6004356131c481610410565b6131d060243591610ddf565b50905f5201602052602060ff60405f2054166040519015158152f35b8051821015610dfb5760209160051b010190565b634e487b7160e01b5f52601160045260245ffd5b5f19810191908211612b7457565b61271003906127108211612b7457565b91908203918211612b7457565b8054821015610dfb575f52601660205f20910201905f90565b6004821015610dfb5701905f90565b90816020910312610339575161126381610612565b6040513d5f823e3d90fd5b9060058110156115eb5760ff80198354169116179055565b60208101929161058b91906115f0565b908160011b9180830460021490151715612b7457565b81810292918115918404141715612b7457565b634e487b7160e01b5f52601260045260245ffd5b81156132f6570490565b6132d8565b6001600160a01b031690815f52600860205260ff60405f205460481c1690604d8211612b745761332e91600a0a906132c5565b905f52600860205267ffffffffffffffff60405f205460081c169081156132f6570490565b61335c906115b1565b506003810180545f198101908111612b74576133836001600160601b039161338c9361323f565b50925416610ddf565b509060038101546005830154116133c9576133b26001600160601b03600a935416610ddf565b5090545f520160205260ff60405f20541615151590565b50505f90565b9081606091031261033957805191604060208301516133ed81610612565b92015161126381610612565b6003613404826115b1565b500180545f19810192908311612b745761344c6001600160a01b036134386134316134859660609661323f565b5054611ec2565b90549060031b1c166001600160a01b031690565b60405180809581947f1c3db16d000000000000000000000000000000000000000000000000000000008352600483019190602083019252565b03915afa908115610a4b575f915f915f916134a1575b50909192565b9150506134c6915060603d6060116134cc575b6134be8183610559565b8101906133cf565b5f61349b565b503d6134b4565b9060018201809211612b7457565b91908201809211612b7457565b90816020910312610339575190565b3d15613527573d9061350e826111f6565b9161351c6040519384610559565b82523d5f602084013e565b606090565b613535906115b1565b5061355f6135506003830161354a8154613214565b9061323f565b5091546001600160601b031690565b600361356a82610ddf565b50920154600583015490919082106135e5576001600160601b03166001036135b25750507f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90565b6135df6135da60046135d161078261126396546001600160601b031690565b500154926132af565b6134d3565b906132c5565b506135df6135da6004611263940154926132af565b905f5b6004811061360a57505050565b6001906020835193019281850155016135fd565b919360a09361058b969298979561012085019915158552602085015260408401526060830152608082015201906110fd565b90604051918281549182825260208201905f5260205f20925f5b81811061367f57505061058b92500383610559565b84546001600160a01b031683526001948501948794506020909301920161366a565b604051815480825290929183906136bf60208301915f5260205f2090565b925f905b80600183011061371a5761058b945491818110613700575b106136e9575b500383610559565b60601c6001600160601b031681526020015f6136e1565b6001600160601b03831684529260019060200193016136db565b91600291935060406001916137588754613745836001600160601b0383166001600160601b03169052565b60601c6001600160601b03166020830152565b0194019201859293916136c3565b60405191905f835b600a82106137855750505061058b61014083610559565b600160208192855481520193019101909161376e565b90613851600c6137a961058d565b938054855260018101546020860152600281015460408601526003810154606086015260048101546080860152600581015460a08601526137ec60068201613650565b60c08601526137fd600782016136a1565b60e08601526008810154610100860152600981015461012086015261384061382f600a8301546001600160a01b031690565b6001600160a01b0316610140870152565b600b81015461016086015201613766565b610180830152565b9190826040910312610339576020825161387281610328565b92015161126381610410565b90815491600160401b83101561055457826138a191600161058b95018155611eda565b9091906001600160a01b038084549260031b9316831b921b1916179055565b9190918054831015610dfb575f52600c600160205f2084821c0193160290565b8054600160401b811015610554576138fd916001820181556138c0565b6001600160601b0380839493549260031b9316831b921b1916179055565b8054600160401b811015610554576139389160018201815561323f565b9091565b94939260609261395e928752602087015260806040870152608086019061152e565b930152565b60065490600160401b8210156105545760018201600655600654821015610dfb5760065f527ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f90910180546001600160a01b0319166001600160a01b03909216919091179055565b600554600160401b8110156105545760018101600555600554811015610dfb5760055f52601560205f20910201905f90565b60405190613a0c602083610559565b5f808352366020840137565b81519167ffffffffffffffff831161055457600160401b8311610554578154838355808410613a70575b50602001905f5260205f205f5b838110613a5c5750505050565b600190602084519401938184015501613a4f565b825f528360205f2091820191015b818110613a8b5750613a42565b5f8155600101613a7e565b8054600160401b81101561055457613ab391600182018155611eda565b819291549060031b91821b915f19901b1916179055565b929461016094602096613b0194989398610140870199151587528887015260408601526060850152608084015260a08301906110fd565b6101406101208201528451809452019201905f5b818110613b225750505090565b8251845260209384019390920191600101613b15565b96949290979593917ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0e5498613b84613b7660ff8c60401c1615151590565b9a67ffffffffffffffff1690565b8a80613d37575b159081613d0f575b50613ce757613bfd988a613bf4600167ffffffffffffffff197ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0e5416177ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0e55565b613c8757613d79565b613c0357565b613c5868ff0000000000000000197ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0e54167ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0e55565b604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a1565b613ce2600160401b68ff0000000000000000197ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0e5416177ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0e55565b613d79565b7f0dc149f0000000000000000000000000000000000000000000000000000000005f5260045ffd5b303b15915081613d22575b50155f613b93565b6001915067ffffffffffffffff16145f613d1a565b50600167ffffffffffffffff821610613b8b565b600654600160401b8110156105545760018101600655600654811015610dfb5760065f5260205f2001905f90565b93613e516001600160601b039699613e35613f5696613e1960019c97613dfd6001600160a01b0398613de17f550ff678017abc294b4786a99a046628d5a1eac07be0f1ea7e89543f13576ee69f9d6001600160a01b03166001600160a01b03195f5416175f55565b6001600160a01b03166001600160a01b03196001541617600155565b6001600160a01b03166001600160a01b03196002541617600255565b6001600160a01b03166001600160a01b03196003541617600355565b6001600160a01b03166001600160a01b03196004541617600455565b613e59613d4b565b5050613e6481613963565b16867f44063d258760b98116d53815adbc906a56b3563e540148cc0fc2457f83b5eeb25f80a3613e926139cb565b5050613e9c6139cb565b5080546bffffffffffffffffffffffff1916815590613ec4613ebc6139fd565b888401613a18565b81546cff000000000000000000000000191688151560601b6cff0000000000000000000000001617825583516002830155602084018051600384015591604085018051600483015590613f36606087019182516005820155613f2985600683016135fa565b546001600160601b031690565b955193519151905191613f476139fd565b94604051988998169b88613aca565b0390a361058b61443c565b613f7a6004613f7261126393615331565b509290610ddf565b5001546132c5565b908160609103126103395780519160406020830151920151600a8110156103395790565b600a11156115eb57565b906001600160601b03811680159081156141f6575b506141e957821515806141d3575b6141c657613fec6109b86004546001600160a01b031690565b60405163c70ba3b960e01b81526001600160a01b03841660048201526001600160601b038316602482015260448101859052600160648201529390606090859060849082905f905af1918215610a4b575f925f955f9161418d575b5061405181613fa6565b8061417c575082614147575b84614110575b6140786109b86004546001600160a01b031690565b91823b15610339576040517faac03ad20000000000000000000000000000000000000000000000000000000081526001600160a01b0390951660048601526001600160601b039091166024850152604484019290925260648301939093526084820152905f90829081838160a4810103925af18015610a4b576140fc575b50600190565b80611e235f61410a93610559565b5f6140f6565b61412f6124a5868661412a6002546001600160a01b031690565b61500d565b156140635750505050506141436001615422565b5f90565b6141686124a5846141606002546001600160a01b031690565b8730916152d4565b1561405d5750505050506141436001615402565b935050505061414391506001615442565b919350506141b491945060603d6060116141bf575b6141ac8183610559565b810190613f82565b94919290945f614047565b503d6141a2565b50505061414360016153e2565b5060026141df82610ddf565b5001548310613fd3565b50505061414360016153c2565b905060055411155f613fc5565b906001600160601b038116801590811561438a575b5061437e5782151580614368575b61435c5761423f6109b86004546001600160a01b031690565b60405163c70ba3b960e01b81526001600160a01b03841660048201526001600160601b0383166024820152604481018590525f60648201819052909491606091869160849183915af1918215610a4b575f925f955f91614333575b506142a481613fa6565b806143235750826142f7575b846142ca576140786109b86004546001600160a01b031690565b6142e46124a5868661412a6002546001600160a01b031690565b156140635750505050506141435f615422565b6143106124a5846141606002546001600160a01b031690565b156142b05750505050506141435f615402565b935050505061414391505f615442565b9193505061435191945060603d6060116141bf576141ac8183610559565b94919290945f61429a565b5050506141435f6153e2565b50600261437482610ddf565b5001548310614226565b5050506141435f6153c2565b905060055411155f614218565b906001600160601b035f92600a6143ad82610ddf565b508486520160205260408420805460ff19169055167fb47629acdf64971062d40984f77d3dee212d735b11e3e8c7a4222d9f0572cc798380a4565b906001600160601b03600192600a6143ff82610ddf565b50845f520160205260405f208460ff19825416179055167fb47629acdf64971062d40984f77d3dee212d735b11e3e8c7a4222d9f0572cc795f80a4565b600a6144486001610ddf565b5060015f520160205260405f20600160ff19825416179055600180807fb47629acdf64971062d40984f77d3dee212d735b11e3e8c7a4222d9f0572cc795f80a4565b81156132f6570690565b9190826040910312610339576020825192015190565b6144b481516115b1565b50906144c760208201516003840161323f565b50916144d96109b86109a58554611ec2565b9060408351926020850151906144f860e087015160608801519061448a565b608087015160a088015185517f9d61ab6e00000000000000000000000000000000000000000000000000000000815260048101989098526024880194909452604487019190915260648601526084850191909152839060a49082905afa8015610a4b575f925f916149c4575b50918261271082116149ba575b612710106149b0575b61459c6109a561459360e087015160608801519061448a565b60068801611eda565b926145ae6125388360018901546132c5565b936145c46109b86004546001600160a01b031690565b803b156103395760405163965af6c760e01b81526001600160a01b038316600482015260248101969096525f908690604490829084905af1908115610a4b576002956147279261499c575b5060208861465f6125388661463a8c61463f6125388c61463a604060c08601519501948551906132ec565b6132c5565b9c866146508f6009819a01546134e1565b600982015501549051906132ec565b9661466e8860088d01546134e1565b60088c0155600a8b01546001600160a01b031688858261498d575090505f8115614984575b5f80809381936001600160a01b038a1690f1505b6146cd6146bf6109b86004546001600160a01b031690565b91546001600160601b031690565b5f6040518097819582947f664bffc300000000000000000000000000000000000000000000000000000000845289600485016001600160601b036040929594936001600160a01b0360608401971683521660208201520152565b03925af1918215610a4b577fa90d30adac7f21a7def444f0fe0a60bdf16d7e8415973dd09bf869db8f94d58e936001600160a01b03936147bf925f91614965575b5015614948575b88519660208a01519861478c600a8d01546001600160a01b031690565b60408051998a5260208a01949094529288015260608701526001600160a01b0316608086015291169290819060a0820190565b0390a460e08101516147dc6147d760608401516132af565b613214565b146147e5575050565b6147f860c0820151600984015490613232565b61480b6002840154600885015490613232565b8115918215809361493f575b614823575b5050505050565b7f6cecfd3ec56289ccb16e30eb194f9a87dfdc12630b9abbc31fc69af5a0b0eaf492614913575b81801580156148a9575b505061489c614874600a602087519701519701546001600160a01b031690565b604051938493849160409194936001600160a01b039160608501968552602085015216910152565b0390a35f8080808061481c565b600a8701546001600160a01b0316806148f557505f80809381936148da6109b86109b885546001600160a01b031690565b9083906148ec575bf1505b815f614854565b506108fc6148e2565b5f5461490d9392506001600160a01b03165b9061500d565b506148e5565b614939816149296002546001600160a01b031690565b5f546001600160a01b0316614907565b5061484a565b50811515614817565b61495f888461412a6002546001600160a01b031690565b5061476f565b61497e915060203d602011610a4457610a368183610559565b5f614768565b506108fc614693565b6149969261500d565b506146a7565b80611e235f6149aa93610559565b5f61460f565b612710925061457a565b6127109150614571565b90506149e991925060403d6040116149f2575b6149e18183610559565b810190614494565b9190915f614564565b503d6149d7565b90816060910312610339578051916040602083015192015190565b7f80000000000000000000000000000000000000000000000000000000000000008114612b74575f0390565b614a4a81516115b1565b50614a5e602083019160038351910161323f565b5090614a706109b86109a58454611ec2565b8351825160e086018051608088015160a08901516040517f149a5dc0000000000000000000000000000000000000000000000000000000008152600481019690965260248601949094526044850191909152606484015260848301919091529094919060208660a481855afa958615610a4b575f96614fec575b506127108611614fe2575b614b0961253860018701546135df89613222565b614b1a6109a5835160068901611eda565b614b2f6109b86004546001600160a01b031690565b803b156103395760405163965af6c760e01b81526001600160a01b038316600482015260248101849052905f908290604490829084905af18015610a4b57614fce575b505f6060614c0e614b9d614b8a875160078d016138c0565b90546001600160601b039160031b1c1690565b94614bb36109b86004546001600160a01b031690565b906040519485809481937f771a27cb0000000000000000000000000000000000000000000000000000000083528a8a600485016001600160601b036040929594936001600160a01b0360608401971683521660208201520152565b03925af1948515610a4b5788955f905f935f91614f97575b508960c08a019c8d614c398482516134e1565b90527fa90d30adac7f21a7def444f0fe0a60bdf16d7e8415973dd09bf869db8f94d58e600a614c6b8d51945195614a14565b9b019a614c7f8c546001600160a01b031690565b6040805185815260208101959095528401919091525f60608401526001600160a01b03908116608084015288169160a090a415908115614f13575b5015614e6357509050614cd86109b86004546001600160a01b031690565b803b15610339576040517faa9ebfb70000000000000000000000000000000000000000000000000000000081526001600160a01b039290921660048301525f908290602490829084905af18015610a4b57614e4f575b505b51614d3e6060840151613214565b1480614e43575b614d52575b505050505190565b7f6cecfd3ec56289ccb16e30eb194f9a87dfdc12630b9abbc31fc69af5a0b0eaf491614d8582546001600160a01b031690565b6001600160a01b038116614e1d57505f808080614daf6109b86109b883546001600160a01b031690565b60028a015490828215614e14575bf1505b614de8614dd56002546001600160a01b031690565b5f546001600160a01b031688519161500d565b5051925193614e086148746002885193015493546001600160a01b031690565b0390a35f808080614d4a565b506108fc614dbd565b614e3d90614e325f546001600160a01b031690565b60028801549161500d565b50614dc0565b50604082015115614d45565b80611e235f614e5d93610559565b5f614d2e565b6002614e6e84610ddf565b50015411614e7e575b5050614d30565b614e936109b86004546001600160a01b031690565b91823b15610339576040517f9d5608670000000000000000000000000000000000000000000000000000000081526001600160a01b039290921660048301526001600160601b03166024820152905f908290604490829084905af18015610a4b57614eff575b80614e77565b80611e235f614f0d93610559565b5f614ef9565b8751895187516040517fba66fde70000000000000000000000000000000000000000000000000000000081526004810193909352602483019190915260448201529150602090829060649082905afa908115610a4b575f91614f78575b50155f614cba565b614f91915060203d602011610a4457610a368183610559565b5f614f70565b915050614fbd91925060603d606011614fc7575b614fb58183610559565b8101906149f9565b929190925f614c26565b503d614fab565b80611e235f614fdc93610559565b5f614b72565b6127109550614af5565b61500691965060203d60201161109e5761108f8183610559565b945f614aea565b6040517fa9059cbb00000000000000000000000000000000000000000000000000000000602082019081526001600160a01b0393841660248301526044808301959095529381525f9384939091849190615068606482610559565b5193165af16150756134fd565b8161507e575090565b805180159250821561508f57505090565b6112639250602080918301019101613267565b6001600160a01b035f5416330361038957565b600754600160401b8110156105545760018101600755600754811015610dfb5760075f52600e60205f20910201905f90565b90919392936150f583615331565b92905061510d6124a561249e85600a61248f87610ddf565b61265d576151d290600a600754986151236150b5565b503360601b6bffffffffffffffffffffffff19166001600160601b038716178155426002820155906151ac612538615173600361516b6151656109a58d611ec2565b9a610ddf565b50950161391b565b50936001600160a01b0387166152be5761519260048201545b856132ec565b99600386019a8b55855560036002820154910154906132c5565b6001830155600282015501906001600160a01b03166001600160a01b0319825416179055565b6151e76109b86004546001600160a01b031690565b90813b156103395760405163d09f392d60e01b8152600481018890525f6024820181905290928390604490829084905af1918215610a4b576001600160a01b03926152aa575b5016905490803b156103395761525e935f8094604051968795869485936302dbb79560e61b85528c6004860161393c565b03925af18015610a4b57615296575b5033827f141dfc18aa6a56fc816f44f0e9e2f1ebc92b15ab167770e17db5b084c10ed9955f80a3565b80611e235f6152a493610559565b5f61526d565b80611e235f6152b893610559565b5f61522d565b6151926152cf6004830154896132fb565b61518c565b905f6001600160a01b03819594829582604051928160208501977f23b872dd000000000000000000000000000000000000000000000000000000008952166024850152166044830152606482015260648152615068608482610559565b80516040116153ac5760208101519160606040830151920151906001600160601b038416801590811561539f575b50615396575b821561538d575b81158015615381575b61537b57565b60019150565b50600654821015615375565b6003925061536c565b60019350615365565b905060055411155f61535f565b50600190600390600190565b600211156115eb57565b6001906153ce816153b8565b1461058b57637c84af5160e01b5f5260045ffd5b6001906153ee816153b8565b1461058b57630caac6b360e31b5f5260045ffd5b60019061540e816153b8565b1461058b57630f323ed960e11b5f5260045ffd5b60019061542e816153b8565b1461058b5763e45e13a360e01b5f5260045ffd5b60019061544e816153b8565b146155475761545c81613fa6565b600281146155385761546d81613fa6565b600381146155295761547e81613fa6565b600481146155015761548f81613fa6565b600581146154f2576154a081613fa6565b600681146154e357806154b4600992613fa6565b146154bb57565b7ff95e58bc000000000000000000000000000000000000000000000000000000005f5260045ffd5b630caac6b360e31b5f5260045ffd5b637c84af5160e01b5f5260045ffd5b7fec8e8768000000000000000000000000000000000000000000000000000000005f5260045ffd5b63e45e13a360e01b5f5260045ffd5b630f323ed960e11b5f5260045ffd5b5056fea26469706673582212209d8693ceca011df52e9dd63f6056bbcd764f392dc1976d1654c7a6599b67d72c64736f6c634300081e0033",
"devdoc": {
"errors": {
"AlreadyInitialized()": [
@@ -1852,28 +1908,16 @@
{
"details": "The contract is not initializing."
}
- ],
- "UUPSUnauthorizedCallContext()": [
- {
- "details": "The call is from an unauthorized context."
- }
- ],
- "UUPSUnsupportedProxiableUUID(bytes32)": [
- {
- "details": "The storage `slot` is unsupported as a UUID."
- }
]
},
"events": {
"AcceptedFeeToken(address,bool)": {
- "details": "To be emitted when an ERC20 token is added or removed as a method to pay fees.",
"params": {
"_accepted": "Whether the token is accepted or not.",
"_token": "The ERC20 token."
}
},
"DisputeCreation(uint256,address)": {
- "details": "To be emitted when a dispute is created.",
"params": {
"_arbitrable": "The contract which created the dispute.",
"_disputeID": "The identifier of the dispute in the Arbitrator contract."
@@ -1883,7 +1927,6 @@
"details": "Triggered when the contract has been initialized or reinitialized."
},
"NewCurrencyRate(address,uint64,uint8)": {
- "details": "To be emitted when the fee for a particular ERC20 token is updated.",
"params": {
"_feeToken": "The ERC20 token.",
"_rateDecimals": "The new decimals of the fee token rate.",
@@ -1891,7 +1934,6 @@
}
},
"Ruling(address,uint256,uint256)": {
- "details": "To be raised when a ruling is given.",
"params": {
"_arbitrable": "The arbitrable receiving the ruling.",
"_disputeID": "The identifier of the dispute in the Arbitrator contract.",
@@ -1907,13 +1949,12 @@
"kind": "dev",
"methods": {
"addNewDisputeKit(address)": {
- "details": "Add a new supported dispute kit module to the court.",
"params": {
"_disputeKitAddress": "The address of the dispute kit contract."
}
},
"appeal(uint256,uint256,bytes)": {
- "details": "Appeals the ruling of a specified dispute. Note: Access restricted to the Dispute Kit for this `disputeID`.",
+ "details": "Access restricted to the Dispute Kit for this `disputeID`.",
"params": {
"_disputeID": "The ID of the dispute.",
"_extraData": "Extradata for the dispute. Can be required during court jump.",
@@ -1921,7 +1962,6 @@
}
},
"appealCost(uint256)": {
- "details": "Gets the cost of appealing a specified dispute.",
"params": {
"_disputeID": "The ID of the dispute."
},
@@ -1930,7 +1970,6 @@
}
},
"appealPeriod(uint256)": {
- "details": "Gets the start and the end of a specified dispute's current appeal period.",
"params": {
"_disputeID": "The ID of the dispute."
},
@@ -1940,7 +1979,7 @@
}
},
"arbitrationCost(bytes)": {
- "details": "Compute the cost of arbitration denominated in ETH. It is recommended not to increase it often, as it can be highly time and gas consuming for the arbitrated contracts to cope with fee augmentation.",
+ "details": "It is recommended not to increase it often, as it can be highly time and gas consuming for the arbitrated contracts to cope with fee augmentation.",
"params": {
"_extraData": "Additional info about the dispute. We use it to pass the ID of the dispute's court (first 32 bytes), the minimum number of jurors required (next 32 bytes) and the ID of the specific dispute kit (last 32 bytes)."
},
@@ -1949,7 +1988,7 @@
}
},
"arbitrationCost(bytes,address)": {
- "details": "Compute the cost of arbitration denominated in `_feeToken`. It is recommended not to increase it often, as it can be highly time and gas consuming for the arbitrated contracts to cope with fee augmentation.",
+ "details": "It is recommended not to increase it often, as it can be highly time and gas consuming for the arbitrated contracts to cope with fee augmentation.",
"params": {
"_extraData": "Additional info about the dispute. We use it to pass the ID of the dispute's court (first 32 bytes), the minimum number of jurors required (next 32 bytes) and the ID of the specific dispute kit (last 32 bytes).",
"_feeToken": "The ERC20 token used to pay fees."
@@ -1959,55 +1998,47 @@
}
},
"changeAcceptedFeeTokens(address,bool)": {
- "details": "Changes the supported fee tokens.",
"params": {
"_accepted": "Whether the token is supported or not as a method of fee payment.",
"_feeToken": "The fee token."
}
},
"changeCurrencyRates(address,uint64,uint8)": {
- "details": "Changes the currency rate of a fee token.",
"params": {
"_feeToken": "The fee token.",
"_rateDecimals": "The new decimals of the fee token rate.",
"_rateInEth": "The new rate of the fee token in ETH."
}
},
- "changeGovernor(address)": {
- "details": "Changes the `governor` storage variable.",
- "params": {
- "_governor": "The new value for the `governor` storage variable."
- }
- },
"changeInstructor(address)": {
- "details": "Changes the `instructor` storage variable.",
"params": {
"_instructor": "The new value for the `instructor` storage variable."
}
},
"changeJurorProsecutionModule(address)": {
- "details": "Changes the `jurorProsecutionModule` storage variable.",
"params": {
"_jurorProsecutionModule": "The new value for the `jurorProsecutionModule` storage variable."
}
},
+ "changeOwner(address)": {
+ "params": {
+ "_owner": "The new value for the `owner` storage variable."
+ }
+ },
"changePinakion(address)": {
- "details": "Changes the `pinakion` storage variable.",
"params": {
"_pinakion": "The new value for the `pinakion` storage variable."
}
},
"changeSortitionModule(address)": {
- "details": "Changes the `_sortitionModule` storage variable. Note that the new module should be initialized for all courts.",
"params": {
"_sortitionModule": "The new value for the `sortitionModule` storage variable."
}
},
"constructor": {
- "details": "Constructor, initializing the implementation to reduce attack surface."
+ "custom:oz-upgrades-unsafe-allow": "constructor"
},
"createCourt(uint96,bool,uint256,uint256,uint256,uint256,uint256[4],uint256[])": {
- "details": "Creates a court under a specified parent court.",
"params": {
"_alpha": "The `alpha` property value of the court.",
"_feeForJuror": "The `feeForJuror` property value of the court.",
@@ -2020,7 +2051,7 @@
}
},
"createDispute(uint256,bytes)": {
- "details": "Create a dispute and pay for the fees in the native currency, typically ETH. Must be called by the arbitrable contract. Must pay at least arbitrationCost(_extraData).",
+ "details": "Must be called by the arbitrable contract and pay at least `arbitrationCost(_extraData)` in ETH.",
"params": {
"_extraData": "Additional info about the dispute. We use it to pass the ID of the dispute's court (first 32 bytes), the minimum number of jurors required (next 32 bytes) and the ID of the specific dispute kit (last 32 bytes).",
"_numberOfChoices": "The number of choices the arbitrator can choose from in this dispute."
@@ -2030,7 +2061,7 @@
}
},
"createDispute(uint256,bytes,address,uint256)": {
- "details": "Create a dispute and pay for the fees in a supported ERC20 token. Must be called by the arbitrable contract. Must pay at least arbitrationCost(_extraData).",
+ "details": "Must be called by the arbitrable contract and pay at least `arbitrationCost(_extraData)` in the supported ERC20 token.",
"params": {
"_extraData": "Additional info about the dispute. We use it to pass the ID of the dispute's court (first 32 bytes), the minimum number of jurors required (next 32 bytes) and the ID of the specific dispute kit (last 32 bytes).",
"_feeAmount": "Amount of the ERC20 token used to pay fees.",
@@ -2042,7 +2073,6 @@
}
},
"currentRuling(uint256)": {
- "details": "Gets the current ruling of a specified dispute.",
"params": {
"_disputeID": "The ID of the dispute."
},
@@ -2053,14 +2083,12 @@
}
},
"draw(uint256,address)": {
- "details": "Draws one juror for the dispute until the number votes paid for is reached.",
"params": {
"_disputeID": "The ID of the dispute.",
"_juror": "The address of the juror to draw."
}
},
"enableDisputeKits(uint96,uint256[],bool)": {
- "details": "Adds/removes court's support for specified dispute kits.",
"params": {
"_courtID": "The ID of the court.",
"_disputeKitIDs": "The IDs of dispute kits which support should be added/removed.",
@@ -2068,15 +2096,13 @@
}
},
"execute(uint256,uint256,uint256)": {
- "details": "Distribute the PNKs at stake and the dispute fees for the specific round of the dispute. Can be called in parts.",
"params": {
"_disputeID": "The ID of the dispute.",
"_iterations": "The number of iterations to run.",
"_round": "The appeal round."
}
},
- "executeGovernorProposal(address,uint256,bytes)": {
- "details": "Allows the governor to call anything on behalf of the contract.",
+ "executeOwnerProposal(address,uint256,bytes)": {
"params": {
"_amount": "The value sent with the call.",
"_data": "The data sent with the call.",
@@ -2084,19 +2110,43 @@
}
},
"executeRuling(uint256)": {
- "details": "Executes a specified dispute's ruling.",
"params": {
"_disputeID": "The ID of the dispute."
}
},
+ "getNumberOfRounds(uint256)": {
+ "params": {
+ "_disputeID": "The ID of the dispute."
+ },
+ "returns": {
+ "_0": "The number of rounds."
+ }
+ },
"getNumberOfVotes(uint256)": {
- "details": "Gets the number of votes permitted for the specified dispute in the latest round.",
"params": {
"_disputeID": "The ID of the dispute."
}
},
+ "getPnkAtStakePerJuror(uint256,uint256)": {
+ "params": {
+ "_disputeID": "The ID of the dispute.",
+ "_round": "The round to get the info for."
+ },
+ "returns": {
+ "_0": "pnkAtStakePerJuror The PNK at stake per juror."
+ }
+ },
+ "getRoundInfo(uint256,uint256)": {
+ "details": "This function must not be called from a non-view function because it returns a dynamic array which might be very large, theoretically exceeding the block gas limit.",
+ "params": {
+ "_disputeID": "The ID of the dispute.",
+ "_round": "The round to get the info for."
+ },
+ "returns": {
+ "_0": "round The round info."
+ }
+ },
"getTimesPerPeriod(uint96)": {
- "details": "Gets the timesPerPeriod array for a given court.",
"params": {
"_courtID": "The ID of the court to get the times from."
},
@@ -2105,21 +2155,19 @@
}
},
"initialize(address,address,address,address,address,bool,uint256[4],uint256[4],address)": {
- "details": "Initializer (constructor equivalent for upgradable contracts).",
"params": {
"_courtParameters": "Numeric parameters of General court (minStake, alpha, feeForJuror and jurorsForCourtJump respectively).",
"_disputeKit": "The address of the default dispute kit.",
- "_governor": "The governor's address.",
"_hiddenVotes": "The `hiddenVotes` property value of the general court.",
"_instructor": "The address of the instructor.",
"_jurorProsecutionModule": "The address of the juror prosecution module.",
+ "_owner": "The owner's address.",
"_pinakion": "The address of the token contract.",
"_sortitionModuleAddress": "The sortition module responsible for sortition of the jurors.",
"_timesPerPeriod": "The `timesPerPeriod` property value of the general court."
}
},
"isDisputeKitJumping(uint256)": {
- "details": "Returns true if the dispute kit will be switched to a parent DK.",
"params": {
"_disputeID": "The ID of the dispute."
},
@@ -2127,40 +2175,59 @@
"_0": "Whether DK will be switched or not."
}
},
+ "isSupported(uint96,uint256)": {
+ "params": {
+ "_courtID": "The ID of the court to check the support for.",
+ "_disputeKitID": "The ID of the dispute kit to check the support for."
+ },
+ "returns": {
+ "_0": "Whether the dispute kit is supported or not."
+ }
+ },
"passPeriod(uint256)": {
- "details": "Passes the period of a specified dispute.",
"params": {
"_disputeID": "The ID of the dispute."
}
},
"proxiableUUID()": {
- "details": "Implementation of the ERC1822 `proxiableUUID` function. This returns the storage slot used by the implementation. It is used to validate the implementation's compatibility when performing an upgrade. IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this function revert if invoked through a proxy. This is guaranteed by the if statement."
+ "details": "IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this function revert if invoked through a proxy. This is guaranteed by the if statement."
},
"setStake(uint96,uint256)": {
- "details": "Sets the caller's stake in a court.",
"params": {
"_courtID": "The ID of the court.",
"_newStake": "The new stake. Note that the existing delayed stake will be nullified as non-relevant."
}
},
- "setStakeBySortitionModule(address,uint96,uint256,bool)": {
- "details": "Sets the stake of a specified account in a court, typically to apply a delayed stake or unstake inactive jurors.",
+ "setStakeBySortitionModule(address,uint96,uint256)": {
"params": {
"_account": "The account whose stake is being set.",
- "_alreadyTransferred": "Whether the PNKs have already been transferred to the contract.",
"_courtID": "The ID of the court.",
"_newStake": "The new stake."
}
},
+ "transferBySortitionModule(address,uint256)": {
+ "params": {
+ "_account": "The account of the juror whose PNK to transfer.",
+ "_amount": "The amount to transfer."
+ }
+ },
"upgradeToAndCall(address,bytes)": {
- "details": "Upgrade mechanism including access control and UUPS-compliance.Reverts if the execution is not performed via delegatecall or the execution context is not of a proxy with an ERC1967-compliant implementation pointing to self.",
+ "details": "Reverts if the execution is not performed via delegatecall or the execution context is not of a proxy with an ERC1967-compliant implementation pointing to self.",
"params": {
"data": "Data used in a delegate call to `newImplementation` if non-empty. This will typically be an encoded function call, and allows initializing the storage of the proxy like a Solidity constructor.",
"newImplementation": "Address of the new implementation contract."
}
}
},
- "title": "KlerosCoreUniversity Core arbitrator contract for educational purposes.",
+ "stateVariables": {
+ "version": {
+ "return": "Version string.",
+ "returns": {
+ "_0": "Version string."
+ }
+ }
+ },
+ "title": "KlerosCoreUniversity",
"version": 1
},
"userdoc": {
@@ -2174,29 +2241,164 @@
{
"notice": "The `implementation` is not UUPS-compliant"
}
+ ],
+ "UUPSUnauthorizedCallContext()": [
+ {
+ "notice": "The call is from an unauthorized context."
+ }
+ ],
+ "UUPSUnsupportedProxiableUUID(bytes32)": [
+ {
+ "notice": "The storage `slot` is unsupported as a UUID."
+ }
]
},
"events": {
+ "AcceptedFeeToken(address,bool)": {
+ "notice": "To be emitted when an ERC20 token is added or removed as a method to pay fees."
+ },
+ "DisputeCreation(uint256,address)": {
+ "notice": "To be emitted when a dispute is created."
+ },
+ "NewCurrencyRate(address,uint64,uint8)": {
+ "notice": "To be emitted when the fee for a particular ERC20 token is updated."
+ },
+ "Ruling(address,uint256,uint256)": {
+ "notice": "To be raised when a ruling is given."
+ },
"Upgraded(address)": {
"notice": "Emitted when the `implementation` has been successfully upgraded."
}
},
"kind": "user",
- "methods": {},
+ "methods": {
+ "addNewDisputeKit(address)": {
+ "notice": "Add a new supported dispute kit module to the court."
+ },
+ "appeal(uint256,uint256,bytes)": {
+ "notice": "Appeals the ruling of a specified dispute."
+ },
+ "appealCost(uint256)": {
+ "notice": "Gets the cost of appealing a specified dispute."
+ },
+ "appealPeriod(uint256)": {
+ "notice": "Gets the start and the end of a specified dispute's current appeal period."
+ },
+ "arbitrationCost(bytes)": {
+ "notice": "Compute the cost of arbitration denominated in the native currency, typically ETH."
+ },
+ "arbitrationCost(bytes,address)": {
+ "notice": "Compute the cost of arbitration denominated in `_feeToken`."
+ },
+ "changeAcceptedFeeTokens(address,bool)": {
+ "notice": "Changes the supported fee tokens."
+ },
+ "changeCurrencyRates(address,uint64,uint8)": {
+ "notice": "Changes the currency rate of a fee token."
+ },
+ "changeInstructor(address)": {
+ "notice": "Changes the `instructor` storage variable."
+ },
+ "changeJurorProsecutionModule(address)": {
+ "notice": "Changes the `jurorProsecutionModule` storage variable."
+ },
+ "changeOwner(address)": {
+ "notice": "Changes the `owner` storage variable."
+ },
+ "changePinakion(address)": {
+ "notice": "Changes the `pinakion` storage variable."
+ },
+ "changeSortitionModule(address)": {
+ "notice": "Changes the `_sortitionModule` storage variable. Note that the new module should be initialized for all courts."
+ },
+ "createCourt(uint96,bool,uint256,uint256,uint256,uint256,uint256[4],uint256[])": {
+ "notice": "Creates a court under a specified parent court."
+ },
+ "createDispute(uint256,bytes)": {
+ "notice": "Create a dispute and pay for the fees in the native currency, typically ETH."
+ },
+ "createDispute(uint256,bytes,address,uint256)": {
+ "notice": "Create a dispute and pay for the fees in a supported ERC20 token."
+ },
+ "currentRuling(uint256)": {
+ "notice": "Gets the current ruling of a specified dispute."
+ },
+ "draw(uint256,address)": {
+ "notice": "Draws one juror for the dispute until the number votes paid for is reached."
+ },
+ "enableDisputeKits(uint96,uint256[],bool)": {
+ "notice": "Adds/removes court's support for specified dispute kits."
+ },
+ "execute(uint256,uint256,uint256)": {
+ "notice": "Distribute the PNKs at stake and the dispute fees for the specific round of the dispute. Can be called in parts."
+ },
+ "executeOwnerProposal(address,uint256,bytes)": {
+ "notice": "Allows the owner to call anything on behalf of the contract."
+ },
+ "executeRuling(uint256)": {
+ "notice": "Executes a specified dispute's ruling."
+ },
+ "getNumberOfRounds(uint256)": {
+ "notice": "Gets the number of rounds for a specified dispute."
+ },
+ "getNumberOfVotes(uint256)": {
+ "notice": "Gets the number of votes permitted for the specified dispute in the latest round."
+ },
+ "getPnkAtStakePerJuror(uint256,uint256)": {
+ "notice": "Gets the PNK at stake per juror for a specified dispute and round."
+ },
+ "getRoundInfo(uint256,uint256)": {
+ "notice": "Gets the round info for a specified dispute and round."
+ },
+ "getTimesPerPeriod(uint96)": {
+ "notice": "Gets the timesPerPeriod array for a given court."
+ },
+ "initialize(address,address,address,address,address,bool,uint256[4],uint256[4],address)": {
+ "notice": "Initializer (constructor equivalent for upgradable contracts)."
+ },
+ "isDisputeKitJumping(uint256)": {
+ "notice": "Returns true if the dispute kit will be switched to a parent DK."
+ },
+ "isSupported(uint96,uint256)": {
+ "notice": "Checks if a given dispute kit is supported by a given court."
+ },
+ "passPeriod(uint256)": {
+ "notice": "Passes the period of a specified dispute."
+ },
+ "proxiableUUID()": {
+ "notice": "Implementation of the ERC1822 `proxiableUUID` function. This returns the storage slot used by the implementation. It is used to validate the implementation's compatibility when performing an upgrade."
+ },
+ "setStake(uint96,uint256)": {
+ "notice": "Sets the caller's stake in a court."
+ },
+ "setStakeBySortitionModule(address,uint96,uint256)": {
+ "notice": "Sets the stake of a specified account in a court, typically to apply a delayed stake or unstake inactive jurors."
+ },
+ "transferBySortitionModule(address,uint256)": {
+ "notice": "Transfers PNK to the juror by SortitionModule."
+ },
+ "upgradeToAndCall(address,bytes)": {
+ "notice": "Upgrade mechanism including access control and UUPS-compliance."
+ },
+ "version()": {
+ "notice": "Returns the version of the implementation."
+ }
+ },
+ "notice": "Core arbitrator contract for educational purposes.",
"version": 1
},
"storageLayout": {
"storage": [
{
- "astId": 23505,
+ "astId": 26659,
"contract": "src/arbitration/university/KlerosCoreUniversity.sol:KlerosCoreUniversity",
- "label": "governor",
+ "label": "owner",
"offset": 0,
"slot": "0",
"type": "t_address"
},
{
- "astId": 23507,
+ "astId": 26661,
"contract": "src/arbitration/university/KlerosCoreUniversity.sol:KlerosCoreUniversity",
"label": "instructor",
"offset": 0,
@@ -2204,15 +2406,15 @@
"type": "t_address"
},
{
- "astId": 23510,
+ "astId": 26664,
"contract": "src/arbitration/university/KlerosCoreUniversity.sol:KlerosCoreUniversity",
"label": "pinakion",
"offset": 0,
"slot": "2",
- "type": "t_contract(IERC20)1229"
+ "type": "t_contract(IERC20)3021"
},
{
- "astId": 23512,
+ "astId": 26666,
"contract": "src/arbitration/university/KlerosCoreUniversity.sol:KlerosCoreUniversity",
"label": "jurorProsecutionModule",
"offset": 0,
@@ -2220,44 +2422,44 @@
"type": "t_address"
},
{
- "astId": 23515,
+ "astId": 26669,
"contract": "src/arbitration/university/KlerosCoreUniversity.sol:KlerosCoreUniversity",
"label": "sortitionModule",
"offset": 0,
"slot": "4",
- "type": "t_contract(ISortitionModuleUniversity)23364"
+ "type": "t_contract(ISortitionModuleUniversity)26504"
},
{
- "astId": 23519,
+ "astId": 26673,
"contract": "src/arbitration/university/KlerosCoreUniversity.sol:KlerosCoreUniversity",
"label": "courts",
"offset": 0,
"slot": "5",
- "type": "t_array(t_struct(Court)23424_storage)dyn_storage"
+ "type": "t_array(t_struct(Court)26570_storage)dyn_storage"
},
{
- "astId": 23523,
+ "astId": 26677,
"contract": "src/arbitration/university/KlerosCoreUniversity.sol:KlerosCoreUniversity",
"label": "disputeKits",
"offset": 0,
"slot": "6",
- "type": "t_array(t_contract(IDisputeKit)23189)dyn_storage"
+ "type": "t_array(t_contract(IDisputeKit)26251)dyn_storage"
},
{
- "astId": 23527,
+ "astId": 26681,
"contract": "src/arbitration/university/KlerosCoreUniversity.sol:KlerosCoreUniversity",
"label": "disputes",
"offset": 0,
"slot": "7",
- "type": "t_array(t_struct(Dispute)23441_storage)dyn_storage"
+ "type": "t_array(t_struct(Dispute)26591_storage)dyn_storage"
},
{
- "astId": 23533,
+ "astId": 26687,
"contract": "src/arbitration/university/KlerosCoreUniversity.sol:KlerosCoreUniversity",
"label": "currencyRates",
"offset": 0,
"slot": "8",
- "type": "t_mapping(t_contract(IERC20)1229,t_struct(CurrencyRate)23490_storage)"
+ "type": "t_mapping(t_contract(IERC20)3021,t_struct(CurrencyRate)26647_storage)"
}
],
"types": {
@@ -2272,30 +2474,36 @@
"label": "address[]",
"numberOfBytes": "32"
},
- "t_array(t_contract(IDisputeKit)23189)dyn_storage": {
- "base": "t_contract(IDisputeKit)23189",
+ "t_array(t_contract(IDisputeKit)26251)dyn_storage": {
+ "base": "t_contract(IDisputeKit)26251",
"encoding": "dynamic_array",
"label": "contract IDisputeKit[]",
"numberOfBytes": "32"
},
- "t_array(t_struct(Court)23424_storage)dyn_storage": {
- "base": "t_struct(Court)23424_storage",
+ "t_array(t_struct(Court)26570_storage)dyn_storage": {
+ "base": "t_struct(Court)26570_storage",
"encoding": "dynamic_array",
"label": "struct KlerosCoreUniversity.Court[]",
"numberOfBytes": "32"
},
- "t_array(t_struct(Dispute)23441_storage)dyn_storage": {
- "base": "t_struct(Dispute)23441_storage",
+ "t_array(t_struct(Dispute)26591_storage)dyn_storage": {
+ "base": "t_struct(Dispute)26591_storage",
"encoding": "dynamic_array",
"label": "struct KlerosCoreUniversity.Dispute[]",
"numberOfBytes": "32"
},
- "t_array(t_struct(Round)23466_storage)dyn_storage": {
- "base": "t_struct(Round)23466_storage",
+ "t_array(t_struct(Round)26623_storage)dyn_storage": {
+ "base": "t_struct(Round)26623_storage",
"encoding": "dynamic_array",
"label": "struct KlerosCoreUniversity.Round[]",
"numberOfBytes": "32"
},
+ "t_array(t_uint256)10_storage": {
+ "base": "t_uint256",
+ "encoding": "inplace",
+ "label": "uint256[10]",
+ "numberOfBytes": "320"
+ },
"t_array(t_uint256)4_storage": {
"base": "t_uint256",
"encoding": "inplace",
@@ -2308,42 +2516,48 @@
"label": "uint256[]",
"numberOfBytes": "32"
},
+ "t_array(t_uint96)dyn_storage": {
+ "base": "t_uint96",
+ "encoding": "dynamic_array",
+ "label": "uint96[]",
+ "numberOfBytes": "32"
+ },
"t_bool": {
"encoding": "inplace",
"label": "bool",
"numberOfBytes": "1"
},
- "t_contract(IArbitrableV2)22946": {
+ "t_contract(IArbitrableV2)25953": {
"encoding": "inplace",
"label": "contract IArbitrableV2",
"numberOfBytes": "20"
},
- "t_contract(IDisputeKit)23189": {
+ "t_contract(IDisputeKit)26251": {
"encoding": "inplace",
"label": "contract IDisputeKit",
"numberOfBytes": "20"
},
- "t_contract(IERC20)1229": {
+ "t_contract(IERC20)3021": {
"encoding": "inplace",
"label": "contract IERC20",
"numberOfBytes": "20"
},
- "t_contract(ISortitionModuleUniversity)23364": {
+ "t_contract(ISortitionModuleUniversity)26504": {
"encoding": "inplace",
"label": "contract ISortitionModuleUniversity",
"numberOfBytes": "20"
},
- "t_enum(Period)23398": {
+ "t_enum(Period)26542": {
"encoding": "inplace",
"label": "enum KlerosCoreUniversity.Period",
"numberOfBytes": "1"
},
- "t_mapping(t_contract(IERC20)1229,t_struct(CurrencyRate)23490_storage)": {
+ "t_mapping(t_contract(IERC20)3021,t_struct(CurrencyRate)26647_storage)": {
"encoding": "mapping",
- "key": "t_contract(IERC20)1229",
+ "key": "t_contract(IERC20)3021",
"label": "mapping(contract IERC20 => struct KlerosCoreUniversity.CurrencyRate)",
"numberOfBytes": "32",
- "value": "t_struct(CurrencyRate)23490_storage"
+ "value": "t_struct(CurrencyRate)26647_storage"
},
"t_mapping(t_uint256,t_bool)": {
"encoding": "mapping",
@@ -2352,12 +2566,12 @@
"numberOfBytes": "32",
"value": "t_bool"
},
- "t_struct(Court)23424_storage": {
+ "t_struct(Court)26570_storage": {
"encoding": "inplace",
"label": "struct KlerosCoreUniversity.Court",
"members": [
{
- "astId": 23400,
+ "astId": 26544,
"contract": "src/arbitration/university/KlerosCoreUniversity.sol:KlerosCoreUniversity",
"label": "parent",
"offset": 0,
@@ -2365,7 +2579,7 @@
"type": "t_uint96"
},
{
- "astId": 23402,
+ "astId": 26546,
"contract": "src/arbitration/university/KlerosCoreUniversity.sol:KlerosCoreUniversity",
"label": "hiddenVotes",
"offset": 12,
@@ -2373,7 +2587,7 @@
"type": "t_bool"
},
{
- "astId": 23405,
+ "astId": 26549,
"contract": "src/arbitration/university/KlerosCoreUniversity.sol:KlerosCoreUniversity",
"label": "children",
"offset": 0,
@@ -2381,7 +2595,7 @@
"type": "t_array(t_uint256)dyn_storage"
},
{
- "astId": 23407,
+ "astId": 26551,
"contract": "src/arbitration/university/KlerosCoreUniversity.sol:KlerosCoreUniversity",
"label": "minStake",
"offset": 0,
@@ -2389,7 +2603,7 @@
"type": "t_uint256"
},
{
- "astId": 23409,
+ "astId": 26553,
"contract": "src/arbitration/university/KlerosCoreUniversity.sol:KlerosCoreUniversity",
"label": "alpha",
"offset": 0,
@@ -2397,7 +2611,7 @@
"type": "t_uint256"
},
{
- "astId": 23411,
+ "astId": 26555,
"contract": "src/arbitration/university/KlerosCoreUniversity.sol:KlerosCoreUniversity",
"label": "feeForJuror",
"offset": 0,
@@ -2405,7 +2619,7 @@
"type": "t_uint256"
},
{
- "astId": 23413,
+ "astId": 26557,
"contract": "src/arbitration/university/KlerosCoreUniversity.sol:KlerosCoreUniversity",
"label": "jurorsForCourtJump",
"offset": 0,
@@ -2413,7 +2627,7 @@
"type": "t_uint256"
},
{
- "astId": 23417,
+ "astId": 26561,
"contract": "src/arbitration/university/KlerosCoreUniversity.sol:KlerosCoreUniversity",
"label": "timesPerPeriod",
"offset": 0,
@@ -2421,7 +2635,7 @@
"type": "t_array(t_uint256)4_storage"
},
{
- "astId": 23421,
+ "astId": 26565,
"contract": "src/arbitration/university/KlerosCoreUniversity.sol:KlerosCoreUniversity",
"label": "supportedDisputeKits",
"offset": 0,
@@ -2429,22 +2643,22 @@
"type": "t_mapping(t_uint256,t_bool)"
},
{
- "astId": 23423,
+ "astId": 26569,
"contract": "src/arbitration/university/KlerosCoreUniversity.sol:KlerosCoreUniversity",
- "label": "disabled",
+ "label": "__gap",
"offset": 0,
"slot": "11",
- "type": "t_bool"
+ "type": "t_array(t_uint256)10_storage"
}
],
- "numberOfBytes": "384"
+ "numberOfBytes": "672"
},
- "t_struct(CurrencyRate)23490_storage": {
+ "t_struct(CurrencyRate)26647_storage": {
"encoding": "inplace",
"label": "struct KlerosCoreUniversity.CurrencyRate",
"members": [
{
- "astId": 23485,
+ "astId": 26642,
"contract": "src/arbitration/university/KlerosCoreUniversity.sol:KlerosCoreUniversity",
"label": "feePaymentAccepted",
"offset": 0,
@@ -2452,7 +2666,7 @@
"type": "t_bool"
},
{
- "astId": 23487,
+ "astId": 26644,
"contract": "src/arbitration/university/KlerosCoreUniversity.sol:KlerosCoreUniversity",
"label": "rateInEth",
"offset": 1,
@@ -2460,7 +2674,7 @@
"type": "t_uint64"
},
{
- "astId": 23489,
+ "astId": 26646,
"contract": "src/arbitration/university/KlerosCoreUniversity.sol:KlerosCoreUniversity",
"label": "rateDecimals",
"offset": 9,
@@ -2470,12 +2684,12 @@
],
"numberOfBytes": "32"
},
- "t_struct(Dispute)23441_storage": {
+ "t_struct(Dispute)26591_storage": {
"encoding": "inplace",
"label": "struct KlerosCoreUniversity.Dispute",
"members": [
{
- "astId": 23426,
+ "astId": 26572,
"contract": "src/arbitration/university/KlerosCoreUniversity.sol:KlerosCoreUniversity",
"label": "courtID",
"offset": 0,
@@ -2483,23 +2697,23 @@
"type": "t_uint96"
},
{
- "astId": 23429,
+ "astId": 26575,
"contract": "src/arbitration/university/KlerosCoreUniversity.sol:KlerosCoreUniversity",
"label": "arbitrated",
"offset": 12,
"slot": "0",
- "type": "t_contract(IArbitrableV2)22946"
+ "type": "t_contract(IArbitrableV2)25953"
},
{
- "astId": 23432,
+ "astId": 26578,
"contract": "src/arbitration/university/KlerosCoreUniversity.sol:KlerosCoreUniversity",
"label": "period",
"offset": 0,
"slot": "1",
- "type": "t_enum(Period)23398"
+ "type": "t_enum(Period)26542"
},
{
- "astId": 23434,
+ "astId": 26580,
"contract": "src/arbitration/university/KlerosCoreUniversity.sol:KlerosCoreUniversity",
"label": "ruled",
"offset": 1,
@@ -2507,7 +2721,7 @@
"type": "t_bool"
},
{
- "astId": 23436,
+ "astId": 26582,
"contract": "src/arbitration/university/KlerosCoreUniversity.sol:KlerosCoreUniversity",
"label": "lastPeriodChange",
"offset": 0,
@@ -2515,22 +2729,30 @@
"type": "t_uint256"
},
{
- "astId": 23440,
+ "astId": 26586,
"contract": "src/arbitration/university/KlerosCoreUniversity.sol:KlerosCoreUniversity",
"label": "rounds",
"offset": 0,
"slot": "3",
- "type": "t_array(t_struct(Round)23466_storage)dyn_storage"
+ "type": "t_array(t_struct(Round)26623_storage)dyn_storage"
+ },
+ {
+ "astId": 26590,
+ "contract": "src/arbitration/university/KlerosCoreUniversity.sol:KlerosCoreUniversity",
+ "label": "__gap",
+ "offset": 0,
+ "slot": "4",
+ "type": "t_array(t_uint256)10_storage"
}
],
- "numberOfBytes": "128"
+ "numberOfBytes": "448"
},
- "t_struct(Round)23466_storage": {
+ "t_struct(Round)26623_storage": {
"encoding": "inplace",
"label": "struct KlerosCoreUniversity.Round",
"members": [
{
- "astId": 23443,
+ "astId": 26593,
"contract": "src/arbitration/university/KlerosCoreUniversity.sol:KlerosCoreUniversity",
"label": "disputeKitID",
"offset": 0,
@@ -2538,7 +2760,7 @@
"type": "t_uint256"
},
{
- "astId": 23445,
+ "astId": 26595,
"contract": "src/arbitration/university/KlerosCoreUniversity.sol:KlerosCoreUniversity",
"label": "pnkAtStakePerJuror",
"offset": 0,
@@ -2546,7 +2768,7 @@
"type": "t_uint256"
},
{
- "astId": 23447,
+ "astId": 26597,
"contract": "src/arbitration/university/KlerosCoreUniversity.sol:KlerosCoreUniversity",
"label": "totalFeesForJurors",
"offset": 0,
@@ -2554,7 +2776,7 @@
"type": "t_uint256"
},
{
- "astId": 23449,
+ "astId": 26599,
"contract": "src/arbitration/university/KlerosCoreUniversity.sol:KlerosCoreUniversity",
"label": "nbVotes",
"offset": 0,
@@ -2562,7 +2784,7 @@
"type": "t_uint256"
},
{
- "astId": 23451,
+ "astId": 26601,
"contract": "src/arbitration/university/KlerosCoreUniversity.sol:KlerosCoreUniversity",
"label": "repartitions",
"offset": 0,
@@ -2570,7 +2792,7 @@
"type": "t_uint256"
},
{
- "astId": 23453,
+ "astId": 26603,
"contract": "src/arbitration/university/KlerosCoreUniversity.sol:KlerosCoreUniversity",
"label": "pnkPenalties",
"offset": 0,
@@ -2578,7 +2800,7 @@
"type": "t_uint256"
},
{
- "astId": 23456,
+ "astId": 26606,
"contract": "src/arbitration/university/KlerosCoreUniversity.sol:KlerosCoreUniversity",
"label": "drawnJurors",
"offset": 0,
@@ -2586,39 +2808,55 @@
"type": "t_array(t_address)dyn_storage"
},
{
- "astId": 23458,
+ "astId": 26609,
"contract": "src/arbitration/university/KlerosCoreUniversity.sol:KlerosCoreUniversity",
- "label": "sumFeeRewardPaid",
+ "label": "drawnJurorFromCourtIDs",
"offset": 0,
"slot": "7",
+ "type": "t_array(t_uint96)dyn_storage"
+ },
+ {
+ "astId": 26611,
+ "contract": "src/arbitration/university/KlerosCoreUniversity.sol:KlerosCoreUniversity",
+ "label": "sumFeeRewardPaid",
+ "offset": 0,
+ "slot": "8",
"type": "t_uint256"
},
{
- "astId": 23460,
+ "astId": 26613,
"contract": "src/arbitration/university/KlerosCoreUniversity.sol:KlerosCoreUniversity",
"label": "sumPnkRewardPaid",
"offset": 0,
- "slot": "8",
+ "slot": "9",
"type": "t_uint256"
},
{
- "astId": 23463,
+ "astId": 26616,
"contract": "src/arbitration/university/KlerosCoreUniversity.sol:KlerosCoreUniversity",
"label": "feeToken",
"offset": 0,
- "slot": "9",
- "type": "t_contract(IERC20)1229"
+ "slot": "10",
+ "type": "t_contract(IERC20)3021"
},
{
- "astId": 23465,
+ "astId": 26618,
"contract": "src/arbitration/university/KlerosCoreUniversity.sol:KlerosCoreUniversity",
"label": "drawIterations",
"offset": 0,
- "slot": "10",
+ "slot": "11",
"type": "t_uint256"
+ },
+ {
+ "astId": 26622,
+ "contract": "src/arbitration/university/KlerosCoreUniversity.sol:KlerosCoreUniversity",
+ "label": "__gap",
+ "offset": 0,
+ "slot": "12",
+ "type": "t_array(t_uint256)10_storage"
}
],
- "numberOfBytes": "352"
+ "numberOfBytes": "704"
},
"t_uint256": {
"encoding": "inplace",
diff --git a/contracts/deployments/arbitrumSepoliaDevnet/KlerosCoreUniversity_Proxy.json b/contracts/deployments/arbitrumSepoliaDevnet/KlerosCoreUniversity_Proxy.json
index ca2512f0b..a6b30105b 100644
--- a/contracts/deployments/arbitrumSepoliaDevnet/KlerosCoreUniversity_Proxy.json
+++ b/contracts/deployments/arbitrumSepoliaDevnet/KlerosCoreUniversity_Proxy.json
@@ -1,5 +1,5 @@
{
- "address": "0x5AB37F38778Bc175852fA353056591D91c744ce6",
+ "address": "0xA34dBBD0E5e1d09bd683455f9dbC393797BC558f",
"abi": [
{
"inputs": [
@@ -26,50 +26,50 @@
"type": "receive"
}
],
- "transactionHash": "0x6d19fdb430b5611f9aedf5792b44a297c36bd84d34e66ddaf82844f33eb1748a",
+ "transactionHash": "0x998456e4bf88144d618ef98fb44d1c7bb857cbbbefe8b7c523399abc23f581c1",
"receipt": {
"to": null,
"from": "0xf1C7c037891525E360C59f708739Ac09A7670c59",
- "contractAddress": "0x5AB37F38778Bc175852fA353056591D91c744ce6",
- "transactionIndex": 1,
- "gasUsed": "484460",
- "logsBloom": "0x00000000000000000000000020000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000080000000000000040000000000000000000000000000020000000000000010200800402000000000000008000000000000008000000000000000000800000000000000000000000080000000000000000000000000000000800008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000060000000001001000000000000000000000008000000000200000000000000000000",
- "blockHash": "0x152fd5195e3f7b8e0ab803f90700d35d20f4452193858d10558fc31c226227c8",
- "transactionHash": "0x6d19fdb430b5611f9aedf5792b44a297c36bd84d34e66ddaf82844f33eb1748a",
+ "contractAddress": "0xA34dBBD0E5e1d09bd683455f9dbC393797BC558f",
+ "transactionIndex": 2,
+ "gasUsed": "453977",
+ "logsBloom": "0x000000000000000000000000200000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000800000000400000000000000000000000000000200000000000000100008004020000000000000000000000000040000008000000000000008000000000000000000000000800000000000100000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000e4000000001000000000000001000000000000000000000000000800000000000000",
+ "blockHash": "0xe5a6d446390c5a4cfe779ab765b5c591e177b2dcfe4263135a1943f55babc82f",
+ "transactionHash": "0x998456e4bf88144d618ef98fb44d1c7bb857cbbbefe8b7c523399abc23f581c1",
"logs": [
{
- "transactionIndex": 1,
- "blockNumber": 96308609,
- "transactionHash": "0x6d19fdb430b5611f9aedf5792b44a297c36bd84d34e66ddaf82844f33eb1748a",
- "address": "0x5AB37F38778Bc175852fA353056591D91c744ce6",
+ "transactionIndex": 2,
+ "blockNumber": 193533818,
+ "transactionHash": "0x998456e4bf88144d618ef98fb44d1c7bb857cbbbefe8b7c523399abc23f581c1",
+ "address": "0xA34dBBD0E5e1d09bd683455f9dbC393797BC558f",
"topics": [
"0x44063d258760b98116d53815adbc906a56b3563e540148cc0fc2457f83b5eeb2",
"0x0000000000000000000000000000000000000000000000000000000000000001",
- "0x000000000000000000000000d6e96b7c993763b5cdda1139c7387b82a7c8b8b5"
+ "0x00000000000000000000000082f2089442979a6b56c80274d144575980092f91"
],
"data": "0x",
- "logIndex": 0,
- "blockHash": "0x152fd5195e3f7b8e0ab803f90700d35d20f4452193858d10558fc31c226227c8"
+ "logIndex": 3,
+ "blockHash": "0xe5a6d446390c5a4cfe779ab765b5c591e177b2dcfe4263135a1943f55babc82f"
},
{
- "transactionIndex": 1,
- "blockNumber": 96308609,
- "transactionHash": "0x6d19fdb430b5611f9aedf5792b44a297c36bd84d34e66ddaf82844f33eb1748a",
- "address": "0x5AB37F38778Bc175852fA353056591D91c744ce6",
+ "transactionIndex": 2,
+ "blockNumber": 193533818,
+ "transactionHash": "0x998456e4bf88144d618ef98fb44d1c7bb857cbbbefe8b7c523399abc23f581c1",
+ "address": "0xA34dBBD0E5e1d09bd683455f9dbC393797BC558f",
"topics": [
- "0x3475f0ed7216dd7d453db663a1c3024e4f36cc925521d54edb9d13e022cbee3d",
+ "0x550ff678017abc294b4786a99a046628d5a1eac07be0f1ea7e89543f13576ee6",
"0x0000000000000000000000000000000000000000000000000000000000000001",
"0x0000000000000000000000000000000000000000000000000000000000000000"
],
"data": "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ad78ebc5ac62000000000000000000000000000000000000000000000000000000000000000002710000000000000000000000000000000000000000000000000016345785d8a00000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000000000",
- "logIndex": 1,
- "blockHash": "0x152fd5195e3f7b8e0ab803f90700d35d20f4452193858d10558fc31c226227c8"
+ "logIndex": 4,
+ "blockHash": "0xe5a6d446390c5a4cfe779ab765b5c591e177b2dcfe4263135a1943f55babc82f"
},
{
- "transactionIndex": 1,
- "blockNumber": 96308609,
- "transactionHash": "0x6d19fdb430b5611f9aedf5792b44a297c36bd84d34e66ddaf82844f33eb1748a",
- "address": "0x5AB37F38778Bc175852fA353056591D91c744ce6",
+ "transactionIndex": 2,
+ "blockNumber": 193533818,
+ "transactionHash": "0x998456e4bf88144d618ef98fb44d1c7bb857cbbbefe8b7c523399abc23f581c1",
+ "address": "0xA34dBBD0E5e1d09bd683455f9dbC393797BC558f",
"topics": [
"0xb47629acdf64971062d40984f77d3dee212d735b11e3e8c7a4222d9f0572cc79",
"0x0000000000000000000000000000000000000000000000000000000000000001",
@@ -77,36 +77,36 @@
"0x0000000000000000000000000000000000000000000000000000000000000001"
],
"data": "0x",
- "logIndex": 2,
- "blockHash": "0x152fd5195e3f7b8e0ab803f90700d35d20f4452193858d10558fc31c226227c8"
+ "logIndex": 5,
+ "blockHash": "0xe5a6d446390c5a4cfe779ab765b5c591e177b2dcfe4263135a1943f55babc82f"
},
{
- "transactionIndex": 1,
- "blockNumber": 96308609,
- "transactionHash": "0x6d19fdb430b5611f9aedf5792b44a297c36bd84d34e66ddaf82844f33eb1748a",
- "address": "0x5AB37F38778Bc175852fA353056591D91c744ce6",
+ "transactionIndex": 2,
+ "blockNumber": 193533818,
+ "transactionHash": "0x998456e4bf88144d618ef98fb44d1c7bb857cbbbefe8b7c523399abc23f581c1",
+ "address": "0xA34dBBD0E5e1d09bd683455f9dbC393797BC558f",
"topics": [
"0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2"
],
"data": "0x0000000000000000000000000000000000000000000000000000000000000001",
- "logIndex": 3,
- "blockHash": "0x152fd5195e3f7b8e0ab803f90700d35d20f4452193858d10558fc31c226227c8"
+ "logIndex": 6,
+ "blockHash": "0xe5a6d446390c5a4cfe779ab765b5c591e177b2dcfe4263135a1943f55babc82f"
}
],
- "blockNumber": 96308609,
- "cumulativeGasUsed": "484460",
+ "blockNumber": 193533818,
+ "cumulativeGasUsed": "582464",
"status": 1,
"byzantium": true
},
"args": [
- "0xF74DaBfC5F5dbdBD07636637204d9C35326D2906",
- "0xe399d29b000000000000000000000000f1c7c037891525e360c59f708739ac09a7670c59000000000000000000000000f1c7c037891525e360c59f708739ac09a7670c5900000000000000000000000034b944d42cacfc8266955d07a80181d2054aa2250000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d6e96b7c993763b5cdda1139c7387b82a7c8b8b5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ad78ebc5ac62000000000000000000000000000000000000000000000000000000000000000002710000000000000000000000000000000000000000000000000016345785d8a00000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000004b2c2d048921f694cce3aea35698c6b1f5fcbb79"
+ "0xb75b0cc01af4aD0D65D50082ae0717004D479Aa0",
+ "0xe399d29b000000000000000000000000f1c7c037891525e360c59f708739ac09a7670c59000000000000000000000000f1c7c037891525e360c59f708739ac09a7670c5900000000000000000000000034b944d42cacfc8266955d07a80181d2054aa225000000000000000000000000000000000000000000000000000000000000000000000000000000000000000082f2089442979a6b56c80274d144575980092f91000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ad78ebc5ac62000000000000000000000000000000000000000000000000000000000000000002710000000000000000000000000000000000000000000000000016345785d8a00000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000009f55804177e7e44e558616cd7d06b865788214ca"
],
"numDeployments": 1,
- "solcInputHash": "a5602534c00c2f67ca4b6a1cab8c717e",
- "metadata": "{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_implementation\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"stateMutability\":\"payable\",\"type\":\"fallback\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/proxy/KlerosProxies.sol\":\"KlerosCoreUniversityProxy\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":100},\"remappings\":[]},\"sources\":{\"src/proxy/KlerosProxies.sol\":{\"content\":\"//SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.24;\\n\\nimport \\\"./UUPSProxy.sol\\\";\\n\\n/// Workaround to get meaningful names for the proxy contracts\\n/// Otherwise all the contracts are called `UUPSProxy` on the chain explorers\\n\\ncontract DisputeKitClassicNeoProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract DisputeKitClassicUniversityProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract DisputeKitClassicProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract DisputeTemplateRegistryProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract EvidenceModuleProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract ForeignGatewayOnEthereumProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract HomeGatewayToEthereumProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract KlerosCoreNeoProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract KlerosCoreRulerProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract KlerosCoreUniversityProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract KlerosCoreProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract PolicyRegistryProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract RandomizerRNGProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract SortitionModuleNeoProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract SortitionModuleUniversityProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract SortitionModuleProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\",\"keccak256\":\"0x4393c05bbfda204b9992e1e546142a0fbf4c92a1c4061f5985463d02a71b84d4\",\"license\":\"MIT\"},\"src/proxy/UUPSProxy.sol\":{\"content\":\"//SPDX-License-Identifier: MIT\\n// Adapted from \\n\\n/**\\n * @authors: [@malatrax]\\n * @reviewers: []\\n * @auditors: []\\n * @bounties: []\\n * @deployments: []\\n */\\npragma solidity 0.8.24;\\n\\n/**\\n * @title UUPS Proxy\\n * @author Simon Malatrait \\n * @dev This contract implements a UUPS Proxy compliant with ERC-1967 & ERC-1822.\\n * @dev This contract delegates all calls to another contract (UUPS Proxiable) through a fallback function and the use of the `delegatecall` EVM instruction.\\n * @dev We refer to the Proxiable contract (as per ERC-1822) with `implementation`.\\n */\\ncontract UUPSProxy {\\n /**\\n * @dev Storage slot with the address of the current implementation.\\n * This is the keccak-256 hash of \\\"eip1967.proxy.implementation\\\" subtracted by 1, and is\\n * validated in the constructor.\\n * NOTE: bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1)\\n */\\n bytes32 private constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\\n\\n // ************************************* //\\n // * Constructor * //\\n // ************************************* //\\n\\n /**\\n * @dev Initializes the upgradeable proxy with an initial implementation specified by `_implementation`.\\n *\\n * If `_data` is nonempty, it's used as data in a delegate call to `_implementation`. This will typically be an encoded\\n * function call, and allows initializing the storage of the proxy like a Solidity constructor.\\n */\\n constructor(address _implementation, bytes memory _data) {\\n assembly {\\n sstore(IMPLEMENTATION_SLOT, _implementation)\\n }\\n\\n if (_data.length != 0) {\\n (bool success, ) = _implementation.delegatecall(_data);\\n require(success, \\\"Proxy Constructor failed\\\");\\n }\\n }\\n\\n // ************************************* //\\n // * State Modifiers * //\\n // ************************************* //\\n\\n /**\\n * @dev Delegates the current call to `implementation`.\\n *\\n * NOTE: This function does not return to its internal call site, it will return directly to the external caller.\\n */\\n function _delegate(address implementation) internal {\\n assembly {\\n // Copy msg.data. We take full control of memory in this inline assembly\\n // block because it will not return to Solidity code. We overwrite the\\n // Solidity scratch pad at memory position 0.\\n calldatacopy(0, 0, calldatasize())\\n\\n // Call the implementation.\\n // out and outsize are 0 because we don't know the size yet.\\n let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)\\n\\n // Copy the returned data.\\n returndatacopy(0, 0, returndatasize())\\n\\n switch result\\n // delegatecall returns 0 on error.\\n case 0 {\\n revert(0, returndatasize())\\n }\\n default {\\n return(0, returndatasize())\\n }\\n }\\n }\\n\\n // ************************************* //\\n // * Internal Views * //\\n // ************************************* //\\n\\n function _getImplementation() internal view returns (address implementation) {\\n assembly {\\n implementation := sload(IMPLEMENTATION_SLOT)\\n }\\n }\\n\\n // ************************************* //\\n // * Fallback * //\\n // ************************************* //\\n\\n /**\\n * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other\\n * function in the contract matches the call data.\\n */\\n fallback() external payable {\\n _delegate(_getImplementation());\\n }\\n\\n receive() external payable {\\n _delegate(_getImplementation());\\n }\\n}\\n\",\"keccak256\":\"0x7aa5f14ce351299722ac1a1afca9e65e1c795f32ea3e9702b0d5faaf7ca822a0\",\"license\":\"MIT\"}},\"version\":1}",
- "bytecode": "0x608060405234801561001057600080fd5b5060405161030238038061030283398101604081905261002f91610151565b8181817f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc55805160001461010e576000826001600160a01b031682604051610077919061021f565b600060405180830381855af49150503d80600081146100b2576040519150601f19603f3d011682016040523d82523d6000602084013e6100b7565b606091505b505090508061010c5760405162461bcd60e51b815260206004820152601860248201527f50726f787920436f6e7374727563746f72206661696c65640000000000000000604482015260640160405180910390fd5b505b5050505061023b565b634e487b7160e01b600052604160045260246000fd5b60005b83811015610148578181015183820152602001610130565b50506000910152565b6000806040838503121561016457600080fd5b82516001600160a01b038116811461017b57600080fd5b60208401519092506001600160401b038082111561019857600080fd5b818501915085601f8301126101ac57600080fd5b8151818111156101be576101be610117565b604051601f8201601f19908116603f011681019083821181831017156101e6576101e6610117565b816040528281528860208487010111156101ff57600080fd5b61021083602083016020880161012d565b80955050505050509250929050565b6000825161023181846020870161012d565b9190910192915050565b60b9806102496000396000f3fe608060405236603757603560317f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5490565b6060565b005b603560317f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5490565b3660008037600080366000845af43d6000803e808015607e573d6000f35b3d6000fdfea2646970667358221220025ed3e852b24305c0ac2e202b83cf5fed6ae313e772bad4b0c1340efea75f0764736f6c63430008180033",
- "deployedBytecode": "0x608060405236603757603560317f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5490565b6060565b005b603560317f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5490565b3660008037600080366000845af43d6000803e808015607e573d6000f35b3d6000fdfea2646970667358221220025ed3e852b24305c0ac2e202b83cf5fed6ae313e772bad4b0c1340efea75f0764736f6c63430008180033",
+ "solcInputHash": "d547d738900bce1310e91a5d1adfc179",
+ "metadata": "{\"compiler\":{\"version\":\"0.8.30+commit.73712a01\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_implementation\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"stateMutability\":\"payable\",\"type\":\"fallback\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/proxy/KlerosProxies.sol\":\"KlerosCoreUniversityProxy\"},\"evmVersion\":\"cancun\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000},\"remappings\":[],\"viaIR\":true},\"sources\":{\"src/proxy/KlerosProxies.sol\":{\"content\":\"//SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.24;\\n\\nimport \\\"./UUPSProxy.sol\\\";\\n\\n/// Workaround to get meaningful names for the proxy contracts\\n/// Otherwise all the contracts are called `UUPSProxy` on the chain explorers\\n\\ncontract DisputeKitClassicUniversityProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract DisputeKitClassicProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract DisputeKitGatedProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract DisputeKitGatedShutterProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract DisputeKitShutterProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract DisputeKitSybilResistantProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract DisputeTemplateRegistryProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract EvidenceModuleProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract ForeignGatewayOnEthereumProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract HomeGatewayToEthereumProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract KlerosCoreRulerProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract KlerosCoreUniversityProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract KlerosCoreProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract PolicyRegistryProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract RandomizerRNGProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract SortitionModuleUniversityProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract SortitionModuleProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\",\"keccak256\":\"0x3160bd320b23c6ec0c21862b455c3044a9b33654ae84a1b6cd76255626c9154b\",\"license\":\"MIT\"},\"src/proxy/UUPSProxy.sol\":{\"content\":\"//SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.24;\\n\\n/// @title UUPS Proxy\\n/// @author Simon Malatrait \\n/// @notice This contract implements a UUPS Proxy compliant with ERC-1967 & ERC-1822.\\n///\\n/// @dev This contract delegates all calls to another contract (UUPS Proxiable) through a fallback function and the use of the `delegatecall` EVM instruction.\\n/// We refer to the Proxiable contract (as per ERC-1822) with `implementation`.\\n/// Adapted from \\ncontract UUPSProxy {\\n /// @dev Storage slot with the address of the current implementation.\\n /// This is the keccak-256 hash of \\\"eip1967.proxy.implementation\\\" subtracted by 1, and is\\n /// validated in the constructor.\\n /// NOTE: bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1)\\n bytes32 private constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\\n\\n // ************************************* //\\n // * Constructor * //\\n // ************************************* //\\n\\n /// @notice Initializes the upgradeable proxy with an initial implementation specified by `_implementation`.\\n /// @dev If `_data` is nonempty, it's used as data in a delegate call to `_implementation`.\\n /// This will typically be an encoded function call, and allows initializing the storage of the proxy like a Solidity constructor.\\n constructor(address _implementation, bytes memory _data) {\\n assembly {\\n sstore(IMPLEMENTATION_SLOT, _implementation)\\n }\\n\\n if (_data.length != 0) {\\n (bool success, ) = _implementation.delegatecall(_data);\\n require(success, \\\"Proxy Constructor failed\\\");\\n }\\n }\\n\\n // ************************************* //\\n // * State Modifiers * //\\n // ************************************* //\\n\\n /// @dev Delegates the current call to `implementation`.\\n /// NOTE: This function does not return to its internal call site, it will return directly to the external caller.\\n function _delegate(address implementation) internal {\\n assembly {\\n // Copy msg.data. We take full control of memory in this inline assembly\\n // block because it will not return to Solidity code. We overwrite the\\n // Solidity scratch pad at memory position 0.\\n calldatacopy(0, 0, calldatasize())\\n\\n // Call the implementation.\\n // out and outsize are 0 because we don't know the size yet.\\n let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)\\n\\n // Copy the returned data.\\n returndatacopy(0, 0, returndatasize())\\n\\n switch result\\n // delegatecall returns 0 on error.\\n case 0 {\\n revert(0, returndatasize())\\n }\\n default {\\n return(0, returndatasize())\\n }\\n }\\n }\\n\\n // ************************************* //\\n // * Internal Views * //\\n // ************************************* //\\n\\n function _getImplementation() internal view returns (address implementation) {\\n assembly {\\n implementation := sload(IMPLEMENTATION_SLOT)\\n }\\n }\\n\\n // ************************************* //\\n // * Fallback * //\\n // ************************************* //\\n\\n /// @dev Fallback function that delegates calls to the address returned by `_implementation()`.\\n /// @dev Will run if no other function in the contract matches the call data.\\n fallback() external payable {\\n _delegate(_getImplementation());\\n }\\n\\n receive() external payable {\\n _delegate(_getImplementation());\\n }\\n}\\n\",\"keccak256\":\"0x2d7b1f81e525787f1b8b033ce381a81cb5f39e411ff31490e019113205a661cd\",\"license\":\"MIT\"}},\"version\":1}",
+ "bytecode": "0x608060405234610144576102148038038061001981610148565b928339810190604081830312610144578051906001600160a01b0382168203610144576020810151906001600160401b038211610144570182601f8201121561014457805161006f61006a82610181565b610148565b9181835260208301946020838301011161014457815f926020809301875e83010152817f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5551806100c9575b6040516077908161019d8239f35b5f9283925af43d1561013f573d6100e261006a82610181565b9081525f60203d92013e5b156100fa575f80806100bb565b60405162461bcd60e51b815260206004820152601860248201527f50726f787920436f6e7374727563746f72206661696c656400000000000000006044820152606490fd5b6100ed565b5f80fd5b6040519190601f01601f191682016001600160401b0381118382101761016d57604052565b634e487b7160e01b5f52604160045260245ffd5b6001600160401b03811161016d57601f01601f19166020019056fe60806040525f807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc54368280378136915af43d5f803e15603d573d5ff35b3d5ffdfea264697066735822122094c812c85dc437a2ab3eda19f621c1ecfc3fbf77e5465f816bde0529d28053a664736f6c634300081e0033",
+ "deployedBytecode": "0x60806040525f807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc54368280378136915af43d5f803e15603d573d5ff35b3d5ffdfea264697066735822122094c812c85dc437a2ab3eda19f621c1ecfc3fbf77e5465f816bde0529d28053a664736f6c634300081e0033",
"devdoc": {
"kind": "dev",
"methods": {},
diff --git a/contracts/deployments/arbitrumSepoliaDevnet/SortitionModuleUniversity.json b/contracts/deployments/arbitrumSepoliaDevnet/SortitionModuleUniversity.json
index 1ce05ea30..539868fe6 100644
--- a/contracts/deployments/arbitrumSepoliaDevnet/SortitionModuleUniversity.json
+++ b/contracts/deployments/arbitrumSepoliaDevnet/SortitionModuleUniversity.json
@@ -1,5 +1,5 @@
{
- "address": "0x4B2c2d048921f694cCE3AEa35698c6B1f5fcbb79",
+ "address": "0x9f55804177e7E44E558616cD7d06B865788214cA",
"abi": [
{
"stateMutability": "payable",
@@ -30,11 +30,26 @@
"name": "InvalidImplementation",
"type": "error"
},
+ {
+ "inputs": [],
+ "name": "KlerosCoreOnly",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "NotEligibleForWithdrawal",
+ "type": "error"
+ },
{
"inputs": [],
"name": "NotInitializing",
"type": "error"
},
+ {
+ "inputs": [],
+ "name": "OwnerOnly",
+ "type": "error"
+ },
{
"inputs": [],
"name": "UUPSUnauthorizedCallContext",
@@ -64,6 +79,44 @@
"name": "Initialized",
"type": "event"
},
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "_account",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "internalType": "uint256",
+ "name": "_amount",
+ "type": "uint256"
+ }
+ ],
+ "name": "LeftoverPNK",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "_account",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "internalType": "uint256",
+ "name": "_amount",
+ "type": "uint256"
+ }
+ ],
+ "name": "LeftoverPNKWithdrawn",
+ "type": "event"
+ },
{
"anonymous": false,
"inputs": [
@@ -122,6 +175,12 @@
"internalType": "uint256",
"name": "_amount",
"type": "uint256"
+ },
+ {
+ "indexed": false,
+ "internalType": "uint256",
+ "name": "_amountAllCourts",
+ "type": "uint256"
}
],
"name": "StakeSet",
@@ -174,9 +233,9 @@
{
"inputs": [
{
- "internalType": "bytes32",
- "name": "_key",
- "type": "bytes32"
+ "internalType": "uint96",
+ "name": "_courtID",
+ "type": "uint96"
},
{
"internalType": "bytes",
@@ -205,9 +264,9 @@
{
"inputs": [
{
- "internalType": "bytes32",
+ "internalType": "uint96",
"name": "",
- "type": "bytes32"
+ "type": "uint96"
},
{
"internalType": "uint256",
@@ -226,11 +285,60 @@
"internalType": "address",
"name": "drawnAddress",
"type": "address"
+ },
+ {
+ "internalType": "uint96",
+ "name": "fromSubcourtID",
+ "type": "uint96"
}
],
"stateMutability": "view",
"type": "function"
},
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "_iterations",
+ "type": "uint256"
+ }
+ ],
+ "name": "executeDelayedStakes",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "_account",
+ "type": "address"
+ },
+ {
+ "internalType": "uint96",
+ "name": "_courtID",
+ "type": "uint96"
+ }
+ ],
+ "name": "forcedUnstake",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "_account",
+ "type": "address"
+ }
+ ],
+ "name": "forcedUnstakeAllCourts",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
{
"inputs": [
{
@@ -290,15 +398,21 @@
"type": "function"
},
{
- "inputs": [],
- "name": "governor",
- "outputs": [
+ "inputs": [
{
"internalType": "address",
- "name": "",
+ "name": "_juror",
"type": "address"
}
],
+ "name": "getJurorLeftoverPNK",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
"stateMutability": "view",
"type": "function"
},
@@ -306,7 +420,7 @@
"inputs": [
{
"internalType": "address",
- "name": "_governor",
+ "name": "_owner",
"type": "address"
},
{
@@ -382,32 +496,21 @@
"type": "function"
},
{
- "inputs": [
+ "inputs": [],
+ "name": "owner",
+ "outputs": [
{
- "internalType": "uint256",
- "name": "_randomNumber",
- "type": "uint256"
+ "internalType": "address",
+ "name": "",
+ "type": "address"
}
],
- "name": "notifyRandomNumber",
- "outputs": [],
- "stateMutability": "nonpayable",
+ "stateMutability": "view",
"type": "function"
},
{
- "inputs": [
- {
- "internalType": "address",
- "name": "_account",
- "type": "address"
- },
- {
- "internalType": "uint256",
- "name": "_relativeAmount",
- "type": "uint256"
- }
- ],
- "name": "penalizeStake",
+ "inputs": [],
+ "name": "passPhase",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
@@ -449,9 +552,29 @@
"internalType": "address",
"name": "_account",
"type": "address"
+ },
+ {
+ "internalType": "uint96",
+ "name": "_courtID",
+ "type": "uint96"
+ },
+ {
+ "internalType": "uint256",
+ "name": "_pnkDeposit",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "_pnkWithdrawal",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "_newStake",
+ "type": "uint256"
}
],
- "name": "setJurorInactive",
+ "name": "setStake",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
@@ -470,31 +593,55 @@
},
{
"internalType": "uint256",
- "name": "_newStake",
+ "name": "_penalty",
"type": "uint256"
- },
- {
- "internalType": "bool",
- "name": "_alreadyTransferred",
- "type": "bool"
}
],
- "name": "setStake",
+ "name": "setStakePenalty",
"outputs": [
{
"internalType": "uint256",
- "name": "pnkDeposit",
+ "name": "pnkBalance",
"type": "uint256"
},
{
"internalType": "uint256",
- "name": "pnkWithdrawal",
+ "name": "newCourtStake",
"type": "uint256"
},
{
- "internalType": "enum StakingResult",
- "name": "stakingResult",
- "type": "uint8"
+ "internalType": "uint256",
+ "name": "availablePenalty",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "_account",
+ "type": "address"
+ },
+ {
+ "internalType": "uint96",
+ "name": "_courtID",
+ "type": "uint96"
+ },
+ {
+ "internalType": "uint256",
+ "name": "_reward",
+ "type": "uint256"
+ }
+ ],
+ "name": "setStakeReward",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "success",
+ "type": "bool"
}
],
"stateMutability": "nonpayable",
@@ -549,6 +696,76 @@
"stateMutability": "payable",
"type": "function"
},
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "_account",
+ "type": "address"
+ },
+ {
+ "internalType": "uint96",
+ "name": "_courtID",
+ "type": "uint96"
+ },
+ {
+ "internalType": "uint256",
+ "name": "_newStake",
+ "type": "uint256"
+ },
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "name": "validateStake",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "pnkDeposit",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "pnkWithdrawal",
+ "type": "uint256"
+ },
+ {
+ "internalType": "enum StakingResult",
+ "name": "stakingResult",
+ "type": "uint8"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "version",
+ "outputs": [
+ {
+ "internalType": "string",
+ "name": "",
+ "type": "string"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "_account",
+ "type": "address"
+ }
+ ],
+ "name": "withdrawLeftoverPNK",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
{
"inputs": [
{
@@ -566,52 +783,52 @@
"type": "constructor"
}
],
- "transactionHash": "0xb26dc1c9ca9c3ed561a1d9c3feaad474af38bc90ea240f927053e5e5868d6a7e",
+ "transactionHash": "0x816a335385508eb3b23f6e38ecbdb464110275a0059895f982bfb692c8e7a452",
"receipt": {
"to": null,
"from": "0xf1C7c037891525E360C59f708739Ac09A7670c59",
- "contractAddress": "0x4B2c2d048921f694cCE3AEa35698c6B1f5fcbb79",
- "transactionIndex": 1,
- "gasUsed": "210047",
- "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010800000020000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
- "blockHash": "0x6a08d6d6cf180ae6bf3126f86fbedfd17212528b22a7a9403addd2dd6b1109c3",
- "transactionHash": "0xb26dc1c9ca9c3ed561a1d9c3feaad474af38bc90ea240f927053e5e5868d6a7e",
+ "contractAddress": "0x9f55804177e7E44E558616cD7d06B865788214cA",
+ "transactionIndex": 2,
+ "gasUsed": "180483",
+ "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000080000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000008000000000000000000000000000000000000000000",
+ "blockHash": "0xeb89982fc4a65212a277169f078d43cd1578b93b962c37ded52f9ddeb92610af",
+ "transactionHash": "0x816a335385508eb3b23f6e38ecbdb464110275a0059895f982bfb692c8e7a452",
"logs": [
{
- "transactionIndex": 1,
- "blockNumber": 96308572,
- "transactionHash": "0xb26dc1c9ca9c3ed561a1d9c3feaad474af38bc90ea240f927053e5e5868d6a7e",
- "address": "0x4B2c2d048921f694cCE3AEa35698c6B1f5fcbb79",
+ "transactionIndex": 2,
+ "blockNumber": 193533797,
+ "transactionHash": "0x816a335385508eb3b23f6e38ecbdb464110275a0059895f982bfb692c8e7a452",
+ "address": "0x9f55804177e7E44E558616cD7d06B865788214cA",
"topics": [
"0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2"
],
"data": "0x0000000000000000000000000000000000000000000000000000000000000001",
- "logIndex": 0,
- "blockHash": "0x6a08d6d6cf180ae6bf3126f86fbedfd17212528b22a7a9403addd2dd6b1109c3"
+ "logIndex": 1,
+ "blockHash": "0xeb89982fc4a65212a277169f078d43cd1578b93b962c37ded52f9ddeb92610af"
}
],
- "blockNumber": 96308572,
- "cumulativeGasUsed": "210047",
+ "blockNumber": 193533797,
+ "cumulativeGasUsed": "214736",
"status": 1,
"byzantium": true
},
"args": [
- "0x5CAD621D69E0535422aCFaCC0017bC32beC7A486",
- "0x485cc955000000000000000000000000f1c7c037891525e360c59f708739ac09a7670c590000000000000000000000005ab37f38778bc175852fa353056591d91c744ce6"
+ "0x270e3D63d3d275604df0a1Bd312E1255DCd96936",
+ "0x485cc955000000000000000000000000f1c7c037891525e360c59f708739ac09a7670c59000000000000000000000000a34dbbd0e5e1d09bd683455f9dbc393797bc558f"
],
"numDeployments": 1,
- "solcInputHash": "a5602534c00c2f67ca4b6a1cab8c717e",
- "metadata": "{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_implementation\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"stateMutability\":\"payable\",\"type\":\"fallback\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/proxy/KlerosProxies.sol\":\"SortitionModuleUniversityProxy\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":100},\"remappings\":[]},\"sources\":{\"src/proxy/KlerosProxies.sol\":{\"content\":\"//SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.24;\\n\\nimport \\\"./UUPSProxy.sol\\\";\\n\\n/// Workaround to get meaningful names for the proxy contracts\\n/// Otherwise all the contracts are called `UUPSProxy` on the chain explorers\\n\\ncontract DisputeKitClassicNeoProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract DisputeKitClassicUniversityProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract DisputeKitClassicProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract DisputeTemplateRegistryProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract EvidenceModuleProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract ForeignGatewayOnEthereumProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract HomeGatewayToEthereumProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract KlerosCoreNeoProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract KlerosCoreRulerProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract KlerosCoreUniversityProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract KlerosCoreProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract PolicyRegistryProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract RandomizerRNGProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract SortitionModuleNeoProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract SortitionModuleUniversityProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract SortitionModuleProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\",\"keccak256\":\"0x4393c05bbfda204b9992e1e546142a0fbf4c92a1c4061f5985463d02a71b84d4\",\"license\":\"MIT\"},\"src/proxy/UUPSProxy.sol\":{\"content\":\"//SPDX-License-Identifier: MIT\\n// Adapted from \\n\\n/**\\n * @authors: [@malatrax]\\n * @reviewers: []\\n * @auditors: []\\n * @bounties: []\\n * @deployments: []\\n */\\npragma solidity 0.8.24;\\n\\n/**\\n * @title UUPS Proxy\\n * @author Simon Malatrait \\n * @dev This contract implements a UUPS Proxy compliant with ERC-1967 & ERC-1822.\\n * @dev This contract delegates all calls to another contract (UUPS Proxiable) through a fallback function and the use of the `delegatecall` EVM instruction.\\n * @dev We refer to the Proxiable contract (as per ERC-1822) with `implementation`.\\n */\\ncontract UUPSProxy {\\n /**\\n * @dev Storage slot with the address of the current implementation.\\n * This is the keccak-256 hash of \\\"eip1967.proxy.implementation\\\" subtracted by 1, and is\\n * validated in the constructor.\\n * NOTE: bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1)\\n */\\n bytes32 private constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\\n\\n // ************************************* //\\n // * Constructor * //\\n // ************************************* //\\n\\n /**\\n * @dev Initializes the upgradeable proxy with an initial implementation specified by `_implementation`.\\n *\\n * If `_data` is nonempty, it's used as data in a delegate call to `_implementation`. This will typically be an encoded\\n * function call, and allows initializing the storage of the proxy like a Solidity constructor.\\n */\\n constructor(address _implementation, bytes memory _data) {\\n assembly {\\n sstore(IMPLEMENTATION_SLOT, _implementation)\\n }\\n\\n if (_data.length != 0) {\\n (bool success, ) = _implementation.delegatecall(_data);\\n require(success, \\\"Proxy Constructor failed\\\");\\n }\\n }\\n\\n // ************************************* //\\n // * State Modifiers * //\\n // ************************************* //\\n\\n /**\\n * @dev Delegates the current call to `implementation`.\\n *\\n * NOTE: This function does not return to its internal call site, it will return directly to the external caller.\\n */\\n function _delegate(address implementation) internal {\\n assembly {\\n // Copy msg.data. We take full control of memory in this inline assembly\\n // block because it will not return to Solidity code. We overwrite the\\n // Solidity scratch pad at memory position 0.\\n calldatacopy(0, 0, calldatasize())\\n\\n // Call the implementation.\\n // out and outsize are 0 because we don't know the size yet.\\n let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)\\n\\n // Copy the returned data.\\n returndatacopy(0, 0, returndatasize())\\n\\n switch result\\n // delegatecall returns 0 on error.\\n case 0 {\\n revert(0, returndatasize())\\n }\\n default {\\n return(0, returndatasize())\\n }\\n }\\n }\\n\\n // ************************************* //\\n // * Internal Views * //\\n // ************************************* //\\n\\n function _getImplementation() internal view returns (address implementation) {\\n assembly {\\n implementation := sload(IMPLEMENTATION_SLOT)\\n }\\n }\\n\\n // ************************************* //\\n // * Fallback * //\\n // ************************************* //\\n\\n /**\\n * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other\\n * function in the contract matches the call data.\\n */\\n fallback() external payable {\\n _delegate(_getImplementation());\\n }\\n\\n receive() external payable {\\n _delegate(_getImplementation());\\n }\\n}\\n\",\"keccak256\":\"0x7aa5f14ce351299722ac1a1afca9e65e1c795f32ea3e9702b0d5faaf7ca822a0\",\"license\":\"MIT\"}},\"version\":1}",
- "bytecode": "0x608060405234801561001057600080fd5b5060405161030238038061030283398101604081905261002f91610151565b8181817f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc55805160001461010e576000826001600160a01b031682604051610077919061021f565b600060405180830381855af49150503d80600081146100b2576040519150601f19603f3d011682016040523d82523d6000602084013e6100b7565b606091505b505090508061010c5760405162461bcd60e51b815260206004820152601860248201527f50726f787920436f6e7374727563746f72206661696c65640000000000000000604482015260640160405180910390fd5b505b5050505061023b565b634e487b7160e01b600052604160045260246000fd5b60005b83811015610148578181015183820152602001610130565b50506000910152565b6000806040838503121561016457600080fd5b82516001600160a01b038116811461017b57600080fd5b60208401519092506001600160401b038082111561019857600080fd5b818501915085601f8301126101ac57600080fd5b8151818111156101be576101be610117565b604051601f8201601f19908116603f011681019083821181831017156101e6576101e6610117565b816040528281528860208487010111156101ff57600080fd5b61021083602083016020880161012d565b80955050505050509250929050565b6000825161023181846020870161012d565b9190910192915050565b60b9806102496000396000f3fe608060405236603757603560317f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5490565b6060565b005b603560317f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5490565b3660008037600080366000845af43d6000803e808015607e573d6000f35b3d6000fdfea2646970667358221220cbf6c95b71e3c03306025a1af7f6aa4f021b4a8c8f5a8c68988b35c4442edb4964736f6c63430008180033",
- "deployedBytecode": "0x608060405236603757603560317f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5490565b6060565b005b603560317f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5490565b3660008037600080366000845af43d6000803e808015607e573d6000f35b3d6000fdfea2646970667358221220cbf6c95b71e3c03306025a1af7f6aa4f021b4a8c8f5a8c68988b35c4442edb4964736f6c63430008180033",
+ "solcInputHash": "d547d738900bce1310e91a5d1adfc179",
+ "metadata": "{\"compiler\":{\"version\":\"0.8.30+commit.73712a01\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_implementation\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"stateMutability\":\"payable\",\"type\":\"fallback\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/proxy/KlerosProxies.sol\":\"SortitionModuleUniversityProxy\"},\"evmVersion\":\"cancun\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000},\"remappings\":[],\"viaIR\":true},\"sources\":{\"src/proxy/KlerosProxies.sol\":{\"content\":\"//SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.24;\\n\\nimport \\\"./UUPSProxy.sol\\\";\\n\\n/// Workaround to get meaningful names for the proxy contracts\\n/// Otherwise all the contracts are called `UUPSProxy` on the chain explorers\\n\\ncontract DisputeKitClassicUniversityProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract DisputeKitClassicProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract DisputeKitGatedProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract DisputeKitGatedShutterProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract DisputeKitShutterProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract DisputeKitSybilResistantProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract DisputeTemplateRegistryProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract EvidenceModuleProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract ForeignGatewayOnEthereumProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract HomeGatewayToEthereumProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract KlerosCoreRulerProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract KlerosCoreUniversityProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract KlerosCoreProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract PolicyRegistryProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract RandomizerRNGProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract SortitionModuleUniversityProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract SortitionModuleProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\",\"keccak256\":\"0x3160bd320b23c6ec0c21862b455c3044a9b33654ae84a1b6cd76255626c9154b\",\"license\":\"MIT\"},\"src/proxy/UUPSProxy.sol\":{\"content\":\"//SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.24;\\n\\n/// @title UUPS Proxy\\n/// @author Simon Malatrait \\n/// @notice This contract implements a UUPS Proxy compliant with ERC-1967 & ERC-1822.\\n///\\n/// @dev This contract delegates all calls to another contract (UUPS Proxiable) through a fallback function and the use of the `delegatecall` EVM instruction.\\n/// We refer to the Proxiable contract (as per ERC-1822) with `implementation`.\\n/// Adapted from \\ncontract UUPSProxy {\\n /// @dev Storage slot with the address of the current implementation.\\n /// This is the keccak-256 hash of \\\"eip1967.proxy.implementation\\\" subtracted by 1, and is\\n /// validated in the constructor.\\n /// NOTE: bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1)\\n bytes32 private constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\\n\\n // ************************************* //\\n // * Constructor * //\\n // ************************************* //\\n\\n /// @notice Initializes the upgradeable proxy with an initial implementation specified by `_implementation`.\\n /// @dev If `_data` is nonempty, it's used as data in a delegate call to `_implementation`.\\n /// This will typically be an encoded function call, and allows initializing the storage of the proxy like a Solidity constructor.\\n constructor(address _implementation, bytes memory _data) {\\n assembly {\\n sstore(IMPLEMENTATION_SLOT, _implementation)\\n }\\n\\n if (_data.length != 0) {\\n (bool success, ) = _implementation.delegatecall(_data);\\n require(success, \\\"Proxy Constructor failed\\\");\\n }\\n }\\n\\n // ************************************* //\\n // * State Modifiers * //\\n // ************************************* //\\n\\n /// @dev Delegates the current call to `implementation`.\\n /// NOTE: This function does not return to its internal call site, it will return directly to the external caller.\\n function _delegate(address implementation) internal {\\n assembly {\\n // Copy msg.data. We take full control of memory in this inline assembly\\n // block because it will not return to Solidity code. We overwrite the\\n // Solidity scratch pad at memory position 0.\\n calldatacopy(0, 0, calldatasize())\\n\\n // Call the implementation.\\n // out and outsize are 0 because we don't know the size yet.\\n let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)\\n\\n // Copy the returned data.\\n returndatacopy(0, 0, returndatasize())\\n\\n switch result\\n // delegatecall returns 0 on error.\\n case 0 {\\n revert(0, returndatasize())\\n }\\n default {\\n return(0, returndatasize())\\n }\\n }\\n }\\n\\n // ************************************* //\\n // * Internal Views * //\\n // ************************************* //\\n\\n function _getImplementation() internal view returns (address implementation) {\\n assembly {\\n implementation := sload(IMPLEMENTATION_SLOT)\\n }\\n }\\n\\n // ************************************* //\\n // * Fallback * //\\n // ************************************* //\\n\\n /// @dev Fallback function that delegates calls to the address returned by `_implementation()`.\\n /// @dev Will run if no other function in the contract matches the call data.\\n fallback() external payable {\\n _delegate(_getImplementation());\\n }\\n\\n receive() external payable {\\n _delegate(_getImplementation());\\n }\\n}\\n\",\"keccak256\":\"0x2d7b1f81e525787f1b8b033ce381a81cb5f39e411ff31490e019113205a661cd\",\"license\":\"MIT\"}},\"version\":1}",
+ "bytecode": "0x608060405234610144576102148038038061001981610148565b928339810190604081830312610144578051906001600160a01b0382168203610144576020810151906001600160401b038211610144570182601f8201121561014457805161006f61006a82610181565b610148565b9181835260208301946020838301011161014457815f926020809301875e83010152817f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5551806100c9575b6040516077908161019d8239f35b5f9283925af43d1561013f573d6100e261006a82610181565b9081525f60203d92013e5b156100fa575f80806100bb565b60405162461bcd60e51b815260206004820152601860248201527f50726f787920436f6e7374727563746f72206661696c656400000000000000006044820152606490fd5b6100ed565b5f80fd5b6040519190601f01601f191682016001600160401b0381118382101761016d57604052565b634e487b7160e01b5f52604160045260245ffd5b6001600160401b03811161016d57601f01601f19166020019056fe60806040525f807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc54368280378136915af43d5f803e15603d573d5ff35b3d5ffdfea2646970667358221220cebc238294db6f217e59b4194d65c951358927be9872c8bda288fff77348423e64736f6c634300081e0033",
+ "deployedBytecode": "0x60806040525f807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc54368280378136915af43d5f803e15603d573d5ff35b3d5ffdfea2646970667358221220cebc238294db6f217e59b4194d65c951358927be9872c8bda288fff77348423e64736f6c634300081e0033",
"execute": {
"methodName": "initialize",
"args": [
"0xf1C7c037891525E360C59f708739Ac09A7670c59",
- "0x5AB37F38778Bc175852fA353056591D91c744ce6"
+ "0xA34dBBD0E5e1d09bd683455f9dbC393797BC558f"
]
},
- "implementation": "0x5CAD621D69E0535422aCFaCC0017bC32beC7A486",
+ "implementation": "0x270e3D63d3d275604df0a1Bd312E1255DCd96936",
"devdoc": {
"kind": "dev",
"methods": {},
diff --git a/contracts/deployments/arbitrumSepoliaDevnet/SortitionModuleUniversity_Implementation.json b/contracts/deployments/arbitrumSepoliaDevnet/SortitionModuleUniversity_Implementation.json
index 21360963b..909027f9a 100644
--- a/contracts/deployments/arbitrumSepoliaDevnet/SortitionModuleUniversity_Implementation.json
+++ b/contracts/deployments/arbitrumSepoliaDevnet/SortitionModuleUniversity_Implementation.json
@@ -1,5 +1,5 @@
{
- "address": "0x5CAD621D69E0535422aCFaCC0017bC32beC7A486",
+ "address": "0x270e3D63d3d275604df0a1Bd312E1255DCd96936",
"abi": [
{
"inputs": [],
@@ -27,11 +27,26 @@
"name": "InvalidImplementation",
"type": "error"
},
+ {
+ "inputs": [],
+ "name": "KlerosCoreOnly",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "NotEligibleForWithdrawal",
+ "type": "error"
+ },
{
"inputs": [],
"name": "NotInitializing",
"type": "error"
},
+ {
+ "inputs": [],
+ "name": "OwnerOnly",
+ "type": "error"
+ },
{
"inputs": [],
"name": "UUPSUnauthorizedCallContext",
@@ -61,6 +76,44 @@
"name": "Initialized",
"type": "event"
},
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "_account",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "internalType": "uint256",
+ "name": "_amount",
+ "type": "uint256"
+ }
+ ],
+ "name": "LeftoverPNK",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "_account",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "internalType": "uint256",
+ "name": "_amount",
+ "type": "uint256"
+ }
+ ],
+ "name": "LeftoverPNKWithdrawn",
+ "type": "event"
+ },
{
"anonymous": false,
"inputs": [
@@ -119,6 +172,12 @@
"internalType": "uint256",
"name": "_amount",
"type": "uint256"
+ },
+ {
+ "indexed": false,
+ "internalType": "uint256",
+ "name": "_amountAllCourts",
+ "type": "uint256"
}
],
"name": "StakeSet",
@@ -171,9 +230,9 @@
{
"inputs": [
{
- "internalType": "bytes32",
- "name": "_key",
- "type": "bytes32"
+ "internalType": "uint96",
+ "name": "_courtID",
+ "type": "uint96"
},
{
"internalType": "bytes",
@@ -202,9 +261,9 @@
{
"inputs": [
{
- "internalType": "bytes32",
+ "internalType": "uint96",
"name": "",
- "type": "bytes32"
+ "type": "uint96"
},
{
"internalType": "uint256",
@@ -223,11 +282,60 @@
"internalType": "address",
"name": "drawnAddress",
"type": "address"
+ },
+ {
+ "internalType": "uint96",
+ "name": "fromSubcourtID",
+ "type": "uint96"
}
],
"stateMutability": "view",
"type": "function"
},
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "_iterations",
+ "type": "uint256"
+ }
+ ],
+ "name": "executeDelayedStakes",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "_account",
+ "type": "address"
+ },
+ {
+ "internalType": "uint96",
+ "name": "_courtID",
+ "type": "uint96"
+ }
+ ],
+ "name": "forcedUnstake",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "_account",
+ "type": "address"
+ }
+ ],
+ "name": "forcedUnstakeAllCourts",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
{
"inputs": [
{
@@ -287,15 +395,21 @@
"type": "function"
},
{
- "inputs": [],
- "name": "governor",
- "outputs": [
+ "inputs": [
{
"internalType": "address",
- "name": "",
+ "name": "_juror",
"type": "address"
}
],
+ "name": "getJurorLeftoverPNK",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
"stateMutability": "view",
"type": "function"
},
@@ -303,7 +417,7 @@
"inputs": [
{
"internalType": "address",
- "name": "_governor",
+ "name": "_owner",
"type": "address"
},
{
@@ -379,32 +493,21 @@
"type": "function"
},
{
- "inputs": [
+ "inputs": [],
+ "name": "owner",
+ "outputs": [
{
- "internalType": "uint256",
- "name": "_randomNumber",
- "type": "uint256"
+ "internalType": "address",
+ "name": "",
+ "type": "address"
}
],
- "name": "notifyRandomNumber",
- "outputs": [],
- "stateMutability": "nonpayable",
+ "stateMutability": "view",
"type": "function"
},
{
- "inputs": [
- {
- "internalType": "address",
- "name": "_account",
- "type": "address"
- },
- {
- "internalType": "uint256",
- "name": "_relativeAmount",
- "type": "uint256"
- }
- ],
- "name": "penalizeStake",
+ "inputs": [],
+ "name": "passPhase",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
@@ -446,9 +549,29 @@
"internalType": "address",
"name": "_account",
"type": "address"
+ },
+ {
+ "internalType": "uint96",
+ "name": "_courtID",
+ "type": "uint96"
+ },
+ {
+ "internalType": "uint256",
+ "name": "_pnkDeposit",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "_pnkWithdrawal",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "_newStake",
+ "type": "uint256"
}
],
- "name": "setJurorInactive",
+ "name": "setStake",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
@@ -467,31 +590,55 @@
},
{
"internalType": "uint256",
- "name": "_newStake",
+ "name": "_penalty",
"type": "uint256"
- },
- {
- "internalType": "bool",
- "name": "_alreadyTransferred",
- "type": "bool"
}
],
- "name": "setStake",
+ "name": "setStakePenalty",
"outputs": [
{
"internalType": "uint256",
- "name": "pnkDeposit",
+ "name": "pnkBalance",
"type": "uint256"
},
{
"internalType": "uint256",
- "name": "pnkWithdrawal",
+ "name": "newCourtStake",
"type": "uint256"
},
{
- "internalType": "enum StakingResult",
- "name": "stakingResult",
- "type": "uint8"
+ "internalType": "uint256",
+ "name": "availablePenalty",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "_account",
+ "type": "address"
+ },
+ {
+ "internalType": "uint96",
+ "name": "_courtID",
+ "type": "uint96"
+ },
+ {
+ "internalType": "uint256",
+ "name": "_reward",
+ "type": "uint256"
+ }
+ ],
+ "name": "setStakeReward",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "success",
+ "type": "bool"
}
],
"stateMutability": "nonpayable",
@@ -545,45 +692,114 @@
"outputs": [],
"stateMutability": "payable",
"type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "_account",
+ "type": "address"
+ },
+ {
+ "internalType": "uint96",
+ "name": "_courtID",
+ "type": "uint96"
+ },
+ {
+ "internalType": "uint256",
+ "name": "_newStake",
+ "type": "uint256"
+ },
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "name": "validateStake",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "pnkDeposit",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "pnkWithdrawal",
+ "type": "uint256"
+ },
+ {
+ "internalType": "enum StakingResult",
+ "name": "stakingResult",
+ "type": "uint8"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "version",
+ "outputs": [
+ {
+ "internalType": "string",
+ "name": "",
+ "type": "string"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "_account",
+ "type": "address"
+ }
+ ],
+ "name": "withdrawLeftoverPNK",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
}
],
- "transactionHash": "0x204b96d9a80952f3d7f84a74ce0fe11b7a03ce93187949d2da7e793d56552c61",
+ "transactionHash": "0x0ccfa8e496e33cfb8956ab152907c8003a17df581534ed86b8ed60a5935d657a",
"receipt": {
"to": null,
"from": "0xf1C7c037891525E360C59f708739Ac09A7670c59",
- "contractAddress": "0x5CAD621D69E0535422aCFaCC0017bC32beC7A486",
+ "contractAddress": "0x270e3D63d3d275604df0a1Bd312E1255DCd96936",
"transactionIndex": 1,
- "gasUsed": "1471948",
- "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000004000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
- "blockHash": "0xa593072d9d6d0d0c6ee98e672a112e47e0501bc4d4bca56a6a66060d7427021a",
- "transactionHash": "0x204b96d9a80952f3d7f84a74ce0fe11b7a03ce93187949d2da7e793d56552c61",
+ "gasUsed": "1639716",
+ "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000080000000000000000000000000000000000000000200000000000000000040000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ "blockHash": "0x44cafbfb6a05aee0aaa7a1e875dee979c45404904686c44cd3cd9f981b60e98b",
+ "transactionHash": "0x0ccfa8e496e33cfb8956ab152907c8003a17df581534ed86b8ed60a5935d657a",
"logs": [
{
"transactionIndex": 1,
- "blockNumber": 96308555,
- "transactionHash": "0x204b96d9a80952f3d7f84a74ce0fe11b7a03ce93187949d2da7e793d56552c61",
- "address": "0x5CAD621D69E0535422aCFaCC0017bC32beC7A486",
+ "blockNumber": 193533787,
+ "transactionHash": "0x0ccfa8e496e33cfb8956ab152907c8003a17df581534ed86b8ed60a5935d657a",
+ "address": "0x270e3D63d3d275604df0a1Bd312E1255DCd96936",
"topics": [
"0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2"
],
"data": "0x000000000000000000000000000000000000000000000000ffffffffffffffff",
"logIndex": 0,
- "blockHash": "0xa593072d9d6d0d0c6ee98e672a112e47e0501bc4d4bca56a6a66060d7427021a"
+ "blockHash": "0x44cafbfb6a05aee0aaa7a1e875dee979c45404904686c44cd3cd9f981b60e98b"
}
],
- "blockNumber": 96308555,
- "cumulativeGasUsed": "1471948",
+ "blockNumber": 193533787,
+ "cumulativeGasUsed": "1639716",
"status": 1,
"byzantium": true
},
"args": [],
"numDeployments": 1,
- "solcInputHash": "a5602534c00c2f67ca4b6a1cab8c717e",
- "metadata": "{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"AlreadyInitialized\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedDelegateCall\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"implementation\",\"type\":\"address\"}],\"name\":\"InvalidImplementation\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotInitializing\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UUPSUnauthorizedCallContext\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"slot\",\"type\":\"bytes32\"}],\"name\":\"UUPSUnsupportedProxiableUUID\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"version\",\"type\":\"uint64\"}],\"name\":\"Initialized\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"enum ISortitionModule.Phase\",\"name\":\"_phase\",\"type\":\"uint8\"}],\"name\":\"NewPhase\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_relativeAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"_unlock\",\"type\":\"bool\"}],\"name\":\"StakeLocked\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_courtID\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"StakeSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newImplementation\",\"type\":\"address\"}],\"name\":\"Upgraded\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"core\",\"outputs\":[{\"internalType\":\"contract KlerosCoreUniversity\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"createDisputeHook\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"_key\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"_extraData\",\"type\":\"bytes\"}],\"name\":\"createTree\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"disputesWithoutJurors\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"draw\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"drawnAddress\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_juror\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"_courtID\",\"type\":\"uint96\"}],\"name\":\"getJurorBalance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"totalStaked\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"totalLocked\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"stakedInCourt\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nbCourts\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_juror\",\"type\":\"address\"}],\"name\":\"getJurorCourtIDs\",\"outputs\":[{\"internalType\":\"uint96[]\",\"name\":\"\",\"type\":\"uint96[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"governor\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_governor\",\"type\":\"address\"},{\"internalType\":\"contract KlerosCoreUniversity\",\"name\":\"_core\",\"type\":\"address\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_juror\",\"type\":\"address\"}],\"name\":\"isJurorStaked\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"jurors\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"stakedPnk\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"lockedPnk\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_account\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_relativeAmount\",\"type\":\"uint256\"}],\"name\":\"lockStake\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_randomNumber\",\"type\":\"uint256\"}],\"name\":\"notifyRandomNumber\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_account\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_relativeAmount\",\"type\":\"uint256\"}],\"name\":\"penalizeStake\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"postDrawHook\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"proxiableUUID\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_account\",\"type\":\"address\"}],\"name\":\"setJurorInactive\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_account\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"_courtID\",\"type\":\"uint96\"},{\"internalType\":\"uint256\",\"name\":\"_newStake\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"_alreadyTransferred\",\"type\":\"bool\"}],\"name\":\"setStake\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"pnkDeposit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"pnkWithdrawal\",\"type\":\"uint256\"},{\"internalType\":\"enum StakingResult\",\"name\":\"stakingResult\",\"type\":\"uint8\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_juror\",\"type\":\"address\"}],\"name\":\"setTransientJuror\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_account\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_relativeAmount\",\"type\":\"uint256\"}],\"name\":\"unlockStake\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newImplementation\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"upgradeToAndCall\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"An adapted version of the SortitionModule contract for educational purposes.\",\"errors\":{\"AlreadyInitialized()\":[{\"details\":\"The contract is already initialized.\"}],\"NotInitializing()\":[{\"details\":\"The contract is not initializing.\"}],\"UUPSUnauthorizedCallContext()\":[{\"details\":\"The call is from an unauthorized context.\"}],\"UUPSUnsupportedProxiableUUID(bytes32)\":[{\"details\":\"The storage `slot` is unsupported as a UUID.\"}]},\"events\":{\"Initialized(uint64)\":{\"details\":\"Triggered when the contract has been initialized or reinitialized.\"},\"Upgraded(address)\":{\"params\":{\"newImplementation\":\"Address of the new implementation the proxy is now forwarding calls to.\"}}},\"kind\":\"dev\",\"methods\":{\"constructor\":{\"details\":\"Constructor, initializing the implementation to reduce attack surface.\"},\"draw(bytes32,uint256,uint256)\":{\"details\":\"Draw an ID from a tree using a number. Note that this function reverts if the sum of all values in the tree is 0.\",\"returns\":{\"drawnAddress\":\"The drawn address. `O(k * log_k(n))` where `k` is the maximum number of children per node in the tree, and `n` is the maximum number of nodes ever appended.\"}},\"getJurorBalance(address,uint96)\":{\"details\":\"Gets the stake of a juror in a court. Warning: `O(n)` complexity where `n` is the number of courts the juror has staked in but acceptable for this educational implementation.\",\"params\":{\"_courtID\":\"The ID of the court.\",\"_juror\":\"The address of the juror.\"},\"returns\":{\"nbCourts\":\"The number of courts the juror has staked in.\",\"stakedInCourt\":\"The amount of tokens staked by the juror in the court.\",\"totalLocked\":\"The total amount of tokens locked by the juror in the court.\",\"totalStaked\":\"The total amount of tokens staked by the juror in the court.\"}},\"getJurorCourtIDs(address)\":{\"details\":\"Gets the court identifiers where a specific `_juror` has staked.\",\"params\":{\"_juror\":\"The address of the juror.\"}},\"initialize(address,address)\":{\"details\":\"Initializer (constructor equivalent for upgradable contracts).\",\"params\":{\"_core\":\"The KlerosCore.\"}},\"notifyRandomNumber(uint256)\":{\"details\":\"Saves the random number to use it in sortition. Not used by this contract because the storing of the number is inlined in passPhase().\",\"params\":{\"_randomNumber\":\"Random number returned by RNG contract.\"}},\"proxiableUUID()\":{\"details\":\"Implementation of the ERC1822 `proxiableUUID` function. This returns the storage slot used by the implementation. It is used to validate the implementation's compatibility when performing an upgrade. IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this function revert if invoked through a proxy. This is guaranteed by the if statement.\"},\"setJurorInactive(address)\":{\"details\":\"Unstakes the inactive juror from all courts. `O(n * (p * log_k(j)) )` where `n` is the number of courts the juror has staked in, `p` is the depth of the court tree, `k` is the minimum number of children per node of one of these courts' sortition sum tree, and `j` is the maximum number of jurors that ever staked in one of these courts simultaneously.\",\"params\":{\"_account\":\"The juror to unstake.\"}},\"setStake(address,uint96,uint256,bool)\":{\"details\":\"Sets the specified juror's stake in a court. `O(n + p * log_k(j))` where `n` is the number of courts the juror has staked in, `p` is the depth of the court tree, `k` is the minimum number of children per node of one of these courts' sortition sum tree, and `j` is the maximum number of jurors that ever staked in one of these courts simultaneously.\",\"params\":{\"_account\":\"The address of the juror.\",\"_alreadyTransferred\":\"True if the tokens were already transferred from juror. Only relevant for delayed stakes.\",\"_courtID\":\"The ID of the court.\",\"_newStake\":\"The new stake.\"},\"returns\":{\"pnkDeposit\":\"The amount of PNK to be deposited.\",\"pnkWithdrawal\":\"The amount of PNK to be withdrawn.\",\"stakingResult\":\"The result of the staking operation.\"}},\"upgradeToAndCall(address,bytes)\":{\"details\":\"Upgrade mechanism including access control and UUPS-compliance.Reverts if the execution is not performed via delegatecall or the execution context is not of a proxy with an ERC1967-compliant implementation pointing to self.\",\"params\":{\"data\":\"Data used in a delegate call to `newImplementation` if non-empty. This will typically be an encoded function call, and allows initializing the storage of the proxy like a Solidity constructor.\",\"newImplementation\":\"Address of the new implementation contract.\"}}},\"title\":\"SortitionModuleUniversity\",\"version\":1},\"userdoc\":{\"errors\":{\"FailedDelegateCall()\":[{\"notice\":\"Failed Delegated call\"}],\"InvalidImplementation(address)\":[{\"notice\":\"The `implementation` is not UUPS-compliant\"}]},\"events\":{\"Upgraded(address)\":{\"notice\":\"Emitted when the `implementation` has been successfully upgraded.\"}},\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/arbitration/university/SortitionModuleUniversity.sol\":\"SortitionModuleUniversity\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":100},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.20;\\n\\n/**\\n * @dev Interface of the ERC-20 standard as defined in the ERC.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n\\n /**\\n * @dev Returns the value of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the value of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 value) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\\n * caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 value) external returns (bool);\\n\\n /**\\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\\n * allowance mechanism. `value` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(address from, address to, uint256 value) external returns (bool);\\n}\\n\",\"keccak256\":\"0xe06a3f08a987af6ad2e1c1e774405d4fe08f1694b67517438b467cecf0da0ef7\",\"license\":\"MIT\"},\"src/arbitration/interfaces/IArbitrableV2.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.24;\\n\\nimport \\\"./IArbitratorV2.sol\\\";\\n\\n/// @title IArbitrableV2\\n/// @notice Arbitrable interface.\\n/// @dev When developing arbitrable contracts, we need to:\\n/// - Define the action taken when a ruling is received by the contract.\\n/// - Allow dispute creation. For this a function must call arbitrator.createDispute{value: _fee}(_choices,_extraData);\\ninterface IArbitrableV2 {\\n /// @dev To be emitted when a dispute is created to link the correct meta-evidence to the disputeID.\\n /// @param _arbitrator The arbitrator of the contract.\\n /// @param _arbitratorDisputeID The identifier of the dispute in the Arbitrator contract.\\n /// @param _externalDisputeID An identifier created outside Kleros by the protocol requesting arbitration.\\n /// @param _templateId The identifier of the dispute template. Should not be used with _templateUri.\\n /// @param _templateUri The URI to the dispute template. For example on IPFS: starting with '/ipfs/'. Should not be used with _templateId.\\n event DisputeRequest(\\n IArbitratorV2 indexed _arbitrator,\\n uint256 indexed _arbitratorDisputeID,\\n uint256 _externalDisputeID,\\n uint256 _templateId,\\n string _templateUri\\n );\\n\\n /// @dev To be raised when a ruling is given.\\n /// @param _arbitrator The arbitrator giving the ruling.\\n /// @param _disputeID The identifier of the dispute in the Arbitrator contract.\\n /// @param _ruling The ruling which was given.\\n event Ruling(IArbitratorV2 indexed _arbitrator, uint256 indexed _disputeID, uint256 _ruling);\\n\\n /// @dev Give a ruling for a dispute.\\n /// Must be called by the arbitrator.\\n /// The purpose of this function is to ensure that the address calling it has the right to rule on the contract.\\n /// @param _disputeID The identifier of the dispute in the Arbitrator contract.\\n /// @param _ruling Ruling given by the arbitrator.\\n /// Note that 0 is reserved for \\\"Not able/wanting to make a decision\\\".\\n function rule(uint256 _disputeID, uint256 _ruling) external;\\n}\\n\",\"keccak256\":\"0xe841a4fe8ec109ce17dde4457bf1583c8b499109b05887c53a49a3207fc6e80b\",\"license\":\"MIT\"},\"src/arbitration/interfaces/IArbitratorV2.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"./IArbitrableV2.sol\\\";\\n\\n/// @title Arbitrator\\n/// Arbitrator interface that implements the new arbitration standard.\\n/// Unlike the ERC-792 this standard is not concerned with appeals, so each arbitrator can implement an appeal system that suits it the most.\\n/// When developing arbitrator contracts we need to:\\n/// - Define the functions for dispute creation (createDispute). Don't forget to store the arbitrated contract and the disputeID (which should be unique, may nbDisputes).\\n/// - Define the functions for cost display (arbitrationCost).\\n/// - Allow giving rulings. For this a function must call arbitrable.rule(disputeID, ruling).\\ninterface IArbitratorV2 {\\n /// @dev To be emitted when a dispute is created.\\n /// @param _disputeID The identifier of the dispute in the Arbitrator contract.\\n /// @param _arbitrable The contract which created the dispute.\\n event DisputeCreation(uint256 indexed _disputeID, IArbitrableV2 indexed _arbitrable);\\n\\n /// @dev To be raised when a ruling is given.\\n /// @param _arbitrable The arbitrable receiving the ruling.\\n /// @param _disputeID The identifier of the dispute in the Arbitrator contract.\\n /// @param _ruling The ruling which was given.\\n event Ruling(IArbitrableV2 indexed _arbitrable, uint256 indexed _disputeID, uint256 _ruling);\\n\\n /// @dev To be emitted when an ERC20 token is added or removed as a method to pay fees.\\n /// @param _token The ERC20 token.\\n /// @param _accepted Whether the token is accepted or not.\\n event AcceptedFeeToken(IERC20 indexed _token, bool indexed _accepted);\\n\\n /// @dev To be emitted when the fee for a particular ERC20 token is updated.\\n /// @param _feeToken The ERC20 token.\\n /// @param _rateInEth The new rate of the fee token in ETH.\\n /// @param _rateDecimals The new decimals of the fee token rate.\\n event NewCurrencyRate(IERC20 indexed _feeToken, uint64 _rateInEth, uint8 _rateDecimals);\\n\\n /// @dev Create a dispute and pay for the fees in the native currency, typically ETH.\\n /// Must be called by the arbitrable contract.\\n /// Must pay at least arbitrationCost(_extraData).\\n /// @param _numberOfChoices The number of choices the arbitrator can choose from in this dispute.\\n /// @param _extraData Additional info about the dispute. We use it to pass the ID of the dispute's court (first 32 bytes), the minimum number of jurors required (next 32 bytes) and the ID of the specific dispute kit (last 32 bytes).\\n /// @return disputeID The identifier of the dispute created.\\n function createDispute(\\n uint256 _numberOfChoices,\\n bytes calldata _extraData\\n ) external payable returns (uint256 disputeID);\\n\\n /// @dev Create a dispute and pay for the fees in a supported ERC20 token.\\n /// Must be called by the arbitrable contract.\\n /// Must pay at least arbitrationCost(_extraData).\\n /// @param _numberOfChoices The number of choices the arbitrator can choose from in this dispute.\\n /// @param _extraData Additional info about the dispute. We use it to pass the ID of the dispute's court (first 32 bytes), the minimum number of jurors required (next 32 bytes) and the ID of the specific dispute kit (last 32 bytes).\\n /// @param _feeToken The ERC20 token used to pay fees.\\n /// @param _feeAmount Amount of the ERC20 token used to pay fees.\\n /// @return disputeID The identifier of the dispute created.\\n function createDispute(\\n uint256 _numberOfChoices,\\n bytes calldata _extraData,\\n IERC20 _feeToken,\\n uint256 _feeAmount\\n ) external returns (uint256 disputeID);\\n\\n /// @dev Compute the cost of arbitration denominated in the native currency, typically ETH.\\n /// It is recommended not to increase it often, as it can be highly time and gas consuming for the arbitrated contracts to cope with fee augmentation.\\n /// @param _extraData Additional info about the dispute. We use it to pass the ID of the dispute's court (first 32 bytes), the minimum number of jurors required (next 32 bytes) and the ID of the specific dispute kit (last 32 bytes).\\n /// @return cost The arbitration cost in ETH.\\n function arbitrationCost(bytes calldata _extraData) external view returns (uint256 cost);\\n\\n /// @dev Compute the cost of arbitration denominated in `_feeToken`.\\n /// It is recommended not to increase it often, as it can be highly time and gas consuming for the arbitrated contracts to cope with fee augmentation.\\n /// @param _extraData Additional info about the dispute. We use it to pass the ID of the dispute's court (first 32 bytes), the minimum number of jurors required (next 32 bytes) and the ID of the specific dispute kit (last 32 bytes).\\n /// @param _feeToken The ERC20 token used to pay fees.\\n /// @return cost The arbitration cost in `_feeToken`.\\n function arbitrationCost(bytes calldata _extraData, IERC20 _feeToken) external view returns (uint256 cost);\\n\\n /// @dev Gets the current ruling of a specified dispute.\\n /// @param _disputeID The ID of the dispute.\\n /// @return ruling The current ruling.\\n /// @return tied Whether it's a tie or not.\\n /// @return overridden Whether the ruling was overridden by appeal funding or not.\\n function currentRuling(uint256 _disputeID) external view returns (uint256 ruling, bool tied, bool overridden);\\n}\\n\",\"keccak256\":\"0xa4dc6b958197adead238de4246cd04e7389c3dc1b9f968acd10985f8fc5b74cf\",\"license\":\"MIT\"},\"src/arbitration/interfaces/IDisputeKit.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\n/// @custom:authors: [@unknownunknown1, @jaybuidl]\\n/// @custom:reviewers: []\\n/// @custom:auditors: []\\n/// @custom:bounties: []\\n/// @custom:deployments: []\\n\\npragma solidity 0.8.24;\\n\\nimport \\\"./IArbitratorV2.sol\\\";\\n\\n/// @title IDisputeKit\\n/// An abstraction of the Dispute Kits intended for interfacing with KlerosCore.\\n/// It does not intend to abstract the interactions with the user (such as voting or appeal funding) to allow for implementation-specific parameters.\\ninterface IDisputeKit {\\n // ************************************ //\\n // * Events * //\\n // ************************************ //\\n\\n /// @dev Emitted when casting a vote to provide the justification of juror's choice.\\n /// @param _coreDisputeID The identifier of the dispute in the Arbitrator contract.\\n /// @param _juror Address of the juror.\\n /// @param _voteIDs The identifiers of the votes in the dispute.\\n /// @param _choice The choice juror voted for.\\n /// @param _justification Justification of the choice.\\n event VoteCast(\\n uint256 indexed _coreDisputeID,\\n address indexed _juror,\\n uint256[] _voteIDs,\\n uint256 indexed _choice,\\n string _justification\\n );\\n\\n // ************************************* //\\n // * State Modifiers * //\\n // ************************************* //\\n\\n /// @dev Creates a local dispute and maps it to the dispute ID in the Core contract.\\n /// Note: Access restricted to Kleros Core only.\\n /// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.\\n /// @param _numberOfChoices Number of choices of the dispute\\n /// @param _extraData Additional info about the dispute, for possible use in future dispute kits.\\n function createDispute(\\n uint256 _coreDisputeID,\\n uint256 _numberOfChoices,\\n bytes calldata _extraData,\\n uint256 _nbVotes\\n ) external;\\n\\n /// @dev Draws the juror from the sortition tree. The drawn address is picked up by Kleros Core.\\n /// Note: Access restricted to Kleros Core only.\\n /// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.\\n /// @param _nonce Nonce.\\n /// @return drawnAddress The drawn address.\\n function draw(uint256 _coreDisputeID, uint256 _nonce) external returns (address drawnAddress);\\n\\n // ************************************* //\\n // * Public Views * //\\n // ************************************* //\\n\\n /// @dev Gets the current ruling of a specified dispute.\\n /// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.\\n /// @return ruling The current ruling.\\n /// @return tied Whether it's a tie or not.\\n /// @return overridden Whether the ruling was overridden by appeal funding or not.\\n function currentRuling(uint256 _coreDisputeID) external view returns (uint256 ruling, bool tied, bool overridden);\\n\\n /// @dev Gets the degree of coherence of a particular voter. This function is called by Kleros Core in order to determine the amount of the reward.\\n /// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.\\n /// @param _coreRoundID The ID of the round in Kleros Core, not in the Dispute Kit.\\n /// @param _voteID The ID of the vote.\\n /// @param _feePerJuror The fee per juror.\\n /// @param _pnkAtStakePerJuror The PNK at stake per juror.\\n /// @return The degree of coherence in basis points.\\n function getDegreeOfCoherence(\\n uint256 _coreDisputeID,\\n uint256 _coreRoundID,\\n uint256 _voteID,\\n uint256 _feePerJuror,\\n uint256 _pnkAtStakePerJuror\\n ) external view returns (uint256);\\n\\n /// @dev Gets the number of jurors who are eligible to a reward in this round.\\n /// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.\\n /// @param _coreRoundID The ID of the round in Kleros Core, not in the Dispute Kit.\\n /// @return The number of coherent jurors.\\n function getCoherentCount(uint256 _coreDisputeID, uint256 _coreRoundID) external view returns (uint256);\\n\\n /// @dev Returns true if all of the jurors have cast their commits for the last round.\\n /// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.\\n /// @return Whether all of the jurors have cast their commits for the last round.\\n function areCommitsAllCast(uint256 _coreDisputeID) external view returns (bool);\\n\\n /// @dev Returns true if all of the jurors have cast their votes for the last round.\\n /// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.\\n /// @return Whether all of the jurors have cast their votes for the last round.\\n function areVotesAllCast(uint256 _coreDisputeID) external view returns (bool);\\n\\n /// @dev Returns true if the specified voter was active in this round.\\n /// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.\\n /// @param _coreRoundID The ID of the round in Kleros Core, not in the Dispute Kit.\\n /// @param _voteID The ID of the voter.\\n /// @return Whether the voter was active or not.\\n function isVoteActive(uint256 _coreDisputeID, uint256 _coreRoundID, uint256 _voteID) external view returns (bool);\\n\\n function getRoundInfo(\\n uint256 _coreDisputeID,\\n uint256 _coreRoundID,\\n uint256 _choice\\n )\\n external\\n view\\n returns (\\n uint256 winningChoice,\\n bool tied,\\n uint256 totalVoted,\\n uint256 totalCommited,\\n uint256 nbVoters,\\n uint256 choiceCount\\n );\\n\\n function getVoteInfo(\\n uint256 _coreDisputeID,\\n uint256 _coreRoundID,\\n uint256 _voteID\\n ) external view returns (address account, bytes32 commit, uint256 choice, bool voted);\\n}\\n\",\"keccak256\":\"0xb9590d05f9df08dd0ed027b2eb40c7b1885b7574a121b1b0b7da0920429bb4d5\",\"license\":\"MIT\"},\"src/arbitration/interfaces/ISortitionModule.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.24;\\n\\nimport \\\"../../libraries/Constants.sol\\\";\\n\\ninterface ISortitionModule {\\n enum Phase {\\n staking, // Stake sum trees can be updated. Pass after `minStakingTime` passes and there is at least one dispute without jurors.\\n generating, // Waiting for a random number. Pass as soon as it is ready.\\n drawing // Jurors can be drawn. Pass after all disputes have jurors or `maxDrawingTime` passes.\\n }\\n\\n event NewPhase(Phase _phase);\\n\\n function createTree(bytes32 _key, bytes memory _extraData) external;\\n\\n function setStake(\\n address _account,\\n uint96 _courtID,\\n uint256 _newStake,\\n bool _alreadyTransferred\\n ) external returns (uint256 pnkDeposit, uint256 pnkWithdrawal, StakingResult stakingResult);\\n\\n function setJurorInactive(address _account) external;\\n\\n function lockStake(address _account, uint256 _relativeAmount) external;\\n\\n function unlockStake(address _account, uint256 _relativeAmount) external;\\n\\n function penalizeStake(address _account, uint256 _relativeAmount) external;\\n\\n function notifyRandomNumber(uint256 _drawnNumber) external;\\n\\n function draw(bytes32 _court, uint256 _coreDisputeID, uint256 _nonce) external view returns (address);\\n\\n function getJurorBalance(\\n address _juror,\\n uint96 _courtID\\n ) external view returns (uint256 totalStaked, uint256 totalLocked, uint256 stakedInCourt, uint256 nbCourts);\\n\\n function getJurorCourtIDs(address _juror) external view returns (uint96[] memory);\\n\\n function isJurorStaked(address _juror) external view returns (bool);\\n\\n function createDisputeHook(uint256 _disputeID, uint256 _roundID) external;\\n\\n function postDrawHook(uint256 _disputeID, uint256 _roundID) external;\\n}\\n\",\"keccak256\":\"0x18a4ff126bb51e7b5b0e3fbff7cf0dbbcfff7195ad79307e69cdbc9226e63502\",\"license\":\"MIT\"},\"src/arbitration/university/ISortitionModuleUniversity.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.24;\\n\\nimport {ISortitionModule} from \\\"../interfaces/ISortitionModule.sol\\\";\\n\\ninterface ISortitionModuleUniversity is ISortitionModule {\\n function setTransientJuror(address _juror) external;\\n}\\n\",\"keccak256\":\"0x57fee0787ae90af01c57a7d2850f8e4ade1ca72163a388341cac017bfdbf163a\",\"license\":\"MIT\"},\"src/arbitration/university/KlerosCoreUniversity.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.24;\\n\\nimport {IArbitrableV2, IArbitratorV2} from \\\"../interfaces/IArbitratorV2.sol\\\";\\nimport {IDisputeKit} from \\\"../interfaces/IDisputeKit.sol\\\";\\nimport {ISortitionModuleUniversity} from \\\"./ISortitionModuleUniversity.sol\\\";\\nimport {SafeERC20, IERC20} from \\\"../../libraries/SafeERC20.sol\\\";\\nimport \\\"../../libraries/Constants.sol\\\";\\nimport {UUPSProxiable} from \\\"../../proxy/UUPSProxiable.sol\\\";\\nimport {Initializable} from \\\"../../proxy/Initializable.sol\\\";\\n\\n/// @title KlerosCoreUniversity\\n/// Core arbitrator contract for educational purposes.\\ncontract KlerosCoreUniversity is IArbitratorV2, UUPSProxiable, Initializable {\\n using SafeERC20 for IERC20;\\n\\n // ************************************* //\\n // * Enums / Structs * //\\n // ************************************* //\\n\\n enum Period {\\n evidence, // Evidence can be submitted. This is also when drawing has to take place.\\n commit, // Jurors commit a hashed vote. This is skipped for courts without hidden votes.\\n vote, // Jurors reveal/cast their vote depending on whether the court has hidden votes or not.\\n appeal, // The dispute can be appealed.\\n execution // Tokens are redistributed and the ruling is executed.\\n }\\n\\n struct Court {\\n uint96 parent; // The parent court.\\n bool hiddenVotes; // Whether to use commit and reveal or not.\\n uint256[] children; // List of child courts.\\n uint256 minStake; // Minimum PNKs needed to stake in the court.\\n uint256 alpha; // Basis point of PNKs that are lost when incoherent.\\n uint256 feeForJuror; // Arbitration fee paid per juror.\\n uint256 jurorsForCourtJump; // The appeal after the one that reaches this number of jurors will go to the parent court if any.\\n uint256[4] timesPerPeriod; // The time allotted to each dispute period in the form `timesPerPeriod[period]`.\\n mapping(uint256 disputeKitId => bool) supportedDisputeKits; // True if DK with this ID is supported by the court. Note that each court must support classic dispute kit.\\n bool disabled; // True if the court is disabled. Unused for now, will be implemented later.\\n }\\n\\n struct Dispute {\\n uint96 courtID; // The ID of the court the dispute is in.\\n IArbitrableV2 arbitrated; // The arbitrable contract.\\n Period period; // The current period of the dispute.\\n bool ruled; // True if the ruling has been executed, false otherwise.\\n uint256 lastPeriodChange; // The last time the period was changed.\\n Round[] rounds;\\n }\\n\\n struct Round {\\n uint256 disputeKitID; // Index of the dispute kit in the array.\\n uint256 pnkAtStakePerJuror; // The amount of PNKs at stake for each juror in this round.\\n uint256 totalFeesForJurors; // The total juror fees paid in this round.\\n uint256 nbVotes; // The total number of votes the dispute can possibly have in the current round. Former votes[_round].length.\\n uint256 repartitions; // A counter of reward repartitions made in this round.\\n uint256 pnkPenalties; // The amount of PNKs collected from penalties in this round.\\n address[] drawnJurors; // Addresses of the jurors that were drawn in this round.\\n uint256 sumFeeRewardPaid; // Total sum of arbitration fees paid to coherent jurors as a reward in this round.\\n uint256 sumPnkRewardPaid; // Total sum of PNK paid to coherent jurors as a reward in this round.\\n IERC20 feeToken; // The token used for paying fees in this round.\\n uint256 drawIterations; // The number of iterations passed drawing the jurors for this round.\\n }\\n\\n // Workaround \\\"stack too deep\\\" errors\\n struct ExecuteParams {\\n uint256 disputeID; // The ID of the dispute to execute.\\n uint256 round; // The round to execute.\\n uint256 coherentCount; // The number of coherent votes in the round.\\n uint256 numberOfVotesInRound; // The number of votes in the round.\\n uint256 feePerJurorInRound; // The fee per juror in the round.\\n uint256 pnkAtStakePerJurorInRound; // The amount of PNKs at stake for each juror in the round.\\n uint256 pnkPenaltiesInRound; // The amount of PNKs collected from penalties in the round.\\n uint256 repartition; // The index of the repartition to execute.\\n }\\n\\n struct CurrencyRate {\\n bool feePaymentAccepted;\\n uint64 rateInEth;\\n uint8 rateDecimals;\\n }\\n\\n // ************************************* //\\n // * Storage * //\\n // ************************************* //\\n\\n uint256 private constant ALPHA_DIVISOR = 1e4; // The number to divide `Court.alpha` by.\\n uint256 private constant NON_PAYABLE_AMOUNT = (2 ** 256 - 2) / 2; // An amount higher than the supply of ETH.\\n\\n address public governor; // The governor of the contract.\\n address public instructor; // The instructor who is allowed to choose the jurors.\\n IERC20 public pinakion; // The Pinakion token contract.\\n address public jurorProsecutionModule; // The module for juror's prosecution.\\n ISortitionModuleUniversity public sortitionModule; // Sortition module for drawing.\\n Court[] public courts; // The courts.\\n IDisputeKit[] public disputeKits; // Array of dispute kits.\\n Dispute[] public disputes; // The disputes.\\n mapping(IERC20 => CurrencyRate) public currencyRates; // The price of each token in ETH.\\n\\n // ************************************* //\\n // * Events * //\\n // ************************************* //\\n\\n event NewPeriod(uint256 indexed _disputeID, Period _period);\\n event AppealPossible(uint256 indexed _disputeID, IArbitrableV2 indexed _arbitrable);\\n event AppealDecision(uint256 indexed _disputeID, IArbitrableV2 indexed _arbitrable);\\n event Draw(address indexed _address, uint256 indexed _disputeID, uint256 _roundID, uint256 _voteID);\\n event CourtCreated(\\n uint256 indexed _courtID,\\n uint96 indexed _parent,\\n bool _hiddenVotes,\\n uint256 _minStake,\\n uint256 _alpha,\\n uint256 _feeForJuror,\\n uint256 _jurorsForCourtJump,\\n uint256[4] _timesPerPeriod,\\n uint256[] _supportedDisputeKits\\n );\\n event CourtModified(\\n uint96 indexed _courtID,\\n bool _hiddenVotes,\\n uint256 _minStake,\\n uint256 _alpha,\\n uint256 _feeForJuror,\\n uint256 _jurorsForCourtJump,\\n uint256[4] _timesPerPeriod\\n );\\n event DisputeKitCreated(uint256 indexed _disputeKitID, IDisputeKit indexed _disputeKitAddress);\\n event DisputeKitEnabled(uint96 indexed _courtID, uint256 indexed _disputeKitID, bool indexed _enable);\\n event CourtJump(\\n uint256 indexed _disputeID,\\n uint256 indexed _roundID,\\n uint96 indexed _fromCourtID,\\n uint96 _toCourtID\\n );\\n event DisputeKitJump(\\n uint256 indexed _disputeID,\\n uint256 indexed _roundID,\\n uint256 indexed _fromDisputeKitID,\\n uint256 _toDisputeKitID\\n );\\n event TokenAndETHShift(\\n address indexed _account,\\n uint256 indexed _disputeID,\\n uint256 indexed _roundID,\\n uint256 _degreeOfCoherency,\\n int256 _pnkAmount,\\n int256 _feeAmount,\\n IERC20 _feeToken\\n );\\n event LeftoverRewardSent(\\n uint256 indexed _disputeID,\\n uint256 indexed _roundID,\\n uint256 _pnkAmount,\\n uint256 _feeAmount,\\n IERC20 _feeToken\\n );\\n\\n // ************************************* //\\n // * Function Modifiers * //\\n // ************************************* //\\n\\n modifier onlyByGovernor() {\\n if (governor != msg.sender) revert GovernorOnly();\\n _;\\n }\\n\\n modifier onlyByInstructor() {\\n if (instructor != msg.sender) revert InstructorOnly();\\n _;\\n }\\n\\n modifier onlyByGovernorOrInstructor() {\\n if (msg.sender != governor && msg.sender != instructor) revert GovernorOrInstructorOnly();\\n _;\\n }\\n\\n // ************************************* //\\n // * Constructor * //\\n // ************************************* //\\n\\n /// @dev Constructor, initializing the implementation to reduce attack surface.\\n constructor() {\\n _disableInitializers();\\n }\\n\\n /// @dev Initializer (constructor equivalent for upgradable contracts).\\n /// @param _governor The governor's address.\\n /// @param _instructor The address of the instructor.\\n /// @param _pinakion The address of the token contract.\\n /// @param _jurorProsecutionModule The address of the juror prosecution module.\\n /// @param _disputeKit The address of the default dispute kit.\\n /// @param _hiddenVotes The `hiddenVotes` property value of the general court.\\n /// @param _courtParameters Numeric parameters of General court (minStake, alpha, feeForJuror and jurorsForCourtJump respectively).\\n /// @param _timesPerPeriod The `timesPerPeriod` property value of the general court.\\n /// @param _sortitionModuleAddress The sortition module responsible for sortition of the jurors.\\n function initialize(\\n address _governor,\\n address _instructor,\\n IERC20 _pinakion,\\n address _jurorProsecutionModule,\\n IDisputeKit _disputeKit,\\n bool _hiddenVotes,\\n uint256[4] memory _courtParameters,\\n uint256[4] memory _timesPerPeriod,\\n ISortitionModuleUniversity _sortitionModuleAddress\\n ) external reinitializer(1) {\\n governor = _governor;\\n instructor = _instructor;\\n pinakion = _pinakion;\\n jurorProsecutionModule = _jurorProsecutionModule;\\n sortitionModule = _sortitionModuleAddress;\\n\\n // NULL_DISPUTE_KIT: an empty element at index 0 to indicate when a dispute kit is not supported.\\n disputeKits.push();\\n\\n // DISPUTE_KIT_CLASSIC\\n disputeKits.push(_disputeKit);\\n\\n emit DisputeKitCreated(DISPUTE_KIT_CLASSIC, _disputeKit);\\n\\n // FORKING_COURT\\n // TODO: Fill the properties for the Forking court, emit CourtCreated.\\n courts.push();\\n\\n // GENERAL_COURT\\n Court storage court = courts.push();\\n court.parent = FORKING_COURT;\\n court.children = new uint256[](0);\\n court.hiddenVotes = _hiddenVotes;\\n court.minStake = _courtParameters[0];\\n court.alpha = _courtParameters[1];\\n court.feeForJuror = _courtParameters[2];\\n court.jurorsForCourtJump = _courtParameters[3];\\n court.timesPerPeriod = _timesPerPeriod;\\n\\n emit CourtCreated(\\n 1,\\n court.parent,\\n _hiddenVotes,\\n _courtParameters[0],\\n _courtParameters[1],\\n _courtParameters[2],\\n _courtParameters[3],\\n _timesPerPeriod,\\n new uint256[](0)\\n );\\n _enableDisputeKit(GENERAL_COURT, DISPUTE_KIT_CLASSIC, true);\\n }\\n\\n // ************************************* //\\n // * Governance * //\\n // ************************************* //\\n\\n /* @dev Access Control to perform implementation upgrades (UUPS Proxiable)\\n * @dev Only the governor can perform upgrades (`onlyByGovernor`)\\n */\\n function _authorizeUpgrade(address) internal view override onlyByGovernor {\\n // NOP\\n }\\n\\n /// @dev Allows the governor to call anything on behalf of the contract.\\n /// @param _destination The destination of the call.\\n /// @param _amount The value sent with the call.\\n /// @param _data The data sent with the call.\\n function executeGovernorProposal(\\n address _destination,\\n uint256 _amount,\\n bytes memory _data\\n ) external onlyByGovernor {\\n (bool success, ) = _destination.call{value: _amount}(_data);\\n if (!success) revert UnsuccessfulCall();\\n }\\n\\n /// @dev Changes the `governor` storage variable.\\n /// @param _governor The new value for the `governor` storage variable.\\n function changeGovernor(address payable _governor) external onlyByGovernor {\\n governor = _governor;\\n }\\n\\n /// @dev Changes the `instructor` storage variable.\\n /// @param _instructor The new value for the `instructor` storage variable.\\n function changeInstructor(address _instructor) external onlyByGovernorOrInstructor {\\n instructor = _instructor;\\n }\\n\\n /// @dev Changes the `pinakion` storage variable.\\n /// @param _pinakion The new value for the `pinakion` storage variable.\\n function changePinakion(IERC20 _pinakion) external onlyByGovernor {\\n pinakion = _pinakion;\\n }\\n\\n /// @dev Changes the `jurorProsecutionModule` storage variable.\\n /// @param _jurorProsecutionModule The new value for the `jurorProsecutionModule` storage variable.\\n function changeJurorProsecutionModule(address _jurorProsecutionModule) external onlyByGovernor {\\n jurorProsecutionModule = _jurorProsecutionModule;\\n }\\n\\n /// @dev Changes the `_sortitionModule` storage variable.\\n /// Note that the new module should be initialized for all courts.\\n /// @param _sortitionModule The new value for the `sortitionModule` storage variable.\\n function changeSortitionModule(ISortitionModuleUniversity _sortitionModule) external onlyByGovernor {\\n sortitionModule = _sortitionModule;\\n }\\n\\n /// @dev Add a new supported dispute kit module to the court.\\n /// @param _disputeKitAddress The address of the dispute kit contract.\\n function addNewDisputeKit(IDisputeKit _disputeKitAddress) external onlyByGovernor {\\n uint256 disputeKitID = disputeKits.length;\\n disputeKits.push(_disputeKitAddress);\\n emit DisputeKitCreated(disputeKitID, _disputeKitAddress);\\n }\\n\\n /// @dev Creates a court under a specified parent court.\\n /// @param _parent The `parent` property value of the court.\\n /// @param _hiddenVotes The `hiddenVotes` property value of the court.\\n /// @param _minStake The `minStake` property value of the court.\\n /// @param _alpha The `alpha` property value of the court.\\n /// @param _feeForJuror The `feeForJuror` property value of the court.\\n /// @param _jurorsForCourtJump The `jurorsForCourtJump` property value of the court.\\n /// @param _timesPerPeriod The `timesPerPeriod` property value of the court.\\n /// @param _supportedDisputeKits Indexes of dispute kits that this court will support.\\n function createCourt(\\n uint96 _parent,\\n bool _hiddenVotes,\\n uint256 _minStake,\\n uint256 _alpha,\\n uint256 _feeForJuror,\\n uint256 _jurorsForCourtJump,\\n uint256[4] memory _timesPerPeriod,\\n uint256[] memory _supportedDisputeKits\\n ) external onlyByGovernor {\\n if (courts[_parent].minStake > _minStake) revert MinStakeLowerThanParentCourt();\\n if (_supportedDisputeKits.length == 0) revert UnsupportedDisputeKit();\\n if (_parent == FORKING_COURT) revert InvalidForkingCourtAsParent();\\n\\n uint256 courtID = courts.length;\\n Court storage court = courts.push();\\n\\n for (uint256 i = 0; i < _supportedDisputeKits.length; i++) {\\n if (_supportedDisputeKits[i] == 0 || _supportedDisputeKits[i] >= disputeKits.length) {\\n revert WrongDisputeKitIndex();\\n }\\n court.supportedDisputeKits[_supportedDisputeKits[i]] = true;\\n }\\n // Check that Classic DK support was added.\\n if (!court.supportedDisputeKits[DISPUTE_KIT_CLASSIC]) revert MustSupportDisputeKitClassic();\\n\\n court.parent = _parent;\\n court.children = new uint256[](0);\\n court.hiddenVotes = _hiddenVotes;\\n court.minStake = _minStake;\\n court.alpha = _alpha;\\n court.feeForJuror = _feeForJuror;\\n court.jurorsForCourtJump = _jurorsForCourtJump;\\n court.timesPerPeriod = _timesPerPeriod;\\n\\n // Update the parent.\\n courts[_parent].children.push(courtID);\\n emit CourtCreated(\\n courtID,\\n _parent,\\n _hiddenVotes,\\n _minStake,\\n _alpha,\\n _feeForJuror,\\n _jurorsForCourtJump,\\n _timesPerPeriod,\\n _supportedDisputeKits\\n );\\n }\\n\\n function changeCourtParameters(\\n uint96 _courtID,\\n bool _hiddenVotes,\\n uint256 _minStake,\\n uint256 _alpha,\\n uint256 _feeForJuror,\\n uint256 _jurorsForCourtJump,\\n uint256[4] memory _timesPerPeriod\\n ) external onlyByGovernor {\\n Court storage court = courts[_courtID];\\n if (_courtID != GENERAL_COURT && courts[court.parent].minStake > _minStake) {\\n revert MinStakeLowerThanParentCourt();\\n }\\n for (uint256 i = 0; i < court.children.length; i++) {\\n if (courts[court.children[i]].minStake < _minStake) {\\n revert MinStakeLowerThanParentCourt();\\n }\\n }\\n court.minStake = _minStake;\\n court.hiddenVotes = _hiddenVotes;\\n court.alpha = _alpha;\\n court.feeForJuror = _feeForJuror;\\n court.jurorsForCourtJump = _jurorsForCourtJump;\\n court.timesPerPeriod = _timesPerPeriod;\\n emit CourtModified(\\n _courtID,\\n _hiddenVotes,\\n _minStake,\\n _alpha,\\n _feeForJuror,\\n _jurorsForCourtJump,\\n _timesPerPeriod\\n );\\n }\\n\\n /// @dev Adds/removes court's support for specified dispute kits.\\n /// @param _courtID The ID of the court.\\n /// @param _disputeKitIDs The IDs of dispute kits which support should be added/removed.\\n /// @param _enable Whether add or remove the dispute kits from the court.\\n function enableDisputeKits(uint96 _courtID, uint256[] memory _disputeKitIDs, bool _enable) external onlyByGovernor {\\n for (uint256 i = 0; i < _disputeKitIDs.length; i++) {\\n if (_enable) {\\n if (_disputeKitIDs[i] == 0 || _disputeKitIDs[i] >= disputeKits.length) {\\n revert WrongDisputeKitIndex();\\n }\\n _enableDisputeKit(_courtID, _disputeKitIDs[i], true);\\n } else {\\n // Classic dispute kit must be supported by all courts.\\n if (_disputeKitIDs[i] == DISPUTE_KIT_CLASSIC) {\\n revert CannotDisableClassicDK();\\n }\\n _enableDisputeKit(_courtID, _disputeKitIDs[i], false);\\n }\\n }\\n }\\n\\n /// @dev Changes the supported fee tokens.\\n /// @param _feeToken The fee token.\\n /// @param _accepted Whether the token is supported or not as a method of fee payment.\\n function changeAcceptedFeeTokens(IERC20 _feeToken, bool _accepted) external onlyByGovernor {\\n currencyRates[_feeToken].feePaymentAccepted = _accepted;\\n emit AcceptedFeeToken(_feeToken, _accepted);\\n }\\n\\n /// @dev Changes the currency rate of a fee token.\\n /// @param _feeToken The fee token.\\n /// @param _rateInEth The new rate of the fee token in ETH.\\n /// @param _rateDecimals The new decimals of the fee token rate.\\n function changeCurrencyRates(IERC20 _feeToken, uint64 _rateInEth, uint8 _rateDecimals) external onlyByGovernor {\\n currencyRates[_feeToken].rateInEth = _rateInEth;\\n currencyRates[_feeToken].rateDecimals = _rateDecimals;\\n emit NewCurrencyRate(_feeToken, _rateInEth, _rateDecimals);\\n }\\n\\n // ************************************* //\\n // * State Modifiers * //\\n // ************************************* //\\n\\n /// @dev Sets the caller's stake in a court.\\n /// @param _courtID The ID of the court.\\n /// @param _newStake The new stake.\\n /// Note that the existing delayed stake will be nullified as non-relevant.\\n function setStake(uint96 _courtID, uint256 _newStake) external {\\n _setStake(msg.sender, _courtID, _newStake, false, OnError.Revert);\\n }\\n\\n /// @dev Sets the stake of a specified account in a court, typically to apply a delayed stake or unstake inactive jurors.\\n /// @param _account The account whose stake is being set.\\n /// @param _courtID The ID of the court.\\n /// @param _newStake The new stake.\\n /// @param _alreadyTransferred Whether the PNKs have already been transferred to the contract.\\n function setStakeBySortitionModule(\\n address _account,\\n uint96 _courtID,\\n uint256 _newStake,\\n bool _alreadyTransferred\\n ) external {\\n if (msg.sender != address(sortitionModule)) revert SortitionModuleOnly();\\n _setStake(_account, _courtID, _newStake, _alreadyTransferred, OnError.Return);\\n }\\n\\n /// @inheritdoc IArbitratorV2\\n function createDispute(\\n uint256 _numberOfChoices,\\n bytes memory _extraData\\n ) external payable override returns (uint256 disputeID) {\\n if (msg.value < arbitrationCost(_extraData)) revert ArbitrationFeesNotEnough();\\n\\n return _createDispute(_numberOfChoices, _extraData, NATIVE_CURRENCY, msg.value);\\n }\\n\\n /// @inheritdoc IArbitratorV2\\n function createDispute(\\n uint256 _numberOfChoices,\\n bytes calldata _extraData,\\n IERC20 _feeToken,\\n uint256 _feeAmount\\n ) external override returns (uint256 disputeID) {\\n if (!currencyRates[_feeToken].feePaymentAccepted) revert TokenNotAccepted();\\n if (_feeAmount < arbitrationCost(_extraData, _feeToken)) revert ArbitrationFeesNotEnough();\\n\\n if (!_feeToken.safeTransferFrom(msg.sender, address(this), _feeAmount)) revert TransferFailed();\\n return _createDispute(_numberOfChoices, _extraData, _feeToken, _feeAmount);\\n }\\n\\n function _createDispute(\\n uint256 _numberOfChoices,\\n bytes memory _extraData,\\n IERC20 _feeToken,\\n uint256 _feeAmount\\n ) internal returns (uint256 disputeID) {\\n (uint96 courtID, , uint256 disputeKitID) = _extraDataToCourtIDMinJurorsDisputeKit(_extraData);\\n if (!courts[courtID].supportedDisputeKits[disputeKitID]) revert DisputeKitNotSupportedByCourt();\\n\\n disputeID = disputes.length;\\n Dispute storage dispute = disputes.push();\\n dispute.courtID = courtID;\\n dispute.arbitrated = IArbitrableV2(msg.sender);\\n dispute.lastPeriodChange = block.timestamp;\\n\\n IDisputeKit disputeKit = disputeKits[disputeKitID];\\n Court storage court = courts[courtID];\\n Round storage round = dispute.rounds.push();\\n\\n // Obtain the feeForJuror in the same currency as the _feeAmount\\n uint256 feeForJuror = (_feeToken == NATIVE_CURRENCY)\\n ? court.feeForJuror\\n : convertEthToTokenAmount(_feeToken, court.feeForJuror);\\n round.nbVotes = _feeAmount / feeForJuror;\\n round.disputeKitID = disputeKitID;\\n round.pnkAtStakePerJuror = (court.minStake * court.alpha) / ALPHA_DIVISOR;\\n round.totalFeesForJurors = _feeAmount;\\n round.feeToken = IERC20(_feeToken);\\n\\n sortitionModule.createDisputeHook(disputeID, 0); // Default round ID.\\n\\n disputeKit.createDispute(disputeID, _numberOfChoices, _extraData, round.nbVotes);\\n emit DisputeCreation(disputeID, IArbitrableV2(msg.sender));\\n }\\n\\n /// @dev Passes the period of a specified dispute.\\n /// @param _disputeID The ID of the dispute.\\n function passPeriod(uint256 _disputeID) external {\\n Dispute storage dispute = disputes[_disputeID];\\n Court storage court = courts[dispute.courtID];\\n\\n uint256 currentRound = dispute.rounds.length - 1;\\n Round storage round = dispute.rounds[currentRound];\\n if (dispute.period == Period.evidence) {\\n if (\\n currentRound == 0 &&\\n block.timestamp - dispute.lastPeriodChange < court.timesPerPeriod[uint256(dispute.period)]\\n ) {\\n revert EvidenceNotPassedAndNotAppeal();\\n }\\n if (round.drawnJurors.length != round.nbVotes) revert DisputeStillDrawing();\\n dispute.period = court.hiddenVotes ? Period.commit : Period.vote;\\n } else if (dispute.period == Period.commit) {\\n if (\\n block.timestamp - dispute.lastPeriodChange < court.timesPerPeriod[uint256(dispute.period)] &&\\n !disputeKits[round.disputeKitID].areCommitsAllCast(_disputeID)\\n ) {\\n revert CommitPeriodNotPassed();\\n }\\n dispute.period = Period.vote;\\n } else if (dispute.period == Period.vote) {\\n if (\\n block.timestamp - dispute.lastPeriodChange < court.timesPerPeriod[uint256(dispute.period)] &&\\n !disputeKits[round.disputeKitID].areVotesAllCast(_disputeID)\\n ) {\\n revert VotePeriodNotPassed();\\n }\\n dispute.period = Period.appeal;\\n emit AppealPossible(_disputeID, dispute.arbitrated);\\n } else if (dispute.period == Period.appeal) {\\n if (block.timestamp - dispute.lastPeriodChange < court.timesPerPeriod[uint256(dispute.period)]) {\\n revert AppealPeriodNotPassed();\\n }\\n dispute.period = Period.execution;\\n } else if (dispute.period == Period.execution) {\\n revert DisputePeriodIsFinal();\\n }\\n\\n dispute.lastPeriodChange = block.timestamp;\\n emit NewPeriod(_disputeID, dispute.period);\\n }\\n\\n /// @dev Draws one juror for the dispute until the number votes paid for is reached.\\n /// @param _disputeID The ID of the dispute.\\n /// @param _juror The address of the juror to draw.\\n function draw(uint256 _disputeID, address _juror) external onlyByGovernorOrInstructor {\\n Dispute storage dispute = disputes[_disputeID];\\n uint256 currentRound = dispute.rounds.length - 1;\\n Round storage round = dispute.rounds[currentRound];\\n if (dispute.period != Period.evidence) revert NotEvidencePeriod();\\n if (round.drawnJurors.length >= round.nbVotes) revert AllJurorsDrawn();\\n\\n sortitionModule.setTransientJuror(_juror);\\n {\\n IDisputeKit disputeKit = disputeKits[round.disputeKitID];\\n uint256 iteration = round.drawIterations + 1;\\n address drawnAddress = disputeKit.draw(_disputeID, iteration);\\n if (drawnAddress == address(0)) {\\n revert NoJurorDrawn();\\n }\\n sortitionModule.lockStake(drawnAddress, round.pnkAtStakePerJuror);\\n emit Draw(drawnAddress, _disputeID, currentRound, round.drawnJurors.length);\\n round.drawnJurors.push(drawnAddress);\\n if (round.drawnJurors.length == round.nbVotes) {\\n sortitionModule.postDrawHook(_disputeID, currentRound);\\n }\\n round.drawIterations = iteration;\\n }\\n sortitionModule.setTransientJuror(address(0));\\n }\\n\\n /// @dev Appeals the ruling of a specified dispute.\\n /// Note: Access restricted to the Dispute Kit for this `disputeID`.\\n /// @param _disputeID The ID of the dispute.\\n /// @param _numberOfChoices Number of choices for the dispute. Can be required during court jump.\\n /// @param _extraData Extradata for the dispute. Can be required during court jump.\\n function appeal(uint256 _disputeID, uint256 _numberOfChoices, bytes memory _extraData) external payable {\\n if (msg.value < appealCost(_disputeID)) revert AppealFeesNotEnough();\\n\\n Dispute storage dispute = disputes[_disputeID];\\n if (dispute.period != Period.appeal) revert DisputeNotAppealable();\\n\\n Round storage round = dispute.rounds[dispute.rounds.length - 1];\\n if (msg.sender != address(disputeKits[round.disputeKitID])) revert DisputeKitOnly();\\n\\n uint96 newCourtID = dispute.courtID;\\n uint256 newDisputeKitID = round.disputeKitID;\\n\\n // Warning: the extra round must be created before calling disputeKit.createDispute()\\n Round storage extraRound = dispute.rounds.push();\\n\\n if (round.nbVotes >= courts[newCourtID].jurorsForCourtJump) {\\n // Jump to parent court.\\n newCourtID = courts[newCourtID].parent;\\n\\n if (!courts[newCourtID].supportedDisputeKits[newDisputeKitID]) {\\n // Switch to classic dispute kit if parent court doesn't support the current one.\\n newDisputeKitID = DISPUTE_KIT_CLASSIC;\\n }\\n\\n if (newCourtID != dispute.courtID) {\\n emit CourtJump(_disputeID, dispute.rounds.length - 1, dispute.courtID, newCourtID);\\n }\\n }\\n\\n dispute.courtID = newCourtID;\\n dispute.period = Period.evidence;\\n dispute.lastPeriodChange = block.timestamp;\\n\\n Court storage court = courts[newCourtID];\\n extraRound.nbVotes = msg.value / court.feeForJuror; // As many votes that can be afforded by the provided funds.\\n extraRound.pnkAtStakePerJuror = (court.minStake * court.alpha) / ALPHA_DIVISOR;\\n extraRound.totalFeesForJurors = msg.value;\\n extraRound.disputeKitID = newDisputeKitID;\\n\\n sortitionModule.createDisputeHook(_disputeID, dispute.rounds.length - 1);\\n\\n // Dispute kit was changed, so create a dispute in the new DK contract.\\n if (extraRound.disputeKitID != round.disputeKitID) {\\n emit DisputeKitJump(_disputeID, dispute.rounds.length - 1, round.disputeKitID, extraRound.disputeKitID);\\n disputeKits[extraRound.disputeKitID].createDispute(\\n _disputeID,\\n _numberOfChoices,\\n _extraData,\\n extraRound.nbVotes\\n );\\n }\\n\\n emit AppealDecision(_disputeID, dispute.arbitrated);\\n emit NewPeriod(_disputeID, Period.evidence);\\n }\\n\\n /// @dev Distribute the PNKs at stake and the dispute fees for the specific round of the dispute. Can be called in parts.\\n /// @param _disputeID The ID of the dispute.\\n /// @param _round The appeal round.\\n /// @param _iterations The number of iterations to run.\\n function execute(uint256 _disputeID, uint256 _round, uint256 _iterations) external {\\n Round storage round;\\n {\\n Dispute storage dispute = disputes[_disputeID];\\n if (dispute.period != Period.execution) revert NotExecutionPeriod();\\n\\n round = dispute.rounds[_round];\\n } // stack too deep workaround\\n\\n uint256 start = round.repartitions;\\n uint256 end = round.repartitions + _iterations;\\n\\n uint256 pnkPenaltiesInRound = round.pnkPenalties; // Keep in memory to save gas.\\n uint256 numberOfVotesInRound = round.drawnJurors.length;\\n uint256 feePerJurorInRound = round.totalFeesForJurors / numberOfVotesInRound;\\n uint256 pnkAtStakePerJurorInRound = round.pnkAtStakePerJuror;\\n uint256 coherentCount;\\n {\\n IDisputeKit disputeKit = disputeKits[round.disputeKitID];\\n coherentCount = disputeKit.getCoherentCount(_disputeID, _round); // Total number of jurors that are eligible to a reward in this round.\\n } // stack too deep workaround\\n\\n if (coherentCount == 0) {\\n // We loop over the votes once as there are no rewards because it is not a tie and no one in this round is coherent with the final outcome.\\n if (end > numberOfVotesInRound) end = numberOfVotesInRound;\\n } else {\\n // We loop over the votes twice, first to collect the PNK penalties, and second to distribute them as rewards along with arbitration fees.\\n if (end > numberOfVotesInRound * 2) end = numberOfVotesInRound * 2;\\n }\\n round.repartitions = end;\\n\\n for (uint256 i = start; i < end; i++) {\\n if (i < numberOfVotesInRound) {\\n pnkPenaltiesInRound = _executePenalties(\\n ExecuteParams({\\n disputeID: _disputeID,\\n round: _round,\\n coherentCount: coherentCount,\\n numberOfVotesInRound: numberOfVotesInRound,\\n feePerJurorInRound: feePerJurorInRound,\\n pnkAtStakePerJurorInRound: pnkAtStakePerJurorInRound,\\n pnkPenaltiesInRound: pnkPenaltiesInRound,\\n repartition: i\\n })\\n );\\n } else {\\n _executeRewards(\\n ExecuteParams({\\n disputeID: _disputeID,\\n round: _round,\\n coherentCount: coherentCount,\\n numberOfVotesInRound: numberOfVotesInRound,\\n feePerJurorInRound: feePerJurorInRound,\\n pnkAtStakePerJurorInRound: pnkAtStakePerJurorInRound,\\n pnkPenaltiesInRound: pnkPenaltiesInRound,\\n repartition: i\\n })\\n );\\n }\\n }\\n if (round.pnkPenalties != pnkPenaltiesInRound) {\\n round.pnkPenalties = pnkPenaltiesInRound; // Reentrancy risk: breaks Check-Effect-Interact\\n }\\n }\\n\\n /// @dev Distribute the PNKs at stake and the dispute fees for the specific round of the dispute, penalties only.\\n /// @param _params The parameters for the execution, see `ExecuteParams`.\\n /// @return pnkPenaltiesInRoundCache The updated penalties in round cache.\\n function _executePenalties(ExecuteParams memory _params) internal returns (uint256) {\\n Dispute storage dispute = disputes[_params.disputeID];\\n Round storage round = dispute.rounds[_params.round];\\n IDisputeKit disputeKit = disputeKits[round.disputeKitID];\\n\\n // [0, 1] value that determines how coherent the juror was in this round, in basis points.\\n uint256 degreeOfCoherence = disputeKit.getDegreeOfCoherence(\\n _params.disputeID,\\n _params.round,\\n _params.repartition,\\n _params.feePerJurorInRound,\\n _params.pnkAtStakePerJurorInRound\\n );\\n if (degreeOfCoherence > ALPHA_DIVISOR) {\\n // Make sure the degree doesn't exceed 1, though it should be ensured by the dispute kit.\\n degreeOfCoherence = ALPHA_DIVISOR;\\n }\\n\\n // Fully coherent jurors won't be penalized.\\n uint256 penalty = (round.pnkAtStakePerJuror * (ALPHA_DIVISOR - degreeOfCoherence)) / ALPHA_DIVISOR;\\n _params.pnkPenaltiesInRound += penalty;\\n\\n // Unlock the PNKs affected by the penalty\\n address account = round.drawnJurors[_params.repartition];\\n sortitionModule.unlockStake(account, penalty);\\n\\n // Apply the penalty to the staked PNKs.\\n sortitionModule.penalizeStake(account, penalty);\\n emit TokenAndETHShift(\\n account,\\n _params.disputeID,\\n _params.round,\\n degreeOfCoherence,\\n -int256(penalty),\\n 0,\\n round.feeToken\\n );\\n\\n if (!disputeKit.isVoteActive(_params.disputeID, _params.round, _params.repartition)) {\\n // The juror is inactive, unstake them.\\n sortitionModule.setJurorInactive(account);\\n }\\n if (_params.repartition == _params.numberOfVotesInRound - 1 && _params.coherentCount == 0) {\\n // No one was coherent, send the rewards to the governor.\\n if (round.feeToken == NATIVE_CURRENCY) {\\n // The dispute fees were paid in ETH\\n payable(governor).send(round.totalFeesForJurors);\\n } else {\\n // The dispute fees were paid in ERC20\\n round.feeToken.safeTransfer(governor, round.totalFeesForJurors);\\n }\\n pinakion.safeTransfer(governor, _params.pnkPenaltiesInRound);\\n emit LeftoverRewardSent(\\n _params.disputeID,\\n _params.round,\\n _params.pnkPenaltiesInRound,\\n round.totalFeesForJurors,\\n round.feeToken\\n );\\n }\\n return _params.pnkPenaltiesInRound;\\n }\\n\\n /// @dev Distribute the PNKs at stake and the dispute fees for the specific round of the dispute, rewards only.\\n /// @param _params The parameters for the execution, see `ExecuteParams`.\\n function _executeRewards(ExecuteParams memory _params) internal {\\n Dispute storage dispute = disputes[_params.disputeID];\\n Round storage round = dispute.rounds[_params.round];\\n IDisputeKit disputeKit = disputeKits[round.disputeKitID];\\n\\n // [0, 1] value that determines how coherent the juror was in this round, in basis points.\\n uint256 degreeOfCoherence = disputeKit.getDegreeOfCoherence(\\n _params.disputeID,\\n _params.round,\\n _params.repartition % _params.numberOfVotesInRound,\\n _params.feePerJurorInRound,\\n _params.pnkAtStakePerJurorInRound\\n );\\n\\n // Make sure the degree doesn't exceed 1, though it should be ensured by the dispute kit.\\n if (degreeOfCoherence > ALPHA_DIVISOR) {\\n degreeOfCoherence = ALPHA_DIVISOR;\\n }\\n\\n address account = round.drawnJurors[_params.repartition % _params.numberOfVotesInRound];\\n uint256 pnkLocked = (round.pnkAtStakePerJuror * degreeOfCoherence) / ALPHA_DIVISOR;\\n\\n // Release the rest of the PNKs of the juror for this round.\\n sortitionModule.unlockStake(account, pnkLocked);\\n\\n // Give back the locked PNKs in case the juror fully unstaked earlier.\\n if (!sortitionModule.isJurorStaked(account)) {\\n pinakion.safeTransfer(account, pnkLocked);\\n }\\n\\n // Transfer the rewards\\n uint256 pnkReward = ((_params.pnkPenaltiesInRound / _params.coherentCount) * degreeOfCoherence) / ALPHA_DIVISOR;\\n round.sumPnkRewardPaid += pnkReward;\\n uint256 feeReward = ((round.totalFeesForJurors / _params.coherentCount) * degreeOfCoherence) / ALPHA_DIVISOR;\\n round.sumFeeRewardPaid += feeReward;\\n pinakion.safeTransfer(account, pnkReward);\\n if (round.feeToken == NATIVE_CURRENCY) {\\n // The dispute fees were paid in ETH\\n payable(account).send(feeReward);\\n } else {\\n // The dispute fees were paid in ERC20\\n round.feeToken.safeTransfer(account, feeReward);\\n }\\n emit TokenAndETHShift(\\n account,\\n _params.disputeID,\\n _params.round,\\n degreeOfCoherence,\\n int256(pnkReward),\\n int256(feeReward),\\n round.feeToken\\n );\\n\\n // Transfer any residual rewards to the governor. It may happen due to partial coherence of the jurors.\\n if (_params.repartition == _params.numberOfVotesInRound * 2 - 1) {\\n uint256 leftoverPnkReward = _params.pnkPenaltiesInRound - round.sumPnkRewardPaid;\\n uint256 leftoverFeeReward = round.totalFeesForJurors - round.sumFeeRewardPaid;\\n if (leftoverPnkReward != 0 || leftoverFeeReward != 0) {\\n if (leftoverPnkReward != 0) {\\n pinakion.safeTransfer(governor, leftoverPnkReward);\\n }\\n if (leftoverFeeReward != 0) {\\n if (round.feeToken == NATIVE_CURRENCY) {\\n // The dispute fees were paid in ETH\\n payable(governor).send(leftoverFeeReward);\\n } else {\\n // The dispute fees were paid in ERC20\\n round.feeToken.safeTransfer(governor, leftoverFeeReward);\\n }\\n }\\n emit LeftoverRewardSent(\\n _params.disputeID,\\n _params.round,\\n leftoverPnkReward,\\n leftoverFeeReward,\\n round.feeToken\\n );\\n }\\n }\\n }\\n\\n /// @dev Executes a specified dispute's ruling.\\n /// @param _disputeID The ID of the dispute.\\n function executeRuling(uint256 _disputeID) external {\\n Dispute storage dispute = disputes[_disputeID];\\n if (dispute.period != Period.execution) revert NotExecutionPeriod();\\n if (dispute.ruled) revert RulingAlreadyExecuted();\\n\\n (uint256 winningChoice, , ) = currentRuling(_disputeID);\\n dispute.ruled = true;\\n emit Ruling(dispute.arbitrated, _disputeID, winningChoice);\\n dispute.arbitrated.rule(_disputeID, winningChoice);\\n }\\n\\n // ************************************* //\\n // * Public Views * //\\n // ************************************* //\\n\\n /// @dev Compute the cost of arbitration denominated in ETH.\\n /// It is recommended not to increase it often, as it can be highly time and gas consuming for the arbitrated contracts to cope with fee augmentation.\\n /// @param _extraData Additional info about the dispute. We use it to pass the ID of the dispute's court (first 32 bytes), the minimum number of jurors required (next 32 bytes) and the ID of the specific dispute kit (last 32 bytes).\\n /// @return cost The arbitration cost in ETH.\\n function arbitrationCost(bytes memory _extraData) public view override returns (uint256 cost) {\\n (uint96 courtID, uint256 minJurors, ) = _extraDataToCourtIDMinJurorsDisputeKit(_extraData);\\n cost = courts[courtID].feeForJuror * minJurors;\\n }\\n\\n /// @dev Compute the cost of arbitration denominated in `_feeToken`.\\n /// It is recommended not to increase it often, as it can be highly time and gas consuming for the arbitrated contracts to cope with fee augmentation.\\n /// @param _extraData Additional info about the dispute. We use it to pass the ID of the dispute's court (first 32 bytes), the minimum number of jurors required (next 32 bytes) and the ID of the specific dispute kit (last 32 bytes).\\n /// @param _feeToken The ERC20 token used to pay fees.\\n /// @return cost The arbitration cost in `_feeToken`.\\n function arbitrationCost(bytes calldata _extraData, IERC20 _feeToken) public view override returns (uint256 cost) {\\n cost = convertEthToTokenAmount(_feeToken, arbitrationCost(_extraData));\\n }\\n\\n /// @dev Gets the cost of appealing a specified dispute.\\n /// @param _disputeID The ID of the dispute.\\n /// @return cost The appeal cost.\\n function appealCost(uint256 _disputeID) public view returns (uint256 cost) {\\n Dispute storage dispute = disputes[_disputeID];\\n Round storage round = dispute.rounds[dispute.rounds.length - 1];\\n Court storage court = courts[dispute.courtID];\\n if (round.nbVotes >= court.jurorsForCourtJump) {\\n // Jump to parent court.\\n if (dispute.courtID == GENERAL_COURT) {\\n // TODO: Handle the forking when appealed in General court.\\n cost = NON_PAYABLE_AMOUNT; // Get the cost of the parent court.\\n } else {\\n cost = courts[court.parent].feeForJuror * ((round.nbVotes * 2) + 1);\\n }\\n } else {\\n // Stay in current court.\\n cost = court.feeForJuror * ((round.nbVotes * 2) + 1);\\n }\\n }\\n\\n /// @dev Gets the start and the end of a specified dispute's current appeal period.\\n /// @param _disputeID The ID of the dispute.\\n /// @return start The start of the appeal period.\\n /// @return end The end of the appeal period.\\n function appealPeriod(uint256 _disputeID) public view returns (uint256 start, uint256 end) {\\n Dispute storage dispute = disputes[_disputeID];\\n if (dispute.period == Period.appeal) {\\n start = dispute.lastPeriodChange;\\n end = dispute.lastPeriodChange + courts[dispute.courtID].timesPerPeriod[uint256(Period.appeal)];\\n } else {\\n start = 0;\\n end = 0;\\n }\\n }\\n\\n /// @dev Gets the current ruling of a specified dispute.\\n /// @param _disputeID The ID of the dispute.\\n /// @return ruling The current ruling.\\n /// @return tied Whether it's a tie or not.\\n /// @return overridden Whether the ruling was overridden by appeal funding or not.\\n function currentRuling(uint256 _disputeID) public view returns (uint256 ruling, bool tied, bool overridden) {\\n Dispute storage dispute = disputes[_disputeID];\\n Round storage round = dispute.rounds[dispute.rounds.length - 1];\\n IDisputeKit disputeKit = disputeKits[round.disputeKitID];\\n (ruling, tied, overridden) = disputeKit.currentRuling(_disputeID);\\n }\\n\\n function getRoundInfo(uint256 _disputeID, uint256 _round) external view returns (Round memory) {\\n return disputes[_disputeID].rounds[_round];\\n }\\n\\n function getNumberOfRounds(uint256 _disputeID) external view returns (uint256) {\\n return disputes[_disputeID].rounds.length;\\n }\\n\\n function isSupported(uint96 _courtID, uint256 _disputeKitID) external view returns (bool) {\\n return courts[_courtID].supportedDisputeKits[_disputeKitID];\\n }\\n\\n /// @dev Gets the timesPerPeriod array for a given court.\\n /// @param _courtID The ID of the court to get the times from.\\n /// @return timesPerPeriod The timesPerPeriod array for the given court.\\n function getTimesPerPeriod(uint96 _courtID) external view returns (uint256[4] memory timesPerPeriod) {\\n timesPerPeriod = courts[_courtID].timesPerPeriod;\\n }\\n\\n // ************************************* //\\n // * Public Views for Dispute Kits * //\\n // ************************************* //\\n\\n /// @dev Gets the number of votes permitted for the specified dispute in the latest round.\\n /// @param _disputeID The ID of the dispute.\\n function getNumberOfVotes(uint256 _disputeID) external view returns (uint256) {\\n Dispute storage dispute = disputes[_disputeID];\\n return dispute.rounds[dispute.rounds.length - 1].nbVotes;\\n }\\n\\n /// @dev Returns true if the dispute kit will be switched to a parent DK.\\n /// @param _disputeID The ID of the dispute.\\n /// @return Whether DK will be switched or not.\\n function isDisputeKitJumping(uint256 _disputeID) external view returns (bool) {\\n Dispute storage dispute = disputes[_disputeID];\\n Round storage round = dispute.rounds[dispute.rounds.length - 1];\\n Court storage court = courts[dispute.courtID];\\n\\n if (round.nbVotes < court.jurorsForCourtJump) {\\n return false;\\n }\\n\\n // Jump if the parent court doesn't support the current DK.\\n return !courts[court.parent].supportedDisputeKits[round.disputeKitID];\\n }\\n\\n function getDisputeKitsLength() external view returns (uint256) {\\n return disputeKits.length;\\n }\\n\\n function convertEthToTokenAmount(IERC20 _toToken, uint256 _amountInEth) public view returns (uint256) {\\n return (_amountInEth * 10 ** currencyRates[_toToken].rateDecimals) / currencyRates[_toToken].rateInEth;\\n }\\n\\n // ************************************* //\\n // * Internal * //\\n // ************************************* //\\n\\n /// @dev Toggles the dispute kit support for a given court.\\n /// @param _courtID The ID of the court to toggle the support for.\\n /// @param _disputeKitID The ID of the dispute kit to toggle the support for.\\n /// @param _enable Whether to enable or disable the support. Note that classic dispute kit should always be enabled.\\n function _enableDisputeKit(uint96 _courtID, uint256 _disputeKitID, bool _enable) internal {\\n courts[_courtID].supportedDisputeKits[_disputeKitID] = _enable;\\n emit DisputeKitEnabled(_courtID, _disputeKitID, _enable);\\n }\\n\\n /// @dev If called only once then set _onError to Revert, otherwise set it to Return\\n /// @param _account The account to set the stake for.\\n /// @param _courtID The ID of the court to set the stake for.\\n /// @param _newStake The new stake.\\n /// @param _alreadyTransferred Whether the PNKs were already transferred to/from the staking contract.\\n /// @param _onError Whether to revert or return false on error.\\n /// @return Whether the stake was successfully set or not.\\n function _setStake(\\n address _account,\\n uint96 _courtID,\\n uint256 _newStake,\\n bool _alreadyTransferred,\\n OnError _onError\\n ) internal returns (bool) {\\n if (_courtID == FORKING_COURT || _courtID > courts.length) {\\n _stakingFailed(_onError, StakingResult.CannotStakeInThisCourt); // Staking directly into the forking court is not allowed.\\n return false;\\n }\\n if (_newStake != 0 && _newStake < courts[_courtID].minStake) {\\n _stakingFailed(_onError, StakingResult.CannotStakeLessThanMinStake); // Staking less than the minimum stake is not allowed.\\n return false;\\n }\\n (uint256 pnkDeposit, uint256 pnkWithdrawal, StakingResult stakingResult) = sortitionModule.setStake(\\n _account,\\n _courtID,\\n _newStake,\\n _alreadyTransferred\\n );\\n if (stakingResult != StakingResult.Successful) {\\n _stakingFailed(_onError, stakingResult);\\n return false;\\n }\\n if (pnkDeposit > 0) {\\n if (!pinakion.safeTransferFrom(_account, address(this), pnkDeposit)) {\\n _stakingFailed(_onError, StakingResult.StakingTransferFailed);\\n return false;\\n }\\n }\\n if (pnkWithdrawal > 0) {\\n if (!pinakion.safeTransfer(_account, pnkWithdrawal)) {\\n _stakingFailed(_onError, StakingResult.UnstakingTransferFailed);\\n return false;\\n }\\n }\\n return true;\\n }\\n\\n /// @dev It may revert depending on the _onError parameter.\\n function _stakingFailed(OnError _onError, StakingResult _result) internal pure virtual {\\n if (_onError == OnError.Return) return;\\n if (_result == StakingResult.StakingTransferFailed) revert StakingTransferFailed();\\n if (_result == StakingResult.UnstakingTransferFailed) revert UnstakingTransferFailed();\\n if (_result == StakingResult.CannotStakeInMoreCourts) revert StakingInTooManyCourts();\\n if (_result == StakingResult.CannotStakeInThisCourt) revert StakingNotPossibeInThisCourt();\\n if (_result == StakingResult.CannotStakeLessThanMinStake) revert StakingLessThanCourtMinStake();\\n }\\n\\n /// @dev Gets a court ID, the minimum number of jurors and an ID of a dispute kit from a specified extra data bytes array.\\n /// Note that if extradata contains an incorrect value then this value will be switched to default.\\n /// @param _extraData The extra data bytes array. The first 32 bytes are the court ID, the next are the minimum number of jurors and the last are the dispute kit ID.\\n /// @return courtID The court ID.\\n /// @return minJurors The minimum number of jurors required.\\n /// @return disputeKitID The ID of the dispute kit.\\n function _extraDataToCourtIDMinJurorsDisputeKit(\\n bytes memory _extraData\\n ) internal view returns (uint96 courtID, uint256 minJurors, uint256 disputeKitID) {\\n // Note that if the extradata doesn't contain 32 bytes for the dispute kit ID it'll return the default 0 index.\\n if (_extraData.length >= 64) {\\n assembly {\\n // solium-disable-line security/no-inline-assembly\\n courtID := mload(add(_extraData, 0x20))\\n minJurors := mload(add(_extraData, 0x40))\\n disputeKitID := mload(add(_extraData, 0x60))\\n }\\n if (courtID == FORKING_COURT || courtID >= courts.length) {\\n courtID = GENERAL_COURT;\\n }\\n if (minJurors == 0) {\\n minJurors = DEFAULT_NB_OF_JURORS;\\n }\\n if (disputeKitID == NULL_DISPUTE_KIT || disputeKitID >= disputeKits.length) {\\n disputeKitID = DISPUTE_KIT_CLASSIC; // 0 index is not used.\\n }\\n } else {\\n courtID = GENERAL_COURT;\\n minJurors = DEFAULT_NB_OF_JURORS;\\n disputeKitID = DISPUTE_KIT_CLASSIC;\\n }\\n }\\n\\n // ************************************* //\\n // * Errors * //\\n // ************************************* //\\n\\n error GovernorOnly();\\n error InstructorOnly();\\n error GovernorOrInstructorOnly();\\n error DisputeKitOnly();\\n error SortitionModuleOnly();\\n error UnsuccessfulCall();\\n error InvalidDisputKitParent();\\n error DepthLevelMax();\\n error MinStakeLowerThanParentCourt();\\n error UnsupportedDisputeKit();\\n error InvalidForkingCourtAsParent();\\n error WrongDisputeKitIndex();\\n error CannotDisableClassicDK();\\n error ArraysLengthMismatch();\\n error StakingInTooManyCourts();\\n error StakingNotPossibeInThisCourt();\\n error StakingLessThanCourtMinStake();\\n error StakingTransferFailed();\\n error UnstakingTransferFailed();\\n error ArbitrationFeesNotEnough();\\n error DisputeKitNotSupportedByCourt();\\n error MustSupportDisputeKitClassic();\\n error TokenNotAccepted();\\n error EvidenceNotPassedAndNotAppeal();\\n error DisputeStillDrawing();\\n error CommitPeriodNotPassed();\\n error VotePeriodNotPassed();\\n error AppealPeriodNotPassed();\\n error NotEvidencePeriod();\\n error AppealFeesNotEnough();\\n error DisputeNotAppealable();\\n error NotExecutionPeriod();\\n error RulingAlreadyExecuted();\\n error DisputePeriodIsFinal();\\n error TransferFailed();\\n error AllJurorsDrawn();\\n error NoJurorDrawn();\\n}\\n\",\"keccak256\":\"0xd636c2294d15110a20dcf97d67f2989e14233cd1de353032807ad44a8e828e49\",\"license\":\"MIT\"},\"src/arbitration/university/SortitionModuleUniversity.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\n/**\\n * @custom:authors: [@epiqueras, @unknownunknown1, @jaybuidl, @shotaronowhere]\\n * @custom:reviewers: []\\n * @custom:auditors: []\\n * @custom:bounties: []\\n * @custom:deployments: []\\n */\\n\\npragma solidity 0.8.24;\\n\\nimport \\\"./KlerosCoreUniversity.sol\\\";\\nimport \\\"./ISortitionModuleUniversity.sol\\\";\\nimport \\\"../interfaces/IDisputeKit.sol\\\";\\nimport \\\"../../proxy/UUPSProxiable.sol\\\";\\nimport \\\"../../proxy/Initializable.sol\\\";\\nimport \\\"../../libraries/Constants.sol\\\";\\n\\n/// @title SortitionModuleUniversity\\n/// @dev An adapted version of the SortitionModule contract for educational purposes.\\ncontract SortitionModuleUniversity is ISortitionModuleUniversity, UUPSProxiable, Initializable {\\n // ************************************* //\\n // * Enums / Structs * //\\n // ************************************* //\\n\\n struct Juror {\\n mapping(uint96 => uint256) stakesByCourtID; // The stakes of the juror in particular courts.\\n uint96[] courtIDs; // The IDs of courts where the juror's stake path ends. A stake path is a path from the general court to a court the juror directly staked in using `_setStake`.\\n uint256 stakedPnk; // The juror's total amount of tokens staked in subcourts. Reflects actual pnk balance.\\n uint256 lockedPnk; // The juror's total amount of tokens locked in disputes. Can reflect actual pnk balance when stakedPnk are fully withdrawn.\\n }\\n\\n // ************************************* //\\n // * Storage * //\\n // ************************************* //\\n\\n address public governor; // The governor of the contract.\\n KlerosCoreUniversity public core; // The core arbitrator contract.\\n uint256 public disputesWithoutJurors; // The number of disputes that have not finished drawing jurors.\\n mapping(address account => Juror) public jurors; // The jurors.\\n address private transientJuror; // The juror address used between calls within the same transaction.\\n\\n // ************************************* //\\n // * Events * //\\n // ************************************* //\\n\\n event StakeSet(address indexed _address, uint256 _courtID, uint256 _amount);\\n event StakeLocked(address indexed _address, uint256 _relativeAmount, bool _unlock);\\n\\n // ************************************* //\\n // * Function Modifiers * //\\n // ************************************* //\\n\\n modifier onlyByGovernor() {\\n require(address(governor) == msg.sender, \\\"Access not allowed: Governor only.\\\");\\n _;\\n }\\n\\n modifier onlyByCore() {\\n require(address(core) == msg.sender, \\\"Access not allowed: KlerosCore only.\\\");\\n _;\\n }\\n\\n // ************************************* //\\n // * Constructor * //\\n // ************************************* //\\n\\n /// @dev Constructor, initializing the implementation to reduce attack surface.\\n constructor() {\\n _disableInitializers();\\n }\\n\\n /// @dev Initializer (constructor equivalent for upgradable contracts).\\n /// @param _core The KlerosCore.\\n function initialize(address _governor, KlerosCoreUniversity _core) external reinitializer(1) {\\n governor = _governor;\\n core = _core;\\n }\\n\\n // ************************************* //\\n // * Governance * //\\n // ************************************* //\\n\\n /**\\n * @dev Access Control to perform implementation upgrades (UUPS Proxiable)\\n * @dev Only the governor can perform upgrades (`onlyByGovernor`)\\n */\\n function _authorizeUpgrade(address) internal view override onlyByGovernor {\\n // NOP\\n }\\n\\n // ************************************* //\\n // * State Modifiers * //\\n // ************************************* //\\n\\n function setTransientJuror(address _juror) external override onlyByCore {\\n transientJuror = _juror;\\n }\\n\\n function createTree(bytes32 _key, bytes memory _extraData) external {\\n // NOP\\n }\\n\\n function createDisputeHook(uint256 /*_disputeID*/, uint256 /*_roundID*/) external override onlyByCore {\\n disputesWithoutJurors++;\\n }\\n\\n function postDrawHook(uint256 /*_disputeID*/, uint256 /*_roundID*/) external override onlyByCore {\\n disputesWithoutJurors--;\\n }\\n\\n /// @dev Saves the random number to use it in sortition. Not used by this contract because the storing of the number is inlined in passPhase().\\n /// @param _randomNumber Random number returned by RNG contract.\\n function notifyRandomNumber(uint256 _randomNumber) public override {}\\n\\n /// @dev Sets the specified juror's stake in a court.\\n /// `O(n + p * log_k(j))` where\\n /// `n` is the number of courts the juror has staked in,\\n /// `p` is the depth of the court tree,\\n /// `k` is the minimum number of children per node of one of these courts' sortition sum tree,\\n /// and `j` is the maximum number of jurors that ever staked in one of these courts simultaneously.\\n /// @param _account The address of the juror.\\n /// @param _courtID The ID of the court.\\n /// @param _newStake The new stake.\\n /// @param _alreadyTransferred True if the tokens were already transferred from juror. Only relevant for delayed stakes.\\n /// @return pnkDeposit The amount of PNK to be deposited.\\n /// @return pnkWithdrawal The amount of PNK to be withdrawn.\\n /// @return stakingResult The result of the staking operation.\\n function setStake(\\n address _account,\\n uint96 _courtID,\\n uint256 _newStake,\\n bool _alreadyTransferred\\n ) external override onlyByCore returns (uint256 pnkDeposit, uint256 pnkWithdrawal, StakingResult stakingResult) {\\n Juror storage juror = jurors[_account];\\n uint256 currentStake = _stakeOf(_account, _courtID);\\n\\n uint256 nbCourts = juror.courtIDs.length;\\n if (_newStake == 0 && (nbCourts >= MAX_STAKE_PATHS || currentStake == 0)) {\\n return (0, 0, StakingResult.CannotStakeInMoreCourts); // Prevent staking beyond MAX_STAKE_PATHS but unstaking is always allowed.\\n }\\n\\n if (_newStake >= currentStake) {\\n if (!_alreadyTransferred) {\\n pnkDeposit = _increaseStake(juror, _courtID, _newStake, currentStake);\\n }\\n } else {\\n pnkWithdrawal += _decreaseStake(juror, _courtID, _newStake, currentStake);\\n }\\n\\n bool finished = false;\\n uint96 currentCourtID = _courtID;\\n while (!finished) {\\n // Tokens are also implicitly staked in parent courts through sortition module to increase the chance of being drawn.\\n juror.stakesByCourtID[currentCourtID] += _newStake;\\n juror.stakesByCourtID[currentCourtID] -= currentStake;\\n if (currentCourtID == GENERAL_COURT) {\\n finished = true;\\n } else {\\n (currentCourtID, , , , , , ) = core.courts(currentCourtID);\\n }\\n }\\n emit StakeSet(_account, _courtID, _newStake);\\n return (pnkDeposit, pnkWithdrawal, StakingResult.Successful);\\n }\\n\\n function _increaseStake(\\n Juror storage juror,\\n uint96 _courtID,\\n uint256 _newStake,\\n uint256 _currentStake\\n ) internal returns (uint256 transferredAmount) {\\n // Stake increase\\n // When stakedPnk becomes lower than lockedPnk count the locked tokens in when transferring tokens from juror.\\n // (E.g. stakedPnk = 0, lockedPnk = 150) which can happen if the juror unstaked fully while having some tokens locked.\\n uint256 previouslyLocked = (juror.lockedPnk >= juror.stakedPnk) ? juror.lockedPnk - juror.stakedPnk : 0; // underflow guard\\n transferredAmount = (_newStake >= _currentStake + previouslyLocked) // underflow guard\\n ? _newStake - _currentStake - previouslyLocked\\n : 0;\\n if (_currentStake == 0) {\\n juror.courtIDs.push(_courtID);\\n }\\n // stakedPnk can become async with _currentStake (e.g. after penalty).\\n juror.stakedPnk = (juror.stakedPnk >= _currentStake) ? juror.stakedPnk - _currentStake + _newStake : _newStake;\\n }\\n\\n function _decreaseStake(\\n Juror storage juror,\\n uint96 _courtID,\\n uint256 _newStake,\\n uint256 _currentStake\\n ) internal returns (uint256 transferredAmount) {\\n // Stakes can be partially delayed only when stake is increased.\\n // Stake decrease: make sure locked tokens always stay in the contract. They can only be released during Execution.\\n if (juror.stakedPnk >= _currentStake - _newStake + juror.lockedPnk) {\\n // We have enough pnk staked to afford withdrawal while keeping locked tokens.\\n transferredAmount = _currentStake - _newStake;\\n } else if (juror.stakedPnk >= juror.lockedPnk) {\\n // Can't afford withdrawing the current stake fully. Take whatever is available while keeping locked tokens.\\n transferredAmount = juror.stakedPnk - juror.lockedPnk;\\n }\\n if (_newStake == 0) {\\n for (uint256 i = juror.courtIDs.length; i > 0; i--) {\\n if (juror.courtIDs[i - 1] == _courtID) {\\n juror.courtIDs[i - 1] = juror.courtIDs[juror.courtIDs.length - 1];\\n juror.courtIDs.pop();\\n break;\\n }\\n }\\n }\\n // stakedPnk can become async with _currentStake (e.g. after penalty).\\n juror.stakedPnk = (juror.stakedPnk >= _currentStake) ? juror.stakedPnk - _currentStake + _newStake : _newStake;\\n }\\n\\n function lockStake(address _account, uint256 _relativeAmount) external override onlyByCore {\\n jurors[_account].lockedPnk += _relativeAmount;\\n emit StakeLocked(_account, _relativeAmount, false);\\n }\\n\\n function unlockStake(address _account, uint256 _relativeAmount) external override onlyByCore {\\n jurors[_account].lockedPnk -= _relativeAmount;\\n emit StakeLocked(_account, _relativeAmount, true);\\n }\\n\\n function penalizeStake(address _account, uint256 _relativeAmount) external override onlyByCore {\\n Juror storage juror = jurors[_account];\\n if (juror.stakedPnk >= _relativeAmount) {\\n juror.stakedPnk -= _relativeAmount;\\n } else {\\n juror.stakedPnk = 0; // stakedPnk might become lower after manual unstaking, but lockedPnk will always cover the difference.\\n }\\n }\\n\\n /// @dev Unstakes the inactive juror from all courts.\\n /// `O(n * (p * log_k(j)) )` where\\n /// `n` is the number of courts the juror has staked in,\\n /// `p` is the depth of the court tree,\\n /// `k` is the minimum number of children per node of one of these courts' sortition sum tree,\\n /// and `j` is the maximum number of jurors that ever staked in one of these courts simultaneously.\\n /// @param _account The juror to unstake.\\n function setJurorInactive(address _account) external override onlyByCore {\\n uint96[] memory courtIDs = getJurorCourtIDs(_account);\\n for (uint256 j = courtIDs.length; j > 0; j--) {\\n core.setStakeBySortitionModule(_account, courtIDs[j - 1], 0, false);\\n }\\n }\\n\\n // ************************************* //\\n // * Public Views * //\\n // ************************************* //\\n\\n /// @dev Draw an ID from a tree using a number.\\n /// Note that this function reverts if the sum of all values in the tree is 0.\\n /// @return drawnAddress The drawn address.\\n /// `O(k * log_k(n))` where\\n /// `k` is the maximum number of children per node in the tree,\\n /// and `n` is the maximum number of nodes ever appended.\\n function draw(bytes32, uint256, uint256) public view override returns (address drawnAddress) {\\n drawnAddress = transientJuror;\\n }\\n\\n /// @dev Gets the stake of a juror in a court.\\n /// Warning: `O(n)` complexity where `n` is the number of courts the juror has staked in\\n /// but acceptable for this educational implementation.\\n /// @param _juror The address of the juror.\\n /// @param _courtID The ID of the court.\\n /// @return totalStaked The total amount of tokens staked by the juror in the court.\\n /// @return totalLocked The total amount of tokens locked by the juror in the court.\\n /// @return stakedInCourt The amount of tokens staked by the juror in the court.\\n /// @return nbCourts The number of courts the juror has staked in.\\n function getJurorBalance(\\n address _juror,\\n uint96 _courtID\\n )\\n external\\n view\\n override\\n returns (uint256 totalStaked, uint256 totalLocked, uint256 stakedInCourt, uint256 nbCourts)\\n {\\n Juror storage juror = jurors[_juror];\\n totalStaked = juror.stakedPnk;\\n totalLocked = juror.lockedPnk;\\n nbCourts = juror.courtIDs.length;\\n for (uint256 i = 0; i < nbCourts; i++) {\\n if (juror.courtIDs[i] == _courtID) {\\n stakedInCourt = juror.stakesByCourtID[_courtID];\\n break;\\n }\\n }\\n }\\n\\n /// @dev Gets the court identifiers where a specific `_juror` has staked.\\n /// @param _juror The address of the juror.\\n function getJurorCourtIDs(address _juror) public view override returns (uint96[] memory) {\\n return jurors[_juror].courtIDs;\\n }\\n\\n function isJurorStaked(address _juror) external view override returns (bool) {\\n return jurors[_juror].stakedPnk > 0;\\n }\\n\\n // ************************************* //\\n // * Internal * //\\n // ************************************* //\\n\\n /// @dev Gets the stake of a juror in a court.\\n /// Warning: `O(n)` complexity where `n` is the number of courts the juror has staked in\\n /// but acceptable for this educational implementation.\\n /// @param _juror The address of the juror.\\n /// @param _courtID The ID of the court.\\n /// @return stakedInCourt The amount of tokens staked by the juror in the court.\\n function _stakeOf(address _juror, uint96 _courtID) internal view returns (uint256 stakedInCourt) {\\n Juror storage juror = jurors[_juror];\\n for (uint256 i = 0; i < juror.courtIDs.length; i++) {\\n if (juror.courtIDs[i] == _courtID) {\\n stakedInCourt = juror.stakesByCourtID[_courtID];\\n break;\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x505563930b74c834195c7ae32792ee2b15e6478d404a9ff612133ad23080026b\",\"license\":\"MIT\"},\"src/libraries/Constants.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n// Courts\\nuint96 constant FORKING_COURT = 0; // Index of the forking court.\\nuint96 constant GENERAL_COURT = 1; // Index of the default (general) court.\\n\\n// Dispute Kits\\nuint256 constant NULL_DISPUTE_KIT = 0; // Null pattern to indicate a top-level DK which has no parent.\\nuint256 constant DISPUTE_KIT_CLASSIC = 1; // Index of the default DK. 0 index is skipped.\\n\\n// Sortition Module\\nuint256 constant MAX_STAKE_PATHS = 4; // The maximum number of stake paths a juror can have.\\nuint256 constant DEFAULT_K = 6; // Default number of children per node.\\n\\n// Defaults\\nuint256 constant DEFAULT_NB_OF_JURORS = 3; // The default number of jurors in a dispute.\\nIERC20 constant NATIVE_CURRENCY = IERC20(address(0)); // The native currency, such as ETH on Arbitrum, Optimism and Ethereum L1.\\n\\nenum OnError {\\n Revert,\\n Return\\n}\\n\\nenum StakingResult {\\n Successful,\\n StakingTransferFailed,\\n UnstakingTransferFailed,\\n CannotStakeInMoreCourts,\\n CannotStakeInThisCourt,\\n CannotStakeLessThanMinStake,\\n CannotStakeMoreThanMaxStakePerJuror,\\n CannotStakeMoreThanMaxTotalStaked\\n}\\n\",\"keccak256\":\"0x486016fb74cc91439c2ec918e97a79190ab4eed223987d516986fff8eaeecfbf\",\"license\":\"MIT\"},\"src/libraries/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// Adapted from https://github.com/OpenZeppelin/openzeppelin-contracts/blob/a7a94c77463acea95d979aae1580fb0ddc3b6a1e/contracts/token/ERC20/utils/SafeERC20.sol\\n\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/// @title SafeERC20\\n/// @dev Wrappers around ERC20 operations that throw on failure (when the token\\n/// contract returns false). Tokens that return no value (and instead revert or\\n/// throw on failure) are also supported, non-reverting calls are assumed to be\\n/// successful.\\n/// To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n/// which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\nlibrary SafeERC20 {\\n /// @dev Increases the allowance granted to `spender` by the caller.\\n /// @param _token Token to transfer.\\n /// @param _spender The address which will spend the funds.\\n /// @param _addedValue The amount of tokens to increase the allowance by.\\n function increaseAllowance(IERC20 _token, address _spender, uint256 _addedValue) internal returns (bool) {\\n _token.approve(_spender, _token.allowance(address(this), _spender) + _addedValue);\\n return true;\\n }\\n\\n /// @dev Calls transfer() without reverting.\\n /// @param _token Token to transfer.\\n /// @param _to Recepient address.\\n /// @param _value Amount transferred.\\n /// @return Whether transfer succeeded or not.\\n function safeTransfer(IERC20 _token, address _to, uint256 _value) internal returns (bool) {\\n (bool success, bytes memory data) = address(_token).call(abi.encodeCall(IERC20.transfer, (_to, _value)));\\n return (success && (data.length == 0 || abi.decode(data, (bool))));\\n }\\n\\n /// @dev Calls transferFrom() without reverting.\\n /// @param _token Token to transfer.\\n /// @param _from Sender address.\\n /// @param _to Recepient address.\\n /// @param _value Amount transferred.\\n /// @return Whether transfer succeeded or not.\\n function safeTransferFrom(IERC20 _token, address _from, address _to, uint256 _value) internal returns (bool) {\\n (bool success, bytes memory data) = address(_token).call(\\n abi.encodeCall(IERC20.transferFrom, (_from, _to, _value))\\n );\\n return (success && (data.length == 0 || abi.decode(data, (bool))));\\n }\\n}\\n\",\"keccak256\":\"0x3e39adb9cdd9f86b0defc8f6e1223533d86f82c804e186193f729c32c10161b1\",\"license\":\"MIT\"},\"src/proxy/Initializable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol) \\n\\npragma solidity 0.8.24;\\n\\n/**\\n * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed\\n * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an\\n * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer\\n * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.\\n *\\n * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be\\n * reused. This mechanism prevents re-execution of each \\\"step\\\" but allows the creation of new initialization steps in\\n * case an upgrade adds a module that needs to be initialized.\\n *\\n * For example:\\n *\\n * ```solidity\\n * contract MyToken is ERC20Upgradeable {\\n * function initialize() initializer public {\\n * __ERC20_init(\\\"MyToken\\\", \\\"MTK\\\");\\n * }\\n * }\\n *\\n * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {\\n * function initializeV2() reinitializer(2) public {\\n * __ERC20Permit_init(\\\"MyToken\\\");\\n * }\\n * }\\n * ```\\n *\\n * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as\\n * possible by providing the encoded function call as the `_data` argument to the proxy constructor\\n *\\n * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure\\n * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.\\n *\\n * [CAUTION]\\n * ====\\n * Avoid leaving a contract uninitialized.\\n *\\n * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation\\n * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke\\n * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:\\n *\\n * ```\\n * /// @custom:oz-upgrades-unsafe-allow constructor\\n * constructor() {\\n * _disableInitializers();\\n * }\\n * ```\\n */\\nabstract contract Initializable {\\n /**\\n * @dev Storage of the initializable contract.\\n *\\n * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions\\n * when using with upgradeable contracts.\\n *\\n * @custom:storage-location erc7201:openzeppelin.storage.Initializable\\n */\\n struct InitializableStorage {\\n /**\\n * @dev Indicates that the contract has been initialized.\\n */\\n uint64 _initialized;\\n /**\\n * @dev Indicates that the contract is in the process of being initialized.\\n */\\n bool _initializing;\\n }\\n\\n // keccak256(abi.encode(uint256(keccak256(\\\"openzeppelin.storage.Initializable\\\")) - 1))\\n bytes32 private constant _INITIALIZABLE_STORAGE =\\n 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0e;\\n\\n /**\\n * @dev The contract is already initialized.\\n */\\n error AlreadyInitialized();\\n\\n /**\\n * @dev The contract is not initializing.\\n */\\n error NotInitializing();\\n\\n /**\\n * @dev Triggered when the contract has been initialized or reinitialized.\\n */\\n event Initialized(uint64 version);\\n\\n /**\\n * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,\\n * `onlyInitializing` functions can be used to initialize parent contracts.\\n *\\n * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a\\n * constructor.\\n *\\n * Emits an {Initialized} event.\\n */\\n modifier initializer() {\\n // solhint-disable-next-line var-name-mixedcase\\n InitializableStorage storage $ = _getInitializableStorage();\\n\\n bool isTopLevelCall = !$._initializing;\\n uint64 initialized = $._initialized;\\n if (!(isTopLevelCall && initialized < 1) && !(address(this).code.length == 0 && initialized == 1)) {\\n revert AlreadyInitialized();\\n }\\n $._initialized = 1;\\n if (isTopLevelCall) {\\n $._initializing = true;\\n }\\n _;\\n if (isTopLevelCall) {\\n $._initializing = false;\\n emit Initialized(1);\\n }\\n }\\n\\n /**\\n * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the\\n * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be\\n * used to initialize parent contracts.\\n *\\n * A reinitializer may be used after the original initialization step. This is essential to configure modules that\\n * are added through upgrades and that require initialization.\\n *\\n * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`\\n * cannot be nested. If one is invoked in the context of another, execution will revert.\\n *\\n * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in\\n * a contract, executing them in the right order is up to the developer or operator.\\n *\\n * WARNING: setting the version to 255 will prevent any future reinitialization.\\n *\\n * Emits an {Initialized} event.\\n */\\n modifier reinitializer(uint64 version) {\\n // solhint-disable-next-line var-name-mixedcase\\n InitializableStorage storage $ = _getInitializableStorage();\\n\\n if ($._initializing || $._initialized >= version) {\\n revert AlreadyInitialized();\\n }\\n $._initialized = version;\\n $._initializing = true;\\n _;\\n $._initializing = false;\\n emit Initialized(version);\\n }\\n\\n /**\\n * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the\\n * {initializer} and {reinitializer} modifiers, directly or indirectly.\\n */\\n modifier onlyInitializing() {\\n _checkInitializing();\\n _;\\n }\\n\\n /**\\n * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.\\n */\\n function _checkInitializing() internal view virtual {\\n if (!_isInitializing()) {\\n revert NotInitializing();\\n }\\n }\\n\\n /**\\n * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.\\n * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized\\n * to any version. It is recommended to use this to lock implementation contracts that are designed to be called\\n * through proxies.\\n *\\n * Emits an {Initialized} event the first time it is successfully executed.\\n */\\n function _disableInitializers() internal virtual {\\n // solhint-disable-next-line var-name-mixedcase\\n InitializableStorage storage $ = _getInitializableStorage();\\n\\n if ($._initializing) {\\n revert AlreadyInitialized();\\n }\\n if ($._initialized != type(uint64).max) {\\n $._initialized = type(uint64).max;\\n emit Initialized(type(uint64).max);\\n }\\n }\\n\\n /**\\n * @dev Returns the highest version that has been initialized. See {reinitializer}.\\n */\\n function _getInitializedVersion() internal view returns (uint64) {\\n return _getInitializableStorage()._initialized;\\n }\\n\\n /**\\n * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.\\n */\\n function _isInitializing() internal view returns (bool) {\\n return _getInitializableStorage()._initializing;\\n }\\n\\n /**\\n * @dev Returns a pointer to the storage namespace.\\n */\\n // solhint-disable-next-line var-name-mixedcase\\n function _getInitializableStorage() private pure returns (InitializableStorage storage $) {\\n assembly {\\n $.slot := _INITIALIZABLE_STORAGE\\n }\\n }\\n}\\n\",\"keccak256\":\"0x560ea64115636ecd6b3596248817125551c038ce1648019fde3cbe02d9759a30\",\"license\":\"MIT\"},\"src/proxy/UUPSProxiable.sol\":{\"content\":\"//SPDX-License-Identifier: MIT\\n// Adapted from \\n\\n/**\\n * @authors: [@malatrax]\\n * @reviewers: []\\n * @auditors: []\\n * @bounties: []\\n * @deployments: []\\n */\\npragma solidity 0.8.24;\\n\\n/**\\n * @title UUPS Proxiable\\n * @author Simon Malatrait \\n * @dev This contract implements an upgradeability mechanism designed for UUPS proxies.\\n * The functions included here can perform an upgrade of an UUPS Proxy, when this contract is set as the implementation behind such a proxy.\\n *\\n * IMPORTANT: A UUPS proxy requires its upgradeability functions to be in the implementation as opposed to the transparent proxy.\\n * This means that if the proxy is upgraded to an implementation that does not support this interface, it will no longer be upgradeable.\\n *\\n * A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is\\n * reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing\\n * `UUPSProxiable` with a custom implementation of upgrades.\\n *\\n * The `_authorizeUpgrade` function must be overridden to include access restriction to the upgrade mechanism.\\n */\\nabstract contract UUPSProxiable {\\n // ************************************* //\\n // * Event * //\\n // ************************************* //\\n\\n /**\\n * Emitted when the `implementation` has been successfully upgraded.\\n * @param newImplementation Address of the new implementation the proxy is now forwarding calls to.\\n */\\n event Upgraded(address indexed newImplementation);\\n\\n // ************************************* //\\n // * Error * //\\n // ************************************* //\\n\\n /**\\n * @dev The call is from an unauthorized context.\\n */\\n error UUPSUnauthorizedCallContext();\\n\\n /**\\n * @dev The storage `slot` is unsupported as a UUID.\\n */\\n error UUPSUnsupportedProxiableUUID(bytes32 slot);\\n\\n /// The `implementation` is not UUPS-compliant\\n error InvalidImplementation(address implementation);\\n\\n /// Failed Delegated call\\n error FailedDelegateCall();\\n\\n // ************************************* //\\n // * Storage * //\\n // ************************************* //\\n\\n /**\\n * @dev Storage slot with the address of the current implementation.\\n * This is the keccak-256 hash of \\\"eip1967.proxy.implementation\\\" subtracted by 1, and is\\n * validated in the constructor.\\n * NOTE: bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1)\\n */\\n bytes32 private constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\\n\\n /**\\n * @dev Storage variable of the proxiable contract address.\\n * It is used to check whether or not the current call is from the proxy.\\n */\\n address private immutable __self = address(this);\\n\\n // ************************************* //\\n // * Governance * //\\n // ************************************* //\\n\\n /**\\n * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract.\\n * @dev Called by {upgradeToAndCall}.\\n */\\n function _authorizeUpgrade(address newImplementation) internal virtual;\\n\\n // ************************************* //\\n // * State Modifiers * //\\n // ************************************* //\\n\\n /**\\n * @dev Upgrade mechanism including access control and UUPS-compliance.\\n * @param newImplementation Address of the new implementation contract.\\n * @param data Data used in a delegate call to `newImplementation` if non-empty. This will typically be an encoded\\n * function call, and allows initializing the storage of the proxy like a Solidity constructor.\\n *\\n * @dev Reverts if the execution is not performed via delegatecall or the execution\\n * context is not of a proxy with an ERC1967-compliant implementation pointing to self.\\n */\\n function upgradeToAndCall(address newImplementation, bytes memory data) public payable virtual {\\n _authorizeUpgrade(newImplementation);\\n\\n /* Check that the execution is being performed through a delegatecall call and that the execution context is\\n a proxy contract with an implementation (as defined in ERC1967) pointing to self. */\\n if (address(this) == __self || _getImplementation() != __self) {\\n revert UUPSUnauthorizedCallContext();\\n }\\n\\n try UUPSProxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {\\n if (slot != IMPLEMENTATION_SLOT) {\\n revert UUPSUnsupportedProxiableUUID(slot);\\n }\\n // Store the new implementation address to the implementation storage slot.\\n assembly {\\n sstore(IMPLEMENTATION_SLOT, newImplementation)\\n }\\n emit Upgraded(newImplementation);\\n\\n if (data.length != 0) {\\n // The return data is not checked (checking, in case of success, that the newImplementation code is non-empty if the return data is empty) because the authorized callee is trusted.\\n (bool success, ) = newImplementation.delegatecall(data);\\n if (!success) {\\n revert FailedDelegateCall();\\n }\\n }\\n } catch {\\n revert InvalidImplementation(newImplementation);\\n }\\n }\\n\\n // ************************************* //\\n // * Public Views * //\\n // ************************************* //\\n\\n /**\\n * @dev Implementation of the ERC1822 `proxiableUUID` function. This returns the storage slot used by the\\n * implementation. It is used to validate the implementation's compatibility when performing an upgrade.\\n *\\n * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks\\n * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this\\n * function revert if invoked through a proxy. This is guaranteed by the if statement.\\n */\\n function proxiableUUID() external view virtual returns (bytes32) {\\n if (address(this) != __self) {\\n // Must not be called through delegatecall\\n revert UUPSUnauthorizedCallContext();\\n }\\n return IMPLEMENTATION_SLOT;\\n }\\n\\n // ************************************* //\\n // * Internal Views * //\\n // ************************************* //\\n\\n function _getImplementation() internal view returns (address implementation) {\\n assembly {\\n implementation := sload(IMPLEMENTATION_SLOT)\\n }\\n }\\n}\\n\",\"keccak256\":\"0x5956855046cdda7aa45f44e379ef45323af7266c44c817d1266d8b32d52b0e22\",\"license\":\"MIT\"}},\"version\":1}",
- "bytecode": "0x60a06040523060805234801561001457600080fd5b5061001d610022565b6100d3565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0e805468010000000000000000900460ff16156100715760405162dc149f60e41b815260040160405180910390fd5b80546001600160401b03908116146100d05780546001600160401b0319166001600160401b0390811782556040519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50565b60805161183f6100fc60003960008181610637015281816106600152610858015261183f6000f3fe60806040526004361061012a5760003560e01c80635d2d7846116100ab578063d09f392d1161006f578063d09f392d1461036c578063d1c1df481461038c578063dca5f6b0146103cc578063f1a5310414610418578063f216de4c14610438578063f2f4eb261461045857600080fd5b80635d2d7846146102925780636624192f146102b2578063965af6c7146102fd578063a5861b901461031d578063b5d69e991461034c57600080fd5b8063485cc955116100f2578063485cc955146101ef5780634c70a0d61461020f5780634f1ef2861461023d57806352d1902d14610250578063543f8a361461026557600080fd5b8063034327441461012f5780630c340a241461015857806321e1625e1461019057806321ea9b3f146101b2578063477a655c146101d0575b600080fd5b34801561013b57600080fd5b5061014560025481565b6040519081526020015b60405180910390f35b34801561016457600080fd5b50600054610178906001600160a01b031681565b6040516001600160a01b03909116815260200161014f565b34801561019c57600080fd5b506101b06101ab36600461130b565b610478565b005b3480156101be57600080fd5b506101b06101cd366004611337565b50565b3480156101dc57600080fd5b506101b06101eb3660046113f3565b5050565b3480156101fb57600080fd5b506101b061020a36600461143a565b610524565b34801561021b57600080fd5b5061017861022a366004611473565b50506004546001600160a01b0316919050565b6101b061024b36600461149f565b610623565b34801561025c57600080fd5b5061014561084b565b34801561027157600080fd5b506102856102803660046114d9565b6108a9565b60405161014f91906114fd565b34801561029e57600080fd5b506101b06102ad36600461154a565b61094a565b3480156102be57600080fd5b506102ed6102cd3660046114d9565b6001600160a01b0316600090815260036020526040902060020154151590565b604051901515815260200161014f565b34801561030957600080fd5b506101b061031836600461130b565b61098d565b34801561032957600080fd5b5061033d61033836600461158f565b610a28565b60405161014f939291906115e2565b34801561035857600080fd5b506101b06103673660046114d9565b610c4f565b34801561037857600080fd5b506101b061038736600461154a565b610d55565b34801561039857600080fd5b506103ac6103a736600461161c565b610d8f565b60408051948552602085019390935291830152606082015260800161014f565b3480156103d857600080fd5b506104036103e73660046114d9565b6003602081905260009182526040909120600281015491015482565b6040805192835260208301919091520161014f565b34801561042457600080fd5b506101b06104333660046114d9565b610e45565b34801561044457600080fd5b506101b061045336600461130b565b610e91565b34801561046457600080fd5b50600154610178906001600160a01b031681565b6001546001600160a01b031633146104ab5760405162461bcd60e51b81526004016104a29061164a565b60405180910390fd5b6001600160a01b038216600090815260036020819052604082200180548392906104d69084906116a4565b909155505060408051828152600060208201526001600160a01b038416917f7a81a4ef419d50dbb5deb116fb983bf6ca7716bcbc84cd1cd2be81ccea9078b091015b60405180910390a25050565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0e805460019190600160401b900460ff168061056e5750805467ffffffffffffffff808416911610155b1561058b5760405162dc149f60e41b815260040160405180910390fd5b805468ffffffffffffffffff191667ffffffffffffffff8316908117600160401b178255600080546001600160a01b038781166001600160a01b0319928316179092556001805492871692909116919091179055815460ff60401b191682556040519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a150505050565b61062c82610f09565b306001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614806106aa57507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031661069e6000805160206117ea8339815191525490565b6001600160a01b031614155b156106c85760405163703e46dd60e11b815260040160405180910390fd5b816001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015610722575060408051601f3d908101601f1916820190925261071f918101906116bd565b60015b61074a57604051630c76093760e01b81526001600160a01b03831660048201526024016104a2565b6000805160206117ea833981519152811461077b57604051632a87526960e21b8152600481018290526024016104a2565b6000805160206117ea8339815191528390556040516001600160a01b038416907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a2815115610846576000836001600160a01b0316836040516107e291906116d6565b600060405180830381855af49150503d806000811461081d576040519150601f19603f3d011682016040523d82523d6000602084013e610822565b606091505b5050905080610844576040516339b21b5d60e11b815260040160405180910390fd5b505b505050565b6000306001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146108965760405163703e46dd60e11b815260040160405180910390fd5b506000805160206117ea83398151915290565b6001600160a01b03811660009081526003602090815260409182902060010180548351818402810184019094528084526060939283018282801561093e57602002820191906000526020600020906000905b82829054906101000a90046001600160601b03166001600160601b0316815260200190600c0190602082600b010492830192600103820291508084116108fb5790505b50505050509050919050565b6001546001600160a01b031633146109745760405162461bcd60e51b81526004016104a29061164a565b6002805490600061098483611705565b91905055505050565b6001546001600160a01b031633146109b75760405162461bcd60e51b81526004016104a29061164a565b6001600160a01b038216600090815260036020819052604082200180548392906109e290849061171c565b909155505060408051828152600160208201526001600160a01b038416917f7a81a4ef419d50dbb5deb116fb983bf6ca7716bcbc84cd1cd2be81ccea9078b09101610518565b600154600090819081906001600160a01b03163314610a595760405162461bcd60e51b81526004016104a29061164a565b6001600160a01b038716600090815260036020526040812090610a7c8989610f6e565b600183015490915087158015610a9b5750600481101580610a9b575081155b15610ab3576000806003955095509550505050610c45565b818810610ad35786610ace57610acb838a8a8561100f565b95505b610aec565b610adf838a8a856110f3565b610ae990866116a4565b94505b6000895b81610bee576001600160601b038116600090815260208690526040812080548c9290610b1d9084906116a4565b90915550506001600160601b03811660009081526020869052604081208054869290610b4a90849061171c565b90915550506000196001600160601b03821601610b6a5760019150610af0565b600154604051630fad06e960e11b81526001600160601b03831660048201526001600160a01b0390911690631f5a0dd29060240160e060405180830381865afa158015610bbb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bdf919061172f565b50949550610af0945050505050565b604080516001600160601b038d168152602081018c90526001600160a01b038e16917f4732545d01e38980276a17e6d394f01577ba63f2fea5eba41af0757d9c060c5c910160405180910390a25060009450505050505b9450945094915050565b6001546001600160a01b03163314610c795760405162461bcd60e51b81526004016104a29061164a565b6000610c84826108a9565b80519091505b801561084657600180546001600160a01b03169063fbb519e79085908590610cb2908661171c565b81518110610cc257610cc26117a4565b60209081029190910101516040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526001600160601b031660248201526000604482018190526064820152608401600060405180830381600087803b158015610d2a57600080fd5b505af1158015610d3e573d6000803e3d6000fd5b505050508080610d4d90611705565b915050610c8a565b6001546001600160a01b03163314610d7f5760405162461bcd60e51b81526004016104a29061164a565b60028054906000610984836117ba565b6001600160a01b038216600090815260036020819052604082206002810154918101546001820154929390929091825b82811015610e3a57866001600160601b0316826001018281548110610de657610de66117a4565b600091825260209091206002820401546001909116600c026101000a90046001600160601b031603610e32576001600160601b0387166000908152602083905260409020549350610e3a565b600101610dbf565b505092959194509250565b6001546001600160a01b03163314610e6f5760405162461bcd60e51b81526004016104a29061164a565b600480546001600160a01b0319166001600160a01b0392909216919091179055565b6001546001600160a01b03163314610ebb5760405162461bcd60e51b81526004016104a29061164a565b6001600160a01b038216600090815260036020526040902060028101548211610efd5781816002016000828254610ef2919061171c565b909155506108469050565b60006002820155505050565b6000546001600160a01b031633146101cd5760405162461bcd60e51b815260206004820152602260248201527f416363657373206e6f7420616c6c6f7765643a20476f7665726e6f72206f6e6c6044820152613c9760f11b60648201526084016104a2565b6001600160a01b0382166000908152600360205260408120815b600182015481101561100757836001600160601b0316826001018281548110610fb357610fb36117a4565b600091825260209091206002820401546001909116600c026101000a90046001600160601b031603610fff576001600160601b0384166000908152602083905260409020549250611007565b600101610f88565b505092915050565b60008085600201548660030154101561102957600061103d565b8560020154866003015461103d919061171c565b905061104981846116a4565b84101561105757600061106c565b80611062848661171c565b61106c919061171c565b9150826000036110b557600186810180548083018255600091825260209091206002820401805491909216600c026101000a6001600160601b0381810219909216918816021790555b82866002015410156110c757836110e2565b838387600201546110d8919061171c565b6110e291906116a4565b866002018190555050949350505050565b6003840154600090611105848461171c565b61110f91906116a4565b85600201541061112a57611123838361171c565b9050611150565b8460030154856002015410611150578460030154856002015461114d919061171c565b90505b826000036112b95760018501545b80156112b757846001600160601b03168660010160018361117f919061171c565b8154811061118f5761118f6117a4565b600091825260209091206002820401546001909116600c026101000a90046001600160601b0316036112a5576001808701805490916111cd9161171c565b815481106111dd576111dd6117a4565b600091825260209091206002820401546001918216600c026101000a90046001600160601b03169087810190611213908461171c565b81548110611223576112236117a4565b9060005260206000209060029182820401919006600c026101000a8154816001600160601b0302191690836001600160601b031602179055508560010180548061126f5761126f6117d3565b60008281526020902060026000199092019182040180546001600160601b03600c60018516026101000a021916905590556112b7565b806112af81611705565b91505061115e565b505b81856002015410156112cb57826112e6565b828286600201546112dc919061171c565b6112e691906116a4565b8560020181905550949350505050565b6001600160a01b03811681146101cd57600080fd5b6000806040838503121561131e57600080fd5b8235611329816112f6565b946020939093013593505050565b60006020828403121561134957600080fd5b5035919050565b634e487b7160e01b600052604160045260246000fd5b600082601f83011261137757600080fd5b813567ffffffffffffffff8082111561139257611392611350565b604051601f8301601f19908116603f011681019082821181831017156113ba576113ba611350565b816040528381528660208588010111156113d357600080fd5b836020870160208301376000602085830101528094505050505092915050565b6000806040838503121561140657600080fd5b82359150602083013567ffffffffffffffff81111561142457600080fd5b61143085828601611366565b9150509250929050565b6000806040838503121561144d57600080fd5b8235611458816112f6565b91506020830135611468816112f6565b809150509250929050565b60008060006060848603121561148857600080fd5b505081359360208301359350604090920135919050565b600080604083850312156114b257600080fd5b82356114bd816112f6565b9150602083013567ffffffffffffffff81111561142457600080fd5b6000602082840312156114eb57600080fd5b81356114f6816112f6565b9392505050565b6020808252825182820181905260009190848201906040850190845b8181101561153e5783516001600160601b031683529284019291840191600101611519565b50909695505050505050565b6000806040838503121561155d57600080fd5b50508035926020909101359150565b6001600160601b03811681146101cd57600080fd5b80151581146101cd57600080fd5b600080600080608085870312156115a557600080fd5b84356115b0816112f6565b935060208501356115c08161156c565b92506040850135915060608501356115d781611581565b939692955090935050565b83815260208101839052606081016008831061160e57634e487b7160e01b600052602160045260246000fd5b826040830152949350505050565b6000806040838503121561162f57600080fd5b823561163a816112f6565b915060208301356114688161156c565b60208082526024908201527f416363657373206e6f7420616c6c6f7765643a204b6c65726f73436f7265206f60408201526337363c9760e11b606082015260800190565b634e487b7160e01b600052601160045260246000fd5b808201808211156116b7576116b761168e565b92915050565b6000602082840312156116cf57600080fd5b5051919050565b6000825160005b818110156116f757602081860181015185830152016116dd565b506000920191825250919050565b6000816117145761171461168e565b506000190190565b818103818111156116b7576116b761168e565b600080600080600080600060e0888a03121561174a57600080fd5b87516117558161156c565b602089015190975061176681611581565b8096505060408801519450606088015193506080880151925060a0880151915060c088015161179481611581565b8091505092959891949750929550565b634e487b7160e01b600052603260045260246000fd5b6000600182016117cc576117cc61168e565b5060010190565b634e487b7160e01b600052603160045260246000fdfe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbca26469706673582212200166151e57cedd4332854be3f1b542627de717718d9832e670b79904c4b162d864736f6c63430008180033",
- "deployedBytecode": "0x60806040526004361061012a5760003560e01c80635d2d7846116100ab578063d09f392d1161006f578063d09f392d1461036c578063d1c1df481461038c578063dca5f6b0146103cc578063f1a5310414610418578063f216de4c14610438578063f2f4eb261461045857600080fd5b80635d2d7846146102925780636624192f146102b2578063965af6c7146102fd578063a5861b901461031d578063b5d69e991461034c57600080fd5b8063485cc955116100f2578063485cc955146101ef5780634c70a0d61461020f5780634f1ef2861461023d57806352d1902d14610250578063543f8a361461026557600080fd5b8063034327441461012f5780630c340a241461015857806321e1625e1461019057806321ea9b3f146101b2578063477a655c146101d0575b600080fd5b34801561013b57600080fd5b5061014560025481565b6040519081526020015b60405180910390f35b34801561016457600080fd5b50600054610178906001600160a01b031681565b6040516001600160a01b03909116815260200161014f565b34801561019c57600080fd5b506101b06101ab36600461130b565b610478565b005b3480156101be57600080fd5b506101b06101cd366004611337565b50565b3480156101dc57600080fd5b506101b06101eb3660046113f3565b5050565b3480156101fb57600080fd5b506101b061020a36600461143a565b610524565b34801561021b57600080fd5b5061017861022a366004611473565b50506004546001600160a01b0316919050565b6101b061024b36600461149f565b610623565b34801561025c57600080fd5b5061014561084b565b34801561027157600080fd5b506102856102803660046114d9565b6108a9565b60405161014f91906114fd565b34801561029e57600080fd5b506101b06102ad36600461154a565b61094a565b3480156102be57600080fd5b506102ed6102cd3660046114d9565b6001600160a01b0316600090815260036020526040902060020154151590565b604051901515815260200161014f565b34801561030957600080fd5b506101b061031836600461130b565b61098d565b34801561032957600080fd5b5061033d61033836600461158f565b610a28565b60405161014f939291906115e2565b34801561035857600080fd5b506101b06103673660046114d9565b610c4f565b34801561037857600080fd5b506101b061038736600461154a565b610d55565b34801561039857600080fd5b506103ac6103a736600461161c565b610d8f565b60408051948552602085019390935291830152606082015260800161014f565b3480156103d857600080fd5b506104036103e73660046114d9565b6003602081905260009182526040909120600281015491015482565b6040805192835260208301919091520161014f565b34801561042457600080fd5b506101b06104333660046114d9565b610e45565b34801561044457600080fd5b506101b061045336600461130b565b610e91565b34801561046457600080fd5b50600154610178906001600160a01b031681565b6001546001600160a01b031633146104ab5760405162461bcd60e51b81526004016104a29061164a565b60405180910390fd5b6001600160a01b038216600090815260036020819052604082200180548392906104d69084906116a4565b909155505060408051828152600060208201526001600160a01b038416917f7a81a4ef419d50dbb5deb116fb983bf6ca7716bcbc84cd1cd2be81ccea9078b091015b60405180910390a25050565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0e805460019190600160401b900460ff168061056e5750805467ffffffffffffffff808416911610155b1561058b5760405162dc149f60e41b815260040160405180910390fd5b805468ffffffffffffffffff191667ffffffffffffffff8316908117600160401b178255600080546001600160a01b038781166001600160a01b0319928316179092556001805492871692909116919091179055815460ff60401b191682556040519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a150505050565b61062c82610f09565b306001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614806106aa57507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031661069e6000805160206117ea8339815191525490565b6001600160a01b031614155b156106c85760405163703e46dd60e11b815260040160405180910390fd5b816001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015610722575060408051601f3d908101601f1916820190925261071f918101906116bd565b60015b61074a57604051630c76093760e01b81526001600160a01b03831660048201526024016104a2565b6000805160206117ea833981519152811461077b57604051632a87526960e21b8152600481018290526024016104a2565b6000805160206117ea8339815191528390556040516001600160a01b038416907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a2815115610846576000836001600160a01b0316836040516107e291906116d6565b600060405180830381855af49150503d806000811461081d576040519150601f19603f3d011682016040523d82523d6000602084013e610822565b606091505b5050905080610844576040516339b21b5d60e11b815260040160405180910390fd5b505b505050565b6000306001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146108965760405163703e46dd60e11b815260040160405180910390fd5b506000805160206117ea83398151915290565b6001600160a01b03811660009081526003602090815260409182902060010180548351818402810184019094528084526060939283018282801561093e57602002820191906000526020600020906000905b82829054906101000a90046001600160601b03166001600160601b0316815260200190600c0190602082600b010492830192600103820291508084116108fb5790505b50505050509050919050565b6001546001600160a01b031633146109745760405162461bcd60e51b81526004016104a29061164a565b6002805490600061098483611705565b91905055505050565b6001546001600160a01b031633146109b75760405162461bcd60e51b81526004016104a29061164a565b6001600160a01b038216600090815260036020819052604082200180548392906109e290849061171c565b909155505060408051828152600160208201526001600160a01b038416917f7a81a4ef419d50dbb5deb116fb983bf6ca7716bcbc84cd1cd2be81ccea9078b09101610518565b600154600090819081906001600160a01b03163314610a595760405162461bcd60e51b81526004016104a29061164a565b6001600160a01b038716600090815260036020526040812090610a7c8989610f6e565b600183015490915087158015610a9b5750600481101580610a9b575081155b15610ab3576000806003955095509550505050610c45565b818810610ad35786610ace57610acb838a8a8561100f565b95505b610aec565b610adf838a8a856110f3565b610ae990866116a4565b94505b6000895b81610bee576001600160601b038116600090815260208690526040812080548c9290610b1d9084906116a4565b90915550506001600160601b03811660009081526020869052604081208054869290610b4a90849061171c565b90915550506000196001600160601b03821601610b6a5760019150610af0565b600154604051630fad06e960e11b81526001600160601b03831660048201526001600160a01b0390911690631f5a0dd29060240160e060405180830381865afa158015610bbb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bdf919061172f565b50949550610af0945050505050565b604080516001600160601b038d168152602081018c90526001600160a01b038e16917f4732545d01e38980276a17e6d394f01577ba63f2fea5eba41af0757d9c060c5c910160405180910390a25060009450505050505b9450945094915050565b6001546001600160a01b03163314610c795760405162461bcd60e51b81526004016104a29061164a565b6000610c84826108a9565b80519091505b801561084657600180546001600160a01b03169063fbb519e79085908590610cb2908661171c565b81518110610cc257610cc26117a4565b60209081029190910101516040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526001600160601b031660248201526000604482018190526064820152608401600060405180830381600087803b158015610d2a57600080fd5b505af1158015610d3e573d6000803e3d6000fd5b505050508080610d4d90611705565b915050610c8a565b6001546001600160a01b03163314610d7f5760405162461bcd60e51b81526004016104a29061164a565b60028054906000610984836117ba565b6001600160a01b038216600090815260036020819052604082206002810154918101546001820154929390929091825b82811015610e3a57866001600160601b0316826001018281548110610de657610de66117a4565b600091825260209091206002820401546001909116600c026101000a90046001600160601b031603610e32576001600160601b0387166000908152602083905260409020549350610e3a565b600101610dbf565b505092959194509250565b6001546001600160a01b03163314610e6f5760405162461bcd60e51b81526004016104a29061164a565b600480546001600160a01b0319166001600160a01b0392909216919091179055565b6001546001600160a01b03163314610ebb5760405162461bcd60e51b81526004016104a29061164a565b6001600160a01b038216600090815260036020526040902060028101548211610efd5781816002016000828254610ef2919061171c565b909155506108469050565b60006002820155505050565b6000546001600160a01b031633146101cd5760405162461bcd60e51b815260206004820152602260248201527f416363657373206e6f7420616c6c6f7765643a20476f7665726e6f72206f6e6c6044820152613c9760f11b60648201526084016104a2565b6001600160a01b0382166000908152600360205260408120815b600182015481101561100757836001600160601b0316826001018281548110610fb357610fb36117a4565b600091825260209091206002820401546001909116600c026101000a90046001600160601b031603610fff576001600160601b0384166000908152602083905260409020549250611007565b600101610f88565b505092915050565b60008085600201548660030154101561102957600061103d565b8560020154866003015461103d919061171c565b905061104981846116a4565b84101561105757600061106c565b80611062848661171c565b61106c919061171c565b9150826000036110b557600186810180548083018255600091825260209091206002820401805491909216600c026101000a6001600160601b0381810219909216918816021790555b82866002015410156110c757836110e2565b838387600201546110d8919061171c565b6110e291906116a4565b866002018190555050949350505050565b6003840154600090611105848461171c565b61110f91906116a4565b85600201541061112a57611123838361171c565b9050611150565b8460030154856002015410611150578460030154856002015461114d919061171c565b90505b826000036112b95760018501545b80156112b757846001600160601b03168660010160018361117f919061171c565b8154811061118f5761118f6117a4565b600091825260209091206002820401546001909116600c026101000a90046001600160601b0316036112a5576001808701805490916111cd9161171c565b815481106111dd576111dd6117a4565b600091825260209091206002820401546001918216600c026101000a90046001600160601b03169087810190611213908461171c565b81548110611223576112236117a4565b9060005260206000209060029182820401919006600c026101000a8154816001600160601b0302191690836001600160601b031602179055508560010180548061126f5761126f6117d3565b60008281526020902060026000199092019182040180546001600160601b03600c60018516026101000a021916905590556112b7565b806112af81611705565b91505061115e565b505b81856002015410156112cb57826112e6565b828286600201546112dc919061171c565b6112e691906116a4565b8560020181905550949350505050565b6001600160a01b03811681146101cd57600080fd5b6000806040838503121561131e57600080fd5b8235611329816112f6565b946020939093013593505050565b60006020828403121561134957600080fd5b5035919050565b634e487b7160e01b600052604160045260246000fd5b600082601f83011261137757600080fd5b813567ffffffffffffffff8082111561139257611392611350565b604051601f8301601f19908116603f011681019082821181831017156113ba576113ba611350565b816040528381528660208588010111156113d357600080fd5b836020870160208301376000602085830101528094505050505092915050565b6000806040838503121561140657600080fd5b82359150602083013567ffffffffffffffff81111561142457600080fd5b61143085828601611366565b9150509250929050565b6000806040838503121561144d57600080fd5b8235611458816112f6565b91506020830135611468816112f6565b809150509250929050565b60008060006060848603121561148857600080fd5b505081359360208301359350604090920135919050565b600080604083850312156114b257600080fd5b82356114bd816112f6565b9150602083013567ffffffffffffffff81111561142457600080fd5b6000602082840312156114eb57600080fd5b81356114f6816112f6565b9392505050565b6020808252825182820181905260009190848201906040850190845b8181101561153e5783516001600160601b031683529284019291840191600101611519565b50909695505050505050565b6000806040838503121561155d57600080fd5b50508035926020909101359150565b6001600160601b03811681146101cd57600080fd5b80151581146101cd57600080fd5b600080600080608085870312156115a557600080fd5b84356115b0816112f6565b935060208501356115c08161156c565b92506040850135915060608501356115d781611581565b939692955090935050565b83815260208101839052606081016008831061160e57634e487b7160e01b600052602160045260246000fd5b826040830152949350505050565b6000806040838503121561162f57600080fd5b823561163a816112f6565b915060208301356114688161156c565b60208082526024908201527f416363657373206e6f7420616c6c6f7765643a204b6c65726f73436f7265206f60408201526337363c9760e11b606082015260800190565b634e487b7160e01b600052601160045260246000fd5b808201808211156116b7576116b761168e565b92915050565b6000602082840312156116cf57600080fd5b5051919050565b6000825160005b818110156116f757602081860181015185830152016116dd565b506000920191825250919050565b6000816117145761171461168e565b506000190190565b818103818111156116b7576116b761168e565b600080600080600080600060e0888a03121561174a57600080fd5b87516117558161156c565b602089015190975061176681611581565b8096505060408801519450606088015193506080880151925060a0880151915060c088015161179481611581565b8091505092959891949750929550565b634e487b7160e01b600052603260045260246000fd5b6000600182016117cc576117cc61168e565b5060010190565b634e487b7160e01b600052603160045260246000fdfe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbca26469706673582212200166151e57cedd4332854be3f1b542627de717718d9832e670b79904c4b162d864736f6c63430008180033",
+ "solcInputHash": "d547d738900bce1310e91a5d1adfc179",
+ "metadata": "{\"compiler\":{\"version\":\"0.8.30+commit.73712a01\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"AlreadyInitialized\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedDelegateCall\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"implementation\",\"type\":\"address\"}],\"name\":\"InvalidImplementation\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"KlerosCoreOnly\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotEligibleForWithdrawal\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotInitializing\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OwnerOnly\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UUPSUnauthorizedCallContext\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"slot\",\"type\":\"bytes32\"}],\"name\":\"UUPSUnsupportedProxiableUUID\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"version\",\"type\":\"uint64\"}],\"name\":\"Initialized\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_account\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"LeftoverPNK\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_account\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"LeftoverPNKWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"enum ISortitionModule.Phase\",\"name\":\"_phase\",\"type\":\"uint8\"}],\"name\":\"NewPhase\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_relativeAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"_unlock\",\"type\":\"bool\"}],\"name\":\"StakeLocked\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_courtID\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amountAllCourts\",\"type\":\"uint256\"}],\"name\":\"StakeSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newImplementation\",\"type\":\"address\"}],\"name\":\"Upgraded\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"core\",\"outputs\":[{\"internalType\":\"contract KlerosCoreUniversity\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"createDisputeHook\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint96\",\"name\":\"_courtID\",\"type\":\"uint96\"},{\"internalType\":\"bytes\",\"name\":\"_extraData\",\"type\":\"bytes\"}],\"name\":\"createTree\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"disputesWithoutJurors\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"draw\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"drawnAddress\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"fromSubcourtID\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_iterations\",\"type\":\"uint256\"}],\"name\":\"executeDelayedStakes\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_account\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"_courtID\",\"type\":\"uint96\"}],\"name\":\"forcedUnstake\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_account\",\"type\":\"address\"}],\"name\":\"forcedUnstakeAllCourts\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_juror\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"_courtID\",\"type\":\"uint96\"}],\"name\":\"getJurorBalance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"totalStaked\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"totalLocked\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"stakedInCourt\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nbCourts\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_juror\",\"type\":\"address\"}],\"name\":\"getJurorCourtIDs\",\"outputs\":[{\"internalType\":\"uint96[]\",\"name\":\"\",\"type\":\"uint96[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_juror\",\"type\":\"address\"}],\"name\":\"getJurorLeftoverPNK\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"},{\"internalType\":\"contract KlerosCoreUniversity\",\"name\":\"_core\",\"type\":\"address\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_juror\",\"type\":\"address\"}],\"name\":\"isJurorStaked\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"jurors\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"stakedPnk\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"lockedPnk\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_account\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_relativeAmount\",\"type\":\"uint256\"}],\"name\":\"lockStake\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"passPhase\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"postDrawHook\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"proxiableUUID\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_account\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"_courtID\",\"type\":\"uint96\"},{\"internalType\":\"uint256\",\"name\":\"_pnkDeposit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_pnkWithdrawal\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_newStake\",\"type\":\"uint256\"}],\"name\":\"setStake\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_account\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"_courtID\",\"type\":\"uint96\"},{\"internalType\":\"uint256\",\"name\":\"_penalty\",\"type\":\"uint256\"}],\"name\":\"setStakePenalty\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"pnkBalance\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"newCourtStake\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"availablePenalty\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_account\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"_courtID\",\"type\":\"uint96\"},{\"internalType\":\"uint256\",\"name\":\"_reward\",\"type\":\"uint256\"}],\"name\":\"setStakeReward\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_juror\",\"type\":\"address\"}],\"name\":\"setTransientJuror\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_account\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_relativeAmount\",\"type\":\"uint256\"}],\"name\":\"unlockStake\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newImplementation\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"upgradeToAndCall\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_account\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"_courtID\",\"type\":\"uint96\"},{\"internalType\":\"uint256\",\"name\":\"_newStake\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"validateStake\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"pnkDeposit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"pnkWithdrawal\",\"type\":\"uint256\"},{\"internalType\":\"enum StakingResult\",\"name\":\"stakingResult\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"version\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_account\",\"type\":\"address\"}],\"name\":\"withdrawLeftoverPNK\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"errors\":{\"AlreadyInitialized()\":[{\"details\":\"The contract is already initialized.\"}],\"NotInitializing()\":[{\"details\":\"The contract is not initializing.\"}]},\"events\":{\"Initialized(uint64)\":{\"details\":\"Triggered when the contract has been initialized or reinitialized.\"},\"LeftoverPNK(address,uint256)\":{\"params\":{\"_account\":\"The account of the juror.\",\"_amount\":\"The amount of PNK available.\"}},\"LeftoverPNKWithdrawn(address,uint256)\":{\"params\":{\"_account\":\"The account of the juror withdrawing PNK.\",\"_amount\":\"The amount of PNK withdrawn.\"}},\"NewPhase(uint8)\":{\"params\":{\"_phase\":\"The new phase.\"}},\"StakeLocked(address,uint256,bool)\":{\"params\":{\"_address\":\"The address of the juror.\",\"_relativeAmount\":\"The amount of tokens locked.\",\"_unlock\":\"Whether the stake is locked or unlocked.\"}},\"StakeSet(address,uint256,uint256,uint256)\":{\"params\":{\"_address\":\"The address of the juror.\",\"_amount\":\"The amount of tokens staked in the court.\",\"_amountAllCourts\":\"The amount of tokens staked in all courts.\",\"_courtID\":\"The ID of the court.\"}},\"Upgraded(address)\":{\"params\":{\"newImplementation\":\"Address of the new implementation the proxy is now forwarding calls to.\"}}},\"kind\":\"dev\",\"methods\":{\"constructor\":{\"custom:oz-upgrades-unsafe-allow\":\"constructor\"},\"createDisputeHook(uint256,uint256)\":{\"params\":{\"_disputeID\":\"The ID of the dispute.\",\"_roundID\":\"The ID of the round.\"}},\"createTree(uint96,bytes)\":{\"params\":{\"_courtID\":\"The ID of the court.\",\"_extraData\":\"Extra data that contains the number of children each node in the tree should have.\"}},\"draw(uint96,uint256,uint256)\":{\"details\":\"that this function reverts if the sum of all values in the tree is 0. `O(k * log_k(n))` where `k` is the maximum number of children per node in the tree, and `n` is the maximum number of nodes ever appended.\",\"params\":{\"_coreDisputeID\":\"Index of the dispute in Kleros Core.\",\"_courtID\":\"The ID of the court.\",\"_nonce\":\"Nonce to hash with random number.\"},\"returns\":{\"drawnAddress\":\"The drawn address.\"}},\"executeDelayedStakes(uint256)\":{\"params\":{\"_iterations\":\"The number of delayed stakes to execute.\"}},\"forcedUnstake(address,uint96)\":{\"details\":\"`O(n * (p * log_k(j)) )` where `n` is the number of courts the juror has staked in, `p` is the depth of the court tree, `k` is the minimum number of children per node of one of these courts' sortition sum tree, and `j` is the maximum number of jurors that ever staked in one of these courts simultaneously.\",\"params\":{\"_account\":\"The juror to unstake.\",\"_courtID\":\"The ID of the court.\"}},\"forcedUnstakeAllCourts(address)\":{\"details\":\"`O(n * (p * log_k(j)) )` where `O(n * (p * log_k(j)) )` where `n` is the number of courts the juror has staked in, `p` is the depth of the court tree, `k` is the minimum number of children per node of one of these courts' sortition sum tree, and `j` is the maximum number of jurors that ever staked in one of these courts simultaneously.\",\"params\":{\"_account\":\"The juror to unstake.\"}},\"getJurorBalance(address,uint96)\":{\"params\":{\"_courtID\":\"The ID of the court.\",\"_juror\":\"The address of the juror.\"},\"returns\":{\"nbCourts\":\"The number of courts the juror has directly staked in.\",\"stakedInCourt\":\"The amount of tokens staked in the specified court including locked tokens and penalty deductions.\",\"totalLocked\":\"The total amount of tokens locked in disputes.\",\"totalStaked\":\"The total amount of tokens staked including locked tokens and penalty deductions. Equivalent to the effective stake in the General court.\"}},\"getJurorCourtIDs(address)\":{\"params\":{\"_juror\":\"The address of the juror.\"}},\"getJurorLeftoverPNK(address)\":{\"params\":{\"_juror\":\"The address of the juror.\"},\"returns\":{\"_0\":\"Whether the juror has leftover PNK.\"}},\"initialize(address,address)\":{\"params\":{\"_core\":\"The KlerosCore.\"}},\"isJurorStaked(address)\":{\"params\":{\"_juror\":\"The address of the juror.\"},\"returns\":{\"_0\":\"Whether the juror is staked or not.\"}},\"lockStake(address,uint256)\":{\"params\":{\"_account\":\"The address of the juror.\",\"_relativeAmount\":\"The amount to lock.\"}},\"postDrawHook(uint256,uint256)\":{\"params\":{\"_disputeID\":\"The ID of the dispute.\",\"_roundID\":\"The ID of the round.\"}},\"proxiableUUID()\":{\"details\":\"IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this function revert if invoked through a proxy. This is guaranteed by the if statement.\"},\"setStake(address,uint96,uint256,uint256,uint256)\":{\"details\":\"`O(n + p * log_k(j))` where `n` is the number of courts the juror has staked in, `p` is the depth of the court tree, `k` is the minimum number of children per node of one of these courts' sortition sum tree, and `j` is the maximum number of jurors that ever staked in one of these courts simultaneously.\",\"params\":{\"_account\":\"The address of the juror.\",\"_courtID\":\"The ID of the court.\",\"_newStake\":\"The new stake.\",\"_pnkDeposit\":\"The amount of PNK to be deposited.\",\"_pnkWithdrawal\":\"The amount of PNK to be withdrawn.\"}},\"setStakePenalty(address,uint96,uint256)\":{\"details\":\"`O(n + p * log_k(j))` where `n` is the number of courts the juror has staked in, `p` is the depth of the court tree, `k` is the minimum number of children per node of one of these courts' sortition sum tree, and `j` is the maximum number of jurors that ever staked in one of these courts simultaneously.\",\"params\":{\"_account\":\"The address of the juror.\",\"_courtID\":\"The ID of the court.\",\"_penalty\":\"The amount of PNK to be deducted.\"},\"returns\":{\"availablePenalty\":\"The amount of PNK that was actually deducted.\",\"newCourtStake\":\"The updated stake of the juror in the court.\",\"pnkBalance\":\"The updated total PNK balance of the juror, including the penalty.\"}},\"setStakeReward(address,uint96,uint256)\":{\"details\":\"`O(n + p * log_k(j))` where `O(n + p * log_k(j))` where `n` is the number of courts the juror has staked in, `p` is the depth of the court tree, `k` is the minimum number of children per node of one of these courts' sortition sum tree, and `j` is the maximum number of jurors that ever staked in one of these courts simultaneously.\",\"params\":{\"_account\":\"The address of the juror.\",\"_courtID\":\"The ID of the court.\",\"_reward\":\"The amount of PNK to be deposited as a reward.\"},\"returns\":{\"success\":\"True if the reward was added successfully.\"}},\"unlockStake(address,uint256)\":{\"params\":{\"_account\":\"The address of the juror.\",\"_relativeAmount\":\"The amount to unlock.\"}},\"upgradeToAndCall(address,bytes)\":{\"details\":\"Reverts if the execution is not performed via delegatecall or the execution context is not of a proxy with an ERC1967-compliant implementation pointing to self.\",\"params\":{\"data\":\"Data used in a delegate call to `newImplementation` if non-empty. This will typically be an encoded function call, and allows initializing the storage of the proxy like a Solidity constructor.\",\"newImplementation\":\"Address of the new implementation contract.\"}},\"validateStake(address,uint96,uint256,bool)\":{\"details\":\"No state changes should be made when returning stakingResult != Successful, otherwise delayed stakes might break invariants.\",\"params\":{\"_account\":\"The address of the juror.\",\"_courtID\":\"The ID of the court.\",\"_newStake\":\"The new stake.\",\"_noDelay\":\"True if the stake change should not be delayed.\"},\"returns\":{\"pnkDeposit\":\"The amount of PNK to be deposited.\",\"pnkWithdrawal\":\"The amount of PNK to be withdrawn.\",\"stakingResult\":\"The result of the staking operation.\"}},\"withdrawLeftoverPNK(address)\":{\"details\":\"that since locked and staked PNK are async it is possible for the juror to have positive staked PNK balance while having 0 stake in courts and 0 locked tokens (eg. when the juror fully unstaked during dispute and later got his tokens unlocked). In this case the juror can use this function to withdraw the leftover tokens. Also note that if the juror has some leftover PNK while not fully unstaked he'll have to manually unstake from all courts to trigger this function.\",\"params\":{\"_account\":\"The juror whose PNK to withdraw.\"}}},\"stateVariables\":{\"version\":{\"return\":\"Version string.\",\"returns\":{\"_0\":\"Version string.\"}}},\"title\":\"SortitionModuleUniversity\",\"version\":1},\"userdoc\":{\"errors\":{\"FailedDelegateCall()\":[{\"notice\":\"Failed Delegated call\"}],\"InvalidImplementation(address)\":[{\"notice\":\"The `implementation` is not UUPS-compliant\"}],\"UUPSUnauthorizedCallContext()\":[{\"notice\":\"The call is from an unauthorized context.\"}],\"UUPSUnsupportedProxiableUUID(bytes32)\":[{\"notice\":\"The storage `slot` is unsupported as a UUID.\"}]},\"events\":{\"LeftoverPNK(address,uint256)\":{\"notice\":\"Emitted when leftover PNK is available.\"},\"LeftoverPNKWithdrawn(address,uint256)\":{\"notice\":\"Emitted when leftover PNK is withdrawn.\"},\"NewPhase(uint8)\":{\"notice\":\"Emitted when the phase is changed.\"},\"StakeLocked(address,uint256,bool)\":{\"notice\":\"Emitted when a juror's stake is locked.\"},\"StakeSet(address,uint256,uint256,uint256)\":{\"notice\":\"Emitted when a juror stakes in a court.\"},\"Upgraded(address)\":{\"notice\":\"Emitted when the `implementation` has been successfully upgraded.\"}},\"kind\":\"user\",\"methods\":{\"createDisputeHook(uint256,uint256)\":{\"notice\":\"Triggers the state changes after dispute creation.\"},\"createTree(uint96,bytes)\":{\"notice\":\"Create a sortition sum tree at the specified key.\"},\"draw(uint96,uint256,uint256)\":{\"notice\":\"Draw an ID from a tree using a number.\"},\"executeDelayedStakes(uint256)\":{\"notice\":\"Executes the next delayed stakes.\"},\"forcedUnstake(address,uint96)\":{\"notice\":\"Unstakes the inactive juror from a specific court.\"},\"forcedUnstakeAllCourts(address)\":{\"notice\":\"Unstakes the inactive juror from all courts.\"},\"getJurorBalance(address,uint96)\":{\"notice\":\"Gets the balance of a juror in a court.\"},\"getJurorCourtIDs(address)\":{\"notice\":\"Gets the court identifiers where a specific `_juror` has staked.\"},\"getJurorLeftoverPNK(address)\":{\"notice\":\"Checks if the juror has any leftover PNK in the contract.\"},\"initialize(address,address)\":{\"notice\":\"Initializer (constructor equivalent for upgradable contracts).\"},\"isJurorStaked(address)\":{\"notice\":\"Checks if the juror is staked in any court.\"},\"lockStake(address,uint256)\":{\"notice\":\"Locks the tokens of the drawn juror.\"},\"passPhase()\":{\"notice\":\"Passes the phase.\"},\"postDrawHook(uint256,uint256)\":{\"notice\":\"Triggers the state changes after drawing.\"},\"proxiableUUID()\":{\"notice\":\"Implementation of the ERC1822 `proxiableUUID` function. This returns the storage slot used by the implementation. It is used to validate the implementation's compatibility when performing an upgrade.\"},\"setStake(address,uint96,uint256,uint256,uint256)\":{\"notice\":\"Update the state of the stakes, called by KC at the end of setStake flow.\"},\"setStakePenalty(address,uint96,uint256)\":{\"notice\":\"Update the state of the stakes with a PNK reward deposit, called by KC during rewards execution.\"},\"setStakeReward(address,uint96,uint256)\":{\"notice\":\"Update the state of the stakes with a PNK reward deposit, called by KC during rewards execution.\"},\"unlockStake(address,uint256)\":{\"notice\":\"Unlocks the tokens of the drawn juror.\"},\"upgradeToAndCall(address,bytes)\":{\"notice\":\"Upgrade mechanism including access control and UUPS-compliance.\"},\"validateStake(address,uint96,uint256,bool)\":{\"notice\":\"Validate the specified juror's new stake for a court.\"},\"version()\":{\"notice\":\"Returns the version of the implementation.\"},\"withdrawLeftoverPNK(address)\":{\"notice\":\"Gives back the locked PNKs in case the juror fully unstaked earlier.\"}},\"notice\":\"An adapted version of the SortitionModule contract for educational purposes.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/arbitration/university/SortitionModuleUniversity.sol\":\"SortitionModuleUniversity\"},\"evmVersion\":\"cancun\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000},\"remappings\":[],\"viaIR\":true},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity >=0.4.16;\\n\\n/**\\n * @dev Interface of the ERC-20 standard as defined in the ERC.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n\\n /**\\n * @dev Returns the value of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the value of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 value) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\\n * caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 value) external returns (bool);\\n\\n /**\\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\\n * allowance mechanism. `value` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(address from, address to, uint256 value) external returns (bool);\\n}\\n\",\"keccak256\":\"0x74ed01eb66b923d0d0cfe3be84604ac04b76482a55f9dd655e1ef4d367f95bc2\",\"license\":\"MIT\"},\"src/arbitration/interfaces/IArbitrableV2.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity >=0.8.0 <0.9.0;\\n\\nimport \\\"./IArbitratorV2.sol\\\";\\n\\n/// @title IArbitrableV2\\n/// @notice Arbitrable interface.\\n/// @dev When developing arbitrable contracts, we need to:\\n/// - Define the action taken when a ruling is received by the contract.\\n/// - Allow dispute creation which calls `arbitrator.createDispute{value: _fee}(_choices,_extraData)`.\\ninterface IArbitrableV2 {\\n // ************************************* //\\n // * Events * //\\n // ************************************* //\\n\\n /// @notice To be emitted when a dispute is created to link the correct template to the disputeID.\\n /// @param _arbitrator The arbitrator of the contract.\\n /// @param _arbitratorDisputeID The identifier of the dispute in the Arbitrator contract.\\n /// @param _externalDisputeID An identifier created outside Kleros by the protocol requesting arbitration.\\n /// @param _templateId The identifier of the dispute template.\\n event DisputeRequest(\\n IArbitratorV2 indexed _arbitrator,\\n uint256 indexed _arbitratorDisputeID,\\n uint256 _externalDisputeID,\\n uint256 _templateId\\n );\\n\\n /// @notice To be raised when a ruling is given.\\n /// @param _arbitrator The arbitrator giving the ruling.\\n /// @param _disputeID The identifier of the dispute in the Arbitrator contract.\\n /// @param _ruling The ruling which was given.\\n event Ruling(IArbitratorV2 indexed _arbitrator, uint256 indexed _disputeID, uint256 _ruling);\\n\\n // ************************************* //\\n // * State Modifiers * //\\n // ************************************* //\\n\\n /// @notice Give a ruling for a dispute.\\n ///\\n /// @dev This is a callback function for the arbitrator to provide the ruling to this contract.\\n /// Only the arbitrator must be allowed to call this function.\\n /// Ruling 0 is reserved for \\\"Not able/wanting to make a decision\\\".\\n ///\\n /// @param _disputeID The identifier of the dispute in the Arbitrator contract.\\n /// @param _ruling Ruling given by the arbitrator.\\n function rule(uint256 _disputeID, uint256 _ruling) external;\\n}\\n\",\"keccak256\":\"0x3afa29a93847399c8705103350b69bb70706b2075ca41b39d523b007e69e23db\",\"license\":\"MIT\"},\"src/arbitration/interfaces/IArbitratorV2.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity >=0.8.0 <0.9.0;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"./IArbitrableV2.sol\\\";\\n\\n/// @title Arbitrator\\n/// @notice Arbitrator interface for the Kleros V2 protocol.\\n/// @dev Unlike the ERC-792 this standard is not concerned with appeals, so each arbitrator can implement an appeal system that suits it the most.\\ninterface IArbitratorV2 {\\n // ************************************* //\\n // * Events * //\\n // ************************************* //\\n\\n /// @notice To be emitted when a dispute is created.\\n /// @param _disputeID The identifier of the dispute in the Arbitrator contract.\\n /// @param _arbitrable The contract which created the dispute.\\n event DisputeCreation(uint256 indexed _disputeID, IArbitrableV2 indexed _arbitrable);\\n\\n /// @notice To be raised when a ruling is given.\\n /// @param _arbitrable The arbitrable receiving the ruling.\\n /// @param _disputeID The identifier of the dispute in the Arbitrator contract.\\n /// @param _ruling The ruling which was given.\\n event Ruling(IArbitrableV2 indexed _arbitrable, uint256 indexed _disputeID, uint256 _ruling);\\n\\n /// @notice To be emitted when an ERC20 token is added or removed as a method to pay fees.\\n /// @param _token The ERC20 token.\\n /// @param _accepted Whether the token is accepted or not.\\n event AcceptedFeeToken(IERC20 indexed _token, bool indexed _accepted);\\n\\n /// @notice To be emitted when the fee for a particular ERC20 token is updated.\\n /// @param _feeToken The ERC20 token.\\n /// @param _rateInEth The new rate of the fee token in ETH.\\n /// @param _rateDecimals The new decimals of the fee token rate.\\n event NewCurrencyRate(IERC20 indexed _feeToken, uint64 _rateInEth, uint8 _rateDecimals);\\n\\n // ************************************* //\\n // * State Modifiers * //\\n // ************************************* //\\n\\n /// @notice Create a dispute and pay for the fees in the native currency, typically ETH.\\n /// @dev Must be called by the arbitrable contract and pay at least `arbitrationCost(_extraData)` in ETH.\\n /// @param _numberOfChoices The number of choices the arbitrator can choose from in this dispute.\\n /// @param _extraData Additional info about the dispute. We use it to pass the ID of the dispute's court (first 32 bytes), the minimum number of jurors required (next 32 bytes) and the ID of the specific dispute kit (last 32 bytes).\\n /// @return disputeID The identifier of the dispute created.\\n function createDispute(\\n uint256 _numberOfChoices,\\n bytes calldata _extraData\\n ) external payable returns (uint256 disputeID);\\n\\n /// @notice Create a dispute and pay for the fees in a supported ERC20 token.\\n /// @dev Must be called by the arbitrable contract and pay at least `arbitrationCost(_extraData)` in the supported ERC20 token.\\n /// @param _numberOfChoices The number of choices the arbitrator can choose from in this dispute.\\n /// @param _extraData Additional info about the dispute. We use it to pass the ID of the dispute's court (first 32 bytes), the minimum number of jurors required (next 32 bytes) and the ID of the specific dispute kit (last 32 bytes).\\n /// @param _feeToken The ERC20 token used to pay fees.\\n /// @param _feeAmount Amount of the ERC20 token used to pay fees.\\n /// @return disputeID The identifier of the dispute created.\\n function createDispute(\\n uint256 _numberOfChoices,\\n bytes calldata _extraData,\\n IERC20 _feeToken,\\n uint256 _feeAmount\\n ) external returns (uint256 disputeID);\\n\\n // ************************************* //\\n // * Public Views * //\\n // ************************************* //\\n\\n /// @notice Compute the cost of arbitration denominated in the native currency, typically ETH.\\n /// @dev It is recommended not to increase it often, as it can be highly time and gas consuming for the arbitrated contracts to cope with fee augmentation.\\n /// @param _extraData Additional info about the dispute. We use it to pass the ID of the dispute's court (first 32 bytes), the minimum number of jurors required (next 32 bytes) and the ID of the specific dispute kit (last 32 bytes).\\n /// @return cost The arbitration cost in ETH.\\n function arbitrationCost(bytes calldata _extraData) external view returns (uint256 cost);\\n\\n /// @notice Compute the cost of arbitration denominated in `_feeToken`.\\n /// @dev It is recommended not to increase it often, as it can be highly time and gas consuming for the arbitrated contracts to cope with fee augmentation.\\n /// @param _extraData Additional info about the dispute. We use it to pass the ID of the dispute's court (first 32 bytes), the minimum number of jurors required (next 32 bytes) and the ID of the specific dispute kit (last 32 bytes).\\n /// @param _feeToken The ERC20 token used to pay fees.\\n /// @return cost The arbitration cost in `_feeToken`.\\n function arbitrationCost(bytes calldata _extraData, IERC20 _feeToken) external view returns (uint256 cost);\\n\\n /// @notice Gets the current ruling of a specified dispute.\\n /// @param _disputeID The ID of the dispute.\\n /// @return ruling The current ruling.\\n /// @return tied Whether it's a tie or not.\\n /// @return overridden Whether the ruling was overridden by appeal funding or not.\\n function currentRuling(uint256 _disputeID) external view returns (uint256 ruling, bool tied, bool overridden);\\n}\\n\",\"keccak256\":\"0x65ba87c5309cd6e6562e569f79778ca423c9be7b0a44b9407e5bd2bdf8fdc3b0\",\"license\":\"MIT\"},\"src/arbitration/interfaces/IDisputeKit.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity >=0.8.0 <0.9.0;\\n\\nimport \\\"./IArbitratorV2.sol\\\";\\n\\n/// @title IDisputeKit\\n/// @notice An abstraction of the Dispute Kits intended for interfacing with KlerosCore.\\n/// @dev It does not intend to abstract the interactions with the user (such as voting or appeal funding) to allow for implementation-specific parameters.\\ninterface IDisputeKit {\\n // ************************************ //\\n // * Events * //\\n // ************************************ //\\n\\n /// @notice Emitted when casting a vote to provide the justification of juror's choice.\\n /// @param _coreDisputeID The identifier of the dispute in the Arbitrator contract.\\n /// @param _juror Address of the juror.\\n /// @param _voteIDs The identifiers of the votes in the dispute.\\n /// @param _choice The choice juror voted for.\\n /// @param _justification Justification of the choice.\\n event VoteCast(\\n uint256 indexed _coreDisputeID,\\n address indexed _juror,\\n uint256[] _voteIDs,\\n uint256 indexed _choice,\\n string _justification\\n );\\n\\n // ************************************* //\\n // * State Modifiers * //\\n // ************************************* //\\n\\n /// @notice Creates a local dispute and maps it to the dispute ID in the Core contract.\\n /// @dev Access restricted to Kleros Core only.\\n /// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.\\n /// @param _numberOfChoices Number of choices of the dispute\\n /// @param _extraData Additional info about the dispute, for possible use in future dispute kits.\\n /// @param _nbVotes Maximal number of votes this dispute can get. Added for future-proofing.\\n function createDispute(\\n uint256 _coreDisputeID,\\n uint256 _numberOfChoices,\\n bytes calldata _extraData,\\n uint256 _nbVotes\\n ) external;\\n\\n /// @notice Draws the juror from the sortition tree. The drawn address is picked up by Kleros Core.\\n /// @dev Access restricted to Kleros Core only.\\n /// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.\\n /// @param _nonce Nonce.\\n /// @return drawnAddress The drawn address.\\n function draw(\\n uint256 _coreDisputeID,\\n uint256 _nonce\\n ) external returns (address drawnAddress, uint96 fromSubcourtID);\\n\\n // ************************************* //\\n // * Public Views * //\\n // ************************************* //\\n\\n /// @notice Gets the current ruling of a specified dispute.\\n /// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.\\n /// @return ruling The current ruling.\\n /// @return tied Whether it's a tie or not.\\n /// @return overridden Whether the ruling was overridden by appeal funding or not.\\n function currentRuling(uint256 _coreDisputeID) external view returns (uint256 ruling, bool tied, bool overridden);\\n\\n /// @notice Gets the degree of coherence of a particular voter.\\n /// @dev This function is called by Kleros Core in order to determine the amount of the reward.\\n /// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.\\n /// @param _coreRoundID The ID of the round in Kleros Core, not in the Dispute Kit.\\n /// @param _voteID The ID of the vote.\\n /// @param _feePerJuror The fee per juror.\\n /// @param _pnkAtStakePerJuror The PNK at stake per juror.\\n /// @return pnkCoherence The degree of coherence in basis points for the dispute PNK reward.\\n /// @return feeCoherence The degree of coherence in basis points for the dispute fee reward.\\n function getDegreeOfCoherenceReward(\\n uint256 _coreDisputeID,\\n uint256 _coreRoundID,\\n uint256 _voteID,\\n uint256 _feePerJuror,\\n uint256 _pnkAtStakePerJuror\\n ) external view returns (uint256 pnkCoherence, uint256 feeCoherence);\\n\\n /// @notice Gets the degree of coherence of a particular voter.\\n /// @dev This function is called by Kleros Core in order to determine the amount of the penalty.\\n /// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.\\n /// @param _coreRoundID The ID of the round in Kleros Core, not in the Dispute Kit.\\n /// @param _voteID The ID of the vote.\\n /// @param _feePerJuror The fee per juror.\\n /// @param _pnkAtStakePerJuror The PNK at stake per juror.\\n /// @return pnkCoherence The degree of coherence in basis points for the dispute PNK reward.\\n function getDegreeOfCoherencePenalty(\\n uint256 _coreDisputeID,\\n uint256 _coreRoundID,\\n uint256 _voteID,\\n uint256 _feePerJuror,\\n uint256 _pnkAtStakePerJuror\\n ) external view returns (uint256 pnkCoherence);\\n\\n /// @notice Gets the number of jurors who are eligible to a reward in this round.\\n /// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.\\n /// @param _coreRoundID The ID of the round in Kleros Core, not in the Dispute Kit.\\n /// @return The number of coherent jurors.\\n function getCoherentCount(uint256 _coreDisputeID, uint256 _coreRoundID) external view returns (uint256);\\n\\n /// @notice Returns true if all of the jurors have cast their commits for the last round.\\n /// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.\\n /// @return Whether all of the jurors have cast their commits for the last round.\\n function areCommitsAllCast(uint256 _coreDisputeID) external view returns (bool);\\n\\n /// @notice Returns true if all of the jurors have cast their votes for the last round.\\n /// @dev This function is to be called directly by the core contract and is not for off-chain usage.\\n /// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.\\n /// @return Whether all of the jurors have cast their votes for the last round.\\n function areVotesAllCast(uint256 _coreDisputeID) external view returns (bool);\\n\\n /// @notice Returns true if the appeal funding is finished prematurely (e.g. when losing side didn't fund).\\n /// @dev This function is to be called directly by the core contract and is not for off-chain usage.\\n /// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.\\n /// @return Whether the appeal funding is finished.\\n function isAppealFunded(uint256 _coreDisputeID) external view returns (bool);\\n\\n /// @dev Returns true if the dispute is jumping to a parent court.\\n /// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.\\n /// @return Whether the dispute is jumping to a parent court or not.\\n function earlyCourtJump(uint256 _coreDisputeID) external view returns (bool);\\n\\n /// @notice Returns the number of votes after the appeal.\\n /// @param _previousDisputeKit The previous Dispute Kit.\\n /// @param _currentNbVotes The number of votes before the appeal.\\n /// @return The number of votes after the appeal.\\n function getNbVotesAfterAppeal(\\n IDisputeKit _previousDisputeKit,\\n uint256 _currentNbVotes\\n ) external view returns (uint256);\\n\\n /// @notice Returns the dispute kit ID to be used after court jump by Kleros Core.\\n /// @return The ID of the dispute kit in Kleros Core disputeKits array.\\n function getJumpDisputeKitID() external view returns (uint256);\\n\\n /// @notice Returns true if the specified voter was active in this round.\\n /// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.\\n /// @param _coreRoundID The ID of the round in Kleros Core, not in the Dispute Kit.\\n /// @param _voteID The ID of the voter.\\n /// @return Whether the voter was active or not.\\n function isVoteActive(uint256 _coreDisputeID, uint256 _coreRoundID, uint256 _voteID) external view returns (bool);\\n\\n /// @notice Returns the info of the specified round in the core contract.\\n /// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.\\n /// @param _coreRoundID The ID of the round in Kleros Core, not in the Dispute Kit.\\n /// @param _choice The choice to query.\\n /// @return winningChoice The winning choice of this round.\\n /// @return tied Whether it's a tie or not.\\n /// @return totalVoted Number of jurors who cast the vote already.\\n /// @return totalCommited Number of jurors who cast the commit already (only relevant for hidden votes).\\n /// @return nbVoters Total number of voters in this round.\\n /// @return choiceCount Number of votes cast for the queried choice.\\n function getRoundInfo(\\n uint256 _coreDisputeID,\\n uint256 _coreRoundID,\\n uint256 _choice\\n )\\n external\\n view\\n returns (\\n uint256 winningChoice,\\n bool tied,\\n uint256 totalVoted,\\n uint256 totalCommited,\\n uint256 nbVoters,\\n uint256 choiceCount\\n );\\n\\n /// @notice Returns the vote information for a given vote ID.\\n /// @param _coreDisputeID The ID of the dispute in Kleros Core.\\n /// @param _coreRoundID The ID of the round in Kleros Core.\\n /// @param _voteID The ID of the vote.\\n /// @return account The address of the juror who cast the vote.\\n /// @return commit The commit of the vote.\\n /// @return choice The choice that got the vote.\\n /// @return voted Whether the vote was cast or not.\\n function getVoteInfo(\\n uint256 _coreDisputeID,\\n uint256 _coreRoundID,\\n uint256 _voteID\\n ) external view returns (address account, bytes32 commit, uint256 choice, bool voted);\\n}\\n\",\"keccak256\":\"0x1f12d2574dffd9bf83cf33a54aa4abbbfa4203251a0f962edd8e5c3b370408bc\",\"license\":\"MIT\"},\"src/arbitration/interfaces/ISortitionModule.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity >=0.8.0 <0.9.0;\\n\\nimport \\\"../../libraries/Constants.sol\\\";\\n\\n/// @title ISortitionModule\\n/// @notice Interface for the SortitionModule contract.\\ninterface ISortitionModule {\\n // ************************************* //\\n // * Enums * //\\n // ************************************* //\\n\\n enum Phase {\\n staking, // Stake sum trees can be updated. Pass after `minStakingTime` passes and there is at least one dispute without jurors.\\n generating, // Waiting for a random number. Pass as soon as it is ready.\\n drawing // Jurors can be drawn. Pass after all disputes have jurors or `maxDrawingTime` passes.\\n }\\n\\n // ************************************* //\\n // * Events * //\\n // ************************************* //\\n\\n /// @notice Emitted when the phase is changed.\\n /// @param _phase The new phase.\\n event NewPhase(Phase _phase);\\n\\n // ************************************* //\\n // * State Modifiers * //\\n // ************************************* //\\n\\n /// @notice Passes the phase.\\n function passPhase() external;\\n\\n /// @notice Executes the next delayed stakes.\\n /// @param _iterations The number of delayed stakes to execute.\\n function executeDelayedStakes(uint256 _iterations) external;\\n\\n /// @notice Create a sortition sum tree at the specified key.\\n /// @param _courtID The ID of the court.\\n /// @param _extraData Extra data that contains the number of children each node in the tree should have.\\n function createTree(uint96 _courtID, bytes memory _extraData) external;\\n\\n /// @notice Validate the specified juror's new stake for a court.\\n /// @dev No state changes should be made when returning stakingResult != Successful, otherwise delayed stakes might break invariants.\\n /// @param _account The address of the juror.\\n /// @param _courtID The ID of the court.\\n /// @param _newStake The new stake.\\n /// @param _noDelay True if the stake change should not be delayed.\\n /// @return pnkDeposit The amount of PNK to be deposited.\\n /// @return pnkWithdrawal The amount of PNK to be withdrawn.\\n /// @return stakingResult The result of the staking operation.\\n function validateStake(\\n address _account,\\n uint96 _courtID,\\n uint256 _newStake,\\n bool _noDelay\\n ) external returns (uint256 pnkDeposit, uint256 pnkWithdrawal, StakingResult stakingResult);\\n\\n /// @notice Update the state of the stakes, called by KC at the end of setStake flow.\\n ///\\n /// @dev `O(n + p * log_k(j))` where\\n /// `n` is the number of courts the juror has staked in,\\n /// `p` is the depth of the court tree,\\n /// `k` is the minimum number of children per node of one of these courts' sortition sum tree,\\n /// and `j` is the maximum number of jurors that ever staked in one of these courts simultaneously.\\n ///\\n /// @param _account The address of the juror.\\n /// @param _courtID The ID of the court.\\n /// @param _pnkDeposit The amount of PNK to be deposited.\\n /// @param _pnkWithdrawal The amount of PNK to be withdrawn.\\n /// @param _newStake The new stake.\\n function setStake(\\n address _account,\\n uint96 _courtID,\\n uint256 _pnkDeposit,\\n uint256 _pnkWithdrawal,\\n uint256 _newStake\\n ) external;\\n\\n /// @notice Update the state of the stakes with a PNK reward deposit, called by KC during rewards execution.\\n ///\\n /// @dev `O(n + p * log_k(j))` where\\n /// `n` is the number of courts the juror has staked in,\\n /// `p` is the depth of the court tree,\\n /// `k` is the minimum number of children per node of one of these courts' sortition sum tree,\\n /// and `j` is the maximum number of jurors that ever staked in one of these courts simultaneously.\\n ///\\n /// @param _account The address of the juror.\\n /// @param _courtID The ID of the court.\\n /// @param _penalty The amount of PNK to be deducted.\\n /// @return pnkBalance The updated total PNK balance of the juror, including the penalty.\\n /// @return newCourtStake The updated stake of the juror in the court.\\n /// @return availablePenalty The amount of PNK that was actually deducted.\\n function setStakePenalty(\\n address _account,\\n uint96 _courtID,\\n uint256 _penalty\\n ) external returns (uint256 pnkBalance, uint256 newCourtStake, uint256 availablePenalty);\\n\\n /// @notice Update the state of the stakes with a PNK reward deposit, called by KC during rewards execution.\\n ///\\n /// @dev `O(n + p * log_k(j))` where\\n /// `O(n + p * log_k(j))` where\\n /// `n` is the number of courts the juror has staked in,\\n /// `p` is the depth of the court tree,\\n /// `k` is the minimum number of children per node of one of these courts' sortition sum tree,\\n /// and `j` is the maximum number of jurors that ever staked in one of these courts simultaneously.\\n ///\\n /// @param _account The address of the juror.\\n /// @param _courtID The ID of the court.\\n /// @param _reward The amount of PNK to be deposited as a reward.\\n /// @return success True if the reward was added successfully.\\n function setStakeReward(address _account, uint96 _courtID, uint256 _reward) external returns (bool success);\\n\\n /// @notice Unstakes the inactive juror from all courts.\\n ///\\n /// @dev `O(n * (p * log_k(j)) )` where\\n /// `O(n * (p * log_k(j)) )` where\\n /// `n` is the number of courts the juror has staked in,\\n /// `p` is the depth of the court tree,\\n /// `k` is the minimum number of children per node of one of these courts' sortition sum tree,\\n /// and `j` is the maximum number of jurors that ever staked in one of these courts simultaneously.\\n ///\\n /// @param _account The juror to unstake.\\n function forcedUnstakeAllCourts(address _account) external;\\n\\n /// @notice Unstakes the inactive juror from a specific court.\\n ///\\n /// @dev `O(n * (p * log_k(j)) )` where\\n /// `n` is the number of courts the juror has staked in,\\n /// `p` is the depth of the court tree,\\n /// `k` is the minimum number of children per node of one of these courts' sortition sum tree,\\n /// and `j` is the maximum number of jurors that ever staked in one of these courts simultaneously.\\n ///\\n /// @param _account The juror to unstake.\\n /// @param _courtID The ID of the court.\\n function forcedUnstake(address _account, uint96 _courtID) external;\\n\\n /// @notice Locks the tokens of the drawn juror.\\n /// @param _account The address of the juror.\\n /// @param _relativeAmount The amount to lock.\\n function lockStake(address _account, uint256 _relativeAmount) external;\\n\\n /// @notice Unlocks the tokens of the drawn juror.\\n /// @param _account The address of the juror.\\n /// @param _relativeAmount The amount to unlock.\\n function unlockStake(address _account, uint256 _relativeAmount) external;\\n\\n /// @notice Triggers the state changes after dispute creation.\\n /// @param _disputeID The ID of the dispute.\\n /// @param _roundID The ID of the round.\\n function createDisputeHook(uint256 _disputeID, uint256 _roundID) external;\\n\\n /// @notice Triggers the state changes after drawing.\\n /// @param _disputeID The ID of the dispute.\\n /// @param _roundID The ID of the round.\\n function postDrawHook(uint256 _disputeID, uint256 _roundID) external;\\n\\n /// @notice Gives back the locked PNKs in case the juror fully unstaked earlier.\\n ///\\n /// @dev that since locked and staked PNK are async it is possible for the juror to have positive staked PNK balance\\n /// while having 0 stake in courts and 0 locked tokens (eg. when the juror fully unstaked during dispute and later got his tokens unlocked).\\n /// In this case the juror can use this function to withdraw the leftover tokens.\\n /// Also note that if the juror has some leftover PNK while not fully unstaked he'll have to manually unstake from all courts to trigger this function.\\n ///\\n /// @param _account The juror whose PNK to withdraw.\\n function withdrawLeftoverPNK(address _account) external;\\n\\n // ************************************* //\\n // * Public Views * //\\n // ************************************* //\\n\\n /// @notice Draw an ID from a tree using a number.\\n ///\\n /// @dev that this function reverts if the sum of all values in the tree is 0.\\n /// `O(k * log_k(n))` where\\n /// `k` is the maximum number of children per node in the tree,\\n /// and `n` is the maximum number of nodes ever appended.\\n ///\\n /// @param _courtID The ID of the court.\\n /// @param _coreDisputeID Index of the dispute in Kleros Core.\\n /// @param _nonce Nonce to hash with random number.\\n /// @return drawnAddress The drawn address.\\n function draw(\\n uint96 _courtID,\\n uint256 _coreDisputeID,\\n uint256 _nonce\\n ) external view returns (address drawnAddress, uint96 fromSubcourtID);\\n\\n /// @notice Gets the balance of a juror in a court.\\n /// @param _juror The address of the juror.\\n /// @param _courtID The ID of the court.\\n /// @return totalStakedPnk The total amount of tokens staked including locked tokens and penalty deductions. Equivalent to the effective stake in the General court.\\n /// @return totalLocked The total amount of tokens locked in disputes.\\n /// @return stakedInCourt The amount of tokens staked in the specified court including locked tokens and penalty deductions.\\n /// @return nbCourts The number of courts the juror has directly staked in.\\n function getJurorBalance(\\n address _juror,\\n uint96 _courtID\\n ) external view returns (uint256 totalStakedPnk, uint256 totalLocked, uint256 stakedInCourt, uint256 nbCourts);\\n\\n /// @notice Gets the court identifiers where a specific `_juror` has staked.\\n /// @param _juror The address of the juror.\\n function getJurorCourtIDs(address _juror) external view returns (uint96[] memory);\\n\\n /// @notice Checks if the juror is staked in any court.\\n /// @param _juror The address of the juror.\\n /// @return Whether the juror is staked or not.\\n function isJurorStaked(address _juror) external view returns (bool);\\n\\n /// @notice Checks if the juror has any leftover PNK in the contract.\\n /// @param _juror The address of the juror.\\n /// @return Whether the juror has leftover PNK.\\n function getJurorLeftoverPNK(address _juror) external view returns (uint256);\\n}\\n\",\"keccak256\":\"0x3eeff4281ddf3c731c6503094bbbcc80d8015e3a60a27c8cadadfffdf1bf5437\",\"license\":\"MIT\"},\"src/arbitration/university/ISortitionModuleUniversity.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.24;\\n\\nimport {ISortitionModule} from \\\"../interfaces/ISortitionModule.sol\\\";\\n\\ninterface ISortitionModuleUniversity is ISortitionModule {\\n function setTransientJuror(address _juror) external;\\n}\\n\",\"keccak256\":\"0x57478726f4dd824eca06d8b5349395b5b37756f7988d3fffb6fdae4d0f4164ee\",\"license\":\"MIT\"},\"src/arbitration/university/KlerosCoreUniversity.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.24;\\n\\nimport {IArbitrableV2, IArbitratorV2} from \\\"../interfaces/IArbitratorV2.sol\\\";\\nimport {IDisputeKit} from \\\"../interfaces/IDisputeKit.sol\\\";\\nimport {ISortitionModuleUniversity} from \\\"./ISortitionModuleUniversity.sol\\\";\\nimport {SafeERC20, IERC20} from \\\"../../libraries/SafeERC20.sol\\\";\\nimport {UUPSProxiable} from \\\"../../proxy/UUPSProxiable.sol\\\";\\nimport {Initializable} from \\\"../../proxy/Initializable.sol\\\";\\nimport \\\"../../libraries/Constants.sol\\\";\\n\\n/// @title KlerosCoreUniversity\\n/// @notice Core arbitrator contract for educational purposes.\\ncontract KlerosCoreUniversity is IArbitratorV2, UUPSProxiable, Initializable {\\n using SafeERC20 for IERC20;\\n\\n string public constant override version = \\\"2.0.0\\\";\\n\\n // ************************************* //\\n // * Enums / Structs * //\\n // ************************************* //\\n\\n enum Period {\\n evidence, // Evidence can be submitted. This is also when drawing has to take place.\\n commit, // Jurors commit a hashed vote. This is skipped for courts without hidden votes.\\n vote, // Jurors reveal/cast their vote depending on whether the court has hidden votes or not.\\n appeal, // The dispute can be appealed.\\n execution // Tokens are redistributed and the ruling is executed.\\n }\\n\\n struct Court {\\n uint96 parent; // The parent court.\\n bool hiddenVotes; // Whether to use commit and reveal or not.\\n uint256[] children; // List of child courts.\\n uint256 minStake; // Minimum PNKs needed to stake in the court.\\n uint256 alpha; // Basis point of PNKs that are lost when incoherent.\\n uint256 feeForJuror; // Arbitration fee paid per juror.\\n uint256 jurorsForCourtJump; // The appeal after the one that reaches this number of jurors will go to the parent court if any.\\n uint256[4] timesPerPeriod; // The time allotted to each dispute period in the form `timesPerPeriod[period]`.\\n mapping(uint256 disputeKitId => bool) supportedDisputeKits; // True if DK with this ID is supported by the court. Note that each court must support classic dispute kit.\\n uint256[10] __gap; // Reserved slots for future upgrades.\\n }\\n\\n struct Dispute {\\n uint96 courtID; // The ID of the court the dispute is in.\\n IArbitrableV2 arbitrated; // The arbitrable contract.\\n Period period; // The current period of the dispute.\\n bool ruled; // True if the ruling has been executed, false otherwise.\\n uint256 lastPeriodChange; // The last time the period was changed.\\n Round[] rounds;\\n uint256[10] __gap; // Reserved slots for future upgrades.\\n }\\n\\n struct Round {\\n uint256 disputeKitID; // Index of the dispute kit in the array.\\n uint256 pnkAtStakePerJuror; // The amount of PNKs at stake for each juror in this round.\\n uint256 totalFeesForJurors; // The total juror fees paid in this round.\\n uint256 nbVotes; // The total number of votes the dispute can possibly have in the current round. Former votes[_round].length.\\n uint256 repartitions; // A counter of reward repartitions made in this round.\\n uint256 pnkPenalties; // The amount of PNKs collected from penalties in this round.\\n address[] drawnJurors; // Addresses of the jurors that were drawn in this round.\\n uint96[] drawnJurorFromCourtIDs; // The courtIDs where the juror was drawn from, possibly their stake in a subcourt.\\n uint256 sumFeeRewardPaid; // Total sum of arbitration fees paid to coherent jurors as a reward in this round.\\n uint256 sumPnkRewardPaid; // Total sum of PNK paid to coherent jurors as a reward in this round.\\n IERC20 feeToken; // The token used for paying fees in this round.\\n uint256 drawIterations; // The number of iterations passed drawing the jurors for this round.\\n uint256[10] __gap; // Reserved slots for future upgrades.\\n }\\n\\n // Workaround \\\"stack too deep\\\" errors\\n struct ExecuteParams {\\n uint256 disputeID; // The ID of the dispute to execute.\\n uint256 round; // The round to execute.\\n uint256 coherentCount; // The number of coherent votes in the round.\\n uint256 numberOfVotesInRound; // The number of votes in the round.\\n uint256 feePerJurorInRound; // The fee per juror in the round.\\n uint256 pnkAtStakePerJurorInRound; // The amount of PNKs at stake for each juror in the round.\\n uint256 pnkPenaltiesInRound; // The amount of PNKs collected from penalties in the round.\\n uint256 repartition; // The index of the repartition to execute.\\n }\\n\\n struct CurrencyRate {\\n bool feePaymentAccepted;\\n uint64 rateInEth;\\n uint8 rateDecimals;\\n }\\n\\n // ************************************* //\\n // * Storage * //\\n // ************************************* //\\n\\n uint256 private constant NON_PAYABLE_AMOUNT = (2 ** 256 - 2) / 2; // An amount higher than the supply of ETH.\\n\\n address public owner; // The owner of the contract.\\n address public instructor; // The instructor who is allowed to choose the jurors.\\n IERC20 public pinakion; // The Pinakion token contract.\\n address public jurorProsecutionModule; // The module for juror's prosecution.\\n ISortitionModuleUniversity public sortitionModule; // Sortition module for drawing.\\n Court[] public courts; // The courts.\\n IDisputeKit[] public disputeKits; // Array of dispute kits.\\n Dispute[] public disputes; // The disputes.\\n mapping(IERC20 => CurrencyRate) public currencyRates; // The price of each token in ETH.\\n\\n // ************************************* //\\n // * Events * //\\n // ************************************* //\\n\\n event NewPeriod(uint256 indexed _disputeID, Period _period);\\n event AppealPossible(uint256 indexed _disputeID, IArbitrableV2 indexed _arbitrable);\\n event AppealDecision(uint256 indexed _disputeID, IArbitrableV2 indexed _arbitrable);\\n event Draw(address indexed _address, uint256 indexed _disputeID, uint256 _roundID, uint256 _voteID);\\n event CourtCreated(\\n uint96 indexed _courtID,\\n uint96 indexed _parent,\\n bool _hiddenVotes,\\n uint256 _minStake,\\n uint256 _alpha,\\n uint256 _feeForJuror,\\n uint256 _jurorsForCourtJump,\\n uint256[4] _timesPerPeriod,\\n uint256[] _supportedDisputeKits\\n );\\n event CourtModified(\\n uint96 indexed _courtID,\\n bool _hiddenVotes,\\n uint256 _minStake,\\n uint256 _alpha,\\n uint256 _feeForJuror,\\n uint256 _jurorsForCourtJump,\\n uint256[4] _timesPerPeriod\\n );\\n event DisputeKitCreated(uint256 indexed _disputeKitID, IDisputeKit indexed _disputeKitAddress);\\n event DisputeKitEnabled(uint96 indexed _courtID, uint256 indexed _disputeKitID, bool indexed _enable);\\n event CourtJump(\\n uint256 indexed _disputeID,\\n uint256 indexed _roundID,\\n uint96 indexed _fromCourtID,\\n uint96 _toCourtID\\n );\\n event DisputeKitJump(\\n uint256 indexed _disputeID,\\n uint256 indexed _roundID,\\n uint256 indexed _fromDisputeKitID,\\n uint256 _toDisputeKitID\\n );\\n event JurorRewardPenalty(\\n address indexed _account,\\n uint256 indexed _disputeID,\\n uint256 indexed _roundID,\\n uint256 _degreeOfCoherencyPnk,\\n uint256 _degreeOfCoherencyFee,\\n int256 _amountPnk,\\n int256 _amountFee,\\n IERC20 _feeToken\\n );\\n event LeftoverRewardSent(\\n uint256 indexed _disputeID,\\n uint256 indexed _roundID,\\n uint256 _amountPnk,\\n uint256 _amountFee,\\n IERC20 _feeToken\\n );\\n\\n // ************************************* //\\n // * Function Modifiers * //\\n // ************************************* //\\n\\n modifier onlyByOwner() {\\n if (owner != msg.sender) revert OwnerOnly();\\n _;\\n }\\n\\n modifier onlyByInstructor() {\\n if (instructor != msg.sender) revert InstructorOnly();\\n _;\\n }\\n\\n modifier onlyByOwnerOrInstructor() {\\n if (msg.sender != owner && msg.sender != instructor) revert OwnerOrInstructorOnly();\\n _;\\n }\\n\\n // ************************************* //\\n // * Constructor * //\\n // ************************************* //\\n\\n /// @custom:oz-upgrades-unsafe-allow constructor\\n constructor() {\\n _disableInitializers();\\n }\\n\\n /// @notice Initializer (constructor equivalent for upgradable contracts).\\n /// @param _owner The owner's address.\\n /// @param _instructor The address of the instructor.\\n /// @param _pinakion The address of the token contract.\\n /// @param _jurorProsecutionModule The address of the juror prosecution module.\\n /// @param _disputeKit The address of the default dispute kit.\\n /// @param _hiddenVotes The `hiddenVotes` property value of the general court.\\n /// @param _courtParameters Numeric parameters of General court (minStake, alpha, feeForJuror and jurorsForCourtJump respectively).\\n /// @param _timesPerPeriod The `timesPerPeriod` property value of the general court.\\n /// @param _sortitionModuleAddress The sortition module responsible for sortition of the jurors.\\n function initialize(\\n address _owner,\\n address _instructor,\\n IERC20 _pinakion,\\n address _jurorProsecutionModule,\\n IDisputeKit _disputeKit,\\n bool _hiddenVotes,\\n uint256[4] memory _courtParameters,\\n uint256[4] memory _timesPerPeriod,\\n ISortitionModuleUniversity _sortitionModuleAddress\\n ) external initializer {\\n owner = _owner;\\n instructor = _instructor;\\n pinakion = _pinakion;\\n jurorProsecutionModule = _jurorProsecutionModule;\\n sortitionModule = _sortitionModuleAddress;\\n\\n // NULL_DISPUTE_KIT: an empty element at index 0 to indicate when a dispute kit is not supported.\\n disputeKits.push();\\n\\n // DISPUTE_KIT_CLASSIC\\n disputeKits.push(_disputeKit);\\n\\n emit DisputeKitCreated(DISPUTE_KIT_CLASSIC, _disputeKit);\\n\\n // FORKING_COURT\\n // TODO: Fill the properties for the Forking court, emit CourtCreated.\\n courts.push();\\n\\n // GENERAL_COURT\\n Court storage court = courts.push();\\n court.parent = FORKING_COURT;\\n court.children = new uint256[](0);\\n court.hiddenVotes = _hiddenVotes;\\n court.minStake = _courtParameters[0];\\n court.alpha = _courtParameters[1];\\n court.feeForJuror = _courtParameters[2];\\n court.jurorsForCourtJump = _courtParameters[3];\\n court.timesPerPeriod = _timesPerPeriod;\\n\\n emit CourtCreated(\\n GENERAL_COURT,\\n court.parent,\\n _hiddenVotes,\\n _courtParameters[0],\\n _courtParameters[1],\\n _courtParameters[2],\\n _courtParameters[3],\\n _timesPerPeriod,\\n new uint256[](0)\\n );\\n _enableDisputeKit(GENERAL_COURT, DISPUTE_KIT_CLASSIC, true);\\n }\\n\\n // ************************************* //\\n // * Governance * //\\n // ************************************* //\\n\\n /* @dev Access Control to perform implementation upgrades (UUPS Proxiable)\\n * @dev Only the owner can perform upgrades (`onlyByOwner`)\\n */\\n function _authorizeUpgrade(address) internal view override onlyByOwner {\\n // NOP\\n }\\n\\n /// @notice Allows the owner to call anything on behalf of the contract.\\n /// @param _destination The destination of the call.\\n /// @param _amount The value sent with the call.\\n /// @param _data The data sent with the call.\\n function executeOwnerProposal(address _destination, uint256 _amount, bytes memory _data) external onlyByOwner {\\n (bool success, ) = _destination.call{value: _amount}(_data);\\n if (!success) revert UnsuccessfulCall();\\n }\\n\\n /// @notice Changes the `owner` storage variable.\\n /// @param _owner The new value for the `owner` storage variable.\\n function changeOwner(address payable _owner) external onlyByOwner {\\n owner = _owner;\\n }\\n\\n /// @notice Changes the `instructor` storage variable.\\n /// @param _instructor The new value for the `instructor` storage variable.\\n function changeInstructor(address _instructor) external onlyByOwnerOrInstructor {\\n instructor = _instructor;\\n }\\n\\n /// @notice Changes the `pinakion` storage variable.\\n /// @param _pinakion The new value for the `pinakion` storage variable.\\n function changePinakion(IERC20 _pinakion) external onlyByOwner {\\n pinakion = _pinakion;\\n }\\n\\n /// @notice Changes the `jurorProsecutionModule` storage variable.\\n /// @param _jurorProsecutionModule The new value for the `jurorProsecutionModule` storage variable.\\n function changeJurorProsecutionModule(address _jurorProsecutionModule) external onlyByOwner {\\n jurorProsecutionModule = _jurorProsecutionModule;\\n }\\n\\n /// @notice Changes the `_sortitionModule` storage variable.\\n /// Note that the new module should be initialized for all courts.\\n /// @param _sortitionModule The new value for the `sortitionModule` storage variable.\\n function changeSortitionModule(ISortitionModuleUniversity _sortitionModule) external onlyByOwner {\\n sortitionModule = _sortitionModule;\\n }\\n\\n /// @notice Add a new supported dispute kit module to the court.\\n /// @param _disputeKitAddress The address of the dispute kit contract.\\n function addNewDisputeKit(IDisputeKit _disputeKitAddress) external onlyByOwner {\\n uint256 disputeKitID = disputeKits.length;\\n disputeKits.push(_disputeKitAddress);\\n emit DisputeKitCreated(disputeKitID, _disputeKitAddress);\\n }\\n\\n /// @notice Creates a court under a specified parent court.\\n /// @param _parent The `parent` property value of the court.\\n /// @param _hiddenVotes The `hiddenVotes` property value of the court.\\n /// @param _minStake The `minStake` property value of the court.\\n /// @param _alpha The `alpha` property value of the court.\\n /// @param _feeForJuror The `feeForJuror` property value of the court.\\n /// @param _jurorsForCourtJump The `jurorsForCourtJump` property value of the court.\\n /// @param _timesPerPeriod The `timesPerPeriod` property value of the court.\\n /// @param _supportedDisputeKits Indexes of dispute kits that this court will support.\\n function createCourt(\\n uint96 _parent,\\n bool _hiddenVotes,\\n uint256 _minStake,\\n uint256 _alpha,\\n uint256 _feeForJuror,\\n uint256 _jurorsForCourtJump,\\n uint256[4] memory _timesPerPeriod,\\n uint256[] memory _supportedDisputeKits\\n ) external onlyByOwner {\\n if (courts[_parent].minStake > _minStake) revert MinStakeLowerThanParentCourt();\\n if (_supportedDisputeKits.length == 0) revert UnsupportedDisputeKit();\\n if (_parent == FORKING_COURT) revert InvalidForkingCourtAsParent();\\n\\n uint256 courtID = courts.length;\\n Court storage court = courts.push();\\n\\n for (uint256 i = 0; i < _supportedDisputeKits.length; i++) {\\n if (_supportedDisputeKits[i] == 0 || _supportedDisputeKits[i] >= disputeKits.length) {\\n revert WrongDisputeKitIndex();\\n }\\n court.supportedDisputeKits[_supportedDisputeKits[i]] = true;\\n }\\n // Check that Classic DK support was added.\\n if (!court.supportedDisputeKits[DISPUTE_KIT_CLASSIC]) revert MustSupportDisputeKitClassic();\\n\\n court.parent = _parent;\\n court.children = new uint256[](0);\\n court.hiddenVotes = _hiddenVotes;\\n court.minStake = _minStake;\\n court.alpha = _alpha;\\n court.feeForJuror = _feeForJuror;\\n court.jurorsForCourtJump = _jurorsForCourtJump;\\n court.timesPerPeriod = _timesPerPeriod;\\n\\n // Update the parent.\\n courts[_parent].children.push(courtID);\\n emit CourtCreated(\\n uint96(courtID),\\n _parent,\\n _hiddenVotes,\\n _minStake,\\n _alpha,\\n _feeForJuror,\\n _jurorsForCourtJump,\\n _timesPerPeriod,\\n _supportedDisputeKits\\n );\\n }\\n\\n function changeCourtParameters(\\n uint96 _courtID,\\n bool _hiddenVotes,\\n uint256 _minStake,\\n uint256 _alpha,\\n uint256 _feeForJuror,\\n uint256 _jurorsForCourtJump,\\n uint256[4] memory _timesPerPeriod\\n ) external onlyByOwner {\\n Court storage court = courts[_courtID];\\n if (_courtID != GENERAL_COURT && courts[court.parent].minStake > _minStake) {\\n revert MinStakeLowerThanParentCourt();\\n }\\n for (uint256 i = 0; i < court.children.length; i++) {\\n if (courts[court.children[i]].minStake < _minStake) {\\n revert MinStakeLowerThanParentCourt();\\n }\\n }\\n court.minStake = _minStake;\\n court.hiddenVotes = _hiddenVotes;\\n court.alpha = _alpha;\\n court.feeForJuror = _feeForJuror;\\n court.jurorsForCourtJump = _jurorsForCourtJump;\\n court.timesPerPeriod = _timesPerPeriod;\\n emit CourtModified(\\n _courtID,\\n _hiddenVotes,\\n _minStake,\\n _alpha,\\n _feeForJuror,\\n _jurorsForCourtJump,\\n _timesPerPeriod\\n );\\n }\\n\\n /// @notice Adds/removes court's support for specified dispute kits.\\n /// @param _courtID The ID of the court.\\n /// @param _disputeKitIDs The IDs of dispute kits which support should be added/removed.\\n /// @param _enable Whether add or remove the dispute kits from the court.\\n function enableDisputeKits(uint96 _courtID, uint256[] memory _disputeKitIDs, bool _enable) external onlyByOwner {\\n for (uint256 i = 0; i < _disputeKitIDs.length; i++) {\\n if (_enable) {\\n if (_disputeKitIDs[i] == 0 || _disputeKitIDs[i] >= disputeKits.length) {\\n revert WrongDisputeKitIndex();\\n }\\n _enableDisputeKit(_courtID, _disputeKitIDs[i], true);\\n } else {\\n // Classic dispute kit must be supported by all courts.\\n if (_disputeKitIDs[i] == DISPUTE_KIT_CLASSIC) {\\n revert CannotDisableClassicDK();\\n }\\n _enableDisputeKit(_courtID, _disputeKitIDs[i], false);\\n }\\n }\\n }\\n\\n /// @notice Changes the supported fee tokens.\\n /// @param _feeToken The fee token.\\n /// @param _accepted Whether the token is supported or not as a method of fee payment.\\n function changeAcceptedFeeTokens(IERC20 _feeToken, bool _accepted) external onlyByOwner {\\n currencyRates[_feeToken].feePaymentAccepted = _accepted;\\n emit AcceptedFeeToken(_feeToken, _accepted);\\n }\\n\\n /// @notice Changes the currency rate of a fee token.\\n /// @param _feeToken The fee token.\\n /// @param _rateInEth The new rate of the fee token in ETH.\\n /// @param _rateDecimals The new decimals of the fee token rate.\\n function changeCurrencyRates(IERC20 _feeToken, uint64 _rateInEth, uint8 _rateDecimals) external onlyByOwner {\\n currencyRates[_feeToken].rateInEth = _rateInEth;\\n currencyRates[_feeToken].rateDecimals = _rateDecimals;\\n emit NewCurrencyRate(_feeToken, _rateInEth, _rateDecimals);\\n }\\n\\n // ************************************* //\\n // * State Modifiers * //\\n // ************************************* //\\n\\n /// @notice Sets the caller's stake in a court.\\n /// @param _courtID The ID of the court.\\n /// @param _newStake The new stake.\\n /// Note that the existing delayed stake will be nullified as non-relevant.\\n function setStake(uint96 _courtID, uint256 _newStake) external {\\n _setStake(msg.sender, _courtID, _newStake, false, OnError.Revert);\\n }\\n\\n /// @notice Sets the stake of a specified account in a court, typically to apply a delayed stake or unstake inactive jurors.\\n /// @param _account The account whose stake is being set.\\n /// @param _courtID The ID of the court.\\n /// @param _newStake The new stake.\\n function setStakeBySortitionModule(address _account, uint96 _courtID, uint256 _newStake) external {\\n if (msg.sender != address(sortitionModule)) revert SortitionModuleOnly();\\n _setStake(_account, _courtID, _newStake, true, OnError.Return);\\n }\\n\\n /// @notice Transfers PNK to the juror by SortitionModule.\\n /// @param _account The account of the juror whose PNK to transfer.\\n /// @param _amount The amount to transfer.\\n function transferBySortitionModule(address _account, uint256 _amount) external {\\n if (msg.sender != address(sortitionModule)) revert SortitionModuleOnly();\\n // Note eligibility is checked in SortitionModule.\\n pinakion.safeTransfer(_account, _amount);\\n }\\n\\n /// @inheritdoc IArbitratorV2\\n function createDispute(\\n uint256 _numberOfChoices,\\n bytes memory _extraData\\n ) external payable override returns (uint256 disputeID) {\\n if (msg.value < arbitrationCost(_extraData)) revert ArbitrationFeesNotEnough();\\n\\n return _createDispute(_numberOfChoices, _extraData, NATIVE_CURRENCY, msg.value);\\n }\\n\\n /// @inheritdoc IArbitratorV2\\n function createDispute(\\n uint256 _numberOfChoices,\\n bytes calldata _extraData,\\n IERC20 _feeToken,\\n uint256 _feeAmount\\n ) external override returns (uint256 disputeID) {\\n if (!currencyRates[_feeToken].feePaymentAccepted) revert TokenNotAccepted();\\n if (_feeAmount < arbitrationCost(_extraData, _feeToken)) revert ArbitrationFeesNotEnough();\\n\\n if (!_feeToken.safeTransferFrom(msg.sender, address(this), _feeAmount)) revert TransferFailed();\\n return _createDispute(_numberOfChoices, _extraData, _feeToken, _feeAmount);\\n }\\n\\n function _createDispute(\\n uint256 _numberOfChoices,\\n bytes memory _extraData,\\n IERC20 _feeToken,\\n uint256 _feeAmount\\n ) internal returns (uint256 disputeID) {\\n (uint96 courtID, , uint256 disputeKitID) = _extraDataToCourtIDMinJurorsDisputeKit(_extraData);\\n if (!courts[courtID].supportedDisputeKits[disputeKitID]) revert DisputeKitNotSupportedByCourt();\\n\\n disputeID = disputes.length;\\n Dispute storage dispute = disputes.push();\\n dispute.courtID = courtID;\\n dispute.arbitrated = IArbitrableV2(msg.sender);\\n dispute.lastPeriodChange = block.timestamp;\\n\\n IDisputeKit disputeKit = disputeKits[disputeKitID];\\n Court storage court = courts[courtID];\\n Round storage round = dispute.rounds.push();\\n\\n // Obtain the feeForJuror in the same currency as the _feeAmount\\n uint256 feeForJuror = (_feeToken == NATIVE_CURRENCY)\\n ? court.feeForJuror\\n : convertEthToTokenAmount(_feeToken, court.feeForJuror);\\n round.nbVotes = _feeAmount / feeForJuror;\\n round.disputeKitID = disputeKitID;\\n round.pnkAtStakePerJuror = (court.minStake * court.alpha) / ONE_BASIS_POINT;\\n round.totalFeesForJurors = _feeAmount;\\n round.feeToken = IERC20(_feeToken);\\n\\n sortitionModule.createDisputeHook(disputeID, 0); // Default round ID.\\n\\n disputeKit.createDispute(disputeID, _numberOfChoices, _extraData, round.nbVotes);\\n emit DisputeCreation(disputeID, IArbitrableV2(msg.sender));\\n }\\n\\n /// @notice Passes the period of a specified dispute.\\n /// @param _disputeID The ID of the dispute.\\n function passPeriod(uint256 _disputeID) external {\\n Dispute storage dispute = disputes[_disputeID];\\n Court storage court = courts[dispute.courtID];\\n\\n uint256 currentRound = dispute.rounds.length - 1;\\n Round storage round = dispute.rounds[currentRound];\\n if (dispute.period == Period.evidence) {\\n if (\\n currentRound == 0 &&\\n block.timestamp - dispute.lastPeriodChange < court.timesPerPeriod[uint256(dispute.period)]\\n ) {\\n revert EvidenceNotPassedAndNotAppeal();\\n }\\n if (round.drawnJurors.length != round.nbVotes) revert DisputeStillDrawing();\\n dispute.period = court.hiddenVotes ? Period.commit : Period.vote;\\n } else if (dispute.period == Period.commit) {\\n if (\\n block.timestamp - dispute.lastPeriodChange < court.timesPerPeriod[uint256(dispute.period)] &&\\n !disputeKits[round.disputeKitID].areCommitsAllCast(_disputeID)\\n ) {\\n revert CommitPeriodNotPassed();\\n }\\n dispute.period = Period.vote;\\n } else if (dispute.period == Period.vote) {\\n if (\\n block.timestamp - dispute.lastPeriodChange < court.timesPerPeriod[uint256(dispute.period)] &&\\n !disputeKits[round.disputeKitID].areVotesAllCast(_disputeID)\\n ) {\\n revert VotePeriodNotPassed();\\n }\\n dispute.period = Period.appeal;\\n emit AppealPossible(_disputeID, dispute.arbitrated);\\n } else if (dispute.period == Period.appeal) {\\n if (\\n block.timestamp - dispute.lastPeriodChange < court.timesPerPeriod[uint256(dispute.period)] &&\\n !disputeKits[round.disputeKitID].isAppealFunded(_disputeID)\\n ) {\\n revert AppealPeriodNotPassed();\\n }\\n dispute.period = Period.execution;\\n } else if (dispute.period == Period.execution) {\\n revert DisputePeriodIsFinal();\\n }\\n\\n dispute.lastPeriodChange = block.timestamp;\\n emit NewPeriod(_disputeID, dispute.period);\\n }\\n\\n /// @notice Draws one juror for the dispute until the number votes paid for is reached.\\n /// @param _disputeID The ID of the dispute.\\n /// @param _juror The address of the juror to draw.\\n function draw(uint256 _disputeID, address _juror) external onlyByOwnerOrInstructor {\\n Dispute storage dispute = disputes[_disputeID];\\n uint256 currentRound = dispute.rounds.length - 1;\\n Round storage round = dispute.rounds[currentRound];\\n if (dispute.period != Period.evidence) revert NotEvidencePeriod();\\n if (round.drawnJurors.length >= round.nbVotes) revert AllJurorsDrawn();\\n\\n sortitionModule.setTransientJuror(_juror);\\n {\\n IDisputeKit disputeKit = disputeKits[round.disputeKitID];\\n uint256 iteration = round.drawIterations + 1;\\n (address drawnAddress, uint96 fromSubcourtID) = disputeKit.draw(_disputeID, iteration);\\n if (drawnAddress == address(0)) {\\n revert NoJurorDrawn();\\n }\\n sortitionModule.lockStake(drawnAddress, round.pnkAtStakePerJuror);\\n emit Draw(drawnAddress, _disputeID, currentRound, round.drawnJurors.length);\\n round.drawnJurors.push(drawnAddress);\\n round.drawnJurorFromCourtIDs.push(fromSubcourtID != 0 ? fromSubcourtID : dispute.courtID);\\n if (round.drawnJurors.length == round.nbVotes) {\\n sortitionModule.postDrawHook(_disputeID, currentRound);\\n }\\n round.drawIterations = iteration;\\n }\\n sortitionModule.setTransientJuror(address(0));\\n }\\n\\n /// @notice Appeals the ruling of a specified dispute.\\n /// @dev Access restricted to the Dispute Kit for this `disputeID`.\\n /// @param _disputeID The ID of the dispute.\\n /// @param _numberOfChoices Number of choices for the dispute. Can be required during court jump.\\n /// @param _extraData Extradata for the dispute. Can be required during court jump.\\n function appeal(uint256 _disputeID, uint256 _numberOfChoices, bytes memory _extraData) external payable {\\n if (msg.value < appealCost(_disputeID)) revert AppealFeesNotEnough();\\n\\n Dispute storage dispute = disputes[_disputeID];\\n if (dispute.period != Period.appeal) revert DisputeNotAppealable();\\n\\n Round storage round = dispute.rounds[dispute.rounds.length - 1];\\n if (msg.sender != address(disputeKits[round.disputeKitID])) revert DisputeKitOnly();\\n\\n uint96 newCourtID = dispute.courtID;\\n uint256 newDisputeKitID = round.disputeKitID;\\n\\n // Warning: the extra round must be created before calling disputeKit.createDispute()\\n Round storage extraRound = dispute.rounds.push();\\n\\n if (round.nbVotes >= courts[newCourtID].jurorsForCourtJump) {\\n // Jump to parent court.\\n newCourtID = courts[newCourtID].parent;\\n\\n if (!courts[newCourtID].supportedDisputeKits[newDisputeKitID]) {\\n // Switch to classic dispute kit if parent court doesn't support the current one.\\n newDisputeKitID = DISPUTE_KIT_CLASSIC;\\n }\\n\\n if (newCourtID != dispute.courtID) {\\n emit CourtJump(_disputeID, dispute.rounds.length - 1, dispute.courtID, newCourtID);\\n }\\n }\\n\\n dispute.courtID = newCourtID;\\n dispute.period = Period.evidence;\\n dispute.lastPeriodChange = block.timestamp;\\n\\n Court storage court = courts[newCourtID];\\n extraRound.nbVotes = msg.value / court.feeForJuror; // As many votes that can be afforded by the provided funds.\\n extraRound.pnkAtStakePerJuror = (court.minStake * court.alpha) / ONE_BASIS_POINT;\\n extraRound.totalFeesForJurors = msg.value;\\n extraRound.disputeKitID = newDisputeKitID;\\n\\n sortitionModule.createDisputeHook(_disputeID, dispute.rounds.length - 1);\\n\\n // Dispute kit was changed, so create a dispute in the new DK contract.\\n if (extraRound.disputeKitID != round.disputeKitID) {\\n emit DisputeKitJump(_disputeID, dispute.rounds.length - 1, round.disputeKitID, extraRound.disputeKitID);\\n disputeKits[extraRound.disputeKitID].createDispute(\\n _disputeID,\\n _numberOfChoices,\\n _extraData,\\n extraRound.nbVotes\\n );\\n }\\n\\n emit AppealDecision(_disputeID, dispute.arbitrated);\\n emit NewPeriod(_disputeID, Period.evidence);\\n }\\n\\n /// @notice Distribute the PNKs at stake and the dispute fees for the specific round of the dispute. Can be called in parts.\\n /// @param _disputeID The ID of the dispute.\\n /// @param _round The appeal round.\\n /// @param _iterations The number of iterations to run.\\n function execute(uint256 _disputeID, uint256 _round, uint256 _iterations) external {\\n Round storage round;\\n {\\n Dispute storage dispute = disputes[_disputeID];\\n if (dispute.period != Period.execution) revert NotExecutionPeriod();\\n\\n round = dispute.rounds[_round];\\n } // stack too deep workaround\\n\\n uint256 start = round.repartitions;\\n uint256 end = round.repartitions + _iterations;\\n\\n uint256 pnkPenaltiesInRound = round.pnkPenalties; // Keep in memory to save gas.\\n uint256 numberOfVotesInRound = round.drawnJurors.length;\\n uint256 feePerJurorInRound = round.totalFeesForJurors / numberOfVotesInRound;\\n uint256 pnkAtStakePerJurorInRound = round.pnkAtStakePerJuror;\\n uint256 coherentCount;\\n {\\n IDisputeKit disputeKit = disputeKits[round.disputeKitID];\\n coherentCount = disputeKit.getCoherentCount(_disputeID, _round); // Total number of jurors that are eligible to a reward in this round.\\n } // stack too deep workaround\\n\\n if (coherentCount == 0) {\\n // We loop over the votes once as there are no rewards because it is not a tie and no one in this round is coherent with the final outcome.\\n if (end > numberOfVotesInRound) end = numberOfVotesInRound;\\n } else {\\n // We loop over the votes twice, first to collect the PNK penalties, and second to distribute them as rewards along with arbitration fees.\\n if (end > numberOfVotesInRound * 2) end = numberOfVotesInRound * 2;\\n }\\n round.repartitions = end;\\n\\n for (uint256 i = start; i < end; i++) {\\n if (i < numberOfVotesInRound) {\\n pnkPenaltiesInRound = _executePenalties(\\n ExecuteParams({\\n disputeID: _disputeID,\\n round: _round,\\n coherentCount: coherentCount,\\n numberOfVotesInRound: numberOfVotesInRound,\\n feePerJurorInRound: feePerJurorInRound,\\n pnkAtStakePerJurorInRound: pnkAtStakePerJurorInRound,\\n pnkPenaltiesInRound: pnkPenaltiesInRound,\\n repartition: i\\n })\\n );\\n } else {\\n _executeRewards(\\n ExecuteParams({\\n disputeID: _disputeID,\\n round: _round,\\n coherentCount: coherentCount,\\n numberOfVotesInRound: numberOfVotesInRound,\\n feePerJurorInRound: feePerJurorInRound,\\n pnkAtStakePerJurorInRound: pnkAtStakePerJurorInRound,\\n pnkPenaltiesInRound: pnkPenaltiesInRound,\\n repartition: i\\n })\\n );\\n }\\n }\\n if (round.pnkPenalties != pnkPenaltiesInRound) {\\n round.pnkPenalties = pnkPenaltiesInRound; // Reentrancy risk: breaks Check-Effect-Interact\\n }\\n }\\n\\n /// @notice Distribute the PNKs at stake and the dispute fees for the specific round of the dispute, penalties only.\\n /// @param _params The parameters for the execution, see `ExecuteParams`.\\n /// @return pnkPenaltiesInRoundCache The updated penalties in round cache.\\n function _executePenalties(ExecuteParams memory _params) internal returns (uint256) {\\n Dispute storage dispute = disputes[_params.disputeID];\\n Round storage round = dispute.rounds[_params.round];\\n IDisputeKit disputeKit = disputeKits[round.disputeKitID];\\n\\n // [0, 1] value that determines how coherent the juror was in this round, in basis points.\\n uint256 coherence = disputeKit.getDegreeOfCoherencePenalty(\\n _params.disputeID,\\n _params.round,\\n _params.repartition,\\n _params.feePerJurorInRound,\\n _params.pnkAtStakePerJurorInRound\\n );\\n\\n // Guard against degree exceeding 1, though it should be ensured by the dispute kit.\\n if (coherence > ONE_BASIS_POINT) {\\n coherence = ONE_BASIS_POINT;\\n }\\n\\n // Fully coherent jurors won't be penalized.\\n uint256 penalty = (round.pnkAtStakePerJuror * (ONE_BASIS_POINT - coherence)) / ONE_BASIS_POINT;\\n\\n // Unlock the PNKs affected by the penalty\\n address account = round.drawnJurors[_params.repartition];\\n sortitionModule.unlockStake(account, penalty);\\n\\n // Apply the penalty to the staked PNKs.\\n uint96 penalizedInCourtID = round.drawnJurorFromCourtIDs[_params.repartition];\\n (uint256 pnkBalance, uint256 newCourtStake, uint256 availablePenalty) = sortitionModule.setStakePenalty(\\n account,\\n penalizedInCourtID,\\n penalty\\n );\\n _params.pnkPenaltiesInRound += availablePenalty;\\n emit JurorRewardPenalty(\\n account,\\n _params.disputeID,\\n _params.round,\\n coherence,\\n coherence,\\n -int256(availablePenalty),\\n 0,\\n round.feeToken\\n );\\n\\n if (pnkBalance == 0 || !disputeKit.isVoteActive(_params.disputeID, _params.round, _params.repartition)) {\\n // The juror is inactive or their balance is can't cover penalties anymore, unstake them from all courts.\\n sortitionModule.forcedUnstakeAllCourts(account);\\n } else if (newCourtStake < courts[penalizedInCourtID].minStake) {\\n // The juror's balance fell below the court minStake, unstake them from the court.\\n sortitionModule.forcedUnstake(account, penalizedInCourtID);\\n }\\n\\n if (_params.repartition == _params.numberOfVotesInRound - 1 && _params.coherentCount == 0) {\\n // No one was coherent, send the rewards to the owner.\\n if (round.feeToken == NATIVE_CURRENCY) {\\n // The dispute fees were paid in ETH\\n payable(owner).send(round.totalFeesForJurors);\\n } else {\\n // The dispute fees were paid in ERC20\\n round.feeToken.safeTransfer(owner, round.totalFeesForJurors);\\n }\\n pinakion.safeTransfer(owner, _params.pnkPenaltiesInRound);\\n emit LeftoverRewardSent(\\n _params.disputeID,\\n _params.round,\\n _params.pnkPenaltiesInRound,\\n round.totalFeesForJurors,\\n round.feeToken\\n );\\n }\\n return _params.pnkPenaltiesInRound;\\n }\\n\\n /// @notice Distribute the PNKs at stake and the dispute fees for the specific round of the dispute, rewards only.\\n /// @param _params The parameters for the execution, see `ExecuteParams`.\\n function _executeRewards(ExecuteParams memory _params) internal {\\n Dispute storage dispute = disputes[_params.disputeID];\\n Round storage round = dispute.rounds[_params.round];\\n IDisputeKit disputeKit = disputeKits[round.disputeKitID];\\n\\n // [0, 1] value that determines how coherent the juror was in this round, in basis points.\\n (uint256 pnkCoherence, uint256 feeCoherence) = disputeKit.getDegreeOfCoherenceReward(\\n _params.disputeID,\\n _params.round,\\n _params.repartition % _params.numberOfVotesInRound,\\n _params.feePerJurorInRound,\\n _params.pnkAtStakePerJurorInRound\\n );\\n\\n // Guard against degree exceeding 1, though it should be ensured by the dispute kit.\\n if (pnkCoherence > ONE_BASIS_POINT) {\\n pnkCoherence = ONE_BASIS_POINT;\\n }\\n if (feeCoherence > ONE_BASIS_POINT) {\\n feeCoherence = ONE_BASIS_POINT;\\n }\\n\\n address account = round.drawnJurors[_params.repartition % _params.numberOfVotesInRound];\\n uint256 pnkLocked = (round.pnkAtStakePerJuror * pnkCoherence) / ONE_BASIS_POINT;\\n\\n // Release the rest of the PNKs of the juror for this round.\\n sortitionModule.unlockStake(account, pnkLocked);\\n\\n // Compute the rewards\\n uint256 pnkReward = ((_params.pnkPenaltiesInRound / _params.coherentCount) * pnkCoherence) / ONE_BASIS_POINT; /// forge-lint: disable-line(divide-before-multiply)\\n round.sumPnkRewardPaid += pnkReward;\\n uint256 feeReward = ((round.totalFeesForJurors / _params.coherentCount) * feeCoherence) / ONE_BASIS_POINT; /// forge-lint: disable-line(divide-before-multiply)\\n round.sumFeeRewardPaid += feeReward;\\n\\n // Transfer the fee reward\\n if (round.feeToken == NATIVE_CURRENCY) {\\n // The dispute fees were paid in ETH\\n payable(account).send(feeReward);\\n } else {\\n // The dispute fees were paid in ERC20\\n round.feeToken.safeTransfer(account, feeReward);\\n }\\n\\n // Stake the PNK reward if possible, by-passes delayed stakes and other checks usually done by validateStake()\\n if (!sortitionModule.setStakeReward(account, dispute.courtID, pnkReward)) {\\n pinakion.safeTransfer(account, pnkReward);\\n }\\n\\n emit JurorRewardPenalty(\\n account,\\n _params.disputeID,\\n _params.round,\\n pnkCoherence,\\n feeCoherence,\\n int256(pnkReward),\\n int256(feeReward),\\n round.feeToken\\n );\\n\\n // Transfer any residual rewards to the owner. It may happen due to partial coherence of the jurors.\\n if (_params.repartition == _params.numberOfVotesInRound * 2 - 1) {\\n uint256 leftoverPnkReward = _params.pnkPenaltiesInRound - round.sumPnkRewardPaid;\\n uint256 leftoverFeeReward = round.totalFeesForJurors - round.sumFeeRewardPaid;\\n if (leftoverPnkReward != 0 || leftoverFeeReward != 0) {\\n if (leftoverPnkReward != 0) {\\n pinakion.safeTransfer(owner, leftoverPnkReward);\\n }\\n if (leftoverFeeReward != 0) {\\n if (round.feeToken == NATIVE_CURRENCY) {\\n // The dispute fees were paid in ETH\\n payable(owner).send(leftoverFeeReward);\\n } else {\\n // The dispute fees were paid in ERC20\\n round.feeToken.safeTransfer(owner, leftoverFeeReward);\\n }\\n }\\n emit LeftoverRewardSent(\\n _params.disputeID,\\n _params.round,\\n leftoverPnkReward,\\n leftoverFeeReward,\\n round.feeToken\\n );\\n }\\n }\\n }\\n\\n /// @notice Executes a specified dispute's ruling.\\n /// @param _disputeID The ID of the dispute.\\n function executeRuling(uint256 _disputeID) external {\\n Dispute storage dispute = disputes[_disputeID];\\n if (dispute.period != Period.execution) revert NotExecutionPeriod();\\n if (dispute.ruled) revert RulingAlreadyExecuted();\\n\\n (uint256 winningChoice, , ) = currentRuling(_disputeID);\\n dispute.ruled = true;\\n emit Ruling(dispute.arbitrated, _disputeID, winningChoice);\\n dispute.arbitrated.rule(_disputeID, winningChoice);\\n }\\n\\n // ************************************* //\\n // * Public Views * //\\n // ************************************* //\\n\\n /// @inheritdoc IArbitratorV2\\n function arbitrationCost(bytes memory _extraData) public view override returns (uint256 cost) {\\n (uint96 courtID, uint256 minJurors, ) = _extraDataToCourtIDMinJurorsDisputeKit(_extraData);\\n cost = courts[courtID].feeForJuror * minJurors;\\n }\\n\\n /// @inheritdoc IArbitratorV2\\n function arbitrationCost(bytes calldata _extraData, IERC20 _feeToken) public view override returns (uint256 cost) {\\n cost = convertEthToTokenAmount(_feeToken, arbitrationCost(_extraData));\\n }\\n\\n /// @notice Gets the cost of appealing a specified dispute.\\n /// @param _disputeID The ID of the dispute.\\n /// @return cost The appeal cost.\\n function appealCost(uint256 _disputeID) public view returns (uint256 cost) {\\n Dispute storage dispute = disputes[_disputeID];\\n Round storage round = dispute.rounds[dispute.rounds.length - 1];\\n Court storage court = courts[dispute.courtID];\\n if (round.nbVotes >= court.jurorsForCourtJump) {\\n // Jump to parent court.\\n if (dispute.courtID == GENERAL_COURT) {\\n // TODO: Handle the forking when appealed in General court.\\n cost = NON_PAYABLE_AMOUNT; // Get the cost of the parent court.\\n } else {\\n cost = courts[court.parent].feeForJuror * ((round.nbVotes * 2) + 1);\\n }\\n } else {\\n // Stay in current court.\\n cost = court.feeForJuror * ((round.nbVotes * 2) + 1);\\n }\\n }\\n\\n /// @notice Gets the start and the end of a specified dispute's current appeal period.\\n /// @param _disputeID The ID of the dispute.\\n /// @return start The start of the appeal period.\\n /// @return end The end of the appeal period.\\n function appealPeriod(uint256 _disputeID) public view returns (uint256 start, uint256 end) {\\n Dispute storage dispute = disputes[_disputeID];\\n if (dispute.period == Period.appeal) {\\n start = dispute.lastPeriodChange;\\n end = dispute.lastPeriodChange + courts[dispute.courtID].timesPerPeriod[uint256(Period.appeal)];\\n } else {\\n start = 0;\\n end = 0;\\n }\\n }\\n\\n /// @inheritdoc IArbitratorV2\\n function currentRuling(uint256 _disputeID) public view returns (uint256 ruling, bool tied, bool overridden) {\\n Dispute storage dispute = disputes[_disputeID];\\n Round storage round = dispute.rounds[dispute.rounds.length - 1];\\n IDisputeKit disputeKit = disputeKits[round.disputeKitID];\\n (ruling, tied, overridden) = disputeKit.currentRuling(_disputeID);\\n }\\n\\n /// @notice Gets the round info for a specified dispute and round.\\n /// @dev This function must not be called from a non-view function because it returns a dynamic array which might be very large, theoretically exceeding the block gas limit.\\n /// @param _disputeID The ID of the dispute.\\n /// @param _round The round to get the info for.\\n /// @return round The round info.\\n function getRoundInfo(uint256 _disputeID, uint256 _round) external view returns (Round memory) {\\n return disputes[_disputeID].rounds[_round];\\n }\\n\\n /// @notice Gets the PNK at stake per juror for a specified dispute and round.\\n /// @param _disputeID The ID of the dispute.\\n /// @param _round The round to get the info for.\\n /// @return pnkAtStakePerJuror The PNK at stake per juror.\\n function getPnkAtStakePerJuror(uint256 _disputeID, uint256 _round) external view returns (uint256) {\\n return disputes[_disputeID].rounds[_round].pnkAtStakePerJuror;\\n }\\n\\n /// @notice Gets the number of rounds for a specified dispute.\\n /// @param _disputeID The ID of the dispute.\\n /// @return The number of rounds.\\n function getNumberOfRounds(uint256 _disputeID) external view returns (uint256) {\\n return disputes[_disputeID].rounds.length;\\n }\\n\\n /// @notice Checks if a given dispute kit is supported by a given court.\\n /// @param _courtID The ID of the court to check the support for.\\n /// @param _disputeKitID The ID of the dispute kit to check the support for.\\n /// @return Whether the dispute kit is supported or not.\\n function isSupported(uint96 _courtID, uint256 _disputeKitID) external view returns (bool) {\\n return courts[_courtID].supportedDisputeKits[_disputeKitID];\\n }\\n\\n /// @notice Gets the timesPerPeriod array for a given court.\\n /// @param _courtID The ID of the court to get the times from.\\n /// @return timesPerPeriod The timesPerPeriod array for the given court.\\n function getTimesPerPeriod(uint96 _courtID) external view returns (uint256[4] memory timesPerPeriod) {\\n timesPerPeriod = courts[_courtID].timesPerPeriod;\\n }\\n\\n // ************************************* //\\n // * Public Views for Dispute Kits * //\\n // ************************************* //\\n\\n /// @notice Gets the number of votes permitted for the specified dispute in the latest round.\\n /// @param _disputeID The ID of the dispute.\\n function getNumberOfVotes(uint256 _disputeID) external view returns (uint256) {\\n Dispute storage dispute = disputes[_disputeID];\\n return dispute.rounds[dispute.rounds.length - 1].nbVotes;\\n }\\n\\n /// @notice Returns true if the dispute kit will be switched to a parent DK.\\n /// @param _disputeID The ID of the dispute.\\n /// @return Whether DK will be switched or not.\\n function isDisputeKitJumping(uint256 _disputeID) external view returns (bool) {\\n Dispute storage dispute = disputes[_disputeID];\\n Round storage round = dispute.rounds[dispute.rounds.length - 1];\\n Court storage court = courts[dispute.courtID];\\n\\n if (round.nbVotes < court.jurorsForCourtJump) {\\n return false;\\n }\\n\\n // Jump if the parent court doesn't support the current DK.\\n return !courts[court.parent].supportedDisputeKits[round.disputeKitID];\\n }\\n\\n function getDisputeKitsLength() external view returns (uint256) {\\n return disputeKits.length;\\n }\\n\\n function convertEthToTokenAmount(IERC20 _toToken, uint256 _amountInEth) public view returns (uint256) {\\n return (_amountInEth * 10 ** currencyRates[_toToken].rateDecimals) / currencyRates[_toToken].rateInEth;\\n }\\n\\n // ************************************* //\\n // * Internal * //\\n // ************************************* //\\n\\n /// @notice Toggles the dispute kit support for a given court.\\n /// @param _courtID The ID of the court to toggle the support for.\\n /// @param _disputeKitID The ID of the dispute kit to toggle the support for.\\n /// @param _enable Whether to enable or disable the support. Note that classic dispute kit should always be enabled.\\n function _enableDisputeKit(uint96 _courtID, uint256 _disputeKitID, bool _enable) internal {\\n courts[_courtID].supportedDisputeKits[_disputeKitID] = _enable;\\n emit DisputeKitEnabled(_courtID, _disputeKitID, _enable);\\n }\\n\\n /// @notice If called only once then set _onError to Revert, otherwise set it to Return\\n /// @param _account The account to set the stake for.\\n /// @param _courtID The ID of the court to set the stake for.\\n /// @param _newStake The new stake.\\n /// @param _noDelay True if the stake change should not be delayed.\\n /// @param _onError Whether to revert or return false on error.\\n /// @return Whether the stake was successfully set or not.\\n function _setStake(\\n address _account,\\n uint96 _courtID,\\n uint256 _newStake,\\n bool _noDelay,\\n OnError _onError\\n ) internal returns (bool) {\\n if (_courtID == FORKING_COURT || _courtID >= courts.length) {\\n _stakingFailed(_onError, StakingResult.CannotStakeInThisCourt); // Staking directly into the forking court is not allowed.\\n return false;\\n }\\n if (_newStake != 0 && _newStake < courts[_courtID].minStake) {\\n _stakingFailed(_onError, StakingResult.CannotStakeLessThanMinStake); // Staking less than the minimum stake is not allowed.\\n return false;\\n }\\n (uint256 pnkDeposit, uint256 pnkWithdrawal, StakingResult stakingResult) = sortitionModule.validateStake(\\n _account,\\n _courtID,\\n _newStake,\\n _noDelay\\n );\\n if (stakingResult != StakingResult.Successful) {\\n _stakingFailed(_onError, stakingResult);\\n return false;\\n }\\n if (pnkDeposit > 0) {\\n if (!pinakion.safeTransferFrom(_account, address(this), pnkDeposit)) {\\n _stakingFailed(_onError, StakingResult.StakingTransferFailed);\\n return false;\\n }\\n }\\n if (pnkWithdrawal > 0) {\\n if (!pinakion.safeTransfer(_account, pnkWithdrawal)) {\\n _stakingFailed(_onError, StakingResult.UnstakingTransferFailed);\\n return false;\\n }\\n }\\n sortitionModule.setStake(_account, _courtID, pnkDeposit, pnkWithdrawal, _newStake);\\n\\n return true;\\n }\\n\\n /// @notice It may revert depending on the _onError parameter.\\n function _stakingFailed(OnError _onError, StakingResult _result) internal pure virtual {\\n if (_onError == OnError.Return) return;\\n if (_result == StakingResult.StakingTransferFailed) revert StakingTransferFailed();\\n if (_result == StakingResult.UnstakingTransferFailed) revert UnstakingTransferFailed();\\n if (_result == StakingResult.CannotStakeInMoreCourts) revert StakingInTooManyCourts();\\n if (_result == StakingResult.CannotStakeInThisCourt) revert StakingNotPossibleInThisCourt();\\n if (_result == StakingResult.CannotStakeLessThanMinStake) revert StakingLessThanCourtMinStake();\\n if (_result == StakingResult.CannotStakeZeroWhenNoStake) revert StakingZeroWhenNoStake();\\n }\\n\\n /// @notice Gets a court ID, the minimum number of jurors and an ID of a dispute kit from a specified extra data bytes array.\\n /// @dev If `_extraData` contains an incorrect value then this value will be switched to default.\\n /// @param _extraData The extra data bytes array. The first 32 bytes are the court ID, the next are the minimum number of jurors and the last are the dispute kit ID.\\n /// @return courtID The court ID.\\n /// @return minJurors The minimum number of jurors required.\\n /// @return disputeKitID The ID of the dispute kit.\\n function _extraDataToCourtIDMinJurorsDisputeKit(\\n bytes memory _extraData\\n ) internal view returns (uint96 courtID, uint256 minJurors, uint256 disputeKitID) {\\n // Note that if the extradata doesn't contain 32 bytes for the dispute kit ID it'll return the default 0 index.\\n if (_extraData.length >= 64) {\\n assembly {\\n // solium-disable-line security/no-inline-assembly\\n courtID := mload(add(_extraData, 0x20))\\n minJurors := mload(add(_extraData, 0x40))\\n disputeKitID := mload(add(_extraData, 0x60))\\n }\\n if (courtID == FORKING_COURT || courtID >= courts.length) {\\n courtID = GENERAL_COURT;\\n }\\n if (minJurors == 0) {\\n minJurors = DEFAULT_NB_OF_JURORS;\\n }\\n if (disputeKitID == NULL_DISPUTE_KIT || disputeKitID >= disputeKits.length) {\\n disputeKitID = DISPUTE_KIT_CLASSIC; // 0 index is not used.\\n }\\n } else {\\n courtID = GENERAL_COURT;\\n minJurors = DEFAULT_NB_OF_JURORS;\\n disputeKitID = DISPUTE_KIT_CLASSIC;\\n }\\n }\\n\\n // ************************************* //\\n // * Errors * //\\n // ************************************* //\\n\\n error OwnerOnly();\\n error InstructorOnly();\\n error OwnerOrInstructorOnly();\\n error DisputeKitOnly();\\n error SortitionModuleOnly();\\n error UnsuccessfulCall();\\n error InvalidDisputKitParent();\\n error MinStakeLowerThanParentCourt();\\n error UnsupportedDisputeKit();\\n error InvalidForkingCourtAsParent();\\n error WrongDisputeKitIndex();\\n error CannotDisableClassicDK();\\n error StakingInTooManyCourts();\\n error StakingNotPossibleInThisCourt();\\n error StakingLessThanCourtMinStake();\\n error StakingTransferFailed();\\n error UnstakingTransferFailed();\\n error ArbitrationFeesNotEnough();\\n error DisputeKitNotSupportedByCourt();\\n error MustSupportDisputeKitClassic();\\n error TokenNotAccepted();\\n error EvidenceNotPassedAndNotAppeal();\\n error DisputeStillDrawing();\\n error CommitPeriodNotPassed();\\n error VotePeriodNotPassed();\\n error AppealPeriodNotPassed();\\n error NotEvidencePeriod();\\n error AppealFeesNotEnough();\\n error DisputeNotAppealable();\\n error NotExecutionPeriod();\\n error RulingAlreadyExecuted();\\n error DisputePeriodIsFinal();\\n error TransferFailed();\\n error AllJurorsDrawn();\\n error NoJurorDrawn();\\n error StakingZeroWhenNoStake();\\n}\\n\",\"keccak256\":\"0x6a0daf9a8720b0618dc69c8b29794fad12f5477d4ec96c778c7c140150b8214d\",\"license\":\"MIT\"},\"src/arbitration/university/SortitionModuleUniversity.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.24;\\n\\nimport \\\"./KlerosCoreUniversity.sol\\\";\\nimport \\\"./ISortitionModuleUniversity.sol\\\";\\nimport \\\"../interfaces/IDisputeKit.sol\\\";\\nimport \\\"../../proxy/UUPSProxiable.sol\\\";\\nimport \\\"../../proxy/Initializable.sol\\\";\\nimport \\\"../../libraries/Constants.sol\\\";\\n\\n/// @title SortitionModuleUniversity\\n/// @notice An adapted version of the SortitionModule contract for educational purposes.\\ncontract SortitionModuleUniversity is ISortitionModuleUniversity, UUPSProxiable, Initializable {\\n string public constant override version = \\\"2.0.0\\\";\\n\\n // ************************************* //\\n // * Enums / Structs * //\\n // ************************************* //\\n\\n struct Juror {\\n mapping(uint96 => uint256) stakesByCourtID; // The stakes of the juror in particular courts.\\n uint96[] courtIDs; // The IDs of courts where the juror's stake path ends. A stake path is a path from the general court to a court the juror directly staked in using `_setStake`.\\n uint256 stakedPnk; // The juror's total amount of tokens staked in subcourts. Reflects actual pnk balance.\\n uint256 lockedPnk; // The juror's total amount of tokens locked in disputes. Can reflect actual pnk balance when stakedPnk are fully withdrawn.\\n }\\n\\n // ************************************* //\\n // * Storage * //\\n // ************************************* //\\n\\n address public owner; // The owner of the contract.\\n KlerosCoreUniversity public core; // The core arbitrator contract.\\n uint256 public disputesWithoutJurors; // The number of disputes that have not finished drawing jurors.\\n mapping(address account => Juror) public jurors; // The jurors.\\n address private transientJuror; // The juror address used between calls within the same transaction.\\n\\n // ************************************* //\\n // * Events * //\\n // ************************************* //\\n\\n /// @notice Emitted when a juror stakes in a court.\\n /// @param _address The address of the juror.\\n /// @param _courtID The ID of the court.\\n /// @param _amount The amount of tokens staked in the court.\\n /// @param _amountAllCourts The amount of tokens staked in all courts.\\n event StakeSet(address indexed _address, uint256 _courtID, uint256 _amount, uint256 _amountAllCourts);\\n\\n /// @notice Emitted when a juror's stake is locked.\\n /// @param _address The address of the juror.\\n /// @param _relativeAmount The amount of tokens locked.\\n /// @param _unlock Whether the stake is locked or unlocked.\\n event StakeLocked(address indexed _address, uint256 _relativeAmount, bool _unlock);\\n\\n /// @notice Emitted when leftover PNK is available.\\n /// @param _account The account of the juror.\\n /// @param _amount The amount of PNK available.\\n event LeftoverPNK(address indexed _account, uint256 _amount);\\n\\n /// @notice Emitted when leftover PNK is withdrawn.\\n /// @param _account The account of the juror withdrawing PNK.\\n /// @param _amount The amount of PNK withdrawn.\\n event LeftoverPNKWithdrawn(address indexed _account, uint256 _amount);\\n\\n // ************************************* //\\n // * Function Modifiers * //\\n // ************************************* //\\n\\n modifier onlyByOwner() {\\n if (owner != msg.sender) revert OwnerOnly();\\n _;\\n }\\n\\n modifier onlyByCore() {\\n if (address(core) != msg.sender) revert KlerosCoreOnly();\\n _;\\n }\\n\\n // ************************************* //\\n // * Constructor * //\\n // ************************************* //\\n\\n /// @custom:oz-upgrades-unsafe-allow constructor\\n constructor() {\\n _disableInitializers();\\n }\\n\\n /// @notice Initializer (constructor equivalent for upgradable contracts).\\n /// @param _core The KlerosCore.\\n function initialize(address _owner, KlerosCoreUniversity _core) external initializer {\\n owner = _owner;\\n core = _core;\\n }\\n\\n // ************************************* //\\n // * Governance * //\\n // ************************************* //\\n\\n /**\\n * @dev Access Control to perform implementation upgrades (UUPS Proxiable)\\n * @dev Only the owner can perform upgrades (`onlyByOwner`)\\n */\\n function _authorizeUpgrade(address) internal view override onlyByOwner {\\n // NOP\\n }\\n\\n // ************************************* //\\n // * State Modifiers * //\\n // ************************************* //\\n\\n /// @inheritdoc ISortitionModule\\n function passPhase() external override onlyByCore {\\n // NOP\\n }\\n\\n /// @inheritdoc ISortitionModule\\n function executeDelayedStakes(uint256 _iterations) external override onlyByCore {\\n // NOP\\n }\\n\\n /// @inheritdoc ISortitionModuleUniversity\\n function setTransientJuror(address _juror) external override onlyByCore {\\n transientJuror = _juror;\\n }\\n\\n /// @inheritdoc ISortitionModule\\n function createTree(uint96 _courtID, bytes memory _extraData) external {\\n // NOP\\n }\\n\\n /// @inheritdoc ISortitionModule\\n function createDisputeHook(uint256 /*_disputeID*/, uint256 /*_roundID*/) external override onlyByCore {\\n disputesWithoutJurors++;\\n }\\n\\n /// @inheritdoc ISortitionModule\\n function postDrawHook(uint256 /*_disputeID*/, uint256 /*_roundID*/) external override onlyByCore {\\n disputesWithoutJurors--;\\n }\\n\\n /// @inheritdoc ISortitionModule\\n function validateStake(\\n address _account,\\n uint96 _courtID,\\n uint256 _newStake,\\n bool /*_noDelay*/\\n )\\n external\\n view\\n override\\n onlyByCore\\n returns (uint256 pnkDeposit, uint256 pnkWithdrawal, StakingResult stakingResult)\\n {\\n Juror storage juror = jurors[_account];\\n uint256 currentStake = _stakeOf(_account, _courtID);\\n\\n uint256 nbCourts = juror.courtIDs.length;\\n if (currentStake == 0 && nbCourts >= MAX_STAKE_PATHS) {\\n return (0, 0, StakingResult.CannotStakeInMoreCourts); // Prevent staking beyond MAX_STAKE_PATHS but unstaking is always allowed.\\n }\\n\\n if (currentStake == 0 && _newStake == 0) {\\n return (0, 0, StakingResult.CannotStakeZeroWhenNoStake); // Forbid staking 0 amount when current stake is 0 to avoid flaky behaviour.\\n }\\n\\n if (_newStake >= currentStake) {\\n pnkDeposit = _newStake - currentStake;\\n } else {\\n pnkWithdrawal = currentStake - _newStake;\\n // Ensure locked tokens remain in the contract. They can only be released during Execution.\\n uint256 possibleWithdrawal = juror.stakedPnk > juror.lockedPnk ? juror.stakedPnk - juror.lockedPnk : 0;\\n if (pnkWithdrawal > possibleWithdrawal) {\\n pnkWithdrawal = possibleWithdrawal;\\n }\\n }\\n return (pnkDeposit, pnkWithdrawal, StakingResult.Successful);\\n }\\n\\n /// @inheritdoc ISortitionModule\\n function setStake(\\n address _account,\\n uint96 _courtID,\\n uint256 _pnkDeposit,\\n uint256 _pnkWithdrawal,\\n uint256 _newStake\\n ) external override onlyByCore {\\n _setStake(_account, _courtID, _pnkDeposit, _pnkWithdrawal, _newStake);\\n }\\n\\n function setStakePenalty(\\n address _account,\\n uint96 _courtID,\\n uint256 _penalty\\n ) external override onlyByCore returns (uint256 pnkBalance, uint256 newCourtStake, uint256 availablePenalty) {\\n Juror storage juror = jurors[_account];\\n availablePenalty = _penalty;\\n newCourtStake = _stakeOf(_account, _courtID);\\n if (juror.stakedPnk < _penalty) {\\n availablePenalty = juror.stakedPnk;\\n }\\n\\n if (availablePenalty == 0) return (juror.stakedPnk, newCourtStake, 0); // No penalty to apply.\\n\\n uint256 currentStake = _stakeOf(_account, _courtID);\\n uint256 newStake = 0;\\n if (currentStake >= availablePenalty) {\\n newStake = currentStake - availablePenalty;\\n }\\n _setStake(_account, _courtID, 0, availablePenalty, newStake);\\n pnkBalance = juror.stakedPnk; // updated by _setStake()\\n newCourtStake = _stakeOf(_account, _courtID); // updated by _setStake()\\n }\\n\\n /// @inheritdoc ISortitionModule\\n function setStakeReward(\\n address _account,\\n uint96 _courtID,\\n uint256 _reward\\n ) external override onlyByCore returns (bool success) {\\n if (_reward == 0) return true; // No reward to add.\\n\\n uint256 currentStake = _stakeOf(_account, _courtID);\\n if (currentStake == 0) return false; // Juror has been unstaked, don't increase their stake.\\n\\n uint256 newStake = currentStake + _reward;\\n _setStake(_account, _courtID, _reward, 0, newStake);\\n return true;\\n }\\n\\n function _setStake(\\n address _account,\\n uint96 _courtID,\\n uint256 _pnkDeposit,\\n uint256 _pnkWithdrawal,\\n uint256 _newStake\\n ) internal {\\n Juror storage juror = jurors[_account];\\n uint256 currentStake = _stakeOf(_account, _courtID);\\n if (_pnkDeposit > 0) {\\n if (currentStake == 0) {\\n juror.courtIDs.push(_courtID);\\n }\\n // Increase juror's balance by deposited amount.\\n juror.stakedPnk += _pnkDeposit;\\n } else {\\n juror.stakedPnk -= _pnkWithdrawal;\\n if (_newStake == 0) {\\n // Cleanup\\n for (uint256 i = juror.courtIDs.length; i > 0; i--) {\\n if (juror.courtIDs[i - 1] == _courtID) {\\n juror.courtIDs[i - 1] = juror.courtIDs[juror.courtIDs.length - 1];\\n juror.courtIDs.pop();\\n break;\\n }\\n }\\n }\\n }\\n\\n bool finished = false;\\n uint96 currentCourtID = _courtID;\\n while (!finished) {\\n // Tokens are also implicitly staked in parent courts through sortition module to increase the chance of being drawn.\\n juror.stakesByCourtID[currentCourtID] += _newStake;\\n juror.stakesByCourtID[currentCourtID] -= currentStake;\\n if (currentCourtID == GENERAL_COURT) {\\n finished = true;\\n } else {\\n (currentCourtID, , , , , ) = core.courts(currentCourtID);\\n }\\n }\\n emit StakeSet(_account, _courtID, _newStake, juror.stakedPnk);\\n }\\n\\n function lockStake(address _account, uint256 _relativeAmount) external override onlyByCore {\\n jurors[_account].lockedPnk += _relativeAmount;\\n emit StakeLocked(_account, _relativeAmount, false);\\n }\\n\\n function unlockStake(address _account, uint256 _relativeAmount) external override onlyByCore {\\n jurors[_account].lockedPnk -= _relativeAmount;\\n emit StakeLocked(_account, _relativeAmount, true);\\n }\\n\\n /// @inheritdoc ISortitionModule\\n function forcedUnstakeAllCourts(address _account) external override onlyByCore {\\n uint96[] memory courtIDs = getJurorCourtIDs(_account);\\n for (uint256 j = courtIDs.length; j > 0; j--) {\\n core.setStakeBySortitionModule(_account, courtIDs[j - 1], 0);\\n }\\n }\\n\\n /// @inheritdoc ISortitionModule\\n function forcedUnstake(address _account, uint96 _courtID) external override onlyByCore {\\n core.setStakeBySortitionModule(_account, _courtID, 0);\\n }\\n\\n /// @inheritdoc ISortitionModule\\n function withdrawLeftoverPNK(address _account) external override {\\n // Can withdraw the leftover PNK if fully unstaked, has no tokens locked and has positive balance.\\n // This withdrawal can't be triggered by calling setStake() in KlerosCore because current stake is technically 0, thus it is done via separate function.\\n uint256 amount = getJurorLeftoverPNK(_account);\\n if (amount == 0) revert NotEligibleForWithdrawal();\\n jurors[_account].stakedPnk = 0;\\n core.transferBySortitionModule(_account, amount);\\n emit LeftoverPNKWithdrawn(_account, amount);\\n }\\n\\n // ************************************* //\\n // * Public Views * //\\n // ************************************* //\\n\\n /// @inheritdoc ISortitionModule\\n function draw(uint96, uint256, uint256) public view override returns (address drawnAddress, uint96 fromSubcourtID) {\\n drawnAddress = transientJuror;\\n }\\n\\n /// @inheritdoc ISortitionModule\\n function getJurorBalance(\\n address _juror,\\n uint96 _courtID\\n )\\n external\\n view\\n override\\n returns (uint256 totalStaked, uint256 totalLocked, uint256 stakedInCourt, uint256 nbCourts)\\n {\\n Juror storage juror = jurors[_juror];\\n totalStaked = juror.stakedPnk;\\n totalLocked = juror.lockedPnk;\\n nbCourts = juror.courtIDs.length;\\n for (uint256 i = 0; i < nbCourts; i++) {\\n if (juror.courtIDs[i] == _courtID) {\\n stakedInCourt = juror.stakesByCourtID[_courtID];\\n break;\\n }\\n }\\n }\\n\\n /// @inheritdoc ISortitionModule\\n function getJurorCourtIDs(address _juror) public view override returns (uint96[] memory) {\\n return jurors[_juror].courtIDs;\\n }\\n\\n /// @inheritdoc ISortitionModule\\n function isJurorStaked(address _juror) external view override returns (bool) {\\n return jurors[_juror].stakedPnk > 0;\\n }\\n\\n /// @inheritdoc ISortitionModule\\n function getJurorLeftoverPNK(address _juror) public view override returns (uint256) {\\n Juror storage juror = jurors[_juror];\\n if (juror.courtIDs.length == 0 && juror.lockedPnk == 0) {\\n return juror.stakedPnk;\\n }\\n return 0;\\n }\\n\\n // ************************************* //\\n // * Internal * //\\n // ************************************* //\\n\\n /// @notice Gets the stake of a juror in a court.\\n ///\\n /// @dev Warning: `O(n)` complexity where `n` is the number of courts the juror has staked in\\n /// but acceptable for this educational implementation.\\n ///\\n /// @param _juror The address of the juror.\\n /// @param _courtID The ID of the court.\\n /// @return stakedInCourt The amount of tokens staked by the juror in the court.\\n function _stakeOf(address _juror, uint96 _courtID) internal view returns (uint256 stakedInCourt) {\\n Juror storage juror = jurors[_juror];\\n for (uint256 i = 0; i < juror.courtIDs.length; i++) {\\n if (juror.courtIDs[i] == _courtID) {\\n stakedInCourt = juror.stakesByCourtID[_courtID];\\n break;\\n }\\n }\\n }\\n\\n // ************************************* //\\n // * Errors * //\\n // ************************************* //\\n\\n error OwnerOnly();\\n error KlerosCoreOnly();\\n error NotEligibleForWithdrawal();\\n}\\n\",\"keccak256\":\"0x518a3b161ea7c1199aed0932c71ec866106bfb13b24e633bd2fd0924c136403d\",\"license\":\"MIT\"},\"src/libraries/Constants.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n// Courts\\nuint96 constant FORKING_COURT = 0; // Index of the forking court.\\nuint96 constant GENERAL_COURT = 1; // Index of the default (general) court.\\n\\n// Dispute Kits\\nuint256 constant NULL_DISPUTE_KIT = 0; // Null pattern to indicate a top-level DK which has no parent.\\nuint256 constant DISPUTE_KIT_CLASSIC = 1; // Index of the default DK. 0 index is skipped.\\n\\n// Sortition Module\\nuint256 constant MAX_STAKE_PATHS = 4; // The maximum number of stake paths a juror can have.\\nuint256 constant DEFAULT_K = 6; // Default number of children per node.\\n\\n// Defaults\\nuint256 constant DEFAULT_NB_OF_JURORS = 3; // The default number of jurors in a dispute.\\nIERC20 constant NATIVE_CURRENCY = IERC20(address(0)); // The native currency, such as ETH on Arbitrum, Optimism and Ethereum L1.\\n\\n// Units\\nuint256 constant ONE_BASIS_POINT = 10000;\\n\\nenum OnError {\\n Revert,\\n Return\\n}\\n\\nenum StakingResult {\\n Successful,\\n Delayed,\\n StakingTransferFailed,\\n UnstakingTransferFailed,\\n CannotStakeInMoreCourts,\\n CannotStakeInThisCourt,\\n CannotStakeLessThanMinStake,\\n CannotStakeMoreThanMaxStakePerJuror,\\n CannotStakeMoreThanMaxTotalStaked,\\n CannotStakeZeroWhenNoStake\\n}\\n\",\"keccak256\":\"0xb8c96c842259ca1384e8450dfb214f0fcd604829c84293dd3f8981f3421b66c9\",\"license\":\"MIT\"},\"src/libraries/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// Adapted from https://github.com/OpenZeppelin/openzeppelin-contracts/blob/a7a94c77463acea95d979aae1580fb0ddc3b6a1e/contracts/token/ERC20/utils/SafeERC20.sol\\n\\npragma solidity ^0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/// @title SafeERC20\\n///\\n/// @notice Wrappers around ERC20 operations\\n///\\n/// @dev Throws on failure (when the token contract returns false).\\n/// Tokens that return no value (and instead revert or throw on failure) are also supported.\\n/// Non-reverting calls are assumed to be successful.\\n/// To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n/// which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\nlibrary SafeERC20 {\\n /// @notice Increases the allowance granted to `spender` by the caller.\\n /// @param _token Token to transfer.\\n /// @param _spender The address which will spend the funds.\\n /// @param _addedValue The amount of tokens to increase the allowance by.\\n function increaseAllowance(IERC20 _token, address _spender, uint256 _addedValue) internal returns (bool) {\\n _token.approve(_spender, _token.allowance(address(this), _spender) + _addedValue);\\n return true;\\n }\\n\\n /// @notice Calls transfer() without reverting.\\n /// @param _token Token to transfer.\\n /// @param _to Recipient address.\\n /// @param _value Amount transferred.\\n /// @return Whether transfer succeeded or not.\\n function safeTransfer(IERC20 _token, address _to, uint256 _value) internal returns (bool) {\\n (bool success, bytes memory data) = address(_token).call(abi.encodeCall(IERC20.transfer, (_to, _value)));\\n return (success && (data.length == 0 || abi.decode(data, (bool))));\\n }\\n\\n /// @notice Calls transferFrom() without reverting.\\n /// @param _token Token to transfer.\\n /// @param _from Sender address.\\n /// @param _to Recipient address.\\n /// @param _value Amount transferred.\\n /// @return Whether transfer succeeded or not.\\n function safeTransferFrom(IERC20 _token, address _from, address _to, uint256 _value) internal returns (bool) {\\n (bool success, bytes memory data) = address(_token).call(\\n abi.encodeCall(IERC20.transferFrom, (_from, _to, _value))\\n );\\n return (success && (data.length == 0 || abi.decode(data, (bool))));\\n }\\n}\\n\",\"keccak256\":\"0x36b92f984484f9dfd63a40ccb1c1e23cde0085db36ec8adb7afe7e98ef667bd7\",\"license\":\"MIT\"},\"src/proxy/Initializable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol) \\n\\npragma solidity ^0.8.24;\\n\\n/**\\n * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed\\n * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an\\n * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer\\n * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.\\n *\\n * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be\\n * reused. This mechanism prevents re-execution of each \\\"step\\\" but allows the creation of new initialization steps in\\n * case an upgrade adds a module that needs to be initialized.\\n *\\n * For example:\\n *\\n * ```solidity\\n * contract MyToken is ERC20Upgradeable {\\n * function initialize() initializer public {\\n * __ERC20_init(\\\"MyToken\\\", \\\"MTK\\\");\\n * }\\n * }\\n *\\n * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {\\n * function initializeV2() reinitializer(2) public {\\n * __ERC20Permit_init(\\\"MyToken\\\");\\n * }\\n * }\\n * ```\\n *\\n * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as\\n * possible by providing the encoded function call as the `_data` argument to the proxy constructor\\n *\\n * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure\\n * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.\\n *\\n * [CAUTION]\\n * ====\\n * Avoid leaving a contract uninitialized.\\n *\\n * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation\\n * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke\\n * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:\\n *\\n * ```\\n * /// @custom:oz-upgrades-unsafe-allow constructor\\n * constructor() {\\n * _disableInitializers();\\n * }\\n * ```\\n */\\nabstract contract Initializable {\\n /**\\n * @dev Storage of the initializable contract.\\n *\\n * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions\\n * when using with upgradeable contracts.\\n *\\n * @custom:storage-location erc7201:openzeppelin.storage.Initializable\\n */\\n struct InitializableStorage {\\n /**\\n * @dev Indicates that the contract has been initialized.\\n */\\n uint64 _initialized;\\n /**\\n * @dev Indicates that the contract is in the process of being initialized.\\n */\\n bool _initializing;\\n }\\n\\n // keccak256(abi.encode(uint256(keccak256(\\\"openzeppelin.storage.Initializable\\\")) - 1))\\n bytes32 private constant _INITIALIZABLE_STORAGE =\\n 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0e;\\n\\n /**\\n * @dev The contract is already initialized.\\n */\\n error AlreadyInitialized();\\n\\n /**\\n * @dev The contract is not initializing.\\n */\\n error NotInitializing();\\n\\n /**\\n * @dev Triggered when the contract has been initialized or reinitialized.\\n */\\n event Initialized(uint64 version);\\n\\n /**\\n * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,\\n * `onlyInitializing` functions can be used to initialize parent contracts.\\n *\\n * Similar to `initializer()`, except that functions marked with `initializer` can be nested in the context of a\\n * constructor.\\n *\\n * Emits an {Initialized} event.\\n */\\n modifier initializer() {\\n // solhint-disable-next-line var-name-mixedcase\\n InitializableStorage storage $ = _getInitializableStorage();\\n\\n bool isTopLevelCall = !$._initializing;\\n uint64 initialized = $._initialized;\\n if (!(isTopLevelCall && initialized < 1) && !(address(this).code.length == 0 && initialized == 1)) {\\n revert AlreadyInitialized();\\n }\\n $._initialized = 1;\\n if (isTopLevelCall) {\\n $._initializing = true;\\n }\\n _;\\n if (isTopLevelCall) {\\n $._initializing = false;\\n emit Initialized(1);\\n }\\n }\\n\\n /**\\n * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the\\n * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be\\n * used to initialize parent contracts.\\n *\\n * A reinitializer may be used after the original initialization step. This is essential to configure modules that\\n * are added through upgrades and that require initialization.\\n *\\n * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`\\n * cannot be nested. If one is invoked in the context of another, execution will revert.\\n *\\n * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in\\n * a contract, executing them in the right order is up to the developer or operator.\\n *\\n * WARNING: setting the version to 255 will prevent any future reinitialization.\\n *\\n * Emits an {Initialized} event.\\n */\\n modifier reinitializer(uint64 version) {\\n // solhint-disable-next-line var-name-mixedcase\\n InitializableStorage storage $ = _getInitializableStorage();\\n\\n if ($._initializing || $._initialized >= version) {\\n revert AlreadyInitialized();\\n }\\n $._initialized = version;\\n $._initializing = true;\\n _;\\n $._initializing = false;\\n emit Initialized(version);\\n }\\n\\n /**\\n * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the\\n * {initializer} and {reinitializer} modifiers, directly or indirectly.\\n */\\n modifier onlyInitializing() {\\n _checkInitializing();\\n _;\\n }\\n\\n /**\\n * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.\\n */\\n function _checkInitializing() internal view virtual {\\n if (!_isInitializing()) {\\n revert NotInitializing();\\n }\\n }\\n\\n /**\\n * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.\\n * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized\\n * to any version. It is recommended to use this to lock implementation contracts that are designed to be called\\n * through proxies.\\n *\\n * Emits an {Initialized} event the first time it is successfully executed.\\n */\\n function _disableInitializers() internal virtual {\\n // solhint-disable-next-line var-name-mixedcase\\n InitializableStorage storage $ = _getInitializableStorage();\\n\\n if ($._initializing) {\\n revert AlreadyInitialized();\\n }\\n if ($._initialized != type(uint64).max) {\\n $._initialized = type(uint64).max;\\n emit Initialized(type(uint64).max);\\n }\\n }\\n\\n /**\\n * @dev Returns the highest version that has been initialized. See {reinitializer}.\\n */\\n function _getInitializedVersion() internal view returns (uint64) {\\n return _getInitializableStorage()._initialized;\\n }\\n\\n /**\\n * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.\\n */\\n function _isInitializing() internal view returns (bool) {\\n return _getInitializableStorage()._initializing;\\n }\\n\\n /**\\n * @dev Returns a pointer to the storage namespace.\\n */\\n // solhint-disable-next-line var-name-mixedcase\\n function _getInitializableStorage() private pure returns (InitializableStorage storage $) {\\n assembly {\\n $.slot := _INITIALIZABLE_STORAGE\\n }\\n }\\n}\\n\",\"keccak256\":\"0xdad09e5f773fa6940dbd8c28480f602a7eaa3c70d3da9d06df140187cbf5dad4\",\"license\":\"MIT\"},\"src/proxy/UUPSProxiable.sol\":{\"content\":\"//SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.24;\\n\\n/// @title UUPS Proxiable\\n/// @author Simon Malatrait \\n/// @notice This contract implements an upgradeability mechanism designed for UUPS proxies.\\n///\\n/// @dev Adapted from \\n/// The functions included here can perform an upgrade of an UUPS Proxy, when this contract is set as the implementation behind such a proxy.\\n///\\n/// IMPORTANT: A UUPS proxy requires its upgradeability functions to be in the implementation as opposed to the transparent proxy.\\n/// This means that if the proxy is upgraded to an implementation that does not support this interface, it will no longer be upgradeable.\\n///\\n/// A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is\\n/// reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing\\n/// `UUPSProxiable` with a custom implementation of upgrades.\\n///\\n/// The `_authorizeUpgrade` function must be overridden to include access restriction to the upgrade mechanism.\\nabstract contract UUPSProxiable {\\n // ************************************* //\\n // * Event * //\\n // ************************************* //\\n\\n /// @notice Emitted when the `implementation` has been successfully upgraded.\\n /// @param newImplementation Address of the new implementation the proxy is now forwarding calls to.\\n event Upgraded(address indexed newImplementation);\\n\\n // ************************************* //\\n // * Error * //\\n // ************************************* //\\n\\n /// @notice The call is from an unauthorized context.\\n error UUPSUnauthorizedCallContext();\\n\\n /// @notice The storage `slot` is unsupported as a UUID.\\n error UUPSUnsupportedProxiableUUID(bytes32 slot);\\n\\n /// @notice The `implementation` is not UUPS-compliant\\n error InvalidImplementation(address implementation);\\n\\n /// Failed Delegated call\\n error FailedDelegateCall();\\n\\n // ************************************* //\\n // * Storage * //\\n // ************************************* //\\n\\n /// @dev Storage slot with the address of the current implementation.\\n /// @dev This is the keccak-256 hash of \\\"eip1967.proxy.implementation\\\" subtracted by 1, and is\\n /// @dev validated in the constructor.\\n /// @dev NOTE: bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1)\\n bytes32 private constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\\n\\n /// @dev Storage variable of the proxiable contract address.\\n /// @dev It is used to check whether or not the current call is from the proxy.\\n /// @custom:oz-upgrades-unsafe-allow state-variable-immutable\\n address private immutable __self = address(this);\\n\\n // ************************************* //\\n // * Governance * //\\n // ************************************* //\\n\\n /// @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract.\\n /// @dev Called by {upgradeToAndCall}.\\n function _authorizeUpgrade(address newImplementation) internal virtual;\\n\\n // ************************************* //\\n // * State Modifiers * //\\n // ************************************* //\\n\\n /// @notice Upgrade mechanism including access control and UUPS-compliance.\\n /// @param newImplementation Address of the new implementation contract.\\n /// @param data Data used in a delegate call to `newImplementation` if non-empty. This will typically be an encoded\\n /// function call, and allows initializing the storage of the proxy like a Solidity constructor.\\n /// @dev Reverts if the execution is not performed via delegatecall or the execution\\n /// context is not of a proxy with an ERC1967-compliant implementation pointing to self.\\n function upgradeToAndCall(address newImplementation, bytes memory data) public payable virtual {\\n _authorizeUpgrade(newImplementation);\\n\\n // Check that the execution is being performed through a delegatecall call and that the execution context is\\n // a proxy contract with an implementation (as defined in ERC1967) pointing to self.\\n if (address(this) == __self || _getImplementation() != __self) {\\n revert UUPSUnauthorizedCallContext();\\n }\\n\\n try UUPSProxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {\\n if (slot != IMPLEMENTATION_SLOT) {\\n revert UUPSUnsupportedProxiableUUID(slot);\\n }\\n // Store the new implementation address to the implementation storage slot.\\n assembly {\\n sstore(IMPLEMENTATION_SLOT, newImplementation)\\n }\\n emit Upgraded(newImplementation);\\n\\n if (data.length != 0) {\\n // The return data is not checked (checking, in case of success, that the newImplementation code is non-empty if the return data is empty) because the authorized callee is trusted.\\n /// @custom:oz-upgrades-unsafe-allow delegatecall\\n (bool success, ) = newImplementation.delegatecall(data);\\n if (!success) {\\n revert FailedDelegateCall();\\n }\\n }\\n } catch {\\n revert InvalidImplementation(newImplementation);\\n }\\n }\\n\\n // ************************************* //\\n // * Public Views * //\\n // ************************************* //\\n\\n /// @notice Implementation of the ERC1822 `proxiableUUID` function. This returns the storage slot used by the\\n /// implementation. It is used to validate the implementation's compatibility when performing an upgrade.\\n ///\\n /// @dev IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks\\n /// bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this\\n /// function revert if invoked through a proxy. This is guaranteed by the if statement.\\n function proxiableUUID() external view virtual returns (bytes32) {\\n if (address(this) != __self) {\\n // Must not be called through delegatecall\\n revert UUPSUnauthorizedCallContext();\\n }\\n return IMPLEMENTATION_SLOT;\\n }\\n\\n /// @notice Returns the version of the implementation.\\n /// @return Version string.\\n function version() external view virtual returns (string memory);\\n\\n // ************************************* //\\n // * Internal Views * //\\n // ************************************* //\\n\\n function _getImplementation() internal view returns (address implementation) {\\n assembly {\\n implementation := sload(IMPLEMENTATION_SLOT)\\n }\\n }\\n}\\n\",\"keccak256\":\"0xa369061748e8a7b02873d597d4c78a2a09328111f04a97428b1c209e82cf5414\",\"license\":\"MIT\"}},\"version\":1}",
+ "bytecode": "0x60a080604052346100c157306080525f516020611d075f395f51905f525460ff8160401c166100b3576002600160401b03196001600160401b03821601610060575b604051611c4190816100c68239608051818181610d720152610e3a0152f35b6001600160401b0319166001600160401b039081175f516020611d075f395f51905f525581527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a15f80610041565b62dc149f60e41b5f5260045ffd5b5f80fdfe6080806040526004361015610012575f80fd5b5f905f3560e01c9081630343274414611336575080630b274f2e1461131e57806321e1625e1461129857806335975f4a1461127f578063485cc9551461107a5780634f1ef28614610dea57806352d1902d14610d58578063543f8a3614610cea57806354fd4d5014610c745780635d2d784614610c425780636624192f14610c05578063664bffc314610bbe57806369f4587714610aa2578063771a27cb14610a5d5780638da5cb5b14610a37578063965af6c7146109ae5780639d560867146109105780639fbb56f1146108e4578063aa9ebfb7146107c6578063aac03ad21461044e578063b4ebe8381461040b578063c70ba3b914610378578063d045e00214610341578063d09f392d146102e8578063d1c1df4814610224578063dca5f6b0146101df578063f1a531041461017b5763f2f4eb2614610152575f80fd5b3461017857806003193601126101785760206001600160a01b0360015416604051908152f35b80fd5b503461017857602036600319011261017857610195611350565b6001600160a01b036001541633036101d1576001600160a01b031673ffffffffffffffffffffffffffffffffffffffff19600454161760045580f35b600482628448c760e31b8152fd5b503461017857602036600319011261017857604080916001600160a01b03610205611350565b1681526003602052206003600282015491015482519182526020820152f35b50346101785760403660031901126101785761023e611350565b610246611414565b916001600160a01b0381921681526003602052604081209160028301549260038101549060018101956001600160601b038754959116905b8581106102a4575b50505060809450604051938452602084015260408301526060820152f35b816001600160601b036102b7838b611b4f565b90549060031b1c16146102cc5760010161027e565b5090919250608095505f5260205260405f2054905f8080610286565b5034610178576102f7366113fe565b50506001600160a01b03600154163303610333576002545f19811461031f5760010160025580f35b602482634e487b7160e01b81526011600452fd5b80628448c760e31b60049252fd5b50346101785760603660031901126101785760409061035e61142a565b506001600160a01b03600454169082519182526020820152f35b503461017857608036600319011261017857610392611350565b61039a611414565b60643580151503610407576001600160a01b036001541633036103f957906103c59160443591611a76565b906040519283526020830152600a8110156103e557606092506040820152f35b602483634e487b7160e01b81526021600452fd5b600483628448c760e31b8152fd5b8280fd5b50346101785760403660031901126101785761042561142a565b5060243567ffffffffffffffff811161044a576104469036906004016113b8565b5080f35b5080fd5b50346101785760a036600319011261017857610468611350565b610470611414565b60443591608435906001600160a01b036001541633036107b8576001600160a01b0381169384865260036020526104ab846040882093611b83565b908015610684578115610620575b6104c86002840191825461148e565b90555b8390865b8015610520575050509160609160027f70ca4ec64687bf265f39041896f3dbf10b9f650503cb38f2b3569fdce7489c36940154906001600160601b036040519316835260208301526040820152a280f35b6001600160601b0383165f528360205260405f2061053f86825461148e565b90556001600160601b0383165f528360205260405f20610560838254611754565b90556001600160601b0383166001810361057d57505060016104cf565b90925060c06001600160a01b036001541691602460405180948193630fad06e960e11b835260048301525afa9081156106155788916105be575b50916104cf565b905060c0813d821161060d575b816105d860c09383611366565b81010312610605578051906001600160601b0382168203610609576020015180151503610605575f6105b7565b8780fd5b8880fd5b3d91506105cb565b6040513d8a823e3d90fd5b60018301805490680100000000000000008210156106705761064c828892600161066b95018155611b4f565b9091906001600160601b038084549260031b9316831b921b1916179055565b6104b9565b602489634e487b7160e01b81526041600452fd5b50600282016106966064358254611754565b9055826104cb57939291906001810194855495866001600160601b038616975b6106c8575b50509091929394506104cb565b5f1981018181116107a457886001600160601b036106e68386611b4f565b90549060031b1c161461070357506106fd9061156b565b806106b6565b91929394959697505081545f198101908111610790579061064c6001600160601b036107326107419486611b4f565b90549060031b1c169184611b4f565b8054801561077c575f19019061076f61075a8383611b4f565b6001600160601b0382549160031b1b19169055565b5590849392915f806106bb565b602488634e487b7160e01b81526031600452fd5b602489634e487b7160e01b81526011600452fd5b60248a634e487b7160e01b81526011600452fd5b600485628448c760e31b8152fd5b5034610178576020366003190112610178576107e0611350565b6001600160a01b036001541633036101d157806108046001600160a01b03926114af565b90815192839116925b610815578380f35b6001546001600160a01b03165f1982018281116108d05783518110156108bc57906001600160601b036020879360051b8601015116813b15610407578291606483926040519485938492630761c14d60e01b84528b600485015260248401528160448401525af180156108b157610898575b50506108929061156b565b8061080d565b816108a291611366565b6108ad57835f610887565b8380fd5b6040513d84823e3d90fd5b602486634e487b7160e01b81526032600452fd5b602486634e487b7160e01b81526011600452fd5b5034610178576020366003190112610178576020610908610903611350565b611a3a565b604051908152f35b50346101785760403660031901126101785761092a611350565b90610933611414565b6001600160a01b03600154163381036103f9578293813b156109a95760646001600160a01b03918580946001600160601b036040519788968795630761c14d60e01b87521660048601521660248401528160448401525af180156108b1576109985750f35b816109a291611366565b6101785780f35b505050fd5b5034610178576040366003190112610178576109c8611350565b602435906001600160a01b036001541633036103f95760406001600160a01b037f7a81a4ef419d50dbb5deb116fb983bf6ca7716bcbc84cd1cd2be81ccea9078b09216928385526003602052600382862001610a25828254611754565b9055815190815260016020820152a280f35b50346101785780600319360112610178576001600160a01b036020915416604051908152f35b503461017857610a6c36611440565b926001600160a01b03600193929354163303610333576060610a8f858585611761565b9060405192835260208301526040820152f35b5034610b92576020366003190112610b9257610abc611350565b610ac581611a3a565b908115610b96576001600160a01b031690815f5260036020525f60026040822001556001600160a01b0360015416803b15610b92575f80916044604051809481937f42c37fa30000000000000000000000000000000000000000000000000000000083528860048401528760248401525af18015610b8757610b71575b5060207f71bb1b604559acc3db697ccf2aa4228d727cd5b133d6ffa419518d51c117c95c91604051908152a280f35b610b7e9193505f90611366565b5f916020610b42565b6040513d5f823e3d90fd5b5f80fd5b7fdc604fd1000000000000000000000000000000000000000000000000000000005f5260045ffd5b34610b9257610bcc36611440565b6001600160a01b03600193929354163303610bf757602092610bed92611577565b6040519015158152f35b628448c760e31b5f5260045ffd5b34610b92576020366003190112610b92576001600160a01b03610c26611350565b165f5260036020526020600260405f2001541515604051908152f35b34610b9257610c50366113fe565b50506001600160a01b03600154163303610bf757610c6f60025461156b565b600255005b34610b92575f366003190112610b92576040805190610c938183611366565b6005825260208201917f322e302e3000000000000000000000000000000000000000000000000000000083528151928391602083525180918160208501528484015e5f828201840152601f01601f19168101030190f35b34610b92576020366003190112610b9257610d0b610d06611350565b6114af565b6040518091602082016020835281518091526020604084019201905f5b818110610d36575050500390f35b82516001600160601b0316845285945060209384019390920191600101610d28565b34610b92575f366003190112610b92576001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003610dc25760206040517f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8152f35b7fe07c8dba000000000000000000000000000000000000000000000000000000005f5260045ffd5b6040366003190112610b9257610dfe611350565b60243567ffffffffffffffff8111610b9257610e1e9036906004016113b8565b906001600160a01b035f54163303611052576001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001680301490811561101d575b50610dc2576001600160a01b038116916040517f52d1902d000000000000000000000000000000000000000000000000000000008152602081600481875afa5f9181610fe9575b50610edd57837f0c760937000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc859203610fbe5750827f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a2805180610f58575b005b5f926020849301905af43d15610fb9573d610f728161139c565b90610f806040519283611366565b81525f60203d92013e5b15610f9157005b7f736436ba000000000000000000000000000000000000000000000000000000005f5260045ffd5b610f8a565b7faa1d49a4000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b9091506020813d602011611015575b8161100560209383611366565b81010312610b9257519085610eac565b3d9150610ff8565b90506001600160a01b037f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5416141583610e65565b7f596dcdb8000000000000000000000000000000000000000000000000000000005f5260045ffd5b34610b92576040366003190112610b9257611093611350565b6024356001600160a01b038116809103610b92577ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0e5460ff8160401c16159267ffffffffffffffff82168480611275575b159081611257575b5061122f5767ffffffffffffffff1982166001177ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0e556001600160a01b0391846111f0575b501673ffffffffffffffffffffffffffffffffffffffff195f5416175f5573ffffffffffffffffffffffffffffffffffffffff19600154161760015561117357005b68ff0000000000000000197ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0e54167ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0e557fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2602060405160018152a1005b68ffffffffffffffffff191668010000000000000001177ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0e5584611131565b7f0dc149f0000000000000000000000000000000000000000000000000000000005f5260045ffd5b303b1591508161126a575b5015856110ec565b600191501485611262565b50600181106110e4565b34610b92576020366003190112610b9257610f5661147a565b34610b92576040366003190112610b92576112b1611350565b602435906001600160a01b03600154163303610bf75760406001600160a01b037f7a81a4ef419d50dbb5deb116fb983bf6ca7716bcbc84cd1cd2be81ccea9078b0921692835f5260036020526003825f200161130e82825461148e565b905581519081525f6020820152a2005b34610b92575f366003190112610b9257610f5661147a565b34610b92575f366003190112610b92576020906002548152f35b600435906001600160a01b0382168203610b9257565b90601f8019910116810190811067ffffffffffffffff82111761138857604052565b634e487b7160e01b5f52604160045260245ffd5b67ffffffffffffffff811161138857601f01601f191660200190565b81601f82011215610b92578035906113cf8261139c565b926113dd6040519485611366565b82845260208383010111610b9257815f926020809301838601378301015290565b6040906003190112610b92576004359060243590565b602435906001600160601b0382168203610b9257565b600435906001600160601b0382168203610b9257565b6060906003190112610b92576004356001600160a01b0381168103610b9257906024356001600160601b0381168103610b92579060443590565b6001600160a01b03600154163303610bf757565b9190820180921161149b57565b634e487b7160e01b5f52601160045260245ffd5b6001600160a01b03165f526003602052600160405f2001604051808260208294549384815201905f5260205f20925f905b80600183011061153a57611506945491818110611520575b10611509575b500382611366565b90565b60601c6001600160601b031681526020015f6114fe565b9260206001916001600160601b03851681520193016114f8565b91600291935060406001916001600160601b038754818116835260601c1660208201520194019201849293916114e0565b801561149b575f190190565b91801561174c576115888284611b83565b801561174457816115989161148e565b906001600160a01b03841693845f5260036020526115ba8460405f2092611b83565b8015611714575b6115d06002830193845461148e565b835584915f5b80156116275750505050916060917f70ca4ec64687bf265f39041896f3dbf10b9f650503cb38f2b3569fdce7489c369354906001600160601b036040519316835260208301526040820152a2600190565b6001600160601b0384165f528160205260405f2061164687825461148e565b90556001600160601b0384165f528160205260405f20611667848254611754565b90556001600160601b0384166001810361168457505060016115d6565b90935060c06001600160a01b036001541691602460405180948193630fad06e960e11b835260048301525afa908115610b87575f916116c5575b50926115d6565b905060c0813d821161170c575b816116df60c09383611366565b81010312610b92578051906001600160601b0382168203610b92576020015180151503610b92575f6116be565b3d91506116d2565b600182018054680100000000000000008110156113885761064c8161173f9360018a94018155611b4f565b6115c1565b505050505f90565b505050600190565b9190820391821161149b57565b919290926001600160a01b03831693845f52600360205260405f20918092600261178b8488611b83565b9101918254908110611a32575b8415611a265750506117aa8286611b83565b955f9684811015611a12575b50805f52600360205260405f206117cd8488611b83565b9060028101916117de878454611754565b83558915611933575b85915f5b801561184657505050506060611843959697987f70ca4ec64687bf265f39041896f3dbf10b9f650503cb38f2b3569fdce7489c369254604051916001600160601b038816835260208301526040820152a25494611b83565b91565b6001600160601b0384165f528160205260405f206118658d825461148e565b90556001600160601b0384165f528160205260405f20611886848254611754565b90556001600160601b038416600181036118a357505060016117eb565b90935060c06001600160a01b036001541691602460405180948193630fad06e960e11b835260048301525afa908115610b87575f916118e4575b50926117eb565b905060c0813d821161192b575b816118fe60c09383611366565b81010312610b92578051906001600160601b0382168203610b92576020015180151503610b92575f6118dd565b3d91506118f1565b979695949392919060018101988954998a6001600160601b0388169b5b611966575b5050909192939495969798506117e7565b5f19810181811161149b578c6001600160601b036119848386611b4f565b90549060031b1c16146119a1575061199b9061156b565b80611950565b9192939495969798999a9b50508154905f19820191821161149b5761064c6001600160601b036107326119d49486611b4f565b805480156119fe575f1901906119ed61075a8383611b4f565b559088979695949392915f80611955565b634e487b7160e01b5f52603160045260245ffd5b611a1f9197508490611754565b955f6117b6565b965094505f9392505050565b935083611798565b6001600160a01b03165f52600360205260405f2060018101541580611a6a575b611a6357505f90565b6002015490565b50600381015415611a5a565b9092915f91611a9b5f956001600160a01b0383165f52600360205260405f2092611b83565b926001820154841580918192611b43575b50611b335780611b2b575b611b1c57838310611ad457505090611ace91611754565b91905f90565b92611ae192919550611754565b92600360028201549101548082115f14611b1457611afe91611754565b808411611b0c575b50611ace565b92505f611b06565b50505f611afe565b5050505090505f905f90600990565b508215611ab7565b505050505090505f905f90600490565b6004915010155f611aac565b9190918054831015611b6f575f52600c600160205f2084821c0193160290565b634e487b7160e01b5f52603260045260245ffd5b91906001600160a01b035f93165f52600360205260405f205f91600182018054935b848110611bb4575b5050505050565b6001600160601b03611bc68284611b4f565b90549060031b1c166001600160601b03841614611be557600101611ba5565b5050909293506001600160601b039150165f5260205260405f2054905f80808080611bad56fea2646970667358221220610dcaf880c7003b3c15c538c4a9a9b4f317449d0eba3fbf1a60083d71651a8464736f6c634300081e0033f0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0e",
+ "deployedBytecode": "0x6080806040526004361015610012575f80fd5b5f905f3560e01c9081630343274414611336575080630b274f2e1461131e57806321e1625e1461129857806335975f4a1461127f578063485cc9551461107a5780634f1ef28614610dea57806352d1902d14610d58578063543f8a3614610cea57806354fd4d5014610c745780635d2d784614610c425780636624192f14610c05578063664bffc314610bbe57806369f4587714610aa2578063771a27cb14610a5d5780638da5cb5b14610a37578063965af6c7146109ae5780639d560867146109105780639fbb56f1146108e4578063aa9ebfb7146107c6578063aac03ad21461044e578063b4ebe8381461040b578063c70ba3b914610378578063d045e00214610341578063d09f392d146102e8578063d1c1df4814610224578063dca5f6b0146101df578063f1a531041461017b5763f2f4eb2614610152575f80fd5b3461017857806003193601126101785760206001600160a01b0360015416604051908152f35b80fd5b503461017857602036600319011261017857610195611350565b6001600160a01b036001541633036101d1576001600160a01b031673ffffffffffffffffffffffffffffffffffffffff19600454161760045580f35b600482628448c760e31b8152fd5b503461017857602036600319011261017857604080916001600160a01b03610205611350565b1681526003602052206003600282015491015482519182526020820152f35b50346101785760403660031901126101785761023e611350565b610246611414565b916001600160a01b0381921681526003602052604081209160028301549260038101549060018101956001600160601b038754959116905b8581106102a4575b50505060809450604051938452602084015260408301526060820152f35b816001600160601b036102b7838b611b4f565b90549060031b1c16146102cc5760010161027e565b5090919250608095505f5260205260405f2054905f8080610286565b5034610178576102f7366113fe565b50506001600160a01b03600154163303610333576002545f19811461031f5760010160025580f35b602482634e487b7160e01b81526011600452fd5b80628448c760e31b60049252fd5b50346101785760603660031901126101785760409061035e61142a565b506001600160a01b03600454169082519182526020820152f35b503461017857608036600319011261017857610392611350565b61039a611414565b60643580151503610407576001600160a01b036001541633036103f957906103c59160443591611a76565b906040519283526020830152600a8110156103e557606092506040820152f35b602483634e487b7160e01b81526021600452fd5b600483628448c760e31b8152fd5b8280fd5b50346101785760403660031901126101785761042561142a565b5060243567ffffffffffffffff811161044a576104469036906004016113b8565b5080f35b5080fd5b50346101785760a036600319011261017857610468611350565b610470611414565b60443591608435906001600160a01b036001541633036107b8576001600160a01b0381169384865260036020526104ab846040882093611b83565b908015610684578115610620575b6104c86002840191825461148e565b90555b8390865b8015610520575050509160609160027f70ca4ec64687bf265f39041896f3dbf10b9f650503cb38f2b3569fdce7489c36940154906001600160601b036040519316835260208301526040820152a280f35b6001600160601b0383165f528360205260405f2061053f86825461148e565b90556001600160601b0383165f528360205260405f20610560838254611754565b90556001600160601b0383166001810361057d57505060016104cf565b90925060c06001600160a01b036001541691602460405180948193630fad06e960e11b835260048301525afa9081156106155788916105be575b50916104cf565b905060c0813d821161060d575b816105d860c09383611366565b81010312610605578051906001600160601b0382168203610609576020015180151503610605575f6105b7565b8780fd5b8880fd5b3d91506105cb565b6040513d8a823e3d90fd5b60018301805490680100000000000000008210156106705761064c828892600161066b95018155611b4f565b9091906001600160601b038084549260031b9316831b921b1916179055565b6104b9565b602489634e487b7160e01b81526041600452fd5b50600282016106966064358254611754565b9055826104cb57939291906001810194855495866001600160601b038616975b6106c8575b50509091929394506104cb565b5f1981018181116107a457886001600160601b036106e68386611b4f565b90549060031b1c161461070357506106fd9061156b565b806106b6565b91929394959697505081545f198101908111610790579061064c6001600160601b036107326107419486611b4f565b90549060031b1c169184611b4f565b8054801561077c575f19019061076f61075a8383611b4f565b6001600160601b0382549160031b1b19169055565b5590849392915f806106bb565b602488634e487b7160e01b81526031600452fd5b602489634e487b7160e01b81526011600452fd5b60248a634e487b7160e01b81526011600452fd5b600485628448c760e31b8152fd5b5034610178576020366003190112610178576107e0611350565b6001600160a01b036001541633036101d157806108046001600160a01b03926114af565b90815192839116925b610815578380f35b6001546001600160a01b03165f1982018281116108d05783518110156108bc57906001600160601b036020879360051b8601015116813b15610407578291606483926040519485938492630761c14d60e01b84528b600485015260248401528160448401525af180156108b157610898575b50506108929061156b565b8061080d565b816108a291611366565b6108ad57835f610887565b8380fd5b6040513d84823e3d90fd5b602486634e487b7160e01b81526032600452fd5b602486634e487b7160e01b81526011600452fd5b5034610178576020366003190112610178576020610908610903611350565b611a3a565b604051908152f35b50346101785760403660031901126101785761092a611350565b90610933611414565b6001600160a01b03600154163381036103f9578293813b156109a95760646001600160a01b03918580946001600160601b036040519788968795630761c14d60e01b87521660048601521660248401528160448401525af180156108b1576109985750f35b816109a291611366565b6101785780f35b505050fd5b5034610178576040366003190112610178576109c8611350565b602435906001600160a01b036001541633036103f95760406001600160a01b037f7a81a4ef419d50dbb5deb116fb983bf6ca7716bcbc84cd1cd2be81ccea9078b09216928385526003602052600382862001610a25828254611754565b9055815190815260016020820152a280f35b50346101785780600319360112610178576001600160a01b036020915416604051908152f35b503461017857610a6c36611440565b926001600160a01b03600193929354163303610333576060610a8f858585611761565b9060405192835260208301526040820152f35b5034610b92576020366003190112610b9257610abc611350565b610ac581611a3a565b908115610b96576001600160a01b031690815f5260036020525f60026040822001556001600160a01b0360015416803b15610b92575f80916044604051809481937f42c37fa30000000000000000000000000000000000000000000000000000000083528860048401528760248401525af18015610b8757610b71575b5060207f71bb1b604559acc3db697ccf2aa4228d727cd5b133d6ffa419518d51c117c95c91604051908152a280f35b610b7e9193505f90611366565b5f916020610b42565b6040513d5f823e3d90fd5b5f80fd5b7fdc604fd1000000000000000000000000000000000000000000000000000000005f5260045ffd5b34610b9257610bcc36611440565b6001600160a01b03600193929354163303610bf757602092610bed92611577565b6040519015158152f35b628448c760e31b5f5260045ffd5b34610b92576020366003190112610b92576001600160a01b03610c26611350565b165f5260036020526020600260405f2001541515604051908152f35b34610b9257610c50366113fe565b50506001600160a01b03600154163303610bf757610c6f60025461156b565b600255005b34610b92575f366003190112610b92576040805190610c938183611366565b6005825260208201917f322e302e3000000000000000000000000000000000000000000000000000000083528151928391602083525180918160208501528484015e5f828201840152601f01601f19168101030190f35b34610b92576020366003190112610b9257610d0b610d06611350565b6114af565b6040518091602082016020835281518091526020604084019201905f5b818110610d36575050500390f35b82516001600160601b0316845285945060209384019390920191600101610d28565b34610b92575f366003190112610b92576001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003610dc25760206040517f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8152f35b7fe07c8dba000000000000000000000000000000000000000000000000000000005f5260045ffd5b6040366003190112610b9257610dfe611350565b60243567ffffffffffffffff8111610b9257610e1e9036906004016113b8565b906001600160a01b035f54163303611052576001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001680301490811561101d575b50610dc2576001600160a01b038116916040517f52d1902d000000000000000000000000000000000000000000000000000000008152602081600481875afa5f9181610fe9575b50610edd57837f0c760937000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc859203610fbe5750827f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a2805180610f58575b005b5f926020849301905af43d15610fb9573d610f728161139c565b90610f806040519283611366565b81525f60203d92013e5b15610f9157005b7f736436ba000000000000000000000000000000000000000000000000000000005f5260045ffd5b610f8a565b7faa1d49a4000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b9091506020813d602011611015575b8161100560209383611366565b81010312610b9257519085610eac565b3d9150610ff8565b90506001600160a01b037f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5416141583610e65565b7f596dcdb8000000000000000000000000000000000000000000000000000000005f5260045ffd5b34610b92576040366003190112610b9257611093611350565b6024356001600160a01b038116809103610b92577ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0e5460ff8160401c16159267ffffffffffffffff82168480611275575b159081611257575b5061122f5767ffffffffffffffff1982166001177ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0e556001600160a01b0391846111f0575b501673ffffffffffffffffffffffffffffffffffffffff195f5416175f5573ffffffffffffffffffffffffffffffffffffffff19600154161760015561117357005b68ff0000000000000000197ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0e54167ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0e557fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2602060405160018152a1005b68ffffffffffffffffff191668010000000000000001177ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0e5584611131565b7f0dc149f0000000000000000000000000000000000000000000000000000000005f5260045ffd5b303b1591508161126a575b5015856110ec565b600191501485611262565b50600181106110e4565b34610b92576020366003190112610b9257610f5661147a565b34610b92576040366003190112610b92576112b1611350565b602435906001600160a01b03600154163303610bf75760406001600160a01b037f7a81a4ef419d50dbb5deb116fb983bf6ca7716bcbc84cd1cd2be81ccea9078b0921692835f5260036020526003825f200161130e82825461148e565b905581519081525f6020820152a2005b34610b92575f366003190112610b9257610f5661147a565b34610b92575f366003190112610b92576020906002548152f35b600435906001600160a01b0382168203610b9257565b90601f8019910116810190811067ffffffffffffffff82111761138857604052565b634e487b7160e01b5f52604160045260245ffd5b67ffffffffffffffff811161138857601f01601f191660200190565b81601f82011215610b92578035906113cf8261139c565b926113dd6040519485611366565b82845260208383010111610b9257815f926020809301838601378301015290565b6040906003190112610b92576004359060243590565b602435906001600160601b0382168203610b9257565b600435906001600160601b0382168203610b9257565b6060906003190112610b92576004356001600160a01b0381168103610b9257906024356001600160601b0381168103610b92579060443590565b6001600160a01b03600154163303610bf757565b9190820180921161149b57565b634e487b7160e01b5f52601160045260245ffd5b6001600160a01b03165f526003602052600160405f2001604051808260208294549384815201905f5260205f20925f905b80600183011061153a57611506945491818110611520575b10611509575b500382611366565b90565b60601c6001600160601b031681526020015f6114fe565b9260206001916001600160601b03851681520193016114f8565b91600291935060406001916001600160601b038754818116835260601c1660208201520194019201849293916114e0565b801561149b575f190190565b91801561174c576115888284611b83565b801561174457816115989161148e565b906001600160a01b03841693845f5260036020526115ba8460405f2092611b83565b8015611714575b6115d06002830193845461148e565b835584915f5b80156116275750505050916060917f70ca4ec64687bf265f39041896f3dbf10b9f650503cb38f2b3569fdce7489c369354906001600160601b036040519316835260208301526040820152a2600190565b6001600160601b0384165f528160205260405f2061164687825461148e565b90556001600160601b0384165f528160205260405f20611667848254611754565b90556001600160601b0384166001810361168457505060016115d6565b90935060c06001600160a01b036001541691602460405180948193630fad06e960e11b835260048301525afa908115610b87575f916116c5575b50926115d6565b905060c0813d821161170c575b816116df60c09383611366565b81010312610b92578051906001600160601b0382168203610b92576020015180151503610b92575f6116be565b3d91506116d2565b600182018054680100000000000000008110156113885761064c8161173f9360018a94018155611b4f565b6115c1565b505050505f90565b505050600190565b9190820391821161149b57565b919290926001600160a01b03831693845f52600360205260405f20918092600261178b8488611b83565b9101918254908110611a32575b8415611a265750506117aa8286611b83565b955f9684811015611a12575b50805f52600360205260405f206117cd8488611b83565b9060028101916117de878454611754565b83558915611933575b85915f5b801561184657505050506060611843959697987f70ca4ec64687bf265f39041896f3dbf10b9f650503cb38f2b3569fdce7489c369254604051916001600160601b038816835260208301526040820152a25494611b83565b91565b6001600160601b0384165f528160205260405f206118658d825461148e565b90556001600160601b0384165f528160205260405f20611886848254611754565b90556001600160601b038416600181036118a357505060016117eb565b90935060c06001600160a01b036001541691602460405180948193630fad06e960e11b835260048301525afa908115610b87575f916118e4575b50926117eb565b905060c0813d821161192b575b816118fe60c09383611366565b81010312610b92578051906001600160601b0382168203610b92576020015180151503610b92575f6118dd565b3d91506118f1565b979695949392919060018101988954998a6001600160601b0388169b5b611966575b5050909192939495969798506117e7565b5f19810181811161149b578c6001600160601b036119848386611b4f565b90549060031b1c16146119a1575061199b9061156b565b80611950565b9192939495969798999a9b50508154905f19820191821161149b5761064c6001600160601b036107326119d49486611b4f565b805480156119fe575f1901906119ed61075a8383611b4f565b559088979695949392915f80611955565b634e487b7160e01b5f52603160045260245ffd5b611a1f9197508490611754565b955f6117b6565b965094505f9392505050565b935083611798565b6001600160a01b03165f52600360205260405f2060018101541580611a6a575b611a6357505f90565b6002015490565b50600381015415611a5a565b9092915f91611a9b5f956001600160a01b0383165f52600360205260405f2092611b83565b926001820154841580918192611b43575b50611b335780611b2b575b611b1c57838310611ad457505090611ace91611754565b91905f90565b92611ae192919550611754565b92600360028201549101548082115f14611b1457611afe91611754565b808411611b0c575b50611ace565b92505f611b06565b50505f611afe565b5050505090505f905f90600990565b508215611ab7565b505050505090505f905f90600490565b6004915010155f611aac565b9190918054831015611b6f575f52600c600160205f2084821c0193160290565b634e487b7160e01b5f52603260045260245ffd5b91906001600160a01b035f93165f52600360205260405f205f91600182018054935b848110611bb4575b5050505050565b6001600160601b03611bc68284611b4f565b90549060031b1c166001600160601b03841614611be557600101611ba5565b5050909293506001600160601b039150165f5260205260405f2054905f80808080611bad56fea2646970667358221220610dcaf880c7003b3c15c538c4a9a9b4f317449d0eba3fbf1a60083d71651a8464736f6c634300081e0033",
"devdoc": {
- "details": "An adapted version of the SortitionModule contract for educational purposes.",
"errors": {
"AlreadyInitialized()": [
{
@@ -594,22 +810,44 @@
{
"details": "The contract is not initializing."
}
- ],
- "UUPSUnauthorizedCallContext()": [
- {
- "details": "The call is from an unauthorized context."
- }
- ],
- "UUPSUnsupportedProxiableUUID(bytes32)": [
- {
- "details": "The storage `slot` is unsupported as a UUID."
- }
]
},
"events": {
"Initialized(uint64)": {
"details": "Triggered when the contract has been initialized or reinitialized."
},
+ "LeftoverPNK(address,uint256)": {
+ "params": {
+ "_account": "The account of the juror.",
+ "_amount": "The amount of PNK available."
+ }
+ },
+ "LeftoverPNKWithdrawn(address,uint256)": {
+ "params": {
+ "_account": "The account of the juror withdrawing PNK.",
+ "_amount": "The amount of PNK withdrawn."
+ }
+ },
+ "NewPhase(uint8)": {
+ "params": {
+ "_phase": "The new phase."
+ }
+ },
+ "StakeLocked(address,uint256,bool)": {
+ "params": {
+ "_address": "The address of the juror.",
+ "_relativeAmount": "The amount of tokens locked.",
+ "_unlock": "Whether the stake is locked or unlocked."
+ }
+ },
+ "StakeSet(address,uint256,uint256,uint256)": {
+ "params": {
+ "_address": "The address of the juror.",
+ "_amount": "The amount of tokens staked in the court.",
+ "_amountAllCourts": "The amount of tokens staked in all courts.",
+ "_courtID": "The ID of the court."
+ }
+ },
"Upgraded(address)": {
"params": {
"newImplementation": "Address of the new implementation the proxy is now forwarding calls to."
@@ -619,74 +857,176 @@
"kind": "dev",
"methods": {
"constructor": {
- "details": "Constructor, initializing the implementation to reduce attack surface."
+ "custom:oz-upgrades-unsafe-allow": "constructor"
},
- "draw(bytes32,uint256,uint256)": {
- "details": "Draw an ID from a tree using a number. Note that this function reverts if the sum of all values in the tree is 0.",
+ "createDisputeHook(uint256,uint256)": {
+ "params": {
+ "_disputeID": "The ID of the dispute.",
+ "_roundID": "The ID of the round."
+ }
+ },
+ "createTree(uint96,bytes)": {
+ "params": {
+ "_courtID": "The ID of the court.",
+ "_extraData": "Extra data that contains the number of children each node in the tree should have."
+ }
+ },
+ "draw(uint96,uint256,uint256)": {
+ "details": "that this function reverts if the sum of all values in the tree is 0. `O(k * log_k(n))` where `k` is the maximum number of children per node in the tree, and `n` is the maximum number of nodes ever appended.",
+ "params": {
+ "_coreDisputeID": "Index of the dispute in Kleros Core.",
+ "_courtID": "The ID of the court.",
+ "_nonce": "Nonce to hash with random number."
+ },
"returns": {
- "drawnAddress": "The drawn address. `O(k * log_k(n))` where `k` is the maximum number of children per node in the tree, and `n` is the maximum number of nodes ever appended."
+ "drawnAddress": "The drawn address."
+ }
+ },
+ "executeDelayedStakes(uint256)": {
+ "params": {
+ "_iterations": "The number of delayed stakes to execute."
+ }
+ },
+ "forcedUnstake(address,uint96)": {
+ "details": "`O(n * (p * log_k(j)) )` where `n` is the number of courts the juror has staked in, `p` is the depth of the court tree, `k` is the minimum number of children per node of one of these courts' sortition sum tree, and `j` is the maximum number of jurors that ever staked in one of these courts simultaneously.",
+ "params": {
+ "_account": "The juror to unstake.",
+ "_courtID": "The ID of the court."
+ }
+ },
+ "forcedUnstakeAllCourts(address)": {
+ "details": "`O(n * (p * log_k(j)) )` where `O(n * (p * log_k(j)) )` where `n` is the number of courts the juror has staked in, `p` is the depth of the court tree, `k` is the minimum number of children per node of one of these courts' sortition sum tree, and `j` is the maximum number of jurors that ever staked in one of these courts simultaneously.",
+ "params": {
+ "_account": "The juror to unstake."
}
},
"getJurorBalance(address,uint96)": {
- "details": "Gets the stake of a juror in a court. Warning: `O(n)` complexity where `n` is the number of courts the juror has staked in but acceptable for this educational implementation.",
"params": {
"_courtID": "The ID of the court.",
"_juror": "The address of the juror."
},
"returns": {
- "nbCourts": "The number of courts the juror has staked in.",
- "stakedInCourt": "The amount of tokens staked by the juror in the court.",
- "totalLocked": "The total amount of tokens locked by the juror in the court.",
- "totalStaked": "The total amount of tokens staked by the juror in the court."
+ "nbCourts": "The number of courts the juror has directly staked in.",
+ "stakedInCourt": "The amount of tokens staked in the specified court including locked tokens and penalty deductions.",
+ "totalLocked": "The total amount of tokens locked in disputes.",
+ "totalStaked": "The total amount of tokens staked including locked tokens and penalty deductions. Equivalent to the effective stake in the General court."
}
},
"getJurorCourtIDs(address)": {
- "details": "Gets the court identifiers where a specific `_juror` has staked.",
"params": {
"_juror": "The address of the juror."
}
},
+ "getJurorLeftoverPNK(address)": {
+ "params": {
+ "_juror": "The address of the juror."
+ },
+ "returns": {
+ "_0": "Whether the juror has leftover PNK."
+ }
+ },
"initialize(address,address)": {
- "details": "Initializer (constructor equivalent for upgradable contracts).",
"params": {
"_core": "The KlerosCore."
}
},
- "notifyRandomNumber(uint256)": {
- "details": "Saves the random number to use it in sortition. Not used by this contract because the storing of the number is inlined in passPhase().",
+ "isJurorStaked(address)": {
"params": {
- "_randomNumber": "Random number returned by RNG contract."
+ "_juror": "The address of the juror."
+ },
+ "returns": {
+ "_0": "Whether the juror is staked or not."
+ }
+ },
+ "lockStake(address,uint256)": {
+ "params": {
+ "_account": "The address of the juror.",
+ "_relativeAmount": "The amount to lock."
+ }
+ },
+ "postDrawHook(uint256,uint256)": {
+ "params": {
+ "_disputeID": "The ID of the dispute.",
+ "_roundID": "The ID of the round."
}
},
"proxiableUUID()": {
- "details": "Implementation of the ERC1822 `proxiableUUID` function. This returns the storage slot used by the implementation. It is used to validate the implementation's compatibility when performing an upgrade. IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this function revert if invoked through a proxy. This is guaranteed by the if statement."
+ "details": "IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this function revert if invoked through a proxy. This is guaranteed by the if statement."
},
- "setJurorInactive(address)": {
- "details": "Unstakes the inactive juror from all courts. `O(n * (p * log_k(j)) )` where `n` is the number of courts the juror has staked in, `p` is the depth of the court tree, `k` is the minimum number of children per node of one of these courts' sortition sum tree, and `j` is the maximum number of jurors that ever staked in one of these courts simultaneously.",
+ "setStake(address,uint96,uint256,uint256,uint256)": {
+ "details": "`O(n + p * log_k(j))` where `n` is the number of courts the juror has staked in, `p` is the depth of the court tree, `k` is the minimum number of children per node of one of these courts' sortition sum tree, and `j` is the maximum number of jurors that ever staked in one of these courts simultaneously.",
"params": {
- "_account": "The juror to unstake."
+ "_account": "The address of the juror.",
+ "_courtID": "The ID of the court.",
+ "_newStake": "The new stake.",
+ "_pnkDeposit": "The amount of PNK to be deposited.",
+ "_pnkWithdrawal": "The amount of PNK to be withdrawn."
}
},
- "setStake(address,uint96,uint256,bool)": {
- "details": "Sets the specified juror's stake in a court. `O(n + p * log_k(j))` where `n` is the number of courts the juror has staked in, `p` is the depth of the court tree, `k` is the minimum number of children per node of one of these courts' sortition sum tree, and `j` is the maximum number of jurors that ever staked in one of these courts simultaneously.",
+ "setStakePenalty(address,uint96,uint256)": {
+ "details": "`O(n + p * log_k(j))` where `n` is the number of courts the juror has staked in, `p` is the depth of the court tree, `k` is the minimum number of children per node of one of these courts' sortition sum tree, and `j` is the maximum number of jurors that ever staked in one of these courts simultaneously.",
"params": {
"_account": "The address of the juror.",
- "_alreadyTransferred": "True if the tokens were already transferred from juror. Only relevant for delayed stakes.",
"_courtID": "The ID of the court.",
- "_newStake": "The new stake."
+ "_penalty": "The amount of PNK to be deducted."
},
"returns": {
- "pnkDeposit": "The amount of PNK to be deposited.",
- "pnkWithdrawal": "The amount of PNK to be withdrawn.",
- "stakingResult": "The result of the staking operation."
+ "availablePenalty": "The amount of PNK that was actually deducted.",
+ "newCourtStake": "The updated stake of the juror in the court.",
+ "pnkBalance": "The updated total PNK balance of the juror, including the penalty."
+ }
+ },
+ "setStakeReward(address,uint96,uint256)": {
+ "details": "`O(n + p * log_k(j))` where `O(n + p * log_k(j))` where `n` is the number of courts the juror has staked in, `p` is the depth of the court tree, `k` is the minimum number of children per node of one of these courts' sortition sum tree, and `j` is the maximum number of jurors that ever staked in one of these courts simultaneously.",
+ "params": {
+ "_account": "The address of the juror.",
+ "_courtID": "The ID of the court.",
+ "_reward": "The amount of PNK to be deposited as a reward."
+ },
+ "returns": {
+ "success": "True if the reward was added successfully."
+ }
+ },
+ "unlockStake(address,uint256)": {
+ "params": {
+ "_account": "The address of the juror.",
+ "_relativeAmount": "The amount to unlock."
}
},
"upgradeToAndCall(address,bytes)": {
- "details": "Upgrade mechanism including access control and UUPS-compliance.Reverts if the execution is not performed via delegatecall or the execution context is not of a proxy with an ERC1967-compliant implementation pointing to self.",
+ "details": "Reverts if the execution is not performed via delegatecall or the execution context is not of a proxy with an ERC1967-compliant implementation pointing to self.",
"params": {
"data": "Data used in a delegate call to `newImplementation` if non-empty. This will typically be an encoded function call, and allows initializing the storage of the proxy like a Solidity constructor.",
"newImplementation": "Address of the new implementation contract."
}
+ },
+ "validateStake(address,uint96,uint256,bool)": {
+ "details": "No state changes should be made when returning stakingResult != Successful, otherwise delayed stakes might break invariants.",
+ "params": {
+ "_account": "The address of the juror.",
+ "_courtID": "The ID of the court.",
+ "_newStake": "The new stake.",
+ "_noDelay": "True if the stake change should not be delayed."
+ },
+ "returns": {
+ "pnkDeposit": "The amount of PNK to be deposited.",
+ "pnkWithdrawal": "The amount of PNK to be withdrawn.",
+ "stakingResult": "The result of the staking operation."
+ }
+ },
+ "withdrawLeftoverPNK(address)": {
+ "details": "that since locked and staked PNK are async it is possible for the juror to have positive staked PNK balance while having 0 stake in courts and 0 locked tokens (eg. when the juror fully unstaked during dispute and later got his tokens unlocked). In this case the juror can use this function to withdraw the leftover tokens. Also note that if the juror has some leftover PNK while not fully unstaked he'll have to manually unstake from all courts to trigger this function.",
+ "params": {
+ "_account": "The juror whose PNK to withdraw."
+ }
+ }
+ },
+ "stateVariables": {
+ "version": {
+ "return": "Version string.",
+ "returns": {
+ "_0": "Version string."
+ }
}
},
"title": "SortitionModuleUniversity",
@@ -703,37 +1043,133 @@
{
"notice": "The `implementation` is not UUPS-compliant"
}
+ ],
+ "UUPSUnauthorizedCallContext()": [
+ {
+ "notice": "The call is from an unauthorized context."
+ }
+ ],
+ "UUPSUnsupportedProxiableUUID(bytes32)": [
+ {
+ "notice": "The storage `slot` is unsupported as a UUID."
+ }
]
},
"events": {
+ "LeftoverPNK(address,uint256)": {
+ "notice": "Emitted when leftover PNK is available."
+ },
+ "LeftoverPNKWithdrawn(address,uint256)": {
+ "notice": "Emitted when leftover PNK is withdrawn."
+ },
+ "NewPhase(uint8)": {
+ "notice": "Emitted when the phase is changed."
+ },
+ "StakeLocked(address,uint256,bool)": {
+ "notice": "Emitted when a juror's stake is locked."
+ },
+ "StakeSet(address,uint256,uint256,uint256)": {
+ "notice": "Emitted when a juror stakes in a court."
+ },
"Upgraded(address)": {
"notice": "Emitted when the `implementation` has been successfully upgraded."
}
},
"kind": "user",
- "methods": {},
+ "methods": {
+ "createDisputeHook(uint256,uint256)": {
+ "notice": "Triggers the state changes after dispute creation."
+ },
+ "createTree(uint96,bytes)": {
+ "notice": "Create a sortition sum tree at the specified key."
+ },
+ "draw(uint96,uint256,uint256)": {
+ "notice": "Draw an ID from a tree using a number."
+ },
+ "executeDelayedStakes(uint256)": {
+ "notice": "Executes the next delayed stakes."
+ },
+ "forcedUnstake(address,uint96)": {
+ "notice": "Unstakes the inactive juror from a specific court."
+ },
+ "forcedUnstakeAllCourts(address)": {
+ "notice": "Unstakes the inactive juror from all courts."
+ },
+ "getJurorBalance(address,uint96)": {
+ "notice": "Gets the balance of a juror in a court."
+ },
+ "getJurorCourtIDs(address)": {
+ "notice": "Gets the court identifiers where a specific `_juror` has staked."
+ },
+ "getJurorLeftoverPNK(address)": {
+ "notice": "Checks if the juror has any leftover PNK in the contract."
+ },
+ "initialize(address,address)": {
+ "notice": "Initializer (constructor equivalent for upgradable contracts)."
+ },
+ "isJurorStaked(address)": {
+ "notice": "Checks if the juror is staked in any court."
+ },
+ "lockStake(address,uint256)": {
+ "notice": "Locks the tokens of the drawn juror."
+ },
+ "passPhase()": {
+ "notice": "Passes the phase."
+ },
+ "postDrawHook(uint256,uint256)": {
+ "notice": "Triggers the state changes after drawing."
+ },
+ "proxiableUUID()": {
+ "notice": "Implementation of the ERC1822 `proxiableUUID` function. This returns the storage slot used by the implementation. It is used to validate the implementation's compatibility when performing an upgrade."
+ },
+ "setStake(address,uint96,uint256,uint256,uint256)": {
+ "notice": "Update the state of the stakes, called by KC at the end of setStake flow."
+ },
+ "setStakePenalty(address,uint96,uint256)": {
+ "notice": "Update the state of the stakes with a PNK reward deposit, called by KC during rewards execution."
+ },
+ "setStakeReward(address,uint96,uint256)": {
+ "notice": "Update the state of the stakes with a PNK reward deposit, called by KC during rewards execution."
+ },
+ "unlockStake(address,uint256)": {
+ "notice": "Unlocks the tokens of the drawn juror."
+ },
+ "upgradeToAndCall(address,bytes)": {
+ "notice": "Upgrade mechanism including access control and UUPS-compliance."
+ },
+ "validateStake(address,uint96,uint256,bool)": {
+ "notice": "Validate the specified juror's new stake for a court."
+ },
+ "version()": {
+ "notice": "Returns the version of the implementation."
+ },
+ "withdrawLeftoverPNK(address)": {
+ "notice": "Gives back the locked PNKs in case the juror fully unstaked earlier."
+ }
+ },
+ "notice": "An adapted version of the SortitionModule contract for educational purposes.",
"version": 1
},
"storageLayout": {
"storage": [
{
- "astId": 26933,
+ "astId": 30225,
"contract": "src/arbitration/university/SortitionModuleUniversity.sol:SortitionModuleUniversity",
- "label": "governor",
+ "label": "owner",
"offset": 0,
"slot": "0",
"type": "t_address"
},
{
- "astId": 26936,
+ "astId": 30228,
"contract": "src/arbitration/university/SortitionModuleUniversity.sol:SortitionModuleUniversity",
"label": "core",
"offset": 0,
"slot": "1",
- "type": "t_contract(KlerosCoreUniversity)26904"
+ "type": "t_contract(KlerosCoreUniversity)30192"
},
{
- "astId": 26938,
+ "astId": 30230,
"contract": "src/arbitration/university/SortitionModuleUniversity.sol:SortitionModuleUniversity",
"label": "disputesWithoutJurors",
"offset": 0,
@@ -741,15 +1177,15 @@
"type": "t_uint256"
},
{
- "astId": 26943,
+ "astId": 30235,
"contract": "src/arbitration/university/SortitionModuleUniversity.sol:SortitionModuleUniversity",
"label": "jurors",
"offset": 0,
"slot": "3",
- "type": "t_mapping(t_address,t_struct(Juror)26931_storage)"
+ "type": "t_mapping(t_address,t_struct(Juror)30223_storage)"
},
{
- "astId": 26945,
+ "astId": 30237,
"contract": "src/arbitration/university/SortitionModuleUniversity.sol:SortitionModuleUniversity",
"label": "transientJuror",
"offset": 0,
@@ -769,17 +1205,17 @@
"label": "uint96[]",
"numberOfBytes": "32"
},
- "t_contract(KlerosCoreUniversity)26904": {
+ "t_contract(KlerosCoreUniversity)30192": {
"encoding": "inplace",
"label": "contract KlerosCoreUniversity",
"numberOfBytes": "20"
},
- "t_mapping(t_address,t_struct(Juror)26931_storage)": {
+ "t_mapping(t_address,t_struct(Juror)30223_storage)": {
"encoding": "mapping",
"key": "t_address",
"label": "mapping(address => struct SortitionModuleUniversity.Juror)",
"numberOfBytes": "32",
- "value": "t_struct(Juror)26931_storage"
+ "value": "t_struct(Juror)30223_storage"
},
"t_mapping(t_uint96,t_uint256)": {
"encoding": "mapping",
@@ -788,12 +1224,12 @@
"numberOfBytes": "32",
"value": "t_uint256"
},
- "t_struct(Juror)26931_storage": {
+ "t_struct(Juror)30223_storage": {
"encoding": "inplace",
"label": "struct SortitionModuleUniversity.Juror",
"members": [
{
- "astId": 26923,
+ "astId": 30215,
"contract": "src/arbitration/university/SortitionModuleUniversity.sol:SortitionModuleUniversity",
"label": "stakesByCourtID",
"offset": 0,
@@ -801,7 +1237,7 @@
"type": "t_mapping(t_uint96,t_uint256)"
},
{
- "astId": 26926,
+ "astId": 30218,
"contract": "src/arbitration/university/SortitionModuleUniversity.sol:SortitionModuleUniversity",
"label": "courtIDs",
"offset": 0,
@@ -809,7 +1245,7 @@
"type": "t_array(t_uint96)dyn_storage"
},
{
- "astId": 26928,
+ "astId": 30220,
"contract": "src/arbitration/university/SortitionModuleUniversity.sol:SortitionModuleUniversity",
"label": "stakedPnk",
"offset": 0,
@@ -817,7 +1253,7 @@
"type": "t_uint256"
},
{
- "astId": 26930,
+ "astId": 30222,
"contract": "src/arbitration/university/SortitionModuleUniversity.sol:SortitionModuleUniversity",
"label": "lockedPnk",
"offset": 0,
diff --git a/contracts/deployments/arbitrumSepoliaDevnet/SortitionModuleUniversity_Proxy.json b/contracts/deployments/arbitrumSepoliaDevnet/SortitionModuleUniversity_Proxy.json
index e098e68d0..642ee37b3 100644
--- a/contracts/deployments/arbitrumSepoliaDevnet/SortitionModuleUniversity_Proxy.json
+++ b/contracts/deployments/arbitrumSepoliaDevnet/SortitionModuleUniversity_Proxy.json
@@ -1,5 +1,5 @@
{
- "address": "0x4B2c2d048921f694cCE3AEa35698c6B1f5fcbb79",
+ "address": "0x9f55804177e7E44E558616cD7d06B865788214cA",
"abi": [
{
"inputs": [
@@ -26,44 +26,44 @@
"type": "receive"
}
],
- "transactionHash": "0xb26dc1c9ca9c3ed561a1d9c3feaad474af38bc90ea240f927053e5e5868d6a7e",
+ "transactionHash": "0x816a335385508eb3b23f6e38ecbdb464110275a0059895f982bfb692c8e7a452",
"receipt": {
"to": null,
"from": "0xf1C7c037891525E360C59f708739Ac09A7670c59",
- "contractAddress": "0x4B2c2d048921f694cCE3AEa35698c6B1f5fcbb79",
- "transactionIndex": 1,
- "gasUsed": "210047",
- "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010800000020000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
- "blockHash": "0x6a08d6d6cf180ae6bf3126f86fbedfd17212528b22a7a9403addd2dd6b1109c3",
- "transactionHash": "0xb26dc1c9ca9c3ed561a1d9c3feaad474af38bc90ea240f927053e5e5868d6a7e",
+ "contractAddress": "0x9f55804177e7E44E558616cD7d06B865788214cA",
+ "transactionIndex": 2,
+ "gasUsed": "180483",
+ "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000080000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000008000000000000000000000000000000000000000000",
+ "blockHash": "0xeb89982fc4a65212a277169f078d43cd1578b93b962c37ded52f9ddeb92610af",
+ "transactionHash": "0x816a335385508eb3b23f6e38ecbdb464110275a0059895f982bfb692c8e7a452",
"logs": [
{
- "transactionIndex": 1,
- "blockNumber": 96308572,
- "transactionHash": "0xb26dc1c9ca9c3ed561a1d9c3feaad474af38bc90ea240f927053e5e5868d6a7e",
- "address": "0x4B2c2d048921f694cCE3AEa35698c6B1f5fcbb79",
+ "transactionIndex": 2,
+ "blockNumber": 193533797,
+ "transactionHash": "0x816a335385508eb3b23f6e38ecbdb464110275a0059895f982bfb692c8e7a452",
+ "address": "0x9f55804177e7E44E558616cD7d06B865788214cA",
"topics": [
"0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2"
],
"data": "0x0000000000000000000000000000000000000000000000000000000000000001",
- "logIndex": 0,
- "blockHash": "0x6a08d6d6cf180ae6bf3126f86fbedfd17212528b22a7a9403addd2dd6b1109c3"
+ "logIndex": 1,
+ "blockHash": "0xeb89982fc4a65212a277169f078d43cd1578b93b962c37ded52f9ddeb92610af"
}
],
- "blockNumber": 96308572,
- "cumulativeGasUsed": "210047",
+ "blockNumber": 193533797,
+ "cumulativeGasUsed": "214736",
"status": 1,
"byzantium": true
},
"args": [
- "0x5CAD621D69E0535422aCFaCC0017bC32beC7A486",
- "0x485cc955000000000000000000000000f1c7c037891525e360c59f708739ac09a7670c590000000000000000000000005ab37f38778bc175852fa353056591d91c744ce6"
+ "0x270e3D63d3d275604df0a1Bd312E1255DCd96936",
+ "0x485cc955000000000000000000000000f1c7c037891525e360c59f708739ac09a7670c59000000000000000000000000a34dbbd0e5e1d09bd683455f9dbc393797bc558f"
],
"numDeployments": 1,
- "solcInputHash": "a5602534c00c2f67ca4b6a1cab8c717e",
- "metadata": "{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_implementation\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"stateMutability\":\"payable\",\"type\":\"fallback\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/proxy/KlerosProxies.sol\":\"SortitionModuleUniversityProxy\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":100},\"remappings\":[]},\"sources\":{\"src/proxy/KlerosProxies.sol\":{\"content\":\"//SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.24;\\n\\nimport \\\"./UUPSProxy.sol\\\";\\n\\n/// Workaround to get meaningful names for the proxy contracts\\n/// Otherwise all the contracts are called `UUPSProxy` on the chain explorers\\n\\ncontract DisputeKitClassicNeoProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract DisputeKitClassicUniversityProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract DisputeKitClassicProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract DisputeTemplateRegistryProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract EvidenceModuleProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract ForeignGatewayOnEthereumProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract HomeGatewayToEthereumProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract KlerosCoreNeoProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract KlerosCoreRulerProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract KlerosCoreUniversityProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract KlerosCoreProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract PolicyRegistryProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract RandomizerRNGProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract SortitionModuleNeoProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract SortitionModuleUniversityProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract SortitionModuleProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\",\"keccak256\":\"0x4393c05bbfda204b9992e1e546142a0fbf4c92a1c4061f5985463d02a71b84d4\",\"license\":\"MIT\"},\"src/proxy/UUPSProxy.sol\":{\"content\":\"//SPDX-License-Identifier: MIT\\n// Adapted from \\n\\n/**\\n * @authors: [@malatrax]\\n * @reviewers: []\\n * @auditors: []\\n * @bounties: []\\n * @deployments: []\\n */\\npragma solidity 0.8.24;\\n\\n/**\\n * @title UUPS Proxy\\n * @author Simon Malatrait \\n * @dev This contract implements a UUPS Proxy compliant with ERC-1967 & ERC-1822.\\n * @dev This contract delegates all calls to another contract (UUPS Proxiable) through a fallback function and the use of the `delegatecall` EVM instruction.\\n * @dev We refer to the Proxiable contract (as per ERC-1822) with `implementation`.\\n */\\ncontract UUPSProxy {\\n /**\\n * @dev Storage slot with the address of the current implementation.\\n * This is the keccak-256 hash of \\\"eip1967.proxy.implementation\\\" subtracted by 1, and is\\n * validated in the constructor.\\n * NOTE: bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1)\\n */\\n bytes32 private constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\\n\\n // ************************************* //\\n // * Constructor * //\\n // ************************************* //\\n\\n /**\\n * @dev Initializes the upgradeable proxy with an initial implementation specified by `_implementation`.\\n *\\n * If `_data` is nonempty, it's used as data in a delegate call to `_implementation`. This will typically be an encoded\\n * function call, and allows initializing the storage of the proxy like a Solidity constructor.\\n */\\n constructor(address _implementation, bytes memory _data) {\\n assembly {\\n sstore(IMPLEMENTATION_SLOT, _implementation)\\n }\\n\\n if (_data.length != 0) {\\n (bool success, ) = _implementation.delegatecall(_data);\\n require(success, \\\"Proxy Constructor failed\\\");\\n }\\n }\\n\\n // ************************************* //\\n // * State Modifiers * //\\n // ************************************* //\\n\\n /**\\n * @dev Delegates the current call to `implementation`.\\n *\\n * NOTE: This function does not return to its internal call site, it will return directly to the external caller.\\n */\\n function _delegate(address implementation) internal {\\n assembly {\\n // Copy msg.data. We take full control of memory in this inline assembly\\n // block because it will not return to Solidity code. We overwrite the\\n // Solidity scratch pad at memory position 0.\\n calldatacopy(0, 0, calldatasize())\\n\\n // Call the implementation.\\n // out and outsize are 0 because we don't know the size yet.\\n let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)\\n\\n // Copy the returned data.\\n returndatacopy(0, 0, returndatasize())\\n\\n switch result\\n // delegatecall returns 0 on error.\\n case 0 {\\n revert(0, returndatasize())\\n }\\n default {\\n return(0, returndatasize())\\n }\\n }\\n }\\n\\n // ************************************* //\\n // * Internal Views * //\\n // ************************************* //\\n\\n function _getImplementation() internal view returns (address implementation) {\\n assembly {\\n implementation := sload(IMPLEMENTATION_SLOT)\\n }\\n }\\n\\n // ************************************* //\\n // * Fallback * //\\n // ************************************* //\\n\\n /**\\n * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other\\n * function in the contract matches the call data.\\n */\\n fallback() external payable {\\n _delegate(_getImplementation());\\n }\\n\\n receive() external payable {\\n _delegate(_getImplementation());\\n }\\n}\\n\",\"keccak256\":\"0x7aa5f14ce351299722ac1a1afca9e65e1c795f32ea3e9702b0d5faaf7ca822a0\",\"license\":\"MIT\"}},\"version\":1}",
- "bytecode": "0x608060405234801561001057600080fd5b5060405161030238038061030283398101604081905261002f91610151565b8181817f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc55805160001461010e576000826001600160a01b031682604051610077919061021f565b600060405180830381855af49150503d80600081146100b2576040519150601f19603f3d011682016040523d82523d6000602084013e6100b7565b606091505b505090508061010c5760405162461bcd60e51b815260206004820152601860248201527f50726f787920436f6e7374727563746f72206661696c65640000000000000000604482015260640160405180910390fd5b505b5050505061023b565b634e487b7160e01b600052604160045260246000fd5b60005b83811015610148578181015183820152602001610130565b50506000910152565b6000806040838503121561016457600080fd5b82516001600160a01b038116811461017b57600080fd5b60208401519092506001600160401b038082111561019857600080fd5b818501915085601f8301126101ac57600080fd5b8151818111156101be576101be610117565b604051601f8201601f19908116603f011681019083821181831017156101e6576101e6610117565b816040528281528860208487010111156101ff57600080fd5b61021083602083016020880161012d565b80955050505050509250929050565b6000825161023181846020870161012d565b9190910192915050565b60b9806102496000396000f3fe608060405236603757603560317f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5490565b6060565b005b603560317f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5490565b3660008037600080366000845af43d6000803e808015607e573d6000f35b3d6000fdfea2646970667358221220cbf6c95b71e3c03306025a1af7f6aa4f021b4a8c8f5a8c68988b35c4442edb4964736f6c63430008180033",
- "deployedBytecode": "0x608060405236603757603560317f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5490565b6060565b005b603560317f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5490565b3660008037600080366000845af43d6000803e808015607e573d6000f35b3d6000fdfea2646970667358221220cbf6c95b71e3c03306025a1af7f6aa4f021b4a8c8f5a8c68988b35c4442edb4964736f6c63430008180033",
+ "solcInputHash": "d547d738900bce1310e91a5d1adfc179",
+ "metadata": "{\"compiler\":{\"version\":\"0.8.30+commit.73712a01\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_implementation\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"stateMutability\":\"payable\",\"type\":\"fallback\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/proxy/KlerosProxies.sol\":\"SortitionModuleUniversityProxy\"},\"evmVersion\":\"cancun\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000},\"remappings\":[],\"viaIR\":true},\"sources\":{\"src/proxy/KlerosProxies.sol\":{\"content\":\"//SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.24;\\n\\nimport \\\"./UUPSProxy.sol\\\";\\n\\n/// Workaround to get meaningful names for the proxy contracts\\n/// Otherwise all the contracts are called `UUPSProxy` on the chain explorers\\n\\ncontract DisputeKitClassicUniversityProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract DisputeKitClassicProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract DisputeKitGatedProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract DisputeKitGatedShutterProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract DisputeKitShutterProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract DisputeKitSybilResistantProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract DisputeTemplateRegistryProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract EvidenceModuleProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract ForeignGatewayOnEthereumProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract HomeGatewayToEthereumProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract KlerosCoreRulerProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract KlerosCoreUniversityProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract KlerosCoreProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract PolicyRegistryProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract RandomizerRNGProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract SortitionModuleUniversityProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\\ncontract SortitionModuleProxy is UUPSProxy {\\n constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}\\n}\\n\",\"keccak256\":\"0x3160bd320b23c6ec0c21862b455c3044a9b33654ae84a1b6cd76255626c9154b\",\"license\":\"MIT\"},\"src/proxy/UUPSProxy.sol\":{\"content\":\"//SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.24;\\n\\n/// @title UUPS Proxy\\n/// @author Simon Malatrait \\n/// @notice This contract implements a UUPS Proxy compliant with ERC-1967 & ERC-1822.\\n///\\n/// @dev This contract delegates all calls to another contract (UUPS Proxiable) through a fallback function and the use of the `delegatecall` EVM instruction.\\n/// We refer to the Proxiable contract (as per ERC-1822) with `implementation`.\\n/// Adapted from \\ncontract UUPSProxy {\\n /// @dev Storage slot with the address of the current implementation.\\n /// This is the keccak-256 hash of \\\"eip1967.proxy.implementation\\\" subtracted by 1, and is\\n /// validated in the constructor.\\n /// NOTE: bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1)\\n bytes32 private constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\\n\\n // ************************************* //\\n // * Constructor * //\\n // ************************************* //\\n\\n /// @notice Initializes the upgradeable proxy with an initial implementation specified by `_implementation`.\\n /// @dev If `_data` is nonempty, it's used as data in a delegate call to `_implementation`.\\n /// This will typically be an encoded function call, and allows initializing the storage of the proxy like a Solidity constructor.\\n constructor(address _implementation, bytes memory _data) {\\n assembly {\\n sstore(IMPLEMENTATION_SLOT, _implementation)\\n }\\n\\n if (_data.length != 0) {\\n (bool success, ) = _implementation.delegatecall(_data);\\n require(success, \\\"Proxy Constructor failed\\\");\\n }\\n }\\n\\n // ************************************* //\\n // * State Modifiers * //\\n // ************************************* //\\n\\n /// @dev Delegates the current call to `implementation`.\\n /// NOTE: This function does not return to its internal call site, it will return directly to the external caller.\\n function _delegate(address implementation) internal {\\n assembly {\\n // Copy msg.data. We take full control of memory in this inline assembly\\n // block because it will not return to Solidity code. We overwrite the\\n // Solidity scratch pad at memory position 0.\\n calldatacopy(0, 0, calldatasize())\\n\\n // Call the implementation.\\n // out and outsize are 0 because we don't know the size yet.\\n let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)\\n\\n // Copy the returned data.\\n returndatacopy(0, 0, returndatasize())\\n\\n switch result\\n // delegatecall returns 0 on error.\\n case 0 {\\n revert(0, returndatasize())\\n }\\n default {\\n return(0, returndatasize())\\n }\\n }\\n }\\n\\n // ************************************* //\\n // * Internal Views * //\\n // ************************************* //\\n\\n function _getImplementation() internal view returns (address implementation) {\\n assembly {\\n implementation := sload(IMPLEMENTATION_SLOT)\\n }\\n }\\n\\n // ************************************* //\\n // * Fallback * //\\n // ************************************* //\\n\\n /// @dev Fallback function that delegates calls to the address returned by `_implementation()`.\\n /// @dev Will run if no other function in the contract matches the call data.\\n fallback() external payable {\\n _delegate(_getImplementation());\\n }\\n\\n receive() external payable {\\n _delegate(_getImplementation());\\n }\\n}\\n\",\"keccak256\":\"0x2d7b1f81e525787f1b8b033ce381a81cb5f39e411ff31490e019113205a661cd\",\"license\":\"MIT\"}},\"version\":1}",
+ "bytecode": "0x608060405234610144576102148038038061001981610148565b928339810190604081830312610144578051906001600160a01b0382168203610144576020810151906001600160401b038211610144570182601f8201121561014457805161006f61006a82610181565b610148565b9181835260208301946020838301011161014457815f926020809301875e83010152817f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5551806100c9575b6040516077908161019d8239f35b5f9283925af43d1561013f573d6100e261006a82610181565b9081525f60203d92013e5b156100fa575f80806100bb565b60405162461bcd60e51b815260206004820152601860248201527f50726f787920436f6e7374727563746f72206661696c656400000000000000006044820152606490fd5b6100ed565b5f80fd5b6040519190601f01601f191682016001600160401b0381118382101761016d57604052565b634e487b7160e01b5f52604160045260245ffd5b6001600160401b03811161016d57601f01601f19166020019056fe60806040525f807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc54368280378136915af43d5f803e15603d573d5ff35b3d5ffdfea2646970667358221220cebc238294db6f217e59b4194d65c951358927be9872c8bda288fff77348423e64736f6c634300081e0033",
+ "deployedBytecode": "0x60806040525f807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc54368280378136915af43d5f803e15603d573d5ff35b3d5ffdfea2646970667358221220cebc238294db6f217e59b4194d65c951358927be9872c8bda288fff77348423e64736f6c634300081e0033",
"devdoc": {
"kind": "dev",
"methods": {},
diff --git a/contracts/deployments/contractsEthers.ts b/contracts/deployments/contractsEthers.ts
index 49bc0552e..dbddee21e 100644
--- a/contracts/deployments/contractsEthers.ts
+++ b/contracts/deployments/contractsEthers.ts
@@ -18,6 +18,7 @@ import {
klerosCoreUniversityConfig as devnetCoreUniversityConfig,
sortitionModuleUniversityConfig as devnetSortitionUniversityConfig,
disputeKitClassicUniversityConfig as devnetDkClassicUniversityConfig,
+ disputeTemplateRegistryUniversityConfig as devnetDtrUniversityConfig,
disputeResolverUniversityConfig as devnetDrUniversityConfig,
} from "./devnet.viem";
import {
@@ -38,13 +39,13 @@ import {
klerosCoreSnapshotProxyConfig as testnetSnapshotProxyConfig,
} from "./testnet.viem";
import {
- klerosCoreNeoConfig as mainnetCoreConfig,
- sortitionModuleNeoConfig as mainnetSortitionConfig,
- disputeKitClassicNeoConfig as mainnetDkcConfig,
- disputeKitShutterNeoConfig as mainnetDkShutterConfig,
- disputeKitGatedNeoConfig as mainnetDkGatedConfig,
- disputeKitGatedShutterNeoConfig as mainnetDkGatedShutterConfig,
- disputeResolverNeoConfig as mainnetDrConfig,
+ klerosCoreConfig as mainnetCoreConfig,
+ sortitionModuleConfig as mainnetSortitionConfig,
+ disputeKitClassicConfig as mainnetDkcConfig,
+ disputeKitShutterConfig as mainnetDkShutterConfig,
+ disputeKitGatedConfig as mainnetDkGatedConfig,
+ disputeKitGatedShutterConfig as mainnetDkGatedShutterConfig,
+ disputeResolverConfig as mainnetDrConfig,
disputeTemplateRegistryConfig as mainnetDtrConfig,
evidenceModuleConfig as mainnetEvidenceConfig,
policyRegistryConfig as mainnetPolicyRegistryConfig,
@@ -92,10 +93,6 @@ import {
KlerosCoreUniversity__factory,
SortitionModuleUniversity,
SortitionModuleUniversity__factory,
- KlerosCoreNeo,
- KlerosCoreNeo__factory,
- SortitionModuleNeo,
- SortitionModuleNeo__factory,
} from "../typechain-types";
import { type ContractConfig, type DeploymentName, deployments, getAddress } from "./utils";
@@ -171,8 +168,8 @@ function getCommonFactories(
export const getContracts = async (provider: ethers.Provider, deployment: DeploymentName) => {
const { chainId } = deployments[deployment];
- let klerosCore: KlerosCore | KlerosCoreNeo | KlerosCoreUniversity;
- let sortition: SortitionModule | SortitionModuleNeo | SortitionModuleUniversity;
+ let klerosCore: KlerosCore | KlerosCoreUniversity;
+ let sortition: SortitionModule | SortitionModuleUniversity;
let commonFactories: CommonFactories;
switch (deployment) {
@@ -210,7 +207,7 @@ export const getContracts = async (provider: ethers.Provider, deployment: Deploy
{
dkClassicConfig: devnetDkClassicUniversityConfig,
drConfig: devnetDrUniversityConfig,
- dtrConfig: devnetDtrConfig,
+ dtrConfig: devnetDtrUniversityConfig,
evidenceConfig: devnetEvidenceConfig,
policyRegistryConfig: devnetPolicyRegistryConfig,
batcherConfig: devnetBatcherConfig,
@@ -247,9 +244,9 @@ export const getContracts = async (provider: ethers.Provider, deployment: Deploy
chainId
);
break;
- case "mainnetNeo":
- klerosCore = KlerosCoreNeo__factory.connect(getAddress(mainnetCoreConfig, chainId), provider);
- sortition = SortitionModuleNeo__factory.connect(getAddress(mainnetSortitionConfig, chainId), provider);
+ case "mainnet":
+ klerosCore = KlerosCore__factory.connect(getAddress(mainnetCoreConfig, chainId), provider);
+ sortition = SortitionModule__factory.connect(getAddress(mainnetSortitionConfig, chainId), provider);
commonFactories = getCommonFactories(
{
dkClassicConfig: mainnetDkcConfig,
diff --git a/contracts/deployments/contractsViem.ts b/contracts/deployments/contractsViem.ts
index 792ce5b3e..f072acd9f 100644
--- a/contracts/deployments/contractsViem.ts
+++ b/contracts/deployments/contractsViem.ts
@@ -19,6 +19,7 @@ import {
klerosCoreUniversityConfig as devnetCoreUniversityConfig,
sortitionModuleUniversityConfig as devnetSortitionUniversityConfig,
disputeKitClassicUniversityConfig as devnetDkClassicUniversityConfig,
+ disputeTemplateRegistryUniversityConfig as devnetDtrUniversityConfig,
disputeResolverUniversityConfig as devnetDrUniversityConfig,
} from "./devnet.viem";
import {
@@ -39,13 +40,13 @@ import {
klerosCoreSnapshotProxyConfig as testnetSnapshotProxyConfig,
} from "./testnet.viem";
import {
- klerosCoreNeoConfig as mainnetCoreConfig,
- sortitionModuleNeoConfig as mainnetSortitionConfig,
- disputeKitClassicNeoConfig as mainnetDkClassicConfig,
- disputeKitShutterNeoConfig as mainnetDkShutterConfig,
- disputeKitGatedNeoConfig as mainnetDkGatedConfig,
- disputeKitGatedShutterNeoConfig as mainnetDkGatedShutterConfig,
- disputeResolverNeoConfig as mainnetDrConfig,
+ klerosCoreConfig as mainnetCoreConfig,
+ sortitionModuleConfig as mainnetSortitionConfig,
+ disputeKitClassicConfig as mainnetDkClassicConfig,
+ disputeKitShutterConfig as mainnetDkShutterConfig,
+ disputeKitGatedConfig as mainnetDkGatedConfig,
+ disputeKitGatedShutterConfig as mainnetDkGatedShutterConfig,
+ disputeResolverConfig as mainnetDrConfig,
disputeTemplateRegistryConfig as mainnetDtrConfig,
evidenceModuleConfig as mainnetEvidenceConfig,
policyRegistryConfig as mainnetPolicyRegistryConfig,
@@ -172,7 +173,7 @@ export const getConfigs = ({ deployment }: { deployment: DeploymentName }): Cont
sortition: getContractConfig({ config: devnetSortitionUniversityConfig, chainId }),
disputeKitClassic: getContractConfig({ config: devnetDkClassicUniversityConfig, chainId }),
disputeResolver: getContractConfig({ config: devnetDrUniversityConfig, chainId }),
- disputeTemplateRegistry: getContractConfig({ config: devnetDtrConfig, chainId }), // FIXME: should not be shared with devnet
+ disputeTemplateRegistry: getContractConfig({ config: devnetDtrUniversityConfig, chainId }),
evidence: getContractConfig({ config: devnetEvidenceConfig, chainId }), // Not arbitrator specific
policyRegistry: getContractConfig({ config: devnetPolicyRegistryConfig, chainId }), // Not arbitrator specific
transactionBatcher: getContractConfig({ config: devnetBatcherConfig, chainId }), // Not arbitrator specific
@@ -203,7 +204,7 @@ export const getConfigs = ({ deployment }: { deployment: DeploymentName }): Cont
},
});
- case "mainnetNeo":
+ case "mainnet":
return getCommonConfigs({
chainId,
configs: {
diff --git a/contracts/deployments/devnet.viem.ts b/contracts/deployments/devnet.viem.ts
index f7a7214bd..9cfb583b9 100644
--- a/contracts/deployments/devnet.viem.ts
+++ b/contracts/deployments/devnet.viem.ts
@@ -2630,25 +2630,43 @@ export const disputeKitClassicConfig = {
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
- * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0xd6E96b7c993763B5CDDa1139C7387B82A7c8B8B5)
+ * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0x82F2089442979A6b56c80274D144575980092F91)
*/
export const disputeKitClassicUniversityAbi = [
{ type: "fallback", stateMutability: "payable" },
{ type: "receive", stateMutability: "payable" },
{ type: "error", inputs: [], name: "AlreadyInitialized" },
+ { type: "error", inputs: [], name: "AppealFeeIsAlreadyPaid" },
+ { type: "error", inputs: [], name: "AppealPeriodIsOver" },
+ { type: "error", inputs: [], name: "AppealPeriodIsOverForLoser" },
+ { type: "error", inputs: [], name: "ChoiceOutOfBounds" },
+ { type: "error", inputs: [], name: "CoreIsPaused" },
+ { type: "error", inputs: [], name: "DisputeJumpedToParentDK" },
+ { type: "error", inputs: [], name: "DisputeNotResolved" },
+ { type: "error", inputs: [], name: "EmptyCommit" },
+ { type: "error", inputs: [], name: "EmptyVoteIDs" },
{ type: "error", inputs: [], name: "FailedDelegateCall" },
+ { type: "error", inputs: [], name: "HashDoesNotMatchHiddenVoteCommitment" },
{
type: "error",
inputs: [{ name: "implementation", internalType: "address", type: "address" }],
name: "InvalidImplementation",
},
+ { type: "error", inputs: [], name: "JurorHasToOwnTheVote" },
+ { type: "error", inputs: [], name: "KlerosCoreOnly" },
+ { type: "error", inputs: [], name: "NotActiveForCoreDisputeID" },
+ { type: "error", inputs: [], name: "NotCommitPeriod" },
{ type: "error", inputs: [], name: "NotInitializing" },
+ { type: "error", inputs: [], name: "NotVotePeriod" },
+ { type: "error", inputs: [], name: "OwnerOnly" },
{ type: "error", inputs: [], name: "UUPSUnauthorizedCallContext" },
{
type: "error",
inputs: [{ name: "slot", internalType: "bytes32", type: "bytes32" }],
name: "UUPSUnsupportedProxiableUUID",
},
+ { type: "error", inputs: [], name: "UnsuccessfulCall" },
+ { type: "error", inputs: [], name: "VoteAlreadyCast" },
{
type: "event",
anonymous: false,
@@ -2881,13 +2899,6 @@ export const disputeKitClassicUniversityAbi = [
outputs: [{ name: "", internalType: "uint256", type: "uint256" }],
stateMutability: "view",
},
- {
- type: "function",
- inputs: [],
- name: "ONE_BASIS_POINT",
- outputs: [{ name: "", internalType: "uint256", type: "uint256" }],
- stateMutability: "view",
- },
{
type: "function",
inputs: [],
@@ -2942,8 +2953,15 @@ export const disputeKitClassicUniversityAbi = [
},
{
type: "function",
- inputs: [{ name: "_governor", internalType: "address payable", type: "address" }],
- name: "changeGovernor",
+ inputs: [{ name: "_jumpDisputeKitID", internalType: "uint256", type: "uint256" }],
+ name: "changeJumpDisputeKitID",
+ outputs: [],
+ stateMutability: "nonpayable",
+ },
+ {
+ type: "function",
+ inputs: [{ name: "_owner", internalType: "address payable", type: "address" }],
+ name: "changeOwner",
outputs: [],
stateMutability: "nonpayable",
},
@@ -2954,6 +2972,13 @@ export const disputeKitClassicUniversityAbi = [
outputs: [{ name: "", internalType: "contract KlerosCore", type: "address" }],
stateMutability: "view",
},
+ {
+ type: "function",
+ inputs: [{ name: "coreDisputeID", internalType: "uint256", type: "uint256" }],
+ name: "coreDisputeIDToActive",
+ outputs: [{ name: "", internalType: "bool", type: "bool" }],
+ stateMutability: "view",
+ },
{
type: "function",
inputs: [{ name: "", internalType: "uint256", type: "uint256" }],
@@ -2967,7 +2992,7 @@ export const disputeKitClassicUniversityAbi = [
{ name: "_coreDisputeID", internalType: "uint256", type: "uint256" },
{ name: "_numberOfChoices", internalType: "uint256", type: "uint256" },
{ name: "_extraData", internalType: "bytes", type: "bytes" },
- { name: "_nbVotes", internalType: "uint256", type: "uint256" },
+ { name: "", internalType: "uint256", type: "uint256" },
],
name: "createDispute",
outputs: [],
@@ -3002,9 +3027,19 @@ export const disputeKitClassicUniversityAbi = [
{ name: "_nonce", internalType: "uint256", type: "uint256" },
],
name: "draw",
- outputs: [{ name: "drawnAddress", internalType: "address", type: "address" }],
+ outputs: [
+ { name: "drawnAddress", internalType: "address", type: "address" },
+ { name: "fromSubcourtID", internalType: "uint96", type: "uint96" },
+ ],
stateMutability: "nonpayable",
},
+ {
+ type: "function",
+ inputs: [{ name: "", internalType: "uint256", type: "uint256" }],
+ name: "earlyCourtJump",
+ outputs: [{ name: "", internalType: "bool", type: "bool" }],
+ stateMutability: "pure",
+ },
{
type: "function",
inputs: [
@@ -3012,7 +3047,7 @@ export const disputeKitClassicUniversityAbi = [
{ name: "_amount", internalType: "uint256", type: "uint256" },
{ name: "_data", internalType: "bytes", type: "bytes" },
],
- name: "executeGovernorProposal",
+ name: "executeOwnerProposal",
outputs: [],
stateMutability: "nonpayable",
},
@@ -3045,8 +3080,24 @@ export const disputeKitClassicUniversityAbi = [
{ name: "", internalType: "uint256", type: "uint256" },
{ name: "", internalType: "uint256", type: "uint256" },
],
- name: "getDegreeOfCoherence",
- outputs: [{ name: "", internalType: "uint256", type: "uint256" }],
+ name: "getDegreeOfCoherencePenalty",
+ outputs: [{ name: "pnkCoherence", internalType: "uint256", type: "uint256" }],
+ stateMutability: "view",
+ },
+ {
+ type: "function",
+ inputs: [
+ { name: "_coreDisputeID", internalType: "uint256", type: "uint256" },
+ { name: "_coreRoundID", internalType: "uint256", type: "uint256" },
+ { name: "_voteID", internalType: "uint256", type: "uint256" },
+ { name: "", internalType: "uint256", type: "uint256" },
+ { name: "", internalType: "uint256", type: "uint256" },
+ ],
+ name: "getDegreeOfCoherenceReward",
+ outputs: [
+ { name: "pnkCoherence", internalType: "uint256", type: "uint256" },
+ { name: "feeCoherence", internalType: "uint256", type: "uint256" },
+ ],
stateMutability: "view",
},
{
@@ -3056,6 +3107,43 @@ export const disputeKitClassicUniversityAbi = [
outputs: [{ name: "fundedChoices", internalType: "uint256[]", type: "uint256[]" }],
stateMutability: "view",
},
+ {
+ type: "function",
+ inputs: [],
+ name: "getJumpDisputeKitID",
+ outputs: [{ name: "", internalType: "uint256", type: "uint256" }],
+ stateMutability: "view",
+ },
+ {
+ type: "function",
+ inputs: [
+ { name: "_coreDisputeID", internalType: "uint256", type: "uint256" },
+ { name: "_coreRoundID", internalType: "uint256", type: "uint256" },
+ ],
+ name: "getLocalDisputeRoundID",
+ outputs: [
+ { name: "localDisputeID", internalType: "uint256", type: "uint256" },
+ { name: "localRoundID", internalType: "uint256", type: "uint256" },
+ ],
+ stateMutability: "view",
+ },
+ {
+ type: "function",
+ inputs: [
+ { name: "", internalType: "contract IDisputeKit", type: "address" },
+ { name: "_currentNbVotes", internalType: "uint256", type: "uint256" },
+ ],
+ name: "getNbVotesAfterAppeal",
+ outputs: [{ name: "", internalType: "uint256", type: "uint256" }],
+ stateMutability: "pure",
+ },
+ {
+ type: "function",
+ inputs: [{ name: "_localDisputeID", internalType: "uint256", type: "uint256" }],
+ name: "getNumberOfRounds",
+ outputs: [{ name: "", internalType: "uint256", type: "uint256" }],
+ stateMutability: "view",
+ },
{
type: "function",
inputs: [
@@ -3068,7 +3156,7 @@ export const disputeKitClassicUniversityAbi = [
{ name: "winningChoice", internalType: "uint256", type: "uint256" },
{ name: "tied", internalType: "bool", type: "bool" },
{ name: "totalVoted", internalType: "uint256", type: "uint256" },
- { name: "totalCommited", internalType: "uint256", type: "uint256" },
+ { name: "totalCommitted", internalType: "uint256", type: "uint256" },
{ name: "nbVoters", internalType: "uint256", type: "uint256" },
{ name: "choiceCount", internalType: "uint256", type: "uint256" },
],
@@ -3092,21 +3180,34 @@ export const disputeKitClassicUniversityAbi = [
},
{
type: "function",
- inputs: [],
- name: "governor",
- outputs: [{ name: "", internalType: "address", type: "address" }],
+ inputs: [
+ { name: "_choice", internalType: "uint256", type: "uint256" },
+ { name: "_salt", internalType: "uint256", type: "uint256" },
+ { name: "", internalType: "string", type: "string" },
+ ],
+ name: "hashVote",
+ outputs: [{ name: "", internalType: "bytes32", type: "bytes32" }],
stateMutability: "view",
},
{
type: "function",
inputs: [
- { name: "_governor", internalType: "address", type: "address" },
+ { name: "_owner", internalType: "address", type: "address" },
{ name: "_core", internalType: "contract KlerosCore", type: "address" },
+ { name: "_wNative", internalType: "address", type: "address" },
+ { name: "_jumpDisputeKitID", internalType: "uint256", type: "uint256" },
],
name: "initialize",
outputs: [],
stateMutability: "nonpayable",
},
+ {
+ type: "function",
+ inputs: [{ name: "_coreDisputeID", internalType: "uint256", type: "uint256" }],
+ name: "isAppealFunded",
+ outputs: [{ name: "", internalType: "bool", type: "bool" }],
+ stateMutability: "view",
+ },
{
type: "function",
inputs: [
@@ -3118,6 +3219,20 @@ export const disputeKitClassicUniversityAbi = [
outputs: [{ name: "", internalType: "bool", type: "bool" }],
stateMutability: "view",
},
+ {
+ type: "function",
+ inputs: [],
+ name: "jumpDisputeKitID",
+ outputs: [{ name: "", internalType: "uint256", type: "uint256" }],
+ stateMutability: "view",
+ },
+ {
+ type: "function",
+ inputs: [],
+ name: "owner",
+ outputs: [{ name: "", internalType: "address", type: "address" }],
+ stateMutability: "view",
+ },
{
type: "function",
inputs: [],
@@ -3125,6 +3240,13 @@ export const disputeKitClassicUniversityAbi = [
outputs: [{ name: "", internalType: "bytes32", type: "bytes32" }],
stateMutability: "view",
},
+ {
+ type: "function",
+ inputs: [],
+ name: "singleDrawPerJuror",
+ outputs: [{ name: "", internalType: "bool", type: "bool" }],
+ stateMutability: "view",
+ },
{
type: "function",
inputs: [
@@ -3135,6 +3257,20 @@ export const disputeKitClassicUniversityAbi = [
outputs: [],
stateMutability: "payable",
},
+ {
+ type: "function",
+ inputs: [],
+ name: "version",
+ outputs: [{ name: "", internalType: "string", type: "string" }],
+ stateMutability: "view",
+ },
+ {
+ type: "function",
+ inputs: [],
+ name: "wNative",
+ outputs: [{ name: "", internalType: "address", type: "address" }],
+ stateMutability: "view",
+ },
{
type: "function",
inputs: [
@@ -3162,14 +3298,14 @@ export const disputeKitClassicUniversityAbi = [
] as const;
/**
- * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0xd6E96b7c993763B5CDDa1139C7387B82A7c8B8B5)
+ * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0x82F2089442979A6b56c80274D144575980092F91)
*/
export const disputeKitClassicUniversityAddress = {
- 421614: "0xd6E96b7c993763B5CDDa1139C7387B82A7c8B8B5",
+ 421614: "0x82F2089442979A6b56c80274D144575980092F91",
} as const;
/**
- * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0xd6E96b7c993763B5CDDa1139C7387B82A7c8B8B5)
+ * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0x82F2089442979A6b56c80274D144575980092F91)
*/
export const disputeKitClassicUniversityConfig = {
address: disputeKitClassicUniversityAddress,
@@ -3181,24 +3317,42 @@ export const disputeKitClassicUniversityConfig = {
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
- * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0x87e863b94d2CB79A8aB53bD87Dc4A10E11C0918B)
+ * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0x602ADa1cE706404BFb5417e497cdDae934436081)
*/
export const disputeKitClassicUniversityImplementationAbi = [
{ type: "constructor", inputs: [], stateMutability: "nonpayable" },
{ type: "error", inputs: [], name: "AlreadyInitialized" },
+ { type: "error", inputs: [], name: "AppealFeeIsAlreadyPaid" },
+ { type: "error", inputs: [], name: "AppealPeriodIsOver" },
+ { type: "error", inputs: [], name: "AppealPeriodIsOverForLoser" },
+ { type: "error", inputs: [], name: "ChoiceOutOfBounds" },
+ { type: "error", inputs: [], name: "CoreIsPaused" },
+ { type: "error", inputs: [], name: "DisputeJumpedToParentDK" },
+ { type: "error", inputs: [], name: "DisputeNotResolved" },
+ { type: "error", inputs: [], name: "EmptyCommit" },
+ { type: "error", inputs: [], name: "EmptyVoteIDs" },
{ type: "error", inputs: [], name: "FailedDelegateCall" },
+ { type: "error", inputs: [], name: "HashDoesNotMatchHiddenVoteCommitment" },
{
type: "error",
inputs: [{ name: "implementation", internalType: "address", type: "address" }],
name: "InvalidImplementation",
},
+ { type: "error", inputs: [], name: "JurorHasToOwnTheVote" },
+ { type: "error", inputs: [], name: "KlerosCoreOnly" },
+ { type: "error", inputs: [], name: "NotActiveForCoreDisputeID" },
+ { type: "error", inputs: [], name: "NotCommitPeriod" },
{ type: "error", inputs: [], name: "NotInitializing" },
+ { type: "error", inputs: [], name: "NotVotePeriod" },
+ { type: "error", inputs: [], name: "OwnerOnly" },
{ type: "error", inputs: [], name: "UUPSUnauthorizedCallContext" },
{
type: "error",
inputs: [{ name: "slot", internalType: "bytes32", type: "bytes32" }],
name: "UUPSUnsupportedProxiableUUID",
},
+ { type: "error", inputs: [], name: "UnsuccessfulCall" },
+ { type: "error", inputs: [], name: "VoteAlreadyCast" },
{
type: "event",
anonymous: false,
@@ -3431,13 +3585,6 @@ export const disputeKitClassicUniversityImplementationAbi = [
outputs: [{ name: "", internalType: "uint256", type: "uint256" }],
stateMutability: "view",
},
- {
- type: "function",
- inputs: [],
- name: "ONE_BASIS_POINT",
- outputs: [{ name: "", internalType: "uint256", type: "uint256" }],
- stateMutability: "view",
- },
{
type: "function",
inputs: [],
@@ -3492,8 +3639,15 @@ export const disputeKitClassicUniversityImplementationAbi = [
},
{
type: "function",
- inputs: [{ name: "_governor", internalType: "address payable", type: "address" }],
- name: "changeGovernor",
+ inputs: [{ name: "_jumpDisputeKitID", internalType: "uint256", type: "uint256" }],
+ name: "changeJumpDisputeKitID",
+ outputs: [],
+ stateMutability: "nonpayable",
+ },
+ {
+ type: "function",
+ inputs: [{ name: "_owner", internalType: "address payable", type: "address" }],
+ name: "changeOwner",
outputs: [],
stateMutability: "nonpayable",
},
@@ -3504,6 +3658,13 @@ export const disputeKitClassicUniversityImplementationAbi = [
outputs: [{ name: "", internalType: "contract KlerosCore", type: "address" }],
stateMutability: "view",
},
+ {
+ type: "function",
+ inputs: [{ name: "coreDisputeID", internalType: "uint256", type: "uint256" }],
+ name: "coreDisputeIDToActive",
+ outputs: [{ name: "", internalType: "bool", type: "bool" }],
+ stateMutability: "view",
+ },
{
type: "function",
inputs: [{ name: "", internalType: "uint256", type: "uint256" }],
@@ -3517,7 +3678,7 @@ export const disputeKitClassicUniversityImplementationAbi = [
{ name: "_coreDisputeID", internalType: "uint256", type: "uint256" },
{ name: "_numberOfChoices", internalType: "uint256", type: "uint256" },
{ name: "_extraData", internalType: "bytes", type: "bytes" },
- { name: "_nbVotes", internalType: "uint256", type: "uint256" },
+ { name: "", internalType: "uint256", type: "uint256" },
],
name: "createDispute",
outputs: [],
@@ -3552,9 +3713,19 @@ export const disputeKitClassicUniversityImplementationAbi = [
{ name: "_nonce", internalType: "uint256", type: "uint256" },
],
name: "draw",
- outputs: [{ name: "drawnAddress", internalType: "address", type: "address" }],
+ outputs: [
+ { name: "drawnAddress", internalType: "address", type: "address" },
+ { name: "fromSubcourtID", internalType: "uint96", type: "uint96" },
+ ],
stateMutability: "nonpayable",
},
+ {
+ type: "function",
+ inputs: [{ name: "", internalType: "uint256", type: "uint256" }],
+ name: "earlyCourtJump",
+ outputs: [{ name: "", internalType: "bool", type: "bool" }],
+ stateMutability: "pure",
+ },
{
type: "function",
inputs: [
@@ -3562,7 +3733,7 @@ export const disputeKitClassicUniversityImplementationAbi = [
{ name: "_amount", internalType: "uint256", type: "uint256" },
{ name: "_data", internalType: "bytes", type: "bytes" },
],
- name: "executeGovernorProposal",
+ name: "executeOwnerProposal",
outputs: [],
stateMutability: "nonpayable",
},
@@ -3595,8 +3766,24 @@ export const disputeKitClassicUniversityImplementationAbi = [
{ name: "", internalType: "uint256", type: "uint256" },
{ name: "", internalType: "uint256", type: "uint256" },
],
- name: "getDegreeOfCoherence",
- outputs: [{ name: "", internalType: "uint256", type: "uint256" }],
+ name: "getDegreeOfCoherencePenalty",
+ outputs: [{ name: "pnkCoherence", internalType: "uint256", type: "uint256" }],
+ stateMutability: "view",
+ },
+ {
+ type: "function",
+ inputs: [
+ { name: "_coreDisputeID", internalType: "uint256", type: "uint256" },
+ { name: "_coreRoundID", internalType: "uint256", type: "uint256" },
+ { name: "_voteID", internalType: "uint256", type: "uint256" },
+ { name: "", internalType: "uint256", type: "uint256" },
+ { name: "", internalType: "uint256", type: "uint256" },
+ ],
+ name: "getDegreeOfCoherenceReward",
+ outputs: [
+ { name: "pnkCoherence", internalType: "uint256", type: "uint256" },
+ { name: "feeCoherence", internalType: "uint256", type: "uint256" },
+ ],
stateMutability: "view",
},
{
@@ -3606,6 +3793,43 @@ export const disputeKitClassicUniversityImplementationAbi = [
outputs: [{ name: "fundedChoices", internalType: "uint256[]", type: "uint256[]" }],
stateMutability: "view",
},
+ {
+ type: "function",
+ inputs: [],
+ name: "getJumpDisputeKitID",
+ outputs: [{ name: "", internalType: "uint256", type: "uint256" }],
+ stateMutability: "view",
+ },
+ {
+ type: "function",
+ inputs: [
+ { name: "_coreDisputeID", internalType: "uint256", type: "uint256" },
+ { name: "_coreRoundID", internalType: "uint256", type: "uint256" },
+ ],
+ name: "getLocalDisputeRoundID",
+ outputs: [
+ { name: "localDisputeID", internalType: "uint256", type: "uint256" },
+ { name: "localRoundID", internalType: "uint256", type: "uint256" },
+ ],
+ stateMutability: "view",
+ },
+ {
+ type: "function",
+ inputs: [
+ { name: "", internalType: "contract IDisputeKit", type: "address" },
+ { name: "_currentNbVotes", internalType: "uint256", type: "uint256" },
+ ],
+ name: "getNbVotesAfterAppeal",
+ outputs: [{ name: "", internalType: "uint256", type: "uint256" }],
+ stateMutability: "pure",
+ },
+ {
+ type: "function",
+ inputs: [{ name: "_localDisputeID", internalType: "uint256", type: "uint256" }],
+ name: "getNumberOfRounds",
+ outputs: [{ name: "", internalType: "uint256", type: "uint256" }],
+ stateMutability: "view",
+ },
{
type: "function",
inputs: [
@@ -3618,7 +3842,7 @@ export const disputeKitClassicUniversityImplementationAbi = [
{ name: "winningChoice", internalType: "uint256", type: "uint256" },
{ name: "tied", internalType: "bool", type: "bool" },
{ name: "totalVoted", internalType: "uint256", type: "uint256" },
- { name: "totalCommited", internalType: "uint256", type: "uint256" },
+ { name: "totalCommitted", internalType: "uint256", type: "uint256" },
{ name: "nbVoters", internalType: "uint256", type: "uint256" },
{ name: "choiceCount", internalType: "uint256", type: "uint256" },
],
@@ -3642,21 +3866,34 @@ export const disputeKitClassicUniversityImplementationAbi = [
},
{
type: "function",
- inputs: [],
- name: "governor",
- outputs: [{ name: "", internalType: "address", type: "address" }],
+ inputs: [
+ { name: "_choice", internalType: "uint256", type: "uint256" },
+ { name: "_salt", internalType: "uint256", type: "uint256" },
+ { name: "", internalType: "string", type: "string" },
+ ],
+ name: "hashVote",
+ outputs: [{ name: "", internalType: "bytes32", type: "bytes32" }],
stateMutability: "view",
},
{
type: "function",
inputs: [
- { name: "_governor", internalType: "address", type: "address" },
+ { name: "_owner", internalType: "address", type: "address" },
{ name: "_core", internalType: "contract KlerosCore", type: "address" },
+ { name: "_wNative", internalType: "address", type: "address" },
+ { name: "_jumpDisputeKitID", internalType: "uint256", type: "uint256" },
],
name: "initialize",
outputs: [],
stateMutability: "nonpayable",
},
+ {
+ type: "function",
+ inputs: [{ name: "_coreDisputeID", internalType: "uint256", type: "uint256" }],
+ name: "isAppealFunded",
+ outputs: [{ name: "", internalType: "bool", type: "bool" }],
+ stateMutability: "view",
+ },
{
type: "function",
inputs: [
@@ -3671,24 +3908,59 @@ export const disputeKitClassicUniversityImplementationAbi = [
{
type: "function",
inputs: [],
- name: "proxiableUUID",
- outputs: [{ name: "", internalType: "bytes32", type: "bytes32" }],
+ name: "jumpDisputeKitID",
+ outputs: [{ name: "", internalType: "uint256", type: "uint256" }],
stateMutability: "view",
},
{
type: "function",
- inputs: [
- { name: "newImplementation", internalType: "address", type: "address" },
- { name: "data", internalType: "bytes", type: "bytes" },
- ],
- name: "upgradeToAndCall",
- outputs: [],
- stateMutability: "payable",
+ inputs: [],
+ name: "owner",
+ outputs: [{ name: "", internalType: "address", type: "address" }],
+ stateMutability: "view",
},
{
type: "function",
- inputs: [
- { name: "_coreDisputeID", internalType: "uint256", type: "uint256" },
+ inputs: [],
+ name: "proxiableUUID",
+ outputs: [{ name: "", internalType: "bytes32", type: "bytes32" }],
+ stateMutability: "view",
+ },
+ {
+ type: "function",
+ inputs: [],
+ name: "singleDrawPerJuror",
+ outputs: [{ name: "", internalType: "bool", type: "bool" }],
+ stateMutability: "view",
+ },
+ {
+ type: "function",
+ inputs: [
+ { name: "newImplementation", internalType: "address", type: "address" },
+ { name: "data", internalType: "bytes", type: "bytes" },
+ ],
+ name: "upgradeToAndCall",
+ outputs: [],
+ stateMutability: "payable",
+ },
+ {
+ type: "function",
+ inputs: [],
+ name: "version",
+ outputs: [{ name: "", internalType: "string", type: "string" }],
+ stateMutability: "view",
+ },
+ {
+ type: "function",
+ inputs: [],
+ name: "wNative",
+ outputs: [{ name: "", internalType: "address", type: "address" }],
+ stateMutability: "view",
+ },
+ {
+ type: "function",
+ inputs: [
+ { name: "_coreDisputeID", internalType: "uint256", type: "uint256" },
{
name: "_beneficiary",
internalType: "address payable",
@@ -3704,14 +3976,14 @@ export const disputeKitClassicUniversityImplementationAbi = [
] as const;
/**
- * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0x87e863b94d2CB79A8aB53bD87Dc4A10E11C0918B)
+ * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0x602ADa1cE706404BFb5417e497cdDae934436081)
*/
export const disputeKitClassicUniversityImplementationAddress = {
- 421614: "0x87e863b94d2CB79A8aB53bD87Dc4A10E11C0918B",
+ 421614: "0x602ADa1cE706404BFb5417e497cdDae934436081",
} as const;
/**
- * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0x87e863b94d2CB79A8aB53bD87Dc4A10E11C0918B)
+ * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0x602ADa1cE706404BFb5417e497cdDae934436081)
*/
export const disputeKitClassicUniversityImplementationConfig = {
address: disputeKitClassicUniversityImplementationAddress,
@@ -3723,7 +3995,7 @@ export const disputeKitClassicUniversityImplementationConfig = {
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
- * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0xd6E96b7c993763B5CDDa1139C7387B82A7c8B8B5)
+ * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0x82F2089442979A6b56c80274D144575980092F91)
*/
export const disputeKitClassicUniversityProxyAbi = [
{
@@ -3739,14 +4011,14 @@ export const disputeKitClassicUniversityProxyAbi = [
] as const;
/**
- * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0xd6E96b7c993763B5CDDa1139C7387B82A7c8B8B5)
+ * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0x82F2089442979A6b56c80274D144575980092F91)
*/
export const disputeKitClassicUniversityProxyAddress = {
- 421614: "0xd6E96b7c993763B5CDDa1139C7387B82A7c8B8B5",
+ 421614: "0x82F2089442979A6b56c80274D144575980092F91",
} as const;
/**
- * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0xd6E96b7c993763B5CDDa1139C7387B82A7c8B8B5)
+ * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0x82F2089442979A6b56c80274D144575980092F91)
*/
export const disputeKitClassicUniversityProxyConfig = {
address: disputeKitClassicUniversityProxyAddress,
@@ -9062,7 +9334,7 @@ export const disputeResolverRulerConfig = {
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
- * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0x2Aa1a94307E772BeE42E9EfbD137b1053F1fCfd4)
+ * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0x8a7902Ef9a5308C7DF0A68A28EEDd6D83436993D)
*/
export const disputeResolverUniversityAbi = [
{
@@ -9081,6 +9353,11 @@ export const disputeResolverUniversityAbi = [
],
stateMutability: "nonpayable",
},
+ { type: "error", inputs: [], name: "ArbitratorOnly" },
+ { type: "error", inputs: [], name: "DisputeAlreadyRuled" },
+ { type: "error", inputs: [], name: "OwnerOnly" },
+ { type: "error", inputs: [], name: "RulingOutOfBounds" },
+ { type: "error", inputs: [], name: "ShouldBeAtLeastTwoRulingOptions" },
{
type: "event",
anonymous: false,
@@ -9109,12 +9386,6 @@ export const disputeResolverUniversityAbi = [
type: "uint256",
indexed: false,
},
- {
- name: "_templateUri",
- internalType: "string",
- type: "string",
- indexed: false,
- },
],
name: "DisputeRequest",
},
@@ -9172,8 +9443,8 @@ export const disputeResolverUniversityAbi = [
},
{
type: "function",
- inputs: [{ name: "_governor", internalType: "address", type: "address" }],
- name: "changeGovernor",
+ inputs: [{ name: "_owner", internalType: "address", type: "address" }],
+ name: "changeOwner",
outputs: [],
stateMutability: "nonpayable",
},
@@ -9210,21 +9481,6 @@ export const disputeResolverUniversityAbi = [
outputs: [{ name: "disputeID", internalType: "uint256", type: "uint256" }],
stateMutability: "payable",
},
- {
- type: "function",
- inputs: [
- { name: "_arbitratorExtraData", internalType: "bytes", type: "bytes" },
- { name: "_disputeTemplateUri", internalType: "string", type: "string" },
- {
- name: "_numberOfRulingOptions",
- internalType: "uint256",
- type: "uint256",
- },
- ],
- name: "createDisputeForTemplateUri",
- outputs: [{ name: "disputeID", internalType: "uint256", type: "uint256" }],
- stateMutability: "payable",
- },
{
type: "function",
inputs: [{ name: "", internalType: "uint256", type: "uint256" }],
@@ -9244,7 +9500,7 @@ export const disputeResolverUniversityAbi = [
{
type: "function",
inputs: [],
- name: "governor",
+ name: "owner",
outputs: [{ name: "", internalType: "address", type: "address" }],
stateMutability: "view",
},
@@ -9278,14 +9534,14 @@ export const disputeResolverUniversityAbi = [
] as const;
/**
- * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0x2Aa1a94307E772BeE42E9EfbD137b1053F1fCfd4)
+ * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0x8a7902Ef9a5308C7DF0A68A28EEDd6D83436993D)
*/
export const disputeResolverUniversityAddress = {
- 421614: "0x2Aa1a94307E772BeE42E9EfbD137b1053F1fCfd4",
+ 421614: "0x8a7902Ef9a5308C7DF0A68A28EEDd6D83436993D",
} as const;
/**
- * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0x2Aa1a94307E772BeE42E9EfbD137b1053F1fCfd4)
+ * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0x8a7902Ef9a5308C7DF0A68A28EEDd6D83436993D)
*/
export const disputeResolverUniversityConfig = {
address: disputeResolverUniversityAddress,
@@ -9473,14 +9729,15 @@ export const disputeTemplateRegistryConfig = {
} as const;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// DisputeTemplateRegistry_Implementation
+// DisputeTemplateRegistryUniversity
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
- * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0xBc9B5643C9B1C478DAe1b950e886CC50D8d868b1)
+ * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0x75A5D16e9A699162506E4d79D68CF646e6600ba1)
*/
-export const disputeTemplateRegistryImplementationAbi = [
- { type: "constructor", inputs: [], stateMutability: "nonpayable" },
+export const disputeTemplateRegistryUniversityAbi = [
+ { type: "fallback", stateMutability: "payable" },
+ { type: "receive", stateMutability: "payable" },
{ type: "error", inputs: [], name: "AlreadyInitialized" },
{ type: "error", inputs: [], name: "FailedDelegateCall" },
{
@@ -9489,6 +9746,7 @@ export const disputeTemplateRegistryImplementationAbi = [
name: "InvalidImplementation",
},
{ type: "error", inputs: [], name: "NotInitializing" },
+ { type: "error", inputs: [], name: "OwnerOnly" },
{ type: "error", inputs: [], name: "UUPSUnauthorizedCallContext" },
{
type: "error",
@@ -9554,21 +9812,14 @@ export const disputeTemplateRegistryImplementationAbi = [
},
{
type: "function",
- inputs: [{ name: "_governor", internalType: "address", type: "address" }],
- name: "changeGovernor",
+ inputs: [{ name: "_owner", internalType: "address", type: "address" }],
+ name: "changeOwner",
outputs: [],
stateMutability: "nonpayable",
},
{
type: "function",
- inputs: [],
- name: "governor",
- outputs: [{ name: "", internalType: "address", type: "address" }],
- stateMutability: "view",
- },
- {
- type: "function",
- inputs: [{ name: "_governor", internalType: "address", type: "address" }],
+ inputs: [{ name: "_owner", internalType: "address", type: "address" }],
name: "initialize",
outputs: [],
stateMutability: "nonpayable",
@@ -9576,9 +9827,9 @@ export const disputeTemplateRegistryImplementationAbi = [
{
type: "function",
inputs: [],
- name: "initialize2",
- outputs: [],
- stateMutability: "nonpayable",
+ name: "owner",
+ outputs: [{ name: "", internalType: "address", type: "address" }],
+ stateMutability: "view",
},
{
type: "function",
@@ -9622,31 +9873,6 @@ export const disputeTemplateRegistryImplementationAbi = [
outputs: [{ name: "", internalType: "string", type: "string" }],
stateMutability: "view",
},
-] as const;
-
-/**
- * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0xBc9B5643C9B1C478DAe1b950e886CC50D8d868b1)
- */
-export const disputeTemplateRegistryImplementationAddress = {
- 421614: "0xBc9B5643C9B1C478DAe1b950e886CC50D8d868b1",
-} as const;
-
-/**
- * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0xBc9B5643C9B1C478DAe1b950e886CC50D8d868b1)
- */
-export const disputeTemplateRegistryImplementationConfig = {
- address: disputeTemplateRegistryImplementationAddress,
- abi: disputeTemplateRegistryImplementationAbi,
-} as const;
-
-//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// DisputeTemplateRegistry_Proxy
-//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-/**
- * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0xc852F94f90E3B06Da6eCfB61d76561ECfb94613f)
- */
-export const disputeTemplateRegistryProxyAbi = [
{
type: "constructor",
inputs: [
@@ -9655,35 +9881,32 @@ export const disputeTemplateRegistryProxyAbi = [
],
stateMutability: "nonpayable",
},
- { type: "fallback", stateMutability: "payable" },
- { type: "receive", stateMutability: "payable" },
] as const;
/**
- * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0xc852F94f90E3B06Da6eCfB61d76561ECfb94613f)
+ * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0x75A5D16e9A699162506E4d79D68CF646e6600ba1)
*/
-export const disputeTemplateRegistryProxyAddress = {
- 421614: "0xc852F94f90E3B06Da6eCfB61d76561ECfb94613f",
+export const disputeTemplateRegistryUniversityAddress = {
+ 421614: "0x75A5D16e9A699162506E4d79D68CF646e6600ba1",
} as const;
/**
- * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0xc852F94f90E3B06Da6eCfB61d76561ECfb94613f)
+ * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0x75A5D16e9A699162506E4d79D68CF646e6600ba1)
*/
-export const disputeTemplateRegistryProxyConfig = {
- address: disputeTemplateRegistryProxyAddress,
- abi: disputeTemplateRegistryProxyAbi,
+export const disputeTemplateRegistryUniversityConfig = {
+ address: disputeTemplateRegistryUniversityAddress,
+ abi: disputeTemplateRegistryUniversityAbi,
} as const;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// EvidenceModule
+// DisputeTemplateRegistryUniversity_Implementation
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
- * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0xA1F72e0445fc395A393247F5B8c958Ec9b7C0B49)
+ * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0xC3f638389635bF33E019c845FdaF2ed9bca3DF67)
*/
-export const evidenceModuleAbi = [
- { type: "fallback", stateMutability: "payable" },
- { type: "receive", stateMutability: "payable" },
+export const disputeTemplateRegistryUniversityImplementationAbi = [
+ { type: "constructor", inputs: [], stateMutability: "nonpayable" },
{ type: "error", inputs: [], name: "AlreadyInitialized" },
{ type: "error", inputs: [], name: "FailedDelegateCall" },
{
@@ -9692,6 +9915,7 @@ export const evidenceModuleAbi = [
name: "InvalidImplementation",
},
{ type: "error", inputs: [], name: "NotInitializing" },
+ { type: "error", inputs: [], name: "OwnerOnly" },
{ type: "error", inputs: [], name: "UUPSUnauthorizedCallContext" },
{
type: "error",
@@ -9703,25 +9927,31 @@ export const evidenceModuleAbi = [
anonymous: false,
inputs: [
{
- name: "_externalDisputeID",
+ name: "_templateId",
internalType: "uint256",
type: "uint256",
indexed: true,
},
{
- name: "_party",
- internalType: "address",
- type: "address",
+ name: "_templateTag",
+ internalType: "string",
+ type: "string",
indexed: true,
},
{
- name: "_evidence",
+ name: "_templateData",
+ internalType: "string",
+ type: "string",
+ indexed: false,
+ },
+ {
+ name: "_templateDataMappings",
internalType: "string",
type: "string",
indexed: false,
},
],
- name: "Evidence",
+ name: "DisputeTemplate",
},
{
type: "event",
@@ -9751,14 +9981,14 @@ export const evidenceModuleAbi = [
},
{
type: "function",
- inputs: [],
- name: "governor",
- outputs: [{ name: "", internalType: "address", type: "address" }],
- stateMutability: "view",
+ inputs: [{ name: "_owner", internalType: "address", type: "address" }],
+ name: "changeOwner",
+ outputs: [],
+ stateMutability: "nonpayable",
},
{
type: "function",
- inputs: [{ name: "_governor", internalType: "address", type: "address" }],
+ inputs: [{ name: "_owner", internalType: "address", type: "address" }],
name: "initialize",
outputs: [],
stateMutability: "nonpayable",
@@ -9766,9 +9996,9 @@ export const evidenceModuleAbi = [
{
type: "function",
inputs: [],
- name: "initialize2",
- outputs: [],
- stateMutability: "nonpayable",
+ name: "owner",
+ outputs: [{ name: "", internalType: "address", type: "address" }],
+ stateMutability: "view",
},
{
type: "function",
@@ -9780,13 +10010,21 @@ export const evidenceModuleAbi = [
{
type: "function",
inputs: [
- { name: "_externalDisputeID", internalType: "uint256", type: "uint256" },
- { name: "_evidence", internalType: "string", type: "string" },
+ { name: "_templateTag", internalType: "string", type: "string" },
+ { name: "_templateData", internalType: "string", type: "string" },
+ { name: "_templateDataMappings", internalType: "string", type: "string" },
],
- name: "submitEvidence",
- outputs: [],
+ name: "setDisputeTemplate",
+ outputs: [{ name: "templateId", internalType: "uint256", type: "uint256" }],
stateMutability: "nonpayable",
},
+ {
+ type: "function",
+ inputs: [],
+ name: "templates",
+ outputs: [{ name: "", internalType: "uint256", type: "uint256" }],
+ stateMutability: "view",
+ },
{
type: "function",
inputs: [
@@ -9804,6 +10042,31 @@ export const evidenceModuleAbi = [
outputs: [{ name: "", internalType: "string", type: "string" }],
stateMutability: "view",
},
+] as const;
+
+/**
+ * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0xC3f638389635bF33E019c845FdaF2ed9bca3DF67)
+ */
+export const disputeTemplateRegistryUniversityImplementationAddress = {
+ 421614: "0xC3f638389635bF33E019c845FdaF2ed9bca3DF67",
+} as const;
+
+/**
+ * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0xC3f638389635bF33E019c845FdaF2ed9bca3DF67)
+ */
+export const disputeTemplateRegistryUniversityImplementationConfig = {
+ address: disputeTemplateRegistryUniversityImplementationAddress,
+ abi: disputeTemplateRegistryUniversityImplementationAbi,
+} as const;
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// DisputeTemplateRegistryUniversity_Proxy
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0x75A5D16e9A699162506E4d79D68CF646e6600ba1)
+ */
+export const disputeTemplateRegistryUniversityProxyAbi = [
{
type: "constructor",
inputs: [
@@ -9812,31 +10075,33 @@ export const evidenceModuleAbi = [
],
stateMutability: "nonpayable",
},
+ { type: "fallback", stateMutability: "payable" },
+ { type: "receive", stateMutability: "payable" },
] as const;
/**
- * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0xA1F72e0445fc395A393247F5B8c958Ec9b7C0B49)
+ * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0x75A5D16e9A699162506E4d79D68CF646e6600ba1)
*/
-export const evidenceModuleAddress = {
- 421614: "0xA1F72e0445fc395A393247F5B8c958Ec9b7C0B49",
+export const disputeTemplateRegistryUniversityProxyAddress = {
+ 421614: "0x75A5D16e9A699162506E4d79D68CF646e6600ba1",
} as const;
/**
- * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0xA1F72e0445fc395A393247F5B8c958Ec9b7C0B49)
+ * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0x75A5D16e9A699162506E4d79D68CF646e6600ba1)
*/
-export const evidenceModuleConfig = {
- address: evidenceModuleAddress,
- abi: evidenceModuleAbi,
+export const disputeTemplateRegistryUniversityProxyConfig = {
+ address: disputeTemplateRegistryUniversityProxyAddress,
+ abi: disputeTemplateRegistryUniversityProxyAbi,
} as const;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// EvidenceModule_Implementation
+// DisputeTemplateRegistry_Implementation
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
- * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0x450Aa35da0ad8B282C5d910254055651417C2200)
+ * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0xBc9B5643C9B1C478DAe1b950e886CC50D8d868b1)
*/
-export const evidenceModuleImplementationAbi = [
+export const disputeTemplateRegistryImplementationAbi = [
{ type: "constructor", inputs: [], stateMutability: "nonpayable" },
{ type: "error", inputs: [], name: "AlreadyInitialized" },
{ type: "error", inputs: [], name: "FailedDelegateCall" },
@@ -9857,25 +10122,31 @@ export const evidenceModuleImplementationAbi = [
anonymous: false,
inputs: [
{
- name: "_externalDisputeID",
+ name: "_templateId",
internalType: "uint256",
type: "uint256",
indexed: true,
},
{
- name: "_party",
- internalType: "address",
- type: "address",
+ name: "_templateTag",
+ internalType: "string",
+ type: "string",
indexed: true,
},
{
- name: "_evidence",
+ name: "_templateData",
+ internalType: "string",
+ type: "string",
+ indexed: false,
+ },
+ {
+ name: "_templateDataMappings",
internalType: "string",
type: "string",
indexed: false,
},
],
- name: "Evidence",
+ name: "DisputeTemplate",
},
{
type: "event",
@@ -9903,6 +10174,13 @@ export const evidenceModuleImplementationAbi = [
],
name: "Upgraded",
},
+ {
+ type: "function",
+ inputs: [{ name: "_governor", internalType: "address", type: "address" }],
+ name: "changeGovernor",
+ outputs: [],
+ stateMutability: "nonpayable",
+ },
{
type: "function",
inputs: [],
@@ -9934,13 +10212,21 @@ export const evidenceModuleImplementationAbi = [
{
type: "function",
inputs: [
- { name: "_externalDisputeID", internalType: "uint256", type: "uint256" },
- { name: "_evidence", internalType: "string", type: "string" },
+ { name: "_templateTag", internalType: "string", type: "string" },
+ { name: "_templateData", internalType: "string", type: "string" },
+ { name: "_templateDataMappings", internalType: "string", type: "string" },
],
- name: "submitEvidence",
- outputs: [],
+ name: "setDisputeTemplate",
+ outputs: [{ name: "templateId", internalType: "uint256", type: "uint256" }],
stateMutability: "nonpayable",
},
+ {
+ type: "function",
+ inputs: [],
+ name: "templates",
+ outputs: [{ name: "", internalType: "uint256", type: "uint256" }],
+ stateMutability: "view",
+ },
{
type: "function",
inputs: [
@@ -9961,14 +10247,350 @@ export const evidenceModuleImplementationAbi = [
] as const;
/**
- * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0x450Aa35da0ad8B282C5d910254055651417C2200)
+ * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0xBc9B5643C9B1C478DAe1b950e886CC50D8d868b1)
*/
-export const evidenceModuleImplementationAddress = {
- 421614: "0x450Aa35da0ad8B282C5d910254055651417C2200",
+export const disputeTemplateRegistryImplementationAddress = {
+ 421614: "0xBc9B5643C9B1C478DAe1b950e886CC50D8d868b1",
} as const;
/**
- * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0x450Aa35da0ad8B282C5d910254055651417C2200)
+ * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0xBc9B5643C9B1C478DAe1b950e886CC50D8d868b1)
+ */
+export const disputeTemplateRegistryImplementationConfig = {
+ address: disputeTemplateRegistryImplementationAddress,
+ abi: disputeTemplateRegistryImplementationAbi,
+} as const;
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// DisputeTemplateRegistry_Proxy
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0xc852F94f90E3B06Da6eCfB61d76561ECfb94613f)
+ */
+export const disputeTemplateRegistryProxyAbi = [
+ {
+ type: "constructor",
+ inputs: [
+ { name: "_implementation", internalType: "address", type: "address" },
+ { name: "_data", internalType: "bytes", type: "bytes" },
+ ],
+ stateMutability: "nonpayable",
+ },
+ { type: "fallback", stateMutability: "payable" },
+ { type: "receive", stateMutability: "payable" },
+] as const;
+
+/**
+ * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0xc852F94f90E3B06Da6eCfB61d76561ECfb94613f)
+ */
+export const disputeTemplateRegistryProxyAddress = {
+ 421614: "0xc852F94f90E3B06Da6eCfB61d76561ECfb94613f",
+} as const;
+
+/**
+ * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0xc852F94f90E3B06Da6eCfB61d76561ECfb94613f)
+ */
+export const disputeTemplateRegistryProxyConfig = {
+ address: disputeTemplateRegistryProxyAddress,
+ abi: disputeTemplateRegistryProxyAbi,
+} as const;
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// EvidenceModule
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0xA1F72e0445fc395A393247F5B8c958Ec9b7C0B49)
+ */
+export const evidenceModuleAbi = [
+ { type: "fallback", stateMutability: "payable" },
+ { type: "receive", stateMutability: "payable" },
+ { type: "error", inputs: [], name: "AlreadyInitialized" },
+ { type: "error", inputs: [], name: "FailedDelegateCall" },
+ {
+ type: "error",
+ inputs: [{ name: "implementation", internalType: "address", type: "address" }],
+ name: "InvalidImplementation",
+ },
+ { type: "error", inputs: [], name: "NotInitializing" },
+ { type: "error", inputs: [], name: "UUPSUnauthorizedCallContext" },
+ {
+ type: "error",
+ inputs: [{ name: "slot", internalType: "bytes32", type: "bytes32" }],
+ name: "UUPSUnsupportedProxiableUUID",
+ },
+ {
+ type: "event",
+ anonymous: false,
+ inputs: [
+ {
+ name: "_externalDisputeID",
+ internalType: "uint256",
+ type: "uint256",
+ indexed: true,
+ },
+ {
+ name: "_party",
+ internalType: "address",
+ type: "address",
+ indexed: true,
+ },
+ {
+ name: "_evidence",
+ internalType: "string",
+ type: "string",
+ indexed: false,
+ },
+ ],
+ name: "Evidence",
+ },
+ {
+ type: "event",
+ anonymous: false,
+ inputs: [
+ {
+ name: "version",
+ internalType: "uint64",
+ type: "uint64",
+ indexed: false,
+ },
+ ],
+ name: "Initialized",
+ },
+ {
+ type: "event",
+ anonymous: false,
+ inputs: [
+ {
+ name: "newImplementation",
+ internalType: "address",
+ type: "address",
+ indexed: true,
+ },
+ ],
+ name: "Upgraded",
+ },
+ {
+ type: "function",
+ inputs: [],
+ name: "governor",
+ outputs: [{ name: "", internalType: "address", type: "address" }],
+ stateMutability: "view",
+ },
+ {
+ type: "function",
+ inputs: [{ name: "_governor", internalType: "address", type: "address" }],
+ name: "initialize",
+ outputs: [],
+ stateMutability: "nonpayable",
+ },
+ {
+ type: "function",
+ inputs: [],
+ name: "initialize2",
+ outputs: [],
+ stateMutability: "nonpayable",
+ },
+ {
+ type: "function",
+ inputs: [],
+ name: "proxiableUUID",
+ outputs: [{ name: "", internalType: "bytes32", type: "bytes32" }],
+ stateMutability: "view",
+ },
+ {
+ type: "function",
+ inputs: [
+ { name: "_externalDisputeID", internalType: "uint256", type: "uint256" },
+ { name: "_evidence", internalType: "string", type: "string" },
+ ],
+ name: "submitEvidence",
+ outputs: [],
+ stateMutability: "nonpayable",
+ },
+ {
+ type: "function",
+ inputs: [
+ { name: "newImplementation", internalType: "address", type: "address" },
+ { name: "data", internalType: "bytes", type: "bytes" },
+ ],
+ name: "upgradeToAndCall",
+ outputs: [],
+ stateMutability: "payable",
+ },
+ {
+ type: "function",
+ inputs: [],
+ name: "version",
+ outputs: [{ name: "", internalType: "string", type: "string" }],
+ stateMutability: "view",
+ },
+ {
+ type: "constructor",
+ inputs: [
+ { name: "_implementation", internalType: "address", type: "address" },
+ { name: "_data", internalType: "bytes", type: "bytes" },
+ ],
+ stateMutability: "nonpayable",
+ },
+] as const;
+
+/**
+ * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0xA1F72e0445fc395A393247F5B8c958Ec9b7C0B49)
+ */
+export const evidenceModuleAddress = {
+ 421614: "0xA1F72e0445fc395A393247F5B8c958Ec9b7C0B49",
+} as const;
+
+/**
+ * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0xA1F72e0445fc395A393247F5B8c958Ec9b7C0B49)
+ */
+export const evidenceModuleConfig = {
+ address: evidenceModuleAddress,
+ abi: evidenceModuleAbi,
+} as const;
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// EvidenceModule_Implementation
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0x450Aa35da0ad8B282C5d910254055651417C2200)
+ */
+export const evidenceModuleImplementationAbi = [
+ { type: "constructor", inputs: [], stateMutability: "nonpayable" },
+ { type: "error", inputs: [], name: "AlreadyInitialized" },
+ { type: "error", inputs: [], name: "FailedDelegateCall" },
+ {
+ type: "error",
+ inputs: [{ name: "implementation", internalType: "address", type: "address" }],
+ name: "InvalidImplementation",
+ },
+ { type: "error", inputs: [], name: "NotInitializing" },
+ { type: "error", inputs: [], name: "UUPSUnauthorizedCallContext" },
+ {
+ type: "error",
+ inputs: [{ name: "slot", internalType: "bytes32", type: "bytes32" }],
+ name: "UUPSUnsupportedProxiableUUID",
+ },
+ {
+ type: "event",
+ anonymous: false,
+ inputs: [
+ {
+ name: "_externalDisputeID",
+ internalType: "uint256",
+ type: "uint256",
+ indexed: true,
+ },
+ {
+ name: "_party",
+ internalType: "address",
+ type: "address",
+ indexed: true,
+ },
+ {
+ name: "_evidence",
+ internalType: "string",
+ type: "string",
+ indexed: false,
+ },
+ ],
+ name: "Evidence",
+ },
+ {
+ type: "event",
+ anonymous: false,
+ inputs: [
+ {
+ name: "version",
+ internalType: "uint64",
+ type: "uint64",
+ indexed: false,
+ },
+ ],
+ name: "Initialized",
+ },
+ {
+ type: "event",
+ anonymous: false,
+ inputs: [
+ {
+ name: "newImplementation",
+ internalType: "address",
+ type: "address",
+ indexed: true,
+ },
+ ],
+ name: "Upgraded",
+ },
+ {
+ type: "function",
+ inputs: [],
+ name: "governor",
+ outputs: [{ name: "", internalType: "address", type: "address" }],
+ stateMutability: "view",
+ },
+ {
+ type: "function",
+ inputs: [{ name: "_governor", internalType: "address", type: "address" }],
+ name: "initialize",
+ outputs: [],
+ stateMutability: "nonpayable",
+ },
+ {
+ type: "function",
+ inputs: [],
+ name: "initialize2",
+ outputs: [],
+ stateMutability: "nonpayable",
+ },
+ {
+ type: "function",
+ inputs: [],
+ name: "proxiableUUID",
+ outputs: [{ name: "", internalType: "bytes32", type: "bytes32" }],
+ stateMutability: "view",
+ },
+ {
+ type: "function",
+ inputs: [
+ { name: "_externalDisputeID", internalType: "uint256", type: "uint256" },
+ { name: "_evidence", internalType: "string", type: "string" },
+ ],
+ name: "submitEvidence",
+ outputs: [],
+ stateMutability: "nonpayable",
+ },
+ {
+ type: "function",
+ inputs: [
+ { name: "newImplementation", internalType: "address", type: "address" },
+ { name: "data", internalType: "bytes", type: "bytes" },
+ ],
+ name: "upgradeToAndCall",
+ outputs: [],
+ stateMutability: "payable",
+ },
+ {
+ type: "function",
+ inputs: [],
+ name: "version",
+ outputs: [{ name: "", internalType: "string", type: "string" }],
+ stateMutability: "view",
+ },
+] as const;
+
+/**
+ * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0x450Aa35da0ad8B282C5d910254055651417C2200)
+ */
+export const evidenceModuleImplementationAddress = {
+ 421614: "0x450Aa35da0ad8B282C5d910254055651417C2200",
+} as const;
+
+/**
+ * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0x450Aa35da0ad8B282C5d910254055651417C2200)
*/
export const evidenceModuleImplementationConfig = {
address: evidenceModuleImplementationAddress,
@@ -10945,12 +11567,6 @@ export const iHomeGatewayAbi = [
type: "uint256",
indexed: false,
},
- {
- name: "_templateUri",
- internalType: "string",
- type: "string",
- indexed: false,
- },
],
name: "CrossChainDisputeIncoming",
},
@@ -10982,12 +11598,6 @@ export const iHomeGatewayAbi = [
type: "uint256",
indexed: false,
},
- {
- name: "_templateUri",
- internalType: "string",
- type: "string",
- indexed: false,
- },
],
name: "DisputeRequest",
},
@@ -11081,16 +11691,14 @@ export const iHomeGatewayAbi = [
type: "uint256",
},
{ name: "templateId", internalType: "uint256", type: "uint256" },
- { name: "templateUri", internalType: "string", type: "string" },
{ name: "choices", internalType: "uint256", type: "uint256" },
{ name: "extraData", internalType: "bytes", type: "bytes" },
],
},
- { name: "_feeAmount", internalType: "uint256", type: "uint256" },
],
name: "relayCreateDispute",
outputs: [],
- stateMutability: "nonpayable",
+ stateMutability: "payable",
},
{
type: "function",
@@ -11122,15 +11730,15 @@ export const iHomeGatewayAbi = [
type: "uint256",
},
{ name: "templateId", internalType: "uint256", type: "uint256" },
- { name: "templateUri", internalType: "string", type: "string" },
{ name: "choices", internalType: "uint256", type: "uint256" },
{ name: "extraData", internalType: "bytes", type: "bytes" },
],
},
+ { name: "_feeAmount", internalType: "uint256", type: "uint256" },
],
name: "relayCreateDispute",
outputs: [],
- stateMutability: "payable",
+ stateMutability: "nonpayable",
},
{
type: "function",
@@ -14457,7 +15065,7 @@ export const klerosCoreSnapshotProxyConfig = {
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
- * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0x5AB37F38778Bc175852fA353056591D91c744ce6)
+ * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0xA34dBBD0E5e1d09bd683455f9dbC393797BC558f)
*/
export const klerosCoreUniversityAbi = [
{ type: "fallback", stateMutability: "payable" },
@@ -14467,10 +15075,8 @@ export const klerosCoreUniversityAbi = [
{ type: "error", inputs: [], name: "AppealFeesNotEnough" },
{ type: "error", inputs: [], name: "AppealPeriodNotPassed" },
{ type: "error", inputs: [], name: "ArbitrationFeesNotEnough" },
- { type: "error", inputs: [], name: "ArraysLengthMismatch" },
{ type: "error", inputs: [], name: "CannotDisableClassicDK" },
{ type: "error", inputs: [], name: "CommitPeriodNotPassed" },
- { type: "error", inputs: [], name: "DepthLevelMax" },
{ type: "error", inputs: [], name: "DisputeKitNotSupportedByCourt" },
{ type: "error", inputs: [], name: "DisputeKitOnly" },
{ type: "error", inputs: [], name: "DisputeNotAppealable" },
@@ -14478,8 +15084,6 @@ export const klerosCoreUniversityAbi = [
{ type: "error", inputs: [], name: "DisputeStillDrawing" },
{ type: "error", inputs: [], name: "EvidenceNotPassedAndNotAppeal" },
{ type: "error", inputs: [], name: "FailedDelegateCall" },
- { type: "error", inputs: [], name: "GovernorOnly" },
- { type: "error", inputs: [], name: "GovernorOrInstructorOnly" },
{ type: "error", inputs: [], name: "InstructorOnly" },
{ type: "error", inputs: [], name: "InvalidDisputKitParent" },
{ type: "error", inputs: [], name: "InvalidForkingCourtAsParent" },
@@ -14494,12 +15098,15 @@ export const klerosCoreUniversityAbi = [
{ type: "error", inputs: [], name: "NotEvidencePeriod" },
{ type: "error", inputs: [], name: "NotExecutionPeriod" },
{ type: "error", inputs: [], name: "NotInitializing" },
+ { type: "error", inputs: [], name: "OwnerOnly" },
+ { type: "error", inputs: [], name: "OwnerOrInstructorOnly" },
{ type: "error", inputs: [], name: "RulingAlreadyExecuted" },
{ type: "error", inputs: [], name: "SortitionModuleOnly" },
{ type: "error", inputs: [], name: "StakingInTooManyCourts" },
{ type: "error", inputs: [], name: "StakingLessThanCourtMinStake" },
- { type: "error", inputs: [], name: "StakingNotPossibeInThisCourt" },
+ { type: "error", inputs: [], name: "StakingNotPossibleInThisCourt" },
{ type: "error", inputs: [], name: "StakingTransferFailed" },
+ { type: "error", inputs: [], name: "StakingZeroWhenNoStake" },
{ type: "error", inputs: [], name: "TokenNotAccepted" },
{ type: "error", inputs: [], name: "TransferFailed" },
{ type: "error", inputs: [], name: "UUPSUnauthorizedCallContext" },
@@ -14571,8 +15178,8 @@ export const klerosCoreUniversityAbi = [
inputs: [
{
name: "_courtID",
- internalType: "uint256",
- type: "uint256",
+ internalType: "uint96",
+ type: "uint96",
indexed: true,
},
{
@@ -14843,6 +15450,12 @@ export const klerosCoreUniversityAbi = [
type: "event",
anonymous: false,
inputs: [
+ {
+ name: "_account",
+ internalType: "address",
+ type: "address",
+ indexed: true,
+ },
{
name: "_disputeID",
internalType: "uint256",
@@ -14856,13 +15469,62 @@ export const klerosCoreUniversityAbi = [
indexed: true,
},
{
- name: "_pnkAmount",
+ name: "_degreeOfCoherencyPnk",
internalType: "uint256",
type: "uint256",
indexed: false,
},
{
- name: "_feeAmount",
+ name: "_degreeOfCoherencyFee",
+ internalType: "uint256",
+ type: "uint256",
+ indexed: false,
+ },
+ {
+ name: "_amountPnk",
+ internalType: "int256",
+ type: "int256",
+ indexed: false,
+ },
+ {
+ name: "_amountFee",
+ internalType: "int256",
+ type: "int256",
+ indexed: false,
+ },
+ {
+ name: "_feeToken",
+ internalType: "contract IERC20",
+ type: "address",
+ indexed: false,
+ },
+ ],
+ name: "JurorRewardPenalty",
+ },
+ {
+ type: "event",
+ anonymous: false,
+ inputs: [
+ {
+ name: "_disputeID",
+ internalType: "uint256",
+ type: "uint256",
+ indexed: true,
+ },
+ {
+ name: "_roundID",
+ internalType: "uint256",
+ type: "uint256",
+ indexed: true,
+ },
+ {
+ name: "_amountPnk",
+ internalType: "uint256",
+ type: "uint256",
+ indexed: false,
+ },
+ {
+ name: "_amountFee",
internalType: "uint256",
type: "uint256",
indexed: false,
@@ -14945,55 +15607,6 @@ export const klerosCoreUniversityAbi = [
],
name: "Ruling",
},
- {
- type: "event",
- anonymous: false,
- inputs: [
- {
- name: "_account",
- internalType: "address",
- type: "address",
- indexed: true,
- },
- {
- name: "_disputeID",
- internalType: "uint256",
- type: "uint256",
- indexed: true,
- },
- {
- name: "_roundID",
- internalType: "uint256",
- type: "uint256",
- indexed: true,
- },
- {
- name: "_degreeOfCoherency",
- internalType: "uint256",
- type: "uint256",
- indexed: false,
- },
- {
- name: "_pnkAmount",
- internalType: "int256",
- type: "int256",
- indexed: false,
- },
- {
- name: "_feeAmount",
- internalType: "int256",
- type: "int256",
- indexed: false,
- },
- {
- name: "_feeToken",
- internalType: "contract IERC20",
- type: "address",
- indexed: false,
- },
- ],
- name: "TokenAndETHShift",
- },
{
type: "event",
anonymous: false,
@@ -15105,13 +15718,6 @@ export const klerosCoreUniversityAbi = [
outputs: [],
stateMutability: "nonpayable",
},
- {
- type: "function",
- inputs: [{ name: "_governor", internalType: "address payable", type: "address" }],
- name: "changeGovernor",
- outputs: [],
- stateMutability: "nonpayable",
- },
{
type: "function",
inputs: [{ name: "_instructor", internalType: "address", type: "address" }],
@@ -15132,6 +15738,13 @@ export const klerosCoreUniversityAbi = [
outputs: [],
stateMutability: "nonpayable",
},
+ {
+ type: "function",
+ inputs: [{ name: "_owner", internalType: "address payable", type: "address" }],
+ name: "changeOwner",
+ outputs: [],
+ stateMutability: "nonpayable",
+ },
{
type: "function",
inputs: [{ name: "_pinakion", internalType: "contract IERC20", type: "address" }],
@@ -15173,7 +15786,6 @@ export const klerosCoreUniversityAbi = [
{ name: "alpha", internalType: "uint256", type: "uint256" },
{ name: "feeForJuror", internalType: "uint256", type: "uint256" },
{ name: "jurorsForCourtJump", internalType: "uint256", type: "uint256" },
- { name: "disabled", internalType: "bool", type: "bool" },
],
stateMutability: "view",
},
@@ -15312,7 +15924,7 @@ export const klerosCoreUniversityAbi = [
{ name: "_amount", internalType: "uint256", type: "uint256" },
{ name: "_data", internalType: "bytes", type: "bytes" },
],
- name: "executeGovernorProposal",
+ name: "executeOwnerProposal",
outputs: [],
stateMutability: "nonpayable",
},
@@ -15344,6 +15956,16 @@ export const klerosCoreUniversityAbi = [
outputs: [{ name: "", internalType: "uint256", type: "uint256" }],
stateMutability: "view",
},
+ {
+ type: "function",
+ inputs: [
+ { name: "_disputeID", internalType: "uint256", type: "uint256" },
+ { name: "_round", internalType: "uint256", type: "uint256" },
+ ],
+ name: "getPnkAtStakePerJuror",
+ outputs: [{ name: "", internalType: "uint256", type: "uint256" }],
+ stateMutability: "view",
+ },
{
type: "function",
inputs: [
@@ -15372,6 +15994,11 @@ export const klerosCoreUniversityAbi = [
{ name: "repartitions", internalType: "uint256", type: "uint256" },
{ name: "pnkPenalties", internalType: "uint256", type: "uint256" },
{ name: "drawnJurors", internalType: "address[]", type: "address[]" },
+ {
+ name: "drawnJurorFromCourtIDs",
+ internalType: "uint96[]",
+ type: "uint96[]",
+ },
{
name: "sumFeeRewardPaid",
internalType: "uint256",
@@ -15388,6 +16015,7 @@ export const klerosCoreUniversityAbi = [
type: "address",
},
{ name: "drawIterations", internalType: "uint256", type: "uint256" },
+ { name: "__gap", internalType: "uint256[10]", type: "uint256[10]" },
],
},
],
@@ -15406,17 +16034,10 @@ export const klerosCoreUniversityAbi = [
],
stateMutability: "view",
},
- {
- type: "function",
- inputs: [],
- name: "governor",
- outputs: [{ name: "", internalType: "address", type: "address" }],
- stateMutability: "view",
- },
{
type: "function",
inputs: [
- { name: "_governor", internalType: "address", type: "address" },
+ { name: "_owner", internalType: "address", type: "address" },
{ name: "_instructor", internalType: "address", type: "address" },
{ name: "_pinakion", internalType: "contract IERC20", type: "address" },
{
@@ -15481,6 +16102,13 @@ export const klerosCoreUniversityAbi = [
outputs: [{ name: "", internalType: "address", type: "address" }],
stateMutability: "view",
},
+ {
+ type: "function",
+ inputs: [],
+ name: "owner",
+ outputs: [{ name: "", internalType: "address", type: "address" }],
+ stateMutability: "view",
+ },
{
type: "function",
inputs: [{ name: "_disputeID", internalType: "uint256", type: "uint256" }],
@@ -15518,7 +16146,6 @@ export const klerosCoreUniversityAbi = [
{ name: "_account", internalType: "address", type: "address" },
{ name: "_courtID", internalType: "uint96", type: "uint96" },
{ name: "_newStake", internalType: "uint256", type: "uint256" },
- { name: "_alreadyTransferred", internalType: "bool", type: "bool" },
],
name: "setStakeBySortitionModule",
outputs: [],
@@ -15537,6 +16164,16 @@ export const klerosCoreUniversityAbi = [
],
stateMutability: "view",
},
+ {
+ type: "function",
+ inputs: [
+ { name: "_account", internalType: "address", type: "address" },
+ { name: "_amount", internalType: "uint256", type: "uint256" },
+ ],
+ name: "transferBySortitionModule",
+ outputs: [],
+ stateMutability: "nonpayable",
+ },
{
type: "function",
inputs: [
@@ -15547,6 +16184,13 @@ export const klerosCoreUniversityAbi = [
outputs: [],
stateMutability: "payable",
},
+ {
+ type: "function",
+ inputs: [],
+ name: "version",
+ outputs: [{ name: "", internalType: "string", type: "string" }],
+ stateMutability: "view",
+ },
{
type: "constructor",
inputs: [
@@ -15558,14 +16202,14 @@ export const klerosCoreUniversityAbi = [
] as const;
/**
- * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0x5AB37F38778Bc175852fA353056591D91c744ce6)
+ * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0xA34dBBD0E5e1d09bd683455f9dbC393797BC558f)
*/
export const klerosCoreUniversityAddress = {
- 421614: "0x5AB37F38778Bc175852fA353056591D91c744ce6",
+ 421614: "0xA34dBBD0E5e1d09bd683455f9dbC393797BC558f",
} as const;
/**
- * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0x5AB37F38778Bc175852fA353056591D91c744ce6)
+ * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0xA34dBBD0E5e1d09bd683455f9dbC393797BC558f)
*/
export const klerosCoreUniversityConfig = {
address: klerosCoreUniversityAddress,
@@ -15577,7 +16221,7 @@ export const klerosCoreUniversityConfig = {
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
- * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0xF74DaBfC5F5dbdBD07636637204d9C35326D2906)
+ * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0xb75b0cc01af4aD0D65D50082ae0717004D479Aa0)
*/
export const klerosCoreUniversityImplementationAbi = [
{ type: "constructor", inputs: [], stateMutability: "nonpayable" },
@@ -15586,10 +16230,8 @@ export const klerosCoreUniversityImplementationAbi = [
{ type: "error", inputs: [], name: "AppealFeesNotEnough" },
{ type: "error", inputs: [], name: "AppealPeriodNotPassed" },
{ type: "error", inputs: [], name: "ArbitrationFeesNotEnough" },
- { type: "error", inputs: [], name: "ArraysLengthMismatch" },
{ type: "error", inputs: [], name: "CannotDisableClassicDK" },
{ type: "error", inputs: [], name: "CommitPeriodNotPassed" },
- { type: "error", inputs: [], name: "DepthLevelMax" },
{ type: "error", inputs: [], name: "DisputeKitNotSupportedByCourt" },
{ type: "error", inputs: [], name: "DisputeKitOnly" },
{ type: "error", inputs: [], name: "DisputeNotAppealable" },
@@ -15597,8 +16239,6 @@ export const klerosCoreUniversityImplementationAbi = [
{ type: "error", inputs: [], name: "DisputeStillDrawing" },
{ type: "error", inputs: [], name: "EvidenceNotPassedAndNotAppeal" },
{ type: "error", inputs: [], name: "FailedDelegateCall" },
- { type: "error", inputs: [], name: "GovernorOnly" },
- { type: "error", inputs: [], name: "GovernorOrInstructorOnly" },
{ type: "error", inputs: [], name: "InstructorOnly" },
{ type: "error", inputs: [], name: "InvalidDisputKitParent" },
{ type: "error", inputs: [], name: "InvalidForkingCourtAsParent" },
@@ -15613,12 +16253,15 @@ export const klerosCoreUniversityImplementationAbi = [
{ type: "error", inputs: [], name: "NotEvidencePeriod" },
{ type: "error", inputs: [], name: "NotExecutionPeriod" },
{ type: "error", inputs: [], name: "NotInitializing" },
+ { type: "error", inputs: [], name: "OwnerOnly" },
+ { type: "error", inputs: [], name: "OwnerOrInstructorOnly" },
{ type: "error", inputs: [], name: "RulingAlreadyExecuted" },
{ type: "error", inputs: [], name: "SortitionModuleOnly" },
{ type: "error", inputs: [], name: "StakingInTooManyCourts" },
{ type: "error", inputs: [], name: "StakingLessThanCourtMinStake" },
- { type: "error", inputs: [], name: "StakingNotPossibeInThisCourt" },
+ { type: "error", inputs: [], name: "StakingNotPossibleInThisCourt" },
{ type: "error", inputs: [], name: "StakingTransferFailed" },
+ { type: "error", inputs: [], name: "StakingZeroWhenNoStake" },
{ type: "error", inputs: [], name: "TokenNotAccepted" },
{ type: "error", inputs: [], name: "TransferFailed" },
{ type: "error", inputs: [], name: "UUPSUnauthorizedCallContext" },
@@ -15690,8 +16333,8 @@ export const klerosCoreUniversityImplementationAbi = [
inputs: [
{
name: "_courtID",
- internalType: "uint256",
- type: "uint256",
+ internalType: "uint96",
+ type: "uint96",
indexed: true,
},
{
@@ -15962,6 +16605,12 @@ export const klerosCoreUniversityImplementationAbi = [
type: "event",
anonymous: false,
inputs: [
+ {
+ name: "_account",
+ internalType: "address",
+ type: "address",
+ indexed: true,
+ },
{
name: "_disputeID",
internalType: "uint256",
@@ -15975,13 +16624,62 @@ export const klerosCoreUniversityImplementationAbi = [
indexed: true,
},
{
- name: "_pnkAmount",
+ name: "_degreeOfCoherencyPnk",
internalType: "uint256",
type: "uint256",
indexed: false,
},
{
- name: "_feeAmount",
+ name: "_degreeOfCoherencyFee",
+ internalType: "uint256",
+ type: "uint256",
+ indexed: false,
+ },
+ {
+ name: "_amountPnk",
+ internalType: "int256",
+ type: "int256",
+ indexed: false,
+ },
+ {
+ name: "_amountFee",
+ internalType: "int256",
+ type: "int256",
+ indexed: false,
+ },
+ {
+ name: "_feeToken",
+ internalType: "contract IERC20",
+ type: "address",
+ indexed: false,
+ },
+ ],
+ name: "JurorRewardPenalty",
+ },
+ {
+ type: "event",
+ anonymous: false,
+ inputs: [
+ {
+ name: "_disputeID",
+ internalType: "uint256",
+ type: "uint256",
+ indexed: true,
+ },
+ {
+ name: "_roundID",
+ internalType: "uint256",
+ type: "uint256",
+ indexed: true,
+ },
+ {
+ name: "_amountPnk",
+ internalType: "uint256",
+ type: "uint256",
+ indexed: false,
+ },
+ {
+ name: "_amountFee",
internalType: "uint256",
type: "uint256",
indexed: false,
@@ -16064,55 +16762,6 @@ export const klerosCoreUniversityImplementationAbi = [
],
name: "Ruling",
},
- {
- type: "event",
- anonymous: false,
- inputs: [
- {
- name: "_account",
- internalType: "address",
- type: "address",
- indexed: true,
- },
- {
- name: "_disputeID",
- internalType: "uint256",
- type: "uint256",
- indexed: true,
- },
- {
- name: "_roundID",
- internalType: "uint256",
- type: "uint256",
- indexed: true,
- },
- {
- name: "_degreeOfCoherency",
- internalType: "uint256",
- type: "uint256",
- indexed: false,
- },
- {
- name: "_pnkAmount",
- internalType: "int256",
- type: "int256",
- indexed: false,
- },
- {
- name: "_feeAmount",
- internalType: "int256",
- type: "int256",
- indexed: false,
- },
- {
- name: "_feeToken",
- internalType: "contract IERC20",
- type: "address",
- indexed: false,
- },
- ],
- name: "TokenAndETHShift",
- },
{
type: "event",
anonymous: false,
@@ -16224,13 +16873,6 @@ export const klerosCoreUniversityImplementationAbi = [
outputs: [],
stateMutability: "nonpayable",
},
- {
- type: "function",
- inputs: [{ name: "_governor", internalType: "address payable", type: "address" }],
- name: "changeGovernor",
- outputs: [],
- stateMutability: "nonpayable",
- },
{
type: "function",
inputs: [{ name: "_instructor", internalType: "address", type: "address" }],
@@ -16251,6 +16893,13 @@ export const klerosCoreUniversityImplementationAbi = [
outputs: [],
stateMutability: "nonpayable",
},
+ {
+ type: "function",
+ inputs: [{ name: "_owner", internalType: "address payable", type: "address" }],
+ name: "changeOwner",
+ outputs: [],
+ stateMutability: "nonpayable",
+ },
{
type: "function",
inputs: [{ name: "_pinakion", internalType: "contract IERC20", type: "address" }],
@@ -16292,7 +16941,6 @@ export const klerosCoreUniversityImplementationAbi = [
{ name: "alpha", internalType: "uint256", type: "uint256" },
{ name: "feeForJuror", internalType: "uint256", type: "uint256" },
{ name: "jurorsForCourtJump", internalType: "uint256", type: "uint256" },
- { name: "disabled", internalType: "bool", type: "bool" },
],
stateMutability: "view",
},
@@ -16431,7 +17079,7 @@ export const klerosCoreUniversityImplementationAbi = [
{ name: "_amount", internalType: "uint256", type: "uint256" },
{ name: "_data", internalType: "bytes", type: "bytes" },
],
- name: "executeGovernorProposal",
+ name: "executeOwnerProposal",
outputs: [],
stateMutability: "nonpayable",
},
@@ -16463,6 +17111,16 @@ export const klerosCoreUniversityImplementationAbi = [
outputs: [{ name: "", internalType: "uint256", type: "uint256" }],
stateMutability: "view",
},
+ {
+ type: "function",
+ inputs: [
+ { name: "_disputeID", internalType: "uint256", type: "uint256" },
+ { name: "_round", internalType: "uint256", type: "uint256" },
+ ],
+ name: "getPnkAtStakePerJuror",
+ outputs: [{ name: "", internalType: "uint256", type: "uint256" }],
+ stateMutability: "view",
+ },
{
type: "function",
inputs: [
@@ -16491,6 +17149,11 @@ export const klerosCoreUniversityImplementationAbi = [
{ name: "repartitions", internalType: "uint256", type: "uint256" },
{ name: "pnkPenalties", internalType: "uint256", type: "uint256" },
{ name: "drawnJurors", internalType: "address[]", type: "address[]" },
+ {
+ name: "drawnJurorFromCourtIDs",
+ internalType: "uint96[]",
+ type: "uint96[]",
+ },
{
name: "sumFeeRewardPaid",
internalType: "uint256",
@@ -16507,6 +17170,7 @@ export const klerosCoreUniversityImplementationAbi = [
type: "address",
},
{ name: "drawIterations", internalType: "uint256", type: "uint256" },
+ { name: "__gap", internalType: "uint256[10]", type: "uint256[10]" },
],
},
],
@@ -16525,17 +17189,10 @@ export const klerosCoreUniversityImplementationAbi = [
],
stateMutability: "view",
},
- {
- type: "function",
- inputs: [],
- name: "governor",
- outputs: [{ name: "", internalType: "address", type: "address" }],
- stateMutability: "view",
- },
{
type: "function",
inputs: [
- { name: "_governor", internalType: "address", type: "address" },
+ { name: "_owner", internalType: "address", type: "address" },
{ name: "_instructor", internalType: "address", type: "address" },
{ name: "_pinakion", internalType: "contract IERC20", type: "address" },
{
@@ -16600,6 +17257,13 @@ export const klerosCoreUniversityImplementationAbi = [
outputs: [{ name: "", internalType: "address", type: "address" }],
stateMutability: "view",
},
+ {
+ type: "function",
+ inputs: [],
+ name: "owner",
+ outputs: [{ name: "", internalType: "address", type: "address" }],
+ stateMutability: "view",
+ },
{
type: "function",
inputs: [{ name: "_disputeID", internalType: "uint256", type: "uint256" }],
@@ -16637,7 +17301,6 @@ export const klerosCoreUniversityImplementationAbi = [
{ name: "_account", internalType: "address", type: "address" },
{ name: "_courtID", internalType: "uint96", type: "uint96" },
{ name: "_newStake", internalType: "uint256", type: "uint256" },
- { name: "_alreadyTransferred", internalType: "bool", type: "bool" },
],
name: "setStakeBySortitionModule",
outputs: [],
@@ -16656,6 +17319,16 @@ export const klerosCoreUniversityImplementationAbi = [
],
stateMutability: "view",
},
+ {
+ type: "function",
+ inputs: [
+ { name: "_account", internalType: "address", type: "address" },
+ { name: "_amount", internalType: "uint256", type: "uint256" },
+ ],
+ name: "transferBySortitionModule",
+ outputs: [],
+ stateMutability: "nonpayable",
+ },
{
type: "function",
inputs: [
@@ -16666,17 +17339,24 @@ export const klerosCoreUniversityImplementationAbi = [
outputs: [],
stateMutability: "payable",
},
+ {
+ type: "function",
+ inputs: [],
+ name: "version",
+ outputs: [{ name: "", internalType: "string", type: "string" }],
+ stateMutability: "view",
+ },
] as const;
/**
- * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0xF74DaBfC5F5dbdBD07636637204d9C35326D2906)
+ * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0xb75b0cc01af4aD0D65D50082ae0717004D479Aa0)
*/
export const klerosCoreUniversityImplementationAddress = {
- 421614: "0xF74DaBfC5F5dbdBD07636637204d9C35326D2906",
+ 421614: "0xb75b0cc01af4aD0D65D50082ae0717004D479Aa0",
} as const;
/**
- * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0xF74DaBfC5F5dbdBD07636637204d9C35326D2906)
+ * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0xb75b0cc01af4aD0D65D50082ae0717004D479Aa0)
*/
export const klerosCoreUniversityImplementationConfig = {
address: klerosCoreUniversityImplementationAddress,
@@ -16688,7 +17368,7 @@ export const klerosCoreUniversityImplementationConfig = {
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
- * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0x5AB37F38778Bc175852fA353056591D91c744ce6)
+ * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0xA34dBBD0E5e1d09bd683455f9dbC393797BC558f)
*/
export const klerosCoreUniversityProxyAbi = [
{
@@ -16704,14 +17384,14 @@ export const klerosCoreUniversityProxyAbi = [
] as const;
/**
- * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0x5AB37F38778Bc175852fA353056591D91c744ce6)
+ * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0xA34dBBD0E5e1d09bd683455f9dbC393797BC558f)
*/
export const klerosCoreUniversityProxyAddress = {
- 421614: "0x5AB37F38778Bc175852fA353056591D91c744ce6",
+ 421614: "0xA34dBBD0E5e1d09bd683455f9dbC393797BC558f",
} as const;
/**
- * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0x5AB37F38778Bc175852fA353056591D91c744ce6)
+ * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0xA34dBBD0E5e1d09bd683455f9dbC393797BC558f)
*/
export const klerosCoreUniversityProxyConfig = {
address: klerosCoreUniversityProxyAddress,
@@ -19560,7 +20240,7 @@ export const sortitionModuleConfig = {
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
- * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0x4B2c2d048921f694cCE3AEa35698c6B1f5fcbb79)
+ * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0x9f55804177e7E44E558616cD7d06B865788214cA)
*/
export const sortitionModuleUniversityAbi = [
{ type: "fallback", stateMutability: "payable" },
@@ -19572,7 +20252,10 @@ export const sortitionModuleUniversityAbi = [
inputs: [{ name: "implementation", internalType: "address", type: "address" }],
name: "InvalidImplementation",
},
+ { type: "error", inputs: [], name: "KlerosCoreOnly" },
+ { type: "error", inputs: [], name: "NotEligibleForWithdrawal" },
{ type: "error", inputs: [], name: "NotInitializing" },
+ { type: "error", inputs: [], name: "OwnerOnly" },
{ type: "error", inputs: [], name: "UUPSUnauthorizedCallContext" },
{
type: "error",
@@ -19592,6 +20275,44 @@ export const sortitionModuleUniversityAbi = [
],
name: "Initialized",
},
+ {
+ type: "event",
+ anonymous: false,
+ inputs: [
+ {
+ name: "_account",
+ internalType: "address",
+ type: "address",
+ indexed: true,
+ },
+ {
+ name: "_amount",
+ internalType: "uint256",
+ type: "uint256",
+ indexed: false,
+ },
+ ],
+ name: "LeftoverPNK",
+ },
+ {
+ type: "event",
+ anonymous: false,
+ inputs: [
+ {
+ name: "_account",
+ internalType: "address",
+ type: "address",
+ indexed: true,
+ },
+ {
+ name: "_amount",
+ internalType: "uint256",
+ type: "uint256",
+ indexed: false,
+ },
+ ],
+ name: "LeftoverPNKWithdrawn",
+ },
{
type: "event",
anonymous: false,
@@ -19647,6 +20368,12 @@ export const sortitionModuleUniversityAbi = [
type: "uint256",
indexed: false,
},
+ {
+ name: "_amountAllCourts",
+ internalType: "uint256",
+ type: "uint256",
+ indexed: false,
+ },
],
name: "StakeSet",
},
@@ -19689,7 +20416,7 @@ export const sortitionModuleUniversityAbi = [
{
type: "function",
inputs: [
- { name: "_key", internalType: "bytes32", type: "bytes32" },
+ { name: "_courtID", internalType: "uint96", type: "uint96" },
{ name: "_extraData", internalType: "bytes", type: "bytes" },
],
name: "createTree",
@@ -19705,14 +20432,41 @@ export const sortitionModuleUniversityAbi = [
},
{
type: "function",
- inputs: [
- { name: "", internalType: "bytes32", type: "bytes32" },
- { name: "", internalType: "uint256", type: "uint256" },
- { name: "", internalType: "uint256", type: "uint256" },
- ],
- name: "draw",
- outputs: [{ name: "drawnAddress", internalType: "address", type: "address" }],
- stateMutability: "view",
+ inputs: [
+ { name: "", internalType: "uint96", type: "uint96" },
+ { name: "", internalType: "uint256", type: "uint256" },
+ { name: "", internalType: "uint256", type: "uint256" },
+ ],
+ name: "draw",
+ outputs: [
+ { name: "drawnAddress", internalType: "address", type: "address" },
+ { name: "fromSubcourtID", internalType: "uint96", type: "uint96" },
+ ],
+ stateMutability: "view",
+ },
+ {
+ type: "function",
+ inputs: [{ name: "_iterations", internalType: "uint256", type: "uint256" }],
+ name: "executeDelayedStakes",
+ outputs: [],
+ stateMutability: "nonpayable",
+ },
+ {
+ type: "function",
+ inputs: [
+ { name: "_account", internalType: "address", type: "address" },
+ { name: "_courtID", internalType: "uint96", type: "uint96" },
+ ],
+ name: "forcedUnstake",
+ outputs: [],
+ stateMutability: "nonpayable",
+ },
+ {
+ type: "function",
+ inputs: [{ name: "_account", internalType: "address", type: "address" }],
+ name: "forcedUnstakeAllCourts",
+ outputs: [],
+ stateMutability: "nonpayable",
},
{
type: "function",
@@ -19738,15 +20492,15 @@ export const sortitionModuleUniversityAbi = [
},
{
type: "function",
- inputs: [],
- name: "governor",
- outputs: [{ name: "", internalType: "address", type: "address" }],
+ inputs: [{ name: "_juror", internalType: "address", type: "address" }],
+ name: "getJurorLeftoverPNK",
+ outputs: [{ name: "", internalType: "uint256", type: "uint256" }],
stateMutability: "view",
},
{
type: "function",
inputs: [
- { name: "_governor", internalType: "address", type: "address" },
+ { name: "_owner", internalType: "address", type: "address" },
{
name: "_core",
internalType: "contract KlerosCoreUniversity",
@@ -19786,18 +20540,15 @@ export const sortitionModuleUniversityAbi = [
},
{
type: "function",
- inputs: [{ name: "_randomNumber", internalType: "uint256", type: "uint256" }],
- name: "notifyRandomNumber",
- outputs: [],
- stateMutability: "nonpayable",
+ inputs: [],
+ name: "owner",
+ outputs: [{ name: "", internalType: "address", type: "address" }],
+ stateMutability: "view",
},
{
type: "function",
- inputs: [
- { name: "_account", internalType: "address", type: "address" },
- { name: "_relativeAmount", internalType: "uint256", type: "uint256" },
- ],
- name: "penalizeStake",
+ inputs: [],
+ name: "passPhase",
outputs: [],
stateMutability: "nonpayable",
},
@@ -19820,8 +20571,14 @@ export const sortitionModuleUniversityAbi = [
},
{
type: "function",
- inputs: [{ name: "_account", internalType: "address", type: "address" }],
- name: "setJurorInactive",
+ inputs: [
+ { name: "_account", internalType: "address", type: "address" },
+ { name: "_courtID", internalType: "uint96", type: "uint96" },
+ { name: "_pnkDeposit", internalType: "uint256", type: "uint256" },
+ { name: "_pnkWithdrawal", internalType: "uint256", type: "uint256" },
+ { name: "_newStake", internalType: "uint256", type: "uint256" },
+ ],
+ name: "setStake",
outputs: [],
stateMutability: "nonpayable",
},
@@ -19830,19 +20587,25 @@ export const sortitionModuleUniversityAbi = [
inputs: [
{ name: "_account", internalType: "address", type: "address" },
{ name: "_courtID", internalType: "uint96", type: "uint96" },
- { name: "_newStake", internalType: "uint256", type: "uint256" },
- { name: "_alreadyTransferred", internalType: "bool", type: "bool" },
+ { name: "_penalty", internalType: "uint256", type: "uint256" },
],
- name: "setStake",
+ name: "setStakePenalty",
outputs: [
- { name: "pnkDeposit", internalType: "uint256", type: "uint256" },
- { name: "pnkWithdrawal", internalType: "uint256", type: "uint256" },
- {
- name: "stakingResult",
- internalType: "enum StakingResult",
- type: "uint8",
- },
+ { name: "pnkBalance", internalType: "uint256", type: "uint256" },
+ { name: "newCourtStake", internalType: "uint256", type: "uint256" },
+ { name: "availablePenalty", internalType: "uint256", type: "uint256" },
+ ],
+ stateMutability: "nonpayable",
+ },
+ {
+ type: "function",
+ inputs: [
+ { name: "_account", internalType: "address", type: "address" },
+ { name: "_courtID", internalType: "uint96", type: "uint96" },
+ { name: "_reward", internalType: "uint256", type: "uint256" },
],
+ name: "setStakeReward",
+ outputs: [{ name: "success", internalType: "bool", type: "bool" }],
stateMutability: "nonpayable",
},
{
@@ -19872,6 +20635,40 @@ export const sortitionModuleUniversityAbi = [
outputs: [],
stateMutability: "payable",
},
+ {
+ type: "function",
+ inputs: [
+ { name: "_account", internalType: "address", type: "address" },
+ { name: "_courtID", internalType: "uint96", type: "uint96" },
+ { name: "_newStake", internalType: "uint256", type: "uint256" },
+ { name: "", internalType: "bool", type: "bool" },
+ ],
+ name: "validateStake",
+ outputs: [
+ { name: "pnkDeposit", internalType: "uint256", type: "uint256" },
+ { name: "pnkWithdrawal", internalType: "uint256", type: "uint256" },
+ {
+ name: "stakingResult",
+ internalType: "enum StakingResult",
+ type: "uint8",
+ },
+ ],
+ stateMutability: "view",
+ },
+ {
+ type: "function",
+ inputs: [],
+ name: "version",
+ outputs: [{ name: "", internalType: "string", type: "string" }],
+ stateMutability: "view",
+ },
+ {
+ type: "function",
+ inputs: [{ name: "_account", internalType: "address", type: "address" }],
+ name: "withdrawLeftoverPNK",
+ outputs: [],
+ stateMutability: "nonpayable",
+ },
{
type: "constructor",
inputs: [
@@ -19883,14 +20680,14 @@ export const sortitionModuleUniversityAbi = [
] as const;
/**
- * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0x4B2c2d048921f694cCE3AEa35698c6B1f5fcbb79)
+ * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0x9f55804177e7E44E558616cD7d06B865788214cA)
*/
export const sortitionModuleUniversityAddress = {
- 421614: "0x4B2c2d048921f694cCE3AEa35698c6B1f5fcbb79",
+ 421614: "0x9f55804177e7E44E558616cD7d06B865788214cA",
} as const;
/**
- * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0x4B2c2d048921f694cCE3AEa35698c6B1f5fcbb79)
+ * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0x9f55804177e7E44E558616cD7d06B865788214cA)
*/
export const sortitionModuleUniversityConfig = {
address: sortitionModuleUniversityAddress,
@@ -19902,7 +20699,7 @@ export const sortitionModuleUniversityConfig = {
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
- * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0x5CAD621D69E0535422aCFaCC0017bC32beC7A486)
+ * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0x270e3D63d3d275604df0a1Bd312E1255DCd96936)
*/
export const sortitionModuleUniversityImplementationAbi = [
{ type: "constructor", inputs: [], stateMutability: "nonpayable" },
@@ -19913,7 +20710,10 @@ export const sortitionModuleUniversityImplementationAbi = [
inputs: [{ name: "implementation", internalType: "address", type: "address" }],
name: "InvalidImplementation",
},
+ { type: "error", inputs: [], name: "KlerosCoreOnly" },
+ { type: "error", inputs: [], name: "NotEligibleForWithdrawal" },
{ type: "error", inputs: [], name: "NotInitializing" },
+ { type: "error", inputs: [], name: "OwnerOnly" },
{ type: "error", inputs: [], name: "UUPSUnauthorizedCallContext" },
{
type: "error",
@@ -19933,6 +20733,44 @@ export const sortitionModuleUniversityImplementationAbi = [
],
name: "Initialized",
},
+ {
+ type: "event",
+ anonymous: false,
+ inputs: [
+ {
+ name: "_account",
+ internalType: "address",
+ type: "address",
+ indexed: true,
+ },
+ {
+ name: "_amount",
+ internalType: "uint256",
+ type: "uint256",
+ indexed: false,
+ },
+ ],
+ name: "LeftoverPNK",
+ },
+ {
+ type: "event",
+ anonymous: false,
+ inputs: [
+ {
+ name: "_account",
+ internalType: "address",
+ type: "address",
+ indexed: true,
+ },
+ {
+ name: "_amount",
+ internalType: "uint256",
+ type: "uint256",
+ indexed: false,
+ },
+ ],
+ name: "LeftoverPNKWithdrawn",
+ },
{
type: "event",
anonymous: false,
@@ -19988,6 +20826,12 @@ export const sortitionModuleUniversityImplementationAbi = [
type: "uint256",
indexed: false,
},
+ {
+ name: "_amountAllCourts",
+ internalType: "uint256",
+ type: "uint256",
+ indexed: false,
+ },
],
name: "StakeSet",
},
@@ -20030,7 +20874,7 @@ export const sortitionModuleUniversityImplementationAbi = [
{
type: "function",
inputs: [
- { name: "_key", internalType: "bytes32", type: "bytes32" },
+ { name: "_courtID", internalType: "uint96", type: "uint96" },
{ name: "_extraData", internalType: "bytes", type: "bytes" },
],
name: "createTree",
@@ -20047,14 +20891,41 @@ export const sortitionModuleUniversityImplementationAbi = [
{
type: "function",
inputs: [
- { name: "", internalType: "bytes32", type: "bytes32" },
+ { name: "", internalType: "uint96", type: "uint96" },
{ name: "", internalType: "uint256", type: "uint256" },
{ name: "", internalType: "uint256", type: "uint256" },
],
name: "draw",
- outputs: [{ name: "drawnAddress", internalType: "address", type: "address" }],
+ outputs: [
+ { name: "drawnAddress", internalType: "address", type: "address" },
+ { name: "fromSubcourtID", internalType: "uint96", type: "uint96" },
+ ],
stateMutability: "view",
},
+ {
+ type: "function",
+ inputs: [{ name: "_iterations", internalType: "uint256", type: "uint256" }],
+ name: "executeDelayedStakes",
+ outputs: [],
+ stateMutability: "nonpayable",
+ },
+ {
+ type: "function",
+ inputs: [
+ { name: "_account", internalType: "address", type: "address" },
+ { name: "_courtID", internalType: "uint96", type: "uint96" },
+ ],
+ name: "forcedUnstake",
+ outputs: [],
+ stateMutability: "nonpayable",
+ },
+ {
+ type: "function",
+ inputs: [{ name: "_account", internalType: "address", type: "address" }],
+ name: "forcedUnstakeAllCourts",
+ outputs: [],
+ stateMutability: "nonpayable",
+ },
{
type: "function",
inputs: [
@@ -20079,15 +20950,15 @@ export const sortitionModuleUniversityImplementationAbi = [
},
{
type: "function",
- inputs: [],
- name: "governor",
- outputs: [{ name: "", internalType: "address", type: "address" }],
+ inputs: [{ name: "_juror", internalType: "address", type: "address" }],
+ name: "getJurorLeftoverPNK",
+ outputs: [{ name: "", internalType: "uint256", type: "uint256" }],
stateMutability: "view",
},
{
type: "function",
inputs: [
- { name: "_governor", internalType: "address", type: "address" },
+ { name: "_owner", internalType: "address", type: "address" },
{
name: "_core",
internalType: "contract KlerosCoreUniversity",
@@ -20127,18 +20998,15 @@ export const sortitionModuleUniversityImplementationAbi = [
},
{
type: "function",
- inputs: [{ name: "_randomNumber", internalType: "uint256", type: "uint256" }],
- name: "notifyRandomNumber",
- outputs: [],
- stateMutability: "nonpayable",
+ inputs: [],
+ name: "owner",
+ outputs: [{ name: "", internalType: "address", type: "address" }],
+ stateMutability: "view",
},
{
type: "function",
- inputs: [
- { name: "_account", internalType: "address", type: "address" },
- { name: "_relativeAmount", internalType: "uint256", type: "uint256" },
- ],
- name: "penalizeStake",
+ inputs: [],
+ name: "passPhase",
outputs: [],
stateMutability: "nonpayable",
},
@@ -20161,8 +21029,14 @@ export const sortitionModuleUniversityImplementationAbi = [
},
{
type: "function",
- inputs: [{ name: "_account", internalType: "address", type: "address" }],
- name: "setJurorInactive",
+ inputs: [
+ { name: "_account", internalType: "address", type: "address" },
+ { name: "_courtID", internalType: "uint96", type: "uint96" },
+ { name: "_pnkDeposit", internalType: "uint256", type: "uint256" },
+ { name: "_pnkWithdrawal", internalType: "uint256", type: "uint256" },
+ { name: "_newStake", internalType: "uint256", type: "uint256" },
+ ],
+ name: "setStake",
outputs: [],
stateMutability: "nonpayable",
},
@@ -20171,19 +21045,25 @@ export const sortitionModuleUniversityImplementationAbi = [
inputs: [
{ name: "_account", internalType: "address", type: "address" },
{ name: "_courtID", internalType: "uint96", type: "uint96" },
- { name: "_newStake", internalType: "uint256", type: "uint256" },
- { name: "_alreadyTransferred", internalType: "bool", type: "bool" },
+ { name: "_penalty", internalType: "uint256", type: "uint256" },
],
- name: "setStake",
+ name: "setStakePenalty",
outputs: [
- { name: "pnkDeposit", internalType: "uint256", type: "uint256" },
- { name: "pnkWithdrawal", internalType: "uint256", type: "uint256" },
- {
- name: "stakingResult",
- internalType: "enum StakingResult",
- type: "uint8",
- },
+ { name: "pnkBalance", internalType: "uint256", type: "uint256" },
+ { name: "newCourtStake", internalType: "uint256", type: "uint256" },
+ { name: "availablePenalty", internalType: "uint256", type: "uint256" },
+ ],
+ stateMutability: "nonpayable",
+ },
+ {
+ type: "function",
+ inputs: [
+ { name: "_account", internalType: "address", type: "address" },
+ { name: "_courtID", internalType: "uint96", type: "uint96" },
+ { name: "_reward", internalType: "uint256", type: "uint256" },
],
+ name: "setStakeReward",
+ outputs: [{ name: "success", internalType: "bool", type: "bool" }],
stateMutability: "nonpayable",
},
{
@@ -20213,17 +21093,51 @@ export const sortitionModuleUniversityImplementationAbi = [
outputs: [],
stateMutability: "payable",
},
+ {
+ type: "function",
+ inputs: [
+ { name: "_account", internalType: "address", type: "address" },
+ { name: "_courtID", internalType: "uint96", type: "uint96" },
+ { name: "_newStake", internalType: "uint256", type: "uint256" },
+ { name: "", internalType: "bool", type: "bool" },
+ ],
+ name: "validateStake",
+ outputs: [
+ { name: "pnkDeposit", internalType: "uint256", type: "uint256" },
+ { name: "pnkWithdrawal", internalType: "uint256", type: "uint256" },
+ {
+ name: "stakingResult",
+ internalType: "enum StakingResult",
+ type: "uint8",
+ },
+ ],
+ stateMutability: "view",
+ },
+ {
+ type: "function",
+ inputs: [],
+ name: "version",
+ outputs: [{ name: "", internalType: "string", type: "string" }],
+ stateMutability: "view",
+ },
+ {
+ type: "function",
+ inputs: [{ name: "_account", internalType: "address", type: "address" }],
+ name: "withdrawLeftoverPNK",
+ outputs: [],
+ stateMutability: "nonpayable",
+ },
] as const;
/**
- * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0x5CAD621D69E0535422aCFaCC0017bC32beC7A486)
+ * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0x270e3D63d3d275604df0a1Bd312E1255DCd96936)
*/
export const sortitionModuleUniversityImplementationAddress = {
- 421614: "0x5CAD621D69E0535422aCFaCC0017bC32beC7A486",
+ 421614: "0x270e3D63d3d275604df0a1Bd312E1255DCd96936",
} as const;
/**
- * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0x5CAD621D69E0535422aCFaCC0017bC32beC7A486)
+ * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0x270e3D63d3d275604df0a1Bd312E1255DCd96936)
*/
export const sortitionModuleUniversityImplementationConfig = {
address: sortitionModuleUniversityImplementationAddress,
@@ -20235,7 +21149,7 @@ export const sortitionModuleUniversityImplementationConfig = {
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
- * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0x4B2c2d048921f694cCE3AEa35698c6B1f5fcbb79)
+ * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0x9f55804177e7E44E558616cD7d06B865788214cA)
*/
export const sortitionModuleUniversityProxyAbi = [
{
@@ -20251,14 +21165,14 @@ export const sortitionModuleUniversityProxyAbi = [
] as const;
/**
- * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0x4B2c2d048921f694cCE3AEa35698c6B1f5fcbb79)
+ * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0x9f55804177e7E44E558616cD7d06B865788214cA)
*/
export const sortitionModuleUniversityProxyAddress = {
- 421614: "0x4B2c2d048921f694cCE3AEa35698c6B1f5fcbb79",
+ 421614: "0x9f55804177e7E44E558616cD7d06B865788214cA",
} as const;
/**
- * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0x4B2c2d048921f694cCE3AEa35698c6B1f5fcbb79)
+ * [__View Contract on Arbitrum Sepolia Arbiscan__](https://sepolia.arbiscan.io/address/0x9f55804177e7E44E558616cD7d06B865788214cA)
*/
export const sortitionModuleUniversityProxyConfig = {
address: sortitionModuleUniversityProxyAddress,
diff --git a/contracts/deployments/disputeKitsViem.ts b/contracts/deployments/disputeKitsViem.ts
new file mode 100644
index 000000000..45ae23998
--- /dev/null
+++ b/contracts/deployments/disputeKitsViem.ts
@@ -0,0 +1,85 @@
+import { getContracts } from "./contractsViem";
+import { Abi, AbiEvent, getAbiItem, PublicClient } from "viem";
+import { DeploymentName } from "./utils";
+
+export type DisputeKitContracts = ReturnType;
+export type DisputeKit =
+ | NonNullable
+ | NonNullable
+ | NonNullable
+ | NonNullable
+ | null;
+export type DisputeKitInfos = {
+ address: `0x${string}`;
+ contract: DisputeKit;
+ isGated: boolean;
+ isShutter: boolean;
+};
+export type DisputeKitByIds = Record;
+
+const fetchDisputeKits = async (client: PublicClient, klerosCoreAddress: `0x${string}`, klerosCoreAbi: Abi) => {
+ const DisputeKitCreated = getAbiItem({
+ abi: klerosCoreAbi,
+ name: "DisputeKitCreated",
+ }) as AbiEvent;
+ const logs = await client.getLogs({
+ address: klerosCoreAddress,
+ event: DisputeKitCreated,
+ fromBlock: 0n,
+ toBlock: "latest",
+ });
+ return Object.fromEntries(
+ logs
+ .filter((log) => {
+ const args = log.args as Record;
+ return "_disputeKitID" in args && "_disputeKitAddress" in args;
+ })
+ .map((log) => {
+ const { _disputeKitID, _disputeKitAddress } = log.args as {
+ _disputeKitID: bigint;
+ _disputeKitAddress: string;
+ };
+ return {
+ disputeKitID: _disputeKitID,
+ disputeKitAddress: _disputeKitAddress,
+ };
+ })
+ .map(({ disputeKitID, disputeKitAddress }) => [disputeKitID!.toString(), disputeKitAddress as `0x${string}`])
+ );
+};
+
+export const getDisputeKits = async (client: PublicClient, deployment: DeploymentName): Promise => {
+ const { klerosCore, disputeKitClassic, disputeKitShutter, disputeKitGated, disputeKitGatedShutter } = getContracts({
+ publicClient: client,
+ deployment: deployment,
+ });
+
+ const isDefined = (kit: T): kit is NonNullable => kit != null;
+ const disputeKitContracts = [disputeKitClassic, disputeKitShutter, disputeKitGated, disputeKitGatedShutter].filter(
+ isDefined
+ );
+ const shutterEnabled = [disputeKitShutter, disputeKitGatedShutter].filter(isDefined);
+ const gatedEnabled = [disputeKitGated, disputeKitGatedShutter].filter(isDefined);
+
+ const disputeKitMap = await fetchDisputeKits(client, klerosCore.address, klerosCore.abi);
+
+ return Object.fromEntries(
+ Object.entries(disputeKitMap).map(([disputeKitID, address]) => {
+ const contract =
+ disputeKitContracts.find((contract) => contract.address.toLowerCase() === address.toLowerCase()) ?? null;
+ return [
+ disputeKitID,
+ {
+ address,
+ contract: contract satisfies DisputeKit,
+ isGated: contract
+ ? gatedEnabled.some((gated) => contract.address.toLowerCase() === gated.address.toLowerCase())
+ : false,
+ isShutter: contract
+ ? shutterEnabled.some((shutter) => contract.address.toLowerCase() === shutter.address.toLowerCase())
+ : false,
+ },
+ ];
+ })
+ );
+};
diff --git a/contracts/deployments/index.ts b/contracts/deployments/index.ts
index 3479c5edf..c94968751 100644
--- a/contracts/deployments/index.ts
+++ b/contracts/deployments/index.ts
@@ -17,3 +17,6 @@ export * from "./utils";
// Contracts getters
export { getContracts as getContractsEthers } from "./contractsEthers";
export { getContracts as getContractsViem } from "./contractsViem";
+
+// Dispute kits getters
+export { getDisputeKits as getDisputeKitsViem, type DisputeKitByIds, type DisputeKitInfos } from "./disputeKitsViem";
diff --git a/contracts/deployments/mainnet.viem.ts b/contracts/deployments/mainnet.viem.ts
index c57906c57..eeada4b95 100644
--- a/contracts/deployments/mainnet.viem.ts
+++ b/contracts/deployments/mainnet.viem.ts
@@ -1725,13 +1725,13 @@ export const daiAddress = {
export const daiConfig = { address: daiAddress, abi: daiAbi } as const;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// DisputeKitClassicNeo
+// DisputeKitClassic
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0x70B464be85A547144C72485eBa2577E5D3A45421)
*/
-export const disputeKitClassicNeoAbi = [
+export const disputeKitClassicAbi = [
{ type: "fallback", stateMutability: "payable" },
{ type: "receive", stateMutability: "payable" },
{ type: "error", inputs: [], name: "AlreadyInitialized" },
@@ -2348,26 +2348,26 @@ export const disputeKitClassicNeoAbi = [
/**
* [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0x70B464be85A547144C72485eBa2577E5D3A45421)
*/
-export const disputeKitClassicNeoAddress = {
+export const disputeKitClassicAddress = {
42161: "0x70B464be85A547144C72485eBa2577E5D3A45421",
} as const;
/**
* [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0x70B464be85A547144C72485eBa2577E5D3A45421)
*/
-export const disputeKitClassicNeoConfig = {
- address: disputeKitClassicNeoAddress,
- abi: disputeKitClassicNeoAbi,
+export const disputeKitClassicConfig = {
+ address: disputeKitClassicAddress,
+ abi: disputeKitClassicAbi,
} as const;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// DisputeKitClassicNeo_Implementation
+// DisputeKitClassic_Implementation
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0x371Aa4B1AE5b5f9422f3Ff1d105029AAd1D319BC)
*/
-export const disputeKitClassicNeoImplementationAbi = [
+export const disputeKitClassicImplementationAbi = [
{ type: "constructor", inputs: [], stateMutability: "nonpayable" },
{ type: "error", inputs: [], name: "AlreadyInitialized" },
{ type: "error", inputs: [], name: "FailedDelegateCall" },
@@ -2975,26 +2975,26 @@ export const disputeKitClassicNeoImplementationAbi = [
/**
* [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0x371Aa4B1AE5b5f9422f3Ff1d105029AAd1D319BC)
*/
-export const disputeKitClassicNeoImplementationAddress = {
+export const disputeKitClassicImplementationAddress = {
42161: "0x371Aa4B1AE5b5f9422f3Ff1d105029AAd1D319BC",
} as const;
/**
* [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0x371Aa4B1AE5b5f9422f3Ff1d105029AAd1D319BC)
*/
-export const disputeKitClassicNeoImplementationConfig = {
- address: disputeKitClassicNeoImplementationAddress,
- abi: disputeKitClassicNeoImplementationAbi,
+export const disputeKitClassicImplementationConfig = {
+ address: disputeKitClassicImplementationAddress,
+ abi: disputeKitClassicImplementationAbi,
} as const;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// DisputeKitClassicNeo_Proxy
+// DisputeKitClassic_Proxy
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0x70B464be85A547144C72485eBa2577E5D3A45421)
*/
-export const disputeKitClassicNeoProxyAbi = [
+export const disputeKitClassicProxyAbi = [
{
type: "constructor",
inputs: [
@@ -3010,26 +3010,26 @@ export const disputeKitClassicNeoProxyAbi = [
/**
* [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0x70B464be85A547144C72485eBa2577E5D3A45421)
*/
-export const disputeKitClassicNeoProxyAddress = {
+export const disputeKitClassicProxyAddress = {
42161: "0x70B464be85A547144C72485eBa2577E5D3A45421",
} as const;
/**
* [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0x70B464be85A547144C72485eBa2577E5D3A45421)
*/
-export const disputeKitClassicNeoProxyConfig = {
- address: disputeKitClassicNeoProxyAddress,
- abi: disputeKitClassicNeoProxyAbi,
+export const disputeKitClassicProxyConfig = {
+ address: disputeKitClassicProxyAddress,
+ abi: disputeKitClassicProxyAbi,
} as const;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// DisputeKitGatedNeo
+// DisputeKitGated
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0xaE1eed20C125B739b64c948820C61F809ad9a925)
*/
-export const disputeKitGatedNeoAbi = [
+export const disputeKitGatedAbi = [
{ type: "fallback", stateMutability: "payable" },
{ type: "receive", stateMutability: "payable" },
{ type: "error", inputs: [], name: "AlreadyInitialized" },
@@ -3657,27 +3657,28 @@ export const disputeKitGatedNeoAbi = [
/**
* [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0xaE1eed20C125B739b64c948820C61F809ad9a925)
*/
-export const disputeKitGatedNeoAddress = {
+export const disputeKitGatedAddress = {
42161: "0xaE1eed20C125B739b64c948820C61F809ad9a925",
} as const;
/**
* [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0xaE1eed20C125B739b64c948820C61F809ad9a925)
*/
-export const disputeKitGatedNeoConfig = {
- address: disputeKitGatedNeoAddress,
- abi: disputeKitGatedNeoAbi,
+export const disputeKitGatedConfig = {
+ address: disputeKitGatedAddress,
+ abi: disputeKitGatedAbi,
} as const;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// DisputeKitGatedNeo_Implementation
+// DisputeKitGatedShutter
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
- * [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0xEA7863E6dE863e8E6d037D8693ad5dA45Db7790a)
+ * [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0x788330092B9704809C19858E39EB9Ac402c2E47b)
*/
-export const disputeKitGatedNeoImplementationAbi = [
- { type: "constructor", inputs: [], stateMutability: "nonpayable" },
+export const disputeKitGatedShutterAbi = [
+ { type: "fallback", stateMutability: "payable" },
+ { type: "receive", stateMutability: "payable" },
{ type: "error", inputs: [], name: "AlreadyInitialized" },
{ type: "error", inputs: [], name: "FailedDelegateCall" },
{
@@ -3748,6 +3749,43 @@ export const disputeKitGatedNeoImplementationAbi = [
],
name: "CommitCast",
},
+ {
+ type: "event",
+ anonymous: false,
+ inputs: [
+ {
+ name: "_coreDisputeID",
+ internalType: "uint256",
+ type: "uint256",
+ indexed: true,
+ },
+ {
+ name: "_juror",
+ internalType: "address",
+ type: "address",
+ indexed: true,
+ },
+ {
+ name: "_commit",
+ internalType: "bytes32",
+ type: "bytes32",
+ indexed: true,
+ },
+ {
+ name: "_identity",
+ internalType: "bytes32",
+ type: "bytes32",
+ indexed: false,
+ },
+ {
+ name: "_encryptedVote",
+ internalType: "bytes",
+ type: "bytes",
+ indexed: false,
+ },
+ ],
+ name: "CommitCastShutter",
+ },
{
type: "event",
anonymous: false,
@@ -3974,6 +4012,19 @@ export const disputeKitGatedNeoImplementationAbi = [
outputs: [],
stateMutability: "nonpayable",
},
+ {
+ type: "function",
+ inputs: [
+ { name: "_coreDisputeID", internalType: "uint256", type: "uint256" },
+ { name: "_voteIDs", internalType: "uint256[]", type: "uint256[]" },
+ { name: "_commit", internalType: "bytes32", type: "bytes32" },
+ { name: "_identity", internalType: "bytes32", type: "bytes32" },
+ { name: "_encryptedVote", internalType: "bytes", type: "bytes" },
+ ],
+ name: "castCommitShutter",
+ outputs: [],
+ stateMutability: "nonpayable",
+ },
{
type: "function",
inputs: [
@@ -3987,6 +4038,19 @@ export const disputeKitGatedNeoImplementationAbi = [
outputs: [],
stateMutability: "nonpayable",
},
+ {
+ type: "function",
+ inputs: [
+ { name: "_coreDisputeID", internalType: "uint256", type: "uint256" },
+ { name: "_voteIDs", internalType: "uint256[]", type: "uint256[]" },
+ { name: "_choice", internalType: "uint256", type: "uint256" },
+ { name: "_salt", internalType: "uint256", type: "uint256" },
+ { name: "_justification", internalType: "string", type: "string" },
+ ],
+ name: "castVoteShutter",
+ outputs: [],
+ stateMutability: "nonpayable",
+ },
{
type: "function",
inputs: [{ name: "_core", internalType: "address", type: "address" }],
@@ -4077,17 +4141,6 @@ export const disputeKitGatedNeoImplementationAbi = [
outputs: [],
stateMutability: "nonpayable",
},
- {
- type: "function",
- inputs: [{ name: "_extraData", internalType: "bytes", type: "bytes" }],
- name: "extraDataToTokenInfo",
- outputs: [
- { name: "tokenGate", internalType: "address", type: "address" },
- { name: "isERC1155", internalType: "bool", type: "bool" },
- { name: "tokenId", internalType: "uint256", type: "uint256" },
- ],
- stateMutability: "pure",
- },
{
type: "function",
inputs: [
@@ -4290,31 +4343,6 @@ export const disputeKitGatedNeoImplementationAbi = [
outputs: [{ name: "amount", internalType: "uint256", type: "uint256" }],
stateMutability: "nonpayable",
},
-] as const;
-
-/**
- * [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0xEA7863E6dE863e8E6d037D8693ad5dA45Db7790a)
- */
-export const disputeKitGatedNeoImplementationAddress = {
- 42161: "0xEA7863E6dE863e8E6d037D8693ad5dA45Db7790a",
-} as const;
-
-/**
- * [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0xEA7863E6dE863e8E6d037D8693ad5dA45Db7790a)
- */
-export const disputeKitGatedNeoImplementationConfig = {
- address: disputeKitGatedNeoImplementationAddress,
- abi: disputeKitGatedNeoImplementationAbi,
-} as const;
-
-//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// DisputeKitGatedNeo_Proxy
-//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-/**
- * [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0xaE1eed20C125B739b64c948820C61F809ad9a925)
- */
-export const disputeKitGatedNeoProxyAbi = [
{
type: "constructor",
inputs: [
@@ -4323,35 +4351,32 @@ export const disputeKitGatedNeoProxyAbi = [
],
stateMutability: "nonpayable",
},
- { type: "fallback", stateMutability: "payable" },
- { type: "receive", stateMutability: "payable" },
] as const;
/**
- * [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0xaE1eed20C125B739b64c948820C61F809ad9a925)
+ * [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0x788330092B9704809C19858E39EB9Ac402c2E47b)
*/
-export const disputeKitGatedNeoProxyAddress = {
- 42161: "0xaE1eed20C125B739b64c948820C61F809ad9a925",
+export const disputeKitGatedShutterAddress = {
+ 42161: "0x788330092B9704809C19858E39EB9Ac402c2E47b",
} as const;
/**
- * [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0xaE1eed20C125B739b64c948820C61F809ad9a925)
+ * [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0x788330092B9704809C19858E39EB9Ac402c2E47b)
*/
-export const disputeKitGatedNeoProxyConfig = {
- address: disputeKitGatedNeoProxyAddress,
- abi: disputeKitGatedNeoProxyAbi,
+export const disputeKitGatedShutterConfig = {
+ address: disputeKitGatedShutterAddress,
+ abi: disputeKitGatedShutterAbi,
} as const;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// DisputeKitGatedShutterNeo
+// DisputeKitGatedShutter_Implementation
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
- * [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0x788330092B9704809C19858E39EB9Ac402c2E47b)
+ * [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0xb12EB4c0716d3A9861a9AC471c6CdDB808d61b32)
*/
-export const disputeKitGatedShutterNeoAbi = [
- { type: "fallback", stateMutability: "payable" },
- { type: "receive", stateMutability: "payable" },
+export const disputeKitGatedShutterImplementationAbi = [
+ { type: "constructor", inputs: [], stateMutability: "nonpayable" },
{ type: "error", inputs: [], name: "AlreadyInitialized" },
{ type: "error", inputs: [], name: "FailedDelegateCall" },
{
@@ -5016,6 +5041,31 @@ export const disputeKitGatedShutterNeoAbi = [
outputs: [{ name: "amount", internalType: "uint256", type: "uint256" }],
stateMutability: "nonpayable",
},
+] as const;
+
+/**
+ * [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0xb12EB4c0716d3A9861a9AC471c6CdDB808d61b32)
+ */
+export const disputeKitGatedShutterImplementationAddress = {
+ 42161: "0xb12EB4c0716d3A9861a9AC471c6CdDB808d61b32",
+} as const;
+
+/**
+ * [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0xb12EB4c0716d3A9861a9AC471c6CdDB808d61b32)
+ */
+export const disputeKitGatedShutterImplementationConfig = {
+ address: disputeKitGatedShutterImplementationAddress,
+ abi: disputeKitGatedShutterImplementationAbi,
+} as const;
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// DisputeKitGatedShutter_Proxy
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0x788330092B9704809C19858E39EB9Ac402c2E47b)
+ */
+export const disputeKitGatedShutterProxyAbi = [
{
type: "constructor",
inputs: [
@@ -5024,31 +5074,33 @@ export const disputeKitGatedShutterNeoAbi = [
],
stateMutability: "nonpayable",
},
+ { type: "fallback", stateMutability: "payable" },
+ { type: "receive", stateMutability: "payable" },
] as const;
/**
* [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0x788330092B9704809C19858E39EB9Ac402c2E47b)
*/
-export const disputeKitGatedShutterNeoAddress = {
+export const disputeKitGatedShutterProxyAddress = {
42161: "0x788330092B9704809C19858E39EB9Ac402c2E47b",
} as const;
/**
* [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0x788330092B9704809C19858E39EB9Ac402c2E47b)
*/
-export const disputeKitGatedShutterNeoConfig = {
- address: disputeKitGatedShutterNeoAddress,
- abi: disputeKitGatedShutterNeoAbi,
+export const disputeKitGatedShutterProxyConfig = {
+ address: disputeKitGatedShutterProxyAddress,
+ abi: disputeKitGatedShutterProxyAbi,
} as const;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// DisputeKitGatedShutterNeo_Implementation
+// DisputeKitGated_Implementation
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
- * [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0xb12EB4c0716d3A9861a9AC471c6CdDB808d61b32)
+ * [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0xEA7863E6dE863e8E6d037D8693ad5dA45Db7790a)
*/
-export const disputeKitGatedShutterNeoImplementationAbi = [
+export const disputeKitGatedImplementationAbi = [
{ type: "constructor", inputs: [], stateMutability: "nonpayable" },
{ type: "error", inputs: [], name: "AlreadyInitialized" },
{ type: "error", inputs: [], name: "FailedDelegateCall" },
@@ -5120,43 +5172,6 @@ export const disputeKitGatedShutterNeoImplementationAbi = [
],
name: "CommitCast",
},
- {
- type: "event",
- anonymous: false,
- inputs: [
- {
- name: "_coreDisputeID",
- internalType: "uint256",
- type: "uint256",
- indexed: true,
- },
- {
- name: "_juror",
- internalType: "address",
- type: "address",
- indexed: true,
- },
- {
- name: "_commit",
- internalType: "bytes32",
- type: "bytes32",
- indexed: true,
- },
- {
- name: "_identity",
- internalType: "bytes32",
- type: "bytes32",
- indexed: false,
- },
- {
- name: "_encryptedVote",
- internalType: "bytes",
- type: "bytes",
- indexed: false,
- },
- ],
- name: "CommitCastShutter",
- },
{
type: "event",
anonymous: false,
@@ -5383,19 +5398,6 @@ export const disputeKitGatedShutterNeoImplementationAbi = [
outputs: [],
stateMutability: "nonpayable",
},
- {
- type: "function",
- inputs: [
- { name: "_coreDisputeID", internalType: "uint256", type: "uint256" },
- { name: "_voteIDs", internalType: "uint256[]", type: "uint256[]" },
- { name: "_commit", internalType: "bytes32", type: "bytes32" },
- { name: "_identity", internalType: "bytes32", type: "bytes32" },
- { name: "_encryptedVote", internalType: "bytes", type: "bytes" },
- ],
- name: "castCommitShutter",
- outputs: [],
- stateMutability: "nonpayable",
- },
{
type: "function",
inputs: [
@@ -5409,19 +5411,6 @@ export const disputeKitGatedShutterNeoImplementationAbi = [
outputs: [],
stateMutability: "nonpayable",
},
- {
- type: "function",
- inputs: [
- { name: "_coreDisputeID", internalType: "uint256", type: "uint256" },
- { name: "_voteIDs", internalType: "uint256[]", type: "uint256[]" },
- { name: "_choice", internalType: "uint256", type: "uint256" },
- { name: "_salt", internalType: "uint256", type: "uint256" },
- { name: "_justification", internalType: "string", type: "string" },
- ],
- name: "castVoteShutter",
- outputs: [],
- stateMutability: "nonpayable",
- },
{
type: "function",
inputs: [{ name: "_core", internalType: "address", type: "address" }],
@@ -5512,6 +5501,17 @@ export const disputeKitGatedShutterNeoImplementationAbi = [
outputs: [],
stateMutability: "nonpayable",
},
+ {
+ type: "function",
+ inputs: [{ name: "_extraData", internalType: "bytes", type: "bytes" }],
+ name: "extraDataToTokenInfo",
+ outputs: [
+ { name: "tokenGate", internalType: "address", type: "address" },
+ { name: "isERC1155", internalType: "bool", type: "bool" },
+ { name: "tokenId", internalType: "uint256", type: "uint256" },
+ ],
+ stateMutability: "pure",
+ },
{
type: "function",
inputs: [
@@ -5717,28 +5717,28 @@ export const disputeKitGatedShutterNeoImplementationAbi = [
] as const;
/**
- * [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0xb12EB4c0716d3A9861a9AC471c6CdDB808d61b32)
+ * [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0xEA7863E6dE863e8E6d037D8693ad5dA45Db7790a)
*/
-export const disputeKitGatedShutterNeoImplementationAddress = {
- 42161: "0xb12EB4c0716d3A9861a9AC471c6CdDB808d61b32",
+export const disputeKitGatedImplementationAddress = {
+ 42161: "0xEA7863E6dE863e8E6d037D8693ad5dA45Db7790a",
} as const;
/**
- * [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0xb12EB4c0716d3A9861a9AC471c6CdDB808d61b32)
+ * [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0xEA7863E6dE863e8E6d037D8693ad5dA45Db7790a)
*/
-export const disputeKitGatedShutterNeoImplementationConfig = {
- address: disputeKitGatedShutterNeoImplementationAddress,
- abi: disputeKitGatedShutterNeoImplementationAbi,
+export const disputeKitGatedImplementationConfig = {
+ address: disputeKitGatedImplementationAddress,
+ abi: disputeKitGatedImplementationAbi,
} as const;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// DisputeKitGatedShutterNeo_Proxy
+// DisputeKitGated_Proxy
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
- * [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0x788330092B9704809C19858E39EB9Ac402c2E47b)
+ * [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0xaE1eed20C125B739b64c948820C61F809ad9a925)
*/
-export const disputeKitGatedShutterNeoProxyAbi = [
+export const disputeKitGatedProxyAbi = [
{
type: "constructor",
inputs: [
@@ -5752,28 +5752,28 @@ export const disputeKitGatedShutterNeoProxyAbi = [
] as const;
/**
- * [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0x788330092B9704809C19858E39EB9Ac402c2E47b)
+ * [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0xaE1eed20C125B739b64c948820C61F809ad9a925)
*/
-export const disputeKitGatedShutterNeoProxyAddress = {
- 42161: "0x788330092B9704809C19858E39EB9Ac402c2E47b",
+export const disputeKitGatedProxyAddress = {
+ 42161: "0xaE1eed20C125B739b64c948820C61F809ad9a925",
} as const;
/**
- * [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0x788330092B9704809C19858E39EB9Ac402c2E47b)
+ * [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0xaE1eed20C125B739b64c948820C61F809ad9a925)
*/
-export const disputeKitGatedShutterNeoProxyConfig = {
- address: disputeKitGatedShutterNeoProxyAddress,
- abi: disputeKitGatedShutterNeoProxyAbi,
+export const disputeKitGatedProxyConfig = {
+ address: disputeKitGatedProxyAddress,
+ abi: disputeKitGatedProxyAbi,
} as const;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// DisputeKitShutterNeo
+// DisputeKitShutter
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0x9D3e3f1765744c2a1BC6F6088549770444BBC768)
*/
-export const disputeKitShutterNeoAbi = [
+export const disputeKitShutterAbi = [
{ type: "fallback", stateMutability: "payable" },
{ type: "receive", stateMutability: "payable" },
{ type: "error", inputs: [], name: "AlreadyInitialized" },
@@ -6453,26 +6453,26 @@ export const disputeKitShutterNeoAbi = [
/**
* [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0x9D3e3f1765744c2a1BC6F6088549770444BBC768)
*/
-export const disputeKitShutterNeoAddress = {
+export const disputeKitShutterAddress = {
42161: "0x9D3e3f1765744c2a1BC6F6088549770444BBC768",
} as const;
/**
* [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0x9D3e3f1765744c2a1BC6F6088549770444BBC768)
*/
-export const disputeKitShutterNeoConfig = {
- address: disputeKitShutterNeoAddress,
- abi: disputeKitShutterNeoAbi,
+export const disputeKitShutterConfig = {
+ address: disputeKitShutterAddress,
+ abi: disputeKitShutterAbi,
} as const;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// DisputeKitShutterNeo_Implementation
+// DisputeKitShutter_Implementation
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0xF3103B46403A0bBd4551648BFb29BCC2b8783947)
*/
-export const disputeKitShutterNeoImplementationAbi = [
+export const disputeKitShutterImplementationAbi = [
{ type: "constructor", inputs: [], stateMutability: "nonpayable" },
{ type: "error", inputs: [], name: "AlreadyInitialized" },
{ type: "error", inputs: [], name: "FailedDelegateCall" },
@@ -7143,26 +7143,26 @@ export const disputeKitShutterNeoImplementationAbi = [
/**
* [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0xF3103B46403A0bBd4551648BFb29BCC2b8783947)
*/
-export const disputeKitShutterNeoImplementationAddress = {
+export const disputeKitShutterImplementationAddress = {
42161: "0xF3103B46403A0bBd4551648BFb29BCC2b8783947",
} as const;
/**
* [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0xF3103B46403A0bBd4551648BFb29BCC2b8783947)
*/
-export const disputeKitShutterNeoImplementationConfig = {
- address: disputeKitShutterNeoImplementationAddress,
- abi: disputeKitShutterNeoImplementationAbi,
+export const disputeKitShutterImplementationConfig = {
+ address: disputeKitShutterImplementationAddress,
+ abi: disputeKitShutterImplementationAbi,
} as const;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// DisputeKitShutterNeo_Proxy
+// DisputeKitShutter_Proxy
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0x9D3e3f1765744c2a1BC6F6088549770444BBC768)
*/
-export const disputeKitShutterNeoProxyAbi = [
+export const disputeKitShutterProxyAbi = [
{
type: "constructor",
inputs: [
@@ -7178,26 +7178,26 @@ export const disputeKitShutterNeoProxyAbi = [
/**
* [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0x9D3e3f1765744c2a1BC6F6088549770444BBC768)
*/
-export const disputeKitShutterNeoProxyAddress = {
+export const disputeKitShutterProxyAddress = {
42161: "0x9D3e3f1765744c2a1BC6F6088549770444BBC768",
} as const;
/**
* [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0x9D3e3f1765744c2a1BC6F6088549770444BBC768)
*/
-export const disputeKitShutterNeoProxyConfig = {
- address: disputeKitShutterNeoProxyAddress,
- abi: disputeKitShutterNeoProxyAbi,
+export const disputeKitShutterProxyConfig = {
+ address: disputeKitShutterProxyAddress,
+ abi: disputeKitShutterProxyAbi,
} as const;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// DisputeResolverNeo
+// DisputeResolver
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0xb5526D022962A1fFf6eD32C93e8b714c901F4323)
*/
-export const disputeResolverNeoAbi = [
+export const disputeResolverAbi = [
{
type: "constructor",
inputs: [
@@ -7413,26 +7413,26 @@ export const disputeResolverNeoAbi = [
/**
* [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0xb5526D022962A1fFf6eD32C93e8b714c901F4323)
*/
-export const disputeResolverNeoAddress = {
+export const disputeResolverAddress = {
42161: "0xb5526D022962A1fFf6eD32C93e8b714c901F4323",
} as const;
/**
* [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0xb5526D022962A1fFf6eD32C93e8b714c901F4323)
*/
-export const disputeResolverNeoConfig = {
- address: disputeResolverNeoAddress,
- abi: disputeResolverNeoAbi,
+export const disputeResolverConfig = {
+ address: disputeResolverAddress,
+ abi: disputeResolverAbi,
} as const;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// DisputeResolverRulerNeo
+// DisputeResolverRuler
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0xb3a5FdEAF461c42caCe148e978e6FBCa97bE6140)
*/
-export const disputeResolverRulerNeoAbi = [
+export const disputeResolverRulerAbi = [
{
type: "constructor",
inputs: [
@@ -7648,16 +7648,16 @@ export const disputeResolverRulerNeoAbi = [
/**
* [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0xb3a5FdEAF461c42caCe148e978e6FBCa97bE6140)
*/
-export const disputeResolverRulerNeoAddress = {
+export const disputeResolverRulerAddress = {
42161: "0xb3a5FdEAF461c42caCe148e978e6FBCa97bE6140",
} as const;
/**
* [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0xb3a5FdEAF461c42caCe148e978e6FBCa97bE6140)
*/
-export const disputeResolverRulerNeoConfig = {
- address: disputeResolverRulerNeoAddress,
- abi: disputeResolverRulerNeoAbi,
+export const disputeResolverRulerConfig = {
+ address: disputeResolverRulerAddress,
+ abi: disputeResolverRulerAbi,
} as const;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -8604,13 +8604,13 @@ export const iHomeGatewayAbi = [
] as const;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// KlerosCoreNeo
+// KlerosCore
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0x991d2df165670b9cac3B022f4B68D65b664222ea)
*/
-export const klerosCoreNeoAbi = [
+export const klerosCoreAbi = [
{ type: "fallback", stateMutability: "payable" },
{ type: "receive", stateMutability: "payable" },
{ type: "error", inputs: [], name: "AlreadyInitialized" },
@@ -9805,65 +9805,46 @@ export const klerosCoreNeoAbi = [
/**
* [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0x991d2df165670b9cac3B022f4B68D65b664222ea)
*/
-export const klerosCoreNeoAddress = {
+export const klerosCoreAddress = {
42161: "0x991d2df165670b9cac3B022f4B68D65b664222ea",
} as const;
/**
* [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0x991d2df165670b9cac3B022f4B68D65b664222ea)
*/
-export const klerosCoreNeoConfig = {
- address: klerosCoreNeoAddress,
- abi: klerosCoreNeoAbi,
+export const klerosCoreConfig = {
+ address: klerosCoreAddress,
+ abi: klerosCoreAbi,
} as const;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// KlerosCoreNeo_Implementation
+// KlerosCoreRuler
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
- * [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0xC1210493804eEF123096F9581Ee82B915150E54c)
+ * [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0xc0169e0B19aE02ac4fADD689260CF038726DFE13)
*/
-export const klerosCoreNeoImplementationAbi = [
- { type: "constructor", inputs: [], stateMutability: "nonpayable" },
+export const klerosCoreRulerAbi = [
+ { type: "fallback", stateMutability: "payable" },
+ { type: "receive", stateMutability: "payable" },
{ type: "error", inputs: [], name: "AlreadyInitialized" },
{ type: "error", inputs: [], name: "AppealFeesNotEnough" },
- { type: "error", inputs: [], name: "AppealPeriodNotPassed" },
- { type: "error", inputs: [], name: "ArbitrableNotWhitelisted" },
{ type: "error", inputs: [], name: "ArbitrationFeesNotEnough" },
- { type: "error", inputs: [], name: "CannotDisableClassicDK" },
- { type: "error", inputs: [], name: "CommitPeriodNotPassed" },
- { type: "error", inputs: [], name: "DisputeKitNotSupportedByCourt" },
- { type: "error", inputs: [], name: "DisputeKitOnly" },
{ type: "error", inputs: [], name: "DisputeNotAppealable" },
- { type: "error", inputs: [], name: "DisputePeriodIsFinal" },
- { type: "error", inputs: [], name: "DisputeStillDrawing" },
- { type: "error", inputs: [], name: "EvidenceNotPassedAndNotAppeal" },
{ type: "error", inputs: [], name: "FailedDelegateCall" },
{ type: "error", inputs: [], name: "GovernorOnly" },
- { type: "error", inputs: [], name: "GuardianOrGovernorOnly" },
- { type: "error", inputs: [], name: "InvalidDisputKitParent" },
+ { type: "error", inputs: [], name: "GovernorOrInstructorOnly" },
{ type: "error", inputs: [], name: "InvalidForkingCourtAsParent" },
{
type: "error",
inputs: [{ name: "implementation", internalType: "address", type: "address" }],
name: "InvalidImplementation",
},
- { type: "error", inputs: [], name: "MinStakeLowerThanParentCourt" },
- { type: "error", inputs: [], name: "MustSupportDisputeKitClassic" },
- { type: "error", inputs: [], name: "NotEligibleForStaking" },
- { type: "error", inputs: [], name: "NotEvidencePeriod" },
- { type: "error", inputs: [], name: "NotExecutionPeriod" },
+ { type: "error", inputs: [], name: "NoRulerSet" },
{ type: "error", inputs: [], name: "NotInitializing" },
+ { type: "error", inputs: [], name: "RulerOnly" },
{ type: "error", inputs: [], name: "RulingAlreadyExecuted" },
- { type: "error", inputs: [], name: "SortitionModuleOnly" },
- { type: "error", inputs: [], name: "StakingInTooManyCourts" },
- { type: "error", inputs: [], name: "StakingLessThanCourtMinStake" },
- { type: "error", inputs: [], name: "StakingMoreThanMaxStakePerJuror" },
- { type: "error", inputs: [], name: "StakingMoreThanMaxTotalStaked" },
- { type: "error", inputs: [], name: "StakingNotPossibleInThisCourt" },
- { type: "error", inputs: [], name: "StakingTransferFailed" },
- { type: "error", inputs: [], name: "StakingZeroWhenNoStake" },
+ { type: "error", inputs: [], name: "RulingModeNotSet" },
{ type: "error", inputs: [], name: "TokenNotAccepted" },
{ type: "error", inputs: [], name: "TransferFailed" },
{ type: "error", inputs: [], name: "UUPSUnauthorizedCallContext" },
@@ -9872,13 +9853,7 @@ export const klerosCoreNeoImplementationAbi = [
inputs: [{ name: "slot", internalType: "bytes32", type: "bytes32" }],
name: "UUPSUnsupportedProxiableUUID",
},
- { type: "error", inputs: [], name: "UnstakingTransferFailed" },
{ type: "error", inputs: [], name: "UnsuccessfulCall" },
- { type: "error", inputs: [], name: "UnsupportedDisputeKit" },
- { type: "error", inputs: [], name: "VotePeriodNotPassed" },
- { type: "error", inputs: [], name: "WhenNotPausedOnly" },
- { type: "error", inputs: [], name: "WhenPausedOnly" },
- { type: "error", inputs: [], name: "WrongDisputeKitIndex" },
{
type: "event",
anonymous: false,
@@ -9931,14 +9906,52 @@ export const klerosCoreNeoImplementationAbi = [
],
name: "AppealPossible",
},
+ {
+ type: "event",
+ anonymous: false,
+ inputs: [
+ {
+ name: "_arbitrable",
+ internalType: "contract IArbitrableV2",
+ type: "address",
+ indexed: true,
+ },
+ {
+ name: "mode",
+ internalType: "enum KlerosCoreRuler.RulingMode",
+ type: "uint8",
+ indexed: true,
+ },
+ {
+ name: "_disputeID",
+ internalType: "uint256",
+ type: "uint256",
+ indexed: true,
+ },
+ {
+ name: "_ruling",
+ internalType: "uint256",
+ type: "uint256",
+ indexed: false,
+ },
+ { name: "tied", internalType: "bool", type: "bool", indexed: false },
+ {
+ name: "overridden",
+ internalType: "bool",
+ type: "bool",
+ indexed: false,
+ },
+ ],
+ name: "AutoRuled",
+ },
{
type: "event",
anonymous: false,
inputs: [
{
name: "_courtID",
- internalType: "uint96",
- type: "uint96",
+ internalType: "uint256",
+ type: "uint256",
indexed: true,
},
{
@@ -9983,12 +9996,6 @@ export const klerosCoreNeoImplementationAbi = [
type: "uint256[4]",
indexed: false,
},
- {
- name: "_supportedDisputeKits",
- internalType: "uint256[]",
- type: "uint256[]",
- indexed: false,
- },
],
name: "CourtCreated",
},
@@ -10091,107 +10098,6 @@ export const klerosCoreNeoImplementationAbi = [
],
name: "DisputeCreation",
},
- {
- type: "event",
- anonymous: false,
- inputs: [
- {
- name: "_disputeKitID",
- internalType: "uint256",
- type: "uint256",
- indexed: true,
- },
- {
- name: "_disputeKitAddress",
- internalType: "contract IDisputeKit",
- type: "address",
- indexed: true,
- },
- ],
- name: "DisputeKitCreated",
- },
- {
- type: "event",
- anonymous: false,
- inputs: [
- {
- name: "_courtID",
- internalType: "uint96",
- type: "uint96",
- indexed: true,
- },
- {
- name: "_disputeKitID",
- internalType: "uint256",
- type: "uint256",
- indexed: true,
- },
- { name: "_enable", internalType: "bool", type: "bool", indexed: true },
- ],
- name: "DisputeKitEnabled",
- },
- {
- type: "event",
- anonymous: false,
- inputs: [
- {
- name: "_disputeID",
- internalType: "uint256",
- type: "uint256",
- indexed: true,
- },
- {
- name: "_roundID",
- internalType: "uint256",
- type: "uint256",
- indexed: true,
- },
- {
- name: "_fromDisputeKitID",
- internalType: "uint256",
- type: "uint256",
- indexed: true,
- },
- {
- name: "_toDisputeKitID",
- internalType: "uint256",
- type: "uint256",
- indexed: false,
- },
- ],
- name: "DisputeKitJump",
- },
- {
- type: "event",
- anonymous: false,
- inputs: [
- {
- name: "_address",
- internalType: "address",
- type: "address",
- indexed: true,
- },
- {
- name: "_disputeID",
- internalType: "uint256",
- type: "uint256",
- indexed: true,
- },
- {
- name: "_roundID",
- internalType: "uint256",
- type: "uint256",
- indexed: false,
- },
- {
- name: "_voteID",
- internalType: "uint256",
- type: "uint256",
- indexed: false,
- },
- ],
- name: "Draw",
- },
{
type: "event",
anonymous: false,
@@ -10279,14 +10185,67 @@ export const klerosCoreNeoImplementationAbi = [
},
{
name: "_period",
- internalType: "enum KlerosCoreBase.Period",
+ internalType: "enum KlerosCoreRuler.Period",
type: "uint8",
indexed: false,
},
],
name: "NewPeriod",
},
- { type: "event", anonymous: false, inputs: [], name: "Paused" },
+ {
+ type: "event",
+ anonymous: false,
+ inputs: [
+ {
+ name: "_arbitrable",
+ internalType: "contract IArbitrableV2",
+ type: "address",
+ indexed: true,
+ },
+ {
+ name: "_oldRuler",
+ internalType: "address",
+ type: "address",
+ indexed: true,
+ },
+ {
+ name: "_newRuler",
+ internalType: "address",
+ type: "address",
+ indexed: true,
+ },
+ ],
+ name: "RulerChanged",
+ },
+ {
+ type: "event",
+ anonymous: false,
+ inputs: [
+ {
+ name: "_arbitrable",
+ internalType: "contract IArbitrableV2",
+ type: "address",
+ indexed: true,
+ },
+ {
+ name: "_settings",
+ internalType: "struct KlerosCoreRuler.RulerSettings",
+ type: "tuple",
+ components: [
+ {
+ name: "rulingMode",
+ internalType: "enum KlerosCoreRuler.RulingMode",
+ type: "uint8",
+ },
+ { name: "presetRuling", internalType: "uint256", type: "uint256" },
+ { name: "presetTied", internalType: "bool", type: "bool" },
+ { name: "presetOverridden", internalType: "bool", type: "bool" },
+ ],
+ indexed: false,
+ },
+ ],
+ name: "RulerSettingsChanged",
+ },
{
type: "event",
anonymous: false,
@@ -10361,7 +10320,6 @@ export const klerosCoreNeoImplementationAbi = [
],
name: "TokenAndETHShift",
},
- { type: "event", anonymous: false, inputs: [], name: "Unpaused" },
{
type: "event",
anonymous: false,
@@ -10375,25 +10333,13 @@ export const klerosCoreNeoImplementationAbi = [
],
name: "Upgraded",
},
- {
- type: "function",
- inputs: [
- {
- name: "_disputeKitAddress",
- internalType: "contract IDisputeKit",
- type: "address",
- },
- ],
- name: "addNewDisputeKit",
- outputs: [],
- stateMutability: "nonpayable",
- },
{
type: "function",
inputs: [
{ name: "_disputeID", internalType: "uint256", type: "uint256" },
{ name: "_numberOfChoices", internalType: "uint256", type: "uint256" },
- { name: "_extraData", internalType: "bytes", type: "bytes" },
+ { name: "", internalType: "bytes", type: "bytes" },
+ { name: "_jump", internalType: "bool", type: "bool" },
],
name: "appeal",
outputs: [],
@@ -10401,28 +10347,14 @@ export const klerosCoreNeoImplementationAbi = [
},
{
type: "function",
- inputs: [{ name: "_disputeID", internalType: "uint256", type: "uint256" }],
+ inputs: [
+ { name: "_disputeID", internalType: "uint256", type: "uint256" },
+ { name: "_jump", internalType: "bool", type: "bool" },
+ ],
name: "appealCost",
outputs: [{ name: "cost", internalType: "uint256", type: "uint256" }],
stateMutability: "view",
},
- {
- type: "function",
- inputs: [{ name: "_disputeID", internalType: "uint256", type: "uint256" }],
- name: "appealPeriod",
- outputs: [
- { name: "start", internalType: "uint256", type: "uint256" },
- { name: "end", internalType: "uint256", type: "uint256" },
- ],
- stateMutability: "view",
- },
- {
- type: "function",
- inputs: [{ name: "", internalType: "address", type: "address" }],
- name: "arbitrableWhitelist",
- outputs: [{ name: "", internalType: "bool", type: "bool" }],
- stateMutability: "view",
- },
{
type: "function",
inputs: [
@@ -10450,16 +10382,6 @@ export const klerosCoreNeoImplementationAbi = [
outputs: [],
stateMutability: "nonpayable",
},
- {
- type: "function",
- inputs: [
- { name: "_arbitrable", internalType: "address", type: "address" },
- { name: "_allowed", internalType: "bool", type: "bool" },
- ],
- name: "changeArbitrableWhitelist",
- outputs: [],
- stateMutability: "nonpayable",
- },
{
type: "function",
inputs: [
@@ -10499,15 +10421,22 @@ export const klerosCoreNeoImplementationAbi = [
},
{
type: "function",
- inputs: [{ name: "_guardian", internalType: "address", type: "address" }],
- name: "changeGuardian",
+ inputs: [{ name: "_pinakion", internalType: "contract IERC20", type: "address" }],
+ name: "changePinakion",
outputs: [],
stateMutability: "nonpayable",
},
{
type: "function",
- inputs: [{ name: "_jurorNft", internalType: "contract IERC721", type: "address" }],
- name: "changeJurorNft",
+ inputs: [
+ {
+ name: "_arbitrable",
+ internalType: "contract IArbitrableV2",
+ type: "address",
+ },
+ { name: "_newRuler", internalType: "address", type: "address" },
+ ],
+ name: "changeRuler",
outputs: [],
stateMutability: "nonpayable",
},
@@ -10515,19 +10444,28 @@ export const klerosCoreNeoImplementationAbi = [
type: "function",
inputs: [
{
- name: "_jurorProsecutionModule",
- internalType: "address",
+ name: "_arbitrable",
+ internalType: "contract IArbitrableV2",
type: "address",
},
+ { name: "_presetRuling", internalType: "uint256", type: "uint256" },
+ { name: "_presetTied", internalType: "bool", type: "bool" },
+ { name: "_presetOverridden", internalType: "bool", type: "bool" },
],
- name: "changeJurorProsecutionModule",
+ name: "changeRulingModeToAutomaticPreset",
outputs: [],
stateMutability: "nonpayable",
},
{
type: "function",
- inputs: [{ name: "_pinakion", internalType: "contract IERC20", type: "address" }],
- name: "changePinakion",
+ inputs: [
+ {
+ name: "_arbitrable",
+ internalType: "contract IArbitrableV2",
+ type: "address",
+ },
+ ],
+ name: "changeRulingModeToAutomaticRandom",
outputs: [],
stateMutability: "nonpayable",
},
@@ -10535,12 +10473,12 @@ export const klerosCoreNeoImplementationAbi = [
type: "function",
inputs: [
{
- name: "_sortitionModule",
- internalType: "contract ISortitionModule",
+ name: "_arbitrable",
+ internalType: "contract IArbitrableV2",
type: "address",
},
],
- name: "changeSortitionModule",
+ name: "changeRulingModeToManual",
outputs: [],
stateMutability: "nonpayable",
},
@@ -10583,12 +10521,6 @@ export const klerosCoreNeoImplementationAbi = [
internalType: "uint256[4]",
type: "uint256[4]",
},
- { name: "_sortitionExtraData", internalType: "bytes", type: "bytes" },
- {
- name: "_supportedDisputeKits",
- internalType: "uint256[]",
- type: "uint256[]",
- },
],
name: "createCourt",
outputs: [],
@@ -10638,13 +10570,6 @@ export const klerosCoreNeoImplementationAbi = [
],
stateMutability: "view",
},
- {
- type: "function",
- inputs: [{ name: "", internalType: "uint256", type: "uint256" }],
- name: "disputeKits",
- outputs: [{ name: "", internalType: "contract IDisputeKit", type: "address" }],
- stateMutability: "view",
- },
{
type: "function",
inputs: [{ name: "", internalType: "uint256", type: "uint256" }],
@@ -10658,41 +10583,18 @@ export const klerosCoreNeoImplementationAbi = [
},
{
name: "period",
- internalType: "enum KlerosCoreBase.Period",
+ internalType: "enum KlerosCoreRuler.Period",
type: "uint8",
},
{ name: "ruled", internalType: "bool", type: "bool" },
- { name: "lastPeriodChange", internalType: "uint256", type: "uint256" },
],
stateMutability: "view",
},
- {
- type: "function",
- inputs: [
- { name: "_disputeID", internalType: "uint256", type: "uint256" },
- { name: "_iterations", internalType: "uint256", type: "uint256" },
- ],
- name: "draw",
- outputs: [{ name: "nbDrawnJurors", internalType: "uint256", type: "uint256" }],
- stateMutability: "nonpayable",
- },
- {
- type: "function",
- inputs: [
- { name: "_courtID", internalType: "uint96", type: "uint96" },
- { name: "_disputeKitIDs", internalType: "uint256[]", type: "uint256[]" },
- { name: "_enable", internalType: "bool", type: "bool" },
- ],
- name: "enableDisputeKits",
- outputs: [],
- stateMutability: "nonpayable",
- },
{
type: "function",
inputs: [
{ name: "_disputeID", internalType: "uint256", type: "uint256" },
{ name: "_round", internalType: "uint256", type: "uint256" },
- { name: "_iterations", internalType: "uint256", type: "uint256" },
],
name: "execute",
outputs: [],
@@ -10711,7 +10613,12 @@ export const klerosCoreNeoImplementationAbi = [
},
{
type: "function",
- inputs: [{ name: "_disputeID", internalType: "uint256", type: "uint256" }],
+ inputs: [
+ { name: "_disputeID", internalType: "uint256", type: "uint256" },
+ { name: "_ruling", internalType: "uint256", type: "uint256" },
+ { name: "tied", internalType: "bool", type: "bool" },
+ { name: "overridden", internalType: "bool", type: "bool" },
+ ],
name: "executeRuling",
outputs: [],
stateMutability: "nonpayable",
@@ -10719,7 +10626,7 @@ export const klerosCoreNeoImplementationAbi = [
{
type: "function",
inputs: [],
- name: "getDisputeKitsLength",
+ name: "getNextDisputeID",
outputs: [{ name: "", internalType: "uint256", type: "uint256" }],
stateMutability: "view",
},
@@ -10737,16 +10644,6 @@ export const klerosCoreNeoImplementationAbi = [
outputs: [{ name: "", internalType: "uint256", type: "uint256" }],
stateMutability: "view",
},
- {
- type: "function",
- inputs: [
- { name: "_disputeID", internalType: "uint256", type: "uint256" },
- { name: "_round", internalType: "uint256", type: "uint256" },
- ],
- name: "getPnkAtStakePerJuror",
- outputs: [{ name: "", internalType: "uint256", type: "uint256" }],
- stateMutability: "view",
- },
{
type: "function",
inputs: [
@@ -10757,40 +10654,24 @@ export const klerosCoreNeoImplementationAbi = [
outputs: [
{
name: "",
- internalType: "struct KlerosCoreBase.Round",
+ internalType: "struct KlerosCoreRuler.Round",
type: "tuple",
components: [
- { name: "disputeKitID", internalType: "uint256", type: "uint256" },
- {
- name: "pnkAtStakePerJuror",
- internalType: "uint256",
- type: "uint256",
- },
{
name: "totalFeesForJurors",
internalType: "uint256",
type: "uint256",
},
- { name: "nbVotes", internalType: "uint256", type: "uint256" },
- { name: "repartitions", internalType: "uint256", type: "uint256" },
- { name: "pnkPenalties", internalType: "uint256", type: "uint256" },
- { name: "drawnJurors", internalType: "address[]", type: "address[]" },
{
name: "sumFeeRewardPaid",
internalType: "uint256",
type: "uint256",
},
- {
- name: "sumPnkRewardPaid",
- internalType: "uint256",
- type: "uint256",
- },
{
name: "feeToken",
internalType: "contract IERC20",
type: "address",
},
- { name: "drawIterations", internalType: "uint256", type: "uint256" },
],
},
],
@@ -10816,257 +10697,125 @@ export const klerosCoreNeoImplementationAbi = [
outputs: [{ name: "", internalType: "address", type: "address" }],
stateMutability: "view",
},
- {
- type: "function",
- inputs: [],
- name: "guardian",
- outputs: [{ name: "", internalType: "address", type: "address" }],
- stateMutability: "view",
- },
{
type: "function",
inputs: [
{ name: "_governor", internalType: "address", type: "address" },
- { name: "_guardian", internalType: "address", type: "address" },
{ name: "_pinakion", internalType: "contract IERC20", type: "address" },
- {
- name: "_jurorProsecutionModule",
- internalType: "address",
- type: "address",
- },
- {
- name: "_disputeKit",
- internalType: "contract IDisputeKit",
- type: "address",
- },
- { name: "_hiddenVotes", internalType: "bool", type: "bool" },
{
name: "_courtParameters",
internalType: "uint256[4]",
type: "uint256[4]",
},
- {
- name: "_timesPerPeriod",
- internalType: "uint256[4]",
- type: "uint256[4]",
- },
- { name: "_sortitionExtraData", internalType: "bytes", type: "bytes" },
- {
- name: "_sortitionModuleAddress",
- internalType: "contract ISortitionModule",
- type: "address",
- },
- { name: "_jurorNft", internalType: "contract IERC721", type: "address" },
- { name: "_wNative", internalType: "address", type: "address" },
],
name: "initialize",
outputs: [],
stateMutability: "nonpayable",
},
- {
- type: "function",
- inputs: [{ name: "_disputeID", internalType: "uint256", type: "uint256" }],
- name: "isDisputeKitJumping",
- outputs: [{ name: "", internalType: "bool", type: "bool" }],
- stateMutability: "view",
- },
- {
- type: "function",
- inputs: [
- { name: "_courtID", internalType: "uint96", type: "uint96" },
- { name: "_disputeKitID", internalType: "uint256", type: "uint256" },
- ],
- name: "isSupported",
- outputs: [{ name: "", internalType: "bool", type: "bool" }],
- stateMutability: "view",
- },
{
type: "function",
inputs: [],
- name: "jurorNft",
- outputs: [{ name: "", internalType: "contract IERC721", type: "address" }],
+ name: "pinakion",
+ outputs: [{ name: "", internalType: "contract IERC20", type: "address" }],
stateMutability: "view",
},
{
type: "function",
inputs: [],
- name: "jurorProsecutionModule",
- outputs: [{ name: "", internalType: "address", type: "address" }],
+ name: "proxiableUUID",
+ outputs: [{ name: "", internalType: "bytes32", type: "bytes32" }],
stateMutability: "view",
},
{
type: "function",
- inputs: [{ name: "_disputeID", internalType: "uint256", type: "uint256" }],
- name: "passPeriod",
- outputs: [],
- stateMutability: "nonpayable",
- },
- {
- type: "function",
- inputs: [],
- name: "pause",
- outputs: [],
- stateMutability: "nonpayable",
- },
- {
- type: "function",
- inputs: [],
- name: "paused",
- outputs: [{ name: "", internalType: "bool", type: "bool" }],
+ inputs: [
+ {
+ name: "arbitrable",
+ internalType: "contract IArbitrableV2",
+ type: "address",
+ },
+ ],
+ name: "rulers",
+ outputs: [{ name: "ruler", internalType: "address", type: "address" }],
stateMutability: "view",
},
{
type: "function",
- inputs: [],
- name: "pinakion",
- outputs: [{ name: "", internalType: "contract IERC20", type: "address" }],
+ inputs: [{ name: "disputeID", internalType: "uint256", type: "uint256" }],
+ name: "rulingResults",
+ outputs: [
+ { name: "ruling", internalType: "uint256", type: "uint256" },
+ { name: "tied", internalType: "bool", type: "bool" },
+ { name: "overridden", internalType: "bool", type: "bool" },
+ ],
stateMutability: "view",
},
{
type: "function",
- inputs: [],
- name: "proxiableUUID",
- outputs: [{ name: "", internalType: "bytes32", type: "bytes32" }],
+ inputs: [
+ {
+ name: "arbitrable",
+ internalType: "contract IArbitrableV2",
+ type: "address",
+ },
+ ],
+ name: "settings",
+ outputs: [
+ {
+ name: "rulingMode",
+ internalType: "enum KlerosCoreRuler.RulingMode",
+ type: "uint8",
+ },
+ { name: "presetRuling", internalType: "uint256", type: "uint256" },
+ { name: "presetTied", internalType: "bool", type: "bool" },
+ { name: "presetOverridden", internalType: "bool", type: "bool" },
+ ],
stateMutability: "view",
},
- {
- type: "function",
- inputs: [{ name: "_wNative", internalType: "address", type: "address" }],
- name: "reinitialize",
- outputs: [],
- stateMutability: "nonpayable",
- },
{
type: "function",
inputs: [
- { name: "_courtID", internalType: "uint96", type: "uint96" },
- { name: "_newStake", internalType: "uint256", type: "uint256" },
+ { name: "newImplementation", internalType: "address", type: "address" },
+ { name: "data", internalType: "bytes", type: "bytes" },
],
- name: "setStake",
+ name: "upgradeToAndCall",
outputs: [],
- stateMutability: "nonpayable",
+ stateMutability: "payable",
},
{
- type: "function",
+ type: "constructor",
inputs: [
- { name: "_account", internalType: "address", type: "address" },
- { name: "_courtID", internalType: "uint96", type: "uint96" },
- { name: "_newStake", internalType: "uint256", type: "uint256" },
- ],
- name: "setStakeBySortitionModule",
- outputs: [],
- stateMutability: "nonpayable",
- },
- {
- type: "function",
- inputs: [],
- name: "sortitionModule",
- outputs: [{ name: "", internalType: "contract ISortitionModule", type: "address" }],
- stateMutability: "view",
- },
- {
- type: "function",
- inputs: [
- { name: "_account", internalType: "address", type: "address" },
- { name: "_amount", internalType: "uint256", type: "uint256" },
- ],
- name: "transferBySortitionModule",
- outputs: [],
- stateMutability: "nonpayable",
- },
- {
- type: "function",
- inputs: [],
- name: "unpause",
- outputs: [],
- stateMutability: "nonpayable",
- },
- {
- type: "function",
- inputs: [
- { name: "newImplementation", internalType: "address", type: "address" },
- { name: "data", internalType: "bytes", type: "bytes" },
- ],
- name: "upgradeToAndCall",
- outputs: [],
- stateMutability: "payable",
- },
- {
- type: "function",
- inputs: [],
- name: "version",
- outputs: [{ name: "", internalType: "string", type: "string" }],
- stateMutability: "view",
- },
- {
- type: "function",
- inputs: [],
- name: "wNative",
- outputs: [{ name: "", internalType: "address", type: "address" }],
- stateMutability: "view",
- },
-] as const;
-
-/**
- * [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0xC1210493804eEF123096F9581Ee82B915150E54c)
- */
-export const klerosCoreNeoImplementationAddress = {
- 42161: "0xC1210493804eEF123096F9581Ee82B915150E54c",
-} as const;
-
-/**
- * [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0xC1210493804eEF123096F9581Ee82B915150E54c)
- */
-export const klerosCoreNeoImplementationConfig = {
- address: klerosCoreNeoImplementationAddress,
- abi: klerosCoreNeoImplementationAbi,
-} as const;
-
-//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// KlerosCoreNeo_Proxy
-//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-/**
- * [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0x991d2df165670b9cac3B022f4B68D65b664222ea)
- */
-export const klerosCoreNeoProxyAbi = [
- {
- type: "constructor",
- inputs: [
- { name: "_implementation", internalType: "address", type: "address" },
- { name: "_data", internalType: "bytes", type: "bytes" },
+ { name: "_implementation", internalType: "address", type: "address" },
+ { name: "_data", internalType: "bytes", type: "bytes" },
],
stateMutability: "nonpayable",
},
- { type: "fallback", stateMutability: "payable" },
- { type: "receive", stateMutability: "payable" },
] as const;
/**
- * [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0x991d2df165670b9cac3B022f4B68D65b664222ea)
+ * [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0xc0169e0B19aE02ac4fADD689260CF038726DFE13)
*/
-export const klerosCoreNeoProxyAddress = {
- 42161: "0x991d2df165670b9cac3B022f4B68D65b664222ea",
+export const klerosCoreRulerAddress = {
+ 42161: "0xc0169e0B19aE02ac4fADD689260CF038726DFE13",
} as const;
/**
- * [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0x991d2df165670b9cac3B022f4B68D65b664222ea)
+ * [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0xc0169e0B19aE02ac4fADD689260CF038726DFE13)
*/
-export const klerosCoreNeoProxyConfig = {
- address: klerosCoreNeoProxyAddress,
- abi: klerosCoreNeoProxyAbi,
+export const klerosCoreRulerConfig = {
+ address: klerosCoreRulerAddress,
+ abi: klerosCoreRulerAbi,
} as const;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// KlerosCoreRulerNeo
+// KlerosCoreRuler_Implementation
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
- * [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0xc0169e0B19aE02ac4fADD689260CF038726DFE13)
+ * [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0x85093b5EDa4F2e2E2fEDae34Da91239D6a08e324)
*/
-export const klerosCoreRulerNeoAbi = [
- { type: "fallback", stateMutability: "payable" },
- { type: "receive", stateMutability: "payable" },
+export const klerosCoreRulerImplementationAbi = [
+ { type: "constructor", inputs: [], stateMutability: "nonpayable" },
{ type: "error", inputs: [], name: "AlreadyInitialized" },
{ type: "error", inputs: [], name: "AppealFeesNotEnough" },
{ type: "error", inputs: [], name: "ArbitrationFeesNotEnough" },
@@ -12022,6 +11771,31 @@ export const klerosCoreRulerNeoAbi = [
outputs: [],
stateMutability: "payable",
},
+] as const;
+
+/**
+ * [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0x85093b5EDa4F2e2E2fEDae34Da91239D6a08e324)
+ */
+export const klerosCoreRulerImplementationAddress = {
+ 42161: "0x85093b5EDa4F2e2E2fEDae34Da91239D6a08e324",
+} as const;
+
+/**
+ * [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0x85093b5EDa4F2e2E2fEDae34Da91239D6a08e324)
+ */
+export const klerosCoreRulerImplementationConfig = {
+ address: klerosCoreRulerImplementationAddress,
+ abi: klerosCoreRulerImplementationAbi,
+} as const;
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// KlerosCoreRuler_Proxy
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0xc0169e0B19aE02ac4fADD689260CF038726DFE13)
+ */
+export const klerosCoreRulerProxyAbi = [
{
type: "constructor",
inputs: [
@@ -12030,50 +11804,161 @@ export const klerosCoreRulerNeoAbi = [
],
stateMutability: "nonpayable",
},
+ { type: "fallback", stateMutability: "payable" },
+ { type: "receive", stateMutability: "payable" },
] as const;
/**
* [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0xc0169e0B19aE02ac4fADD689260CF038726DFE13)
*/
-export const klerosCoreRulerNeoAddress = {
+export const klerosCoreRulerProxyAddress = {
42161: "0xc0169e0B19aE02ac4fADD689260CF038726DFE13",
} as const;
/**
* [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0xc0169e0B19aE02ac4fADD689260CF038726DFE13)
*/
-export const klerosCoreRulerNeoConfig = {
- address: klerosCoreRulerNeoAddress,
- abi: klerosCoreRulerNeoAbi,
+export const klerosCoreRulerProxyConfig = {
+ address: klerosCoreRulerProxyAddress,
+ abi: klerosCoreRulerProxyAbi,
} as const;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// KlerosCoreRulerNeo_Implementation
+// KlerosCoreSnapshotProxy
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
- * [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0x85093b5EDa4F2e2E2fEDae34Da91239D6a08e324)
+ * [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0xEF719a5B3352F607e6C4E17b7e0cDAd8322fEC95)
+ */
+export const klerosCoreSnapshotProxyAbi = [
+ {
+ type: "constructor",
+ inputs: [
+ { name: "_governor", internalType: "address", type: "address" },
+ { name: "_core", internalType: "contract IKlerosCore", type: "address" },
+ ],
+ stateMutability: "nonpayable",
+ },
+ {
+ type: "function",
+ inputs: [{ name: "_account", internalType: "address", type: "address" }],
+ name: "balanceOf",
+ outputs: [{ name: "totalStaked", internalType: "uint256", type: "uint256" }],
+ stateMutability: "view",
+ },
+ {
+ type: "function",
+ inputs: [{ name: "_core", internalType: "contract IKlerosCore", type: "address" }],
+ name: "changeCore",
+ outputs: [],
+ stateMutability: "nonpayable",
+ },
+ {
+ type: "function",
+ inputs: [{ name: "_governor", internalType: "address", type: "address" }],
+ name: "changeGovernor",
+ outputs: [],
+ stateMutability: "nonpayable",
+ },
+ {
+ type: "function",
+ inputs: [],
+ name: "core",
+ outputs: [{ name: "", internalType: "contract IKlerosCore", type: "address" }],
+ stateMutability: "view",
+ },
+ {
+ type: "function",
+ inputs: [],
+ name: "decimals",
+ outputs: [{ name: "", internalType: "uint8", type: "uint8" }],
+ stateMutability: "view",
+ },
+ {
+ type: "function",
+ inputs: [],
+ name: "governor",
+ outputs: [{ name: "", internalType: "address", type: "address" }],
+ stateMutability: "view",
+ },
+ {
+ type: "function",
+ inputs: [],
+ name: "name",
+ outputs: [{ name: "", internalType: "string", type: "string" }],
+ stateMutability: "view",
+ },
+ {
+ type: "function",
+ inputs: [],
+ name: "symbol",
+ outputs: [{ name: "", internalType: "string", type: "string" }],
+ stateMutability: "view",
+ },
+] as const;
+
+/**
+ * [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0xEF719a5B3352F607e6C4E17b7e0cDAd8322fEC95)
+ */
+export const klerosCoreSnapshotProxyAddress = {
+ 42161: "0xEF719a5B3352F607e6C4E17b7e0cDAd8322fEC95",
+} as const;
+
+/**
+ * [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0xEF719a5B3352F607e6C4E17b7e0cDAd8322fEC95)
+ */
+export const klerosCoreSnapshotProxyConfig = {
+ address: klerosCoreSnapshotProxyAddress,
+ abi: klerosCoreSnapshotProxyAbi,
+} as const;
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// KlerosCore_Implementation
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0xC1210493804eEF123096F9581Ee82B915150E54c)
*/
-export const klerosCoreRulerNeoImplementationAbi = [
+export const klerosCoreImplementationAbi = [
{ type: "constructor", inputs: [], stateMutability: "nonpayable" },
{ type: "error", inputs: [], name: "AlreadyInitialized" },
{ type: "error", inputs: [], name: "AppealFeesNotEnough" },
+ { type: "error", inputs: [], name: "AppealPeriodNotPassed" },
+ { type: "error", inputs: [], name: "ArbitrableNotWhitelisted" },
{ type: "error", inputs: [], name: "ArbitrationFeesNotEnough" },
+ { type: "error", inputs: [], name: "CannotDisableClassicDK" },
+ { type: "error", inputs: [], name: "CommitPeriodNotPassed" },
+ { type: "error", inputs: [], name: "DisputeKitNotSupportedByCourt" },
+ { type: "error", inputs: [], name: "DisputeKitOnly" },
{ type: "error", inputs: [], name: "DisputeNotAppealable" },
+ { type: "error", inputs: [], name: "DisputePeriodIsFinal" },
+ { type: "error", inputs: [], name: "DisputeStillDrawing" },
+ { type: "error", inputs: [], name: "EvidenceNotPassedAndNotAppeal" },
{ type: "error", inputs: [], name: "FailedDelegateCall" },
{ type: "error", inputs: [], name: "GovernorOnly" },
- { type: "error", inputs: [], name: "GovernorOrInstructorOnly" },
+ { type: "error", inputs: [], name: "GuardianOrGovernorOnly" },
+ { type: "error", inputs: [], name: "InvalidDisputKitParent" },
{ type: "error", inputs: [], name: "InvalidForkingCourtAsParent" },
{
type: "error",
inputs: [{ name: "implementation", internalType: "address", type: "address" }],
name: "InvalidImplementation",
},
- { type: "error", inputs: [], name: "NoRulerSet" },
+ { type: "error", inputs: [], name: "MinStakeLowerThanParentCourt" },
+ { type: "error", inputs: [], name: "MustSupportDisputeKitClassic" },
+ { type: "error", inputs: [], name: "NotEligibleForStaking" },
+ { type: "error", inputs: [], name: "NotEvidencePeriod" },
+ { type: "error", inputs: [], name: "NotExecutionPeriod" },
{ type: "error", inputs: [], name: "NotInitializing" },
- { type: "error", inputs: [], name: "RulerOnly" },
{ type: "error", inputs: [], name: "RulingAlreadyExecuted" },
- { type: "error", inputs: [], name: "RulingModeNotSet" },
+ { type: "error", inputs: [], name: "SortitionModuleOnly" },
+ { type: "error", inputs: [], name: "StakingInTooManyCourts" },
+ { type: "error", inputs: [], name: "StakingLessThanCourtMinStake" },
+ { type: "error", inputs: [], name: "StakingMoreThanMaxStakePerJuror" },
+ { type: "error", inputs: [], name: "StakingMoreThanMaxTotalStaked" },
+ { type: "error", inputs: [], name: "StakingNotPossibleInThisCourt" },
+ { type: "error", inputs: [], name: "StakingTransferFailed" },
+ { type: "error", inputs: [], name: "StakingZeroWhenNoStake" },
{ type: "error", inputs: [], name: "TokenNotAccepted" },
{ type: "error", inputs: [], name: "TransferFailed" },
{ type: "error", inputs: [], name: "UUPSUnauthorizedCallContext" },
@@ -12082,7 +11967,13 @@ export const klerosCoreRulerNeoImplementationAbi = [
inputs: [{ name: "slot", internalType: "bytes32", type: "bytes32" }],
name: "UUPSUnsupportedProxiableUUID",
},
+ { type: "error", inputs: [], name: "UnstakingTransferFailed" },
{ type: "error", inputs: [], name: "UnsuccessfulCall" },
+ { type: "error", inputs: [], name: "UnsupportedDisputeKit" },
+ { type: "error", inputs: [], name: "VotePeriodNotPassed" },
+ { type: "error", inputs: [], name: "WhenNotPausedOnly" },
+ { type: "error", inputs: [], name: "WhenPausedOnly" },
+ { type: "error", inputs: [], name: "WrongDisputeKitIndex" },
{
type: "event",
anonymous: false,
@@ -12140,60 +12031,22 @@ export const klerosCoreRulerNeoImplementationAbi = [
anonymous: false,
inputs: [
{
- name: "_arbitrable",
- internalType: "contract IArbitrableV2",
- type: "address",
+ name: "_courtID",
+ internalType: "uint96",
+ type: "uint96",
indexed: true,
},
{
- name: "mode",
- internalType: "enum KlerosCoreRuler.RulingMode",
- type: "uint8",
+ name: "_parent",
+ internalType: "uint96",
+ type: "uint96",
indexed: true,
},
{
- name: "_disputeID",
- internalType: "uint256",
- type: "uint256",
- indexed: true,
- },
- {
- name: "_ruling",
- internalType: "uint256",
- type: "uint256",
- indexed: false,
- },
- { name: "tied", internalType: "bool", type: "bool", indexed: false },
- {
- name: "overridden",
- internalType: "bool",
- type: "bool",
- indexed: false,
- },
- ],
- name: "AutoRuled",
- },
- {
- type: "event",
- anonymous: false,
- inputs: [
- {
- name: "_courtID",
- internalType: "uint256",
- type: "uint256",
- indexed: true,
- },
- {
- name: "_parent",
- internalType: "uint96",
- type: "uint96",
- indexed: true,
- },
- {
- name: "_hiddenVotes",
- internalType: "bool",
- type: "bool",
- indexed: false,
+ name: "_hiddenVotes",
+ internalType: "bool",
+ type: "bool",
+ indexed: false,
},
{
name: "_minStake",
@@ -12225,6 +12078,12 @@ export const klerosCoreRulerNeoImplementationAbi = [
type: "uint256[4]",
indexed: false,
},
+ {
+ name: "_supportedDisputeKits",
+ internalType: "uint256[]",
+ type: "uint256[]",
+ indexed: false,
+ },
],
name: "CourtCreated",
},
@@ -12327,6 +12186,107 @@ export const klerosCoreRulerNeoImplementationAbi = [
],
name: "DisputeCreation",
},
+ {
+ type: "event",
+ anonymous: false,
+ inputs: [
+ {
+ name: "_disputeKitID",
+ internalType: "uint256",
+ type: "uint256",
+ indexed: true,
+ },
+ {
+ name: "_disputeKitAddress",
+ internalType: "contract IDisputeKit",
+ type: "address",
+ indexed: true,
+ },
+ ],
+ name: "DisputeKitCreated",
+ },
+ {
+ type: "event",
+ anonymous: false,
+ inputs: [
+ {
+ name: "_courtID",
+ internalType: "uint96",
+ type: "uint96",
+ indexed: true,
+ },
+ {
+ name: "_disputeKitID",
+ internalType: "uint256",
+ type: "uint256",
+ indexed: true,
+ },
+ { name: "_enable", internalType: "bool", type: "bool", indexed: true },
+ ],
+ name: "DisputeKitEnabled",
+ },
+ {
+ type: "event",
+ anonymous: false,
+ inputs: [
+ {
+ name: "_disputeID",
+ internalType: "uint256",
+ type: "uint256",
+ indexed: true,
+ },
+ {
+ name: "_roundID",
+ internalType: "uint256",
+ type: "uint256",
+ indexed: true,
+ },
+ {
+ name: "_fromDisputeKitID",
+ internalType: "uint256",
+ type: "uint256",
+ indexed: true,
+ },
+ {
+ name: "_toDisputeKitID",
+ internalType: "uint256",
+ type: "uint256",
+ indexed: false,
+ },
+ ],
+ name: "DisputeKitJump",
+ },
+ {
+ type: "event",
+ anonymous: false,
+ inputs: [
+ {
+ name: "_address",
+ internalType: "address",
+ type: "address",
+ indexed: true,
+ },
+ {
+ name: "_disputeID",
+ internalType: "uint256",
+ type: "uint256",
+ indexed: true,
+ },
+ {
+ name: "_roundID",
+ internalType: "uint256",
+ type: "uint256",
+ indexed: false,
+ },
+ {
+ name: "_voteID",
+ internalType: "uint256",
+ type: "uint256",
+ indexed: false,
+ },
+ ],
+ name: "Draw",
+ },
{
type: "event",
anonymous: false,
@@ -12414,67 +12374,14 @@ export const klerosCoreRulerNeoImplementationAbi = [
},
{
name: "_period",
- internalType: "enum KlerosCoreRuler.Period",
+ internalType: "enum KlerosCoreBase.Period",
type: "uint8",
indexed: false,
},
],
name: "NewPeriod",
},
- {
- type: "event",
- anonymous: false,
- inputs: [
- {
- name: "_arbitrable",
- internalType: "contract IArbitrableV2",
- type: "address",
- indexed: true,
- },
- {
- name: "_oldRuler",
- internalType: "address",
- type: "address",
- indexed: true,
- },
- {
- name: "_newRuler",
- internalType: "address",
- type: "address",
- indexed: true,
- },
- ],
- name: "RulerChanged",
- },
- {
- type: "event",
- anonymous: false,
- inputs: [
- {
- name: "_arbitrable",
- internalType: "contract IArbitrableV2",
- type: "address",
- indexed: true,
- },
- {
- name: "_settings",
- internalType: "struct KlerosCoreRuler.RulerSettings",
- type: "tuple",
- components: [
- {
- name: "rulingMode",
- internalType: "enum KlerosCoreRuler.RulingMode",
- type: "uint8",
- },
- { name: "presetRuling", internalType: "uint256", type: "uint256" },
- { name: "presetTied", internalType: "bool", type: "bool" },
- { name: "presetOverridden", internalType: "bool", type: "bool" },
- ],
- indexed: false,
- },
- ],
- name: "RulerSettingsChanged",
- },
+ { type: "event", anonymous: false, inputs: [], name: "Paused" },
{
type: "event",
anonymous: false,
@@ -12549,6 +12456,7 @@ export const klerosCoreRulerNeoImplementationAbi = [
],
name: "TokenAndETHShift",
},
+ { type: "event", anonymous: false, inputs: [], name: "Unpaused" },
{
type: "event",
anonymous: false,
@@ -12562,13 +12470,25 @@ export const klerosCoreRulerNeoImplementationAbi = [
],
name: "Upgraded",
},
+ {
+ type: "function",
+ inputs: [
+ {
+ name: "_disputeKitAddress",
+ internalType: "contract IDisputeKit",
+ type: "address",
+ },
+ ],
+ name: "addNewDisputeKit",
+ outputs: [],
+ stateMutability: "nonpayable",
+ },
{
type: "function",
inputs: [
{ name: "_disputeID", internalType: "uint256", type: "uint256" },
{ name: "_numberOfChoices", internalType: "uint256", type: "uint256" },
- { name: "", internalType: "bytes", type: "bytes" },
- { name: "_jump", internalType: "bool", type: "bool" },
+ { name: "_extraData", internalType: "bytes", type: "bytes" },
],
name: "appeal",
outputs: [],
@@ -12576,14 +12496,28 @@ export const klerosCoreRulerNeoImplementationAbi = [
},
{
type: "function",
- inputs: [
- { name: "_disputeID", internalType: "uint256", type: "uint256" },
- { name: "_jump", internalType: "bool", type: "bool" },
- ],
+ inputs: [{ name: "_disputeID", internalType: "uint256", type: "uint256" }],
name: "appealCost",
outputs: [{ name: "cost", internalType: "uint256", type: "uint256" }],
stateMutability: "view",
},
+ {
+ type: "function",
+ inputs: [{ name: "_disputeID", internalType: "uint256", type: "uint256" }],
+ name: "appealPeriod",
+ outputs: [
+ { name: "start", internalType: "uint256", type: "uint256" },
+ { name: "end", internalType: "uint256", type: "uint256" },
+ ],
+ stateMutability: "view",
+ },
+ {
+ type: "function",
+ inputs: [{ name: "", internalType: "address", type: "address" }],
+ name: "arbitrableWhitelist",
+ outputs: [{ name: "", internalType: "bool", type: "bool" }],
+ stateMutability: "view",
+ },
{
type: "function",
inputs: [
@@ -12611,6 +12545,16 @@ export const klerosCoreRulerNeoImplementationAbi = [
outputs: [],
stateMutability: "nonpayable",
},
+ {
+ type: "function",
+ inputs: [
+ { name: "_arbitrable", internalType: "address", type: "address" },
+ { name: "_allowed", internalType: "bool", type: "bool" },
+ ],
+ name: "changeArbitrableWhitelist",
+ outputs: [],
+ stateMutability: "nonpayable",
+ },
{
type: "function",
inputs: [
@@ -12650,22 +12594,15 @@ export const klerosCoreRulerNeoImplementationAbi = [
},
{
type: "function",
- inputs: [{ name: "_pinakion", internalType: "contract IERC20", type: "address" }],
- name: "changePinakion",
+ inputs: [{ name: "_guardian", internalType: "address", type: "address" }],
+ name: "changeGuardian",
outputs: [],
stateMutability: "nonpayable",
},
{
type: "function",
- inputs: [
- {
- name: "_arbitrable",
- internalType: "contract IArbitrableV2",
- type: "address",
- },
- { name: "_newRuler", internalType: "address", type: "address" },
- ],
- name: "changeRuler",
+ inputs: [{ name: "_jurorNft", internalType: "contract IERC721", type: "address" }],
+ name: "changeJurorNft",
outputs: [],
stateMutability: "nonpayable",
},
@@ -12673,28 +12610,19 @@ export const klerosCoreRulerNeoImplementationAbi = [
type: "function",
inputs: [
{
- name: "_arbitrable",
- internalType: "contract IArbitrableV2",
+ name: "_jurorProsecutionModule",
+ internalType: "address",
type: "address",
},
- { name: "_presetRuling", internalType: "uint256", type: "uint256" },
- { name: "_presetTied", internalType: "bool", type: "bool" },
- { name: "_presetOverridden", internalType: "bool", type: "bool" },
],
- name: "changeRulingModeToAutomaticPreset",
+ name: "changeJurorProsecutionModule",
outputs: [],
stateMutability: "nonpayable",
},
{
type: "function",
- inputs: [
- {
- name: "_arbitrable",
- internalType: "contract IArbitrableV2",
- type: "address",
- },
- ],
- name: "changeRulingModeToAutomaticRandom",
+ inputs: [{ name: "_pinakion", internalType: "contract IERC20", type: "address" }],
+ name: "changePinakion",
outputs: [],
stateMutability: "nonpayable",
},
@@ -12702,12 +12630,12 @@ export const klerosCoreRulerNeoImplementationAbi = [
type: "function",
inputs: [
{
- name: "_arbitrable",
- internalType: "contract IArbitrableV2",
+ name: "_sortitionModule",
+ internalType: "contract ISortitionModule",
type: "address",
},
],
- name: "changeRulingModeToManual",
+ name: "changeSortitionModule",
outputs: [],
stateMutability: "nonpayable",
},
@@ -12750,6 +12678,12 @@ export const klerosCoreRulerNeoImplementationAbi = [
internalType: "uint256[4]",
type: "uint256[4]",
},
+ { name: "_sortitionExtraData", internalType: "bytes", type: "bytes" },
+ {
+ name: "_supportedDisputeKits",
+ internalType: "uint256[]",
+ type: "uint256[]",
+ },
],
name: "createCourt",
outputs: [],
@@ -12799,6 +12733,13 @@ export const klerosCoreRulerNeoImplementationAbi = [
],
stateMutability: "view",
},
+ {
+ type: "function",
+ inputs: [{ name: "", internalType: "uint256", type: "uint256" }],
+ name: "disputeKits",
+ outputs: [{ name: "", internalType: "contract IDisputeKit", type: "address" }],
+ stateMutability: "view",
+ },
{
type: "function",
inputs: [{ name: "", internalType: "uint256", type: "uint256" }],
@@ -12812,18 +12753,41 @@ export const klerosCoreRulerNeoImplementationAbi = [
},
{
name: "period",
- internalType: "enum KlerosCoreRuler.Period",
+ internalType: "enum KlerosCoreBase.Period",
type: "uint8",
},
{ name: "ruled", internalType: "bool", type: "bool" },
+ { name: "lastPeriodChange", internalType: "uint256", type: "uint256" },
],
stateMutability: "view",
},
+ {
+ type: "function",
+ inputs: [
+ { name: "_disputeID", internalType: "uint256", type: "uint256" },
+ { name: "_iterations", internalType: "uint256", type: "uint256" },
+ ],
+ name: "draw",
+ outputs: [{ name: "nbDrawnJurors", internalType: "uint256", type: "uint256" }],
+ stateMutability: "nonpayable",
+ },
+ {
+ type: "function",
+ inputs: [
+ { name: "_courtID", internalType: "uint96", type: "uint96" },
+ { name: "_disputeKitIDs", internalType: "uint256[]", type: "uint256[]" },
+ { name: "_enable", internalType: "bool", type: "bool" },
+ ],
+ name: "enableDisputeKits",
+ outputs: [],
+ stateMutability: "nonpayable",
+ },
{
type: "function",
inputs: [
{ name: "_disputeID", internalType: "uint256", type: "uint256" },
{ name: "_round", internalType: "uint256", type: "uint256" },
+ { name: "_iterations", internalType: "uint256", type: "uint256" },
],
name: "execute",
outputs: [],
@@ -12842,12 +12806,7 @@ export const klerosCoreRulerNeoImplementationAbi = [
},
{
type: "function",
- inputs: [
- { name: "_disputeID", internalType: "uint256", type: "uint256" },
- { name: "_ruling", internalType: "uint256", type: "uint256" },
- { name: "tied", internalType: "bool", type: "bool" },
- { name: "overridden", internalType: "bool", type: "bool" },
- ],
+ inputs: [{ name: "_disputeID", internalType: "uint256", type: "uint256" }],
name: "executeRuling",
outputs: [],
stateMutability: "nonpayable",
@@ -12855,7 +12814,7 @@ export const klerosCoreRulerNeoImplementationAbi = [
{
type: "function",
inputs: [],
- name: "getNextDisputeID",
+ name: "getDisputeKitsLength",
outputs: [{ name: "", internalType: "uint256", type: "uint256" }],
stateMutability: "view",
},
@@ -12873,6 +12832,16 @@ export const klerosCoreRulerNeoImplementationAbi = [
outputs: [{ name: "", internalType: "uint256", type: "uint256" }],
stateMutability: "view",
},
+ {
+ type: "function",
+ inputs: [
+ { name: "_disputeID", internalType: "uint256", type: "uint256" },
+ { name: "_round", internalType: "uint256", type: "uint256" },
+ ],
+ name: "getPnkAtStakePerJuror",
+ outputs: [{ name: "", internalType: "uint256", type: "uint256" }],
+ stateMutability: "view",
+ },
{
type: "function",
inputs: [
@@ -12883,24 +12852,40 @@ export const klerosCoreRulerNeoImplementationAbi = [
outputs: [
{
name: "",
- internalType: "struct KlerosCoreRuler.Round",
+ internalType: "struct KlerosCoreBase.Round",
type: "tuple",
components: [
+ { name: "disputeKitID", internalType: "uint256", type: "uint256" },
+ {
+ name: "pnkAtStakePerJuror",
+ internalType: "uint256",
+ type: "uint256",
+ },
{
name: "totalFeesForJurors",
internalType: "uint256",
type: "uint256",
},
+ { name: "nbVotes", internalType: "uint256", type: "uint256" },
+ { name: "repartitions", internalType: "uint256", type: "uint256" },
+ { name: "pnkPenalties", internalType: "uint256", type: "uint256" },
+ { name: "drawnJurors", internalType: "address[]", type: "address[]" },
{
name: "sumFeeRewardPaid",
internalType: "uint256",
type: "uint256",
},
+ {
+ name: "sumPnkRewardPaid",
+ internalType: "uint256",
+ type: "uint256",
+ },
{
name: "feeToken",
internalType: "contract IERC20",
type: "address",
},
+ { name: "drawIterations", internalType: "uint256", type: "uint256" },
],
},
],
@@ -12926,230 +12911,245 @@ export const klerosCoreRulerNeoImplementationAbi = [
outputs: [{ name: "", internalType: "address", type: "address" }],
stateMutability: "view",
},
+ {
+ type: "function",
+ inputs: [],
+ name: "guardian",
+ outputs: [{ name: "", internalType: "address", type: "address" }],
+ stateMutability: "view",
+ },
{
type: "function",
inputs: [
{ name: "_governor", internalType: "address", type: "address" },
+ { name: "_guardian", internalType: "address", type: "address" },
{ name: "_pinakion", internalType: "contract IERC20", type: "address" },
+ {
+ name: "_jurorProsecutionModule",
+ internalType: "address",
+ type: "address",
+ },
+ {
+ name: "_disputeKit",
+ internalType: "contract IDisputeKit",
+ type: "address",
+ },
+ { name: "_hiddenVotes", internalType: "bool", type: "bool" },
{
name: "_courtParameters",
internalType: "uint256[4]",
type: "uint256[4]",
},
+ {
+ name: "_timesPerPeriod",
+ internalType: "uint256[4]",
+ type: "uint256[4]",
+ },
+ { name: "_sortitionExtraData", internalType: "bytes", type: "bytes" },
+ {
+ name: "_sortitionModuleAddress",
+ internalType: "contract ISortitionModule",
+ type: "address",
+ },
+ { name: "_jurorNft", internalType: "contract IERC721", type: "address" },
+ { name: "_wNative", internalType: "address", type: "address" },
],
name: "initialize",
outputs: [],
stateMutability: "nonpayable",
},
+ {
+ type: "function",
+ inputs: [{ name: "_disputeID", internalType: "uint256", type: "uint256" }],
+ name: "isDisputeKitJumping",
+ outputs: [{ name: "", internalType: "bool", type: "bool" }],
+ stateMutability: "view",
+ },
+ {
+ type: "function",
+ inputs: [
+ { name: "_courtID", internalType: "uint96", type: "uint96" },
+ { name: "_disputeKitID", internalType: "uint256", type: "uint256" },
+ ],
+ name: "isSupported",
+ outputs: [{ name: "", internalType: "bool", type: "bool" }],
+ stateMutability: "view",
+ },
{
type: "function",
inputs: [],
- name: "pinakion",
- outputs: [{ name: "", internalType: "contract IERC20", type: "address" }],
+ name: "jurorNft",
+ outputs: [{ name: "", internalType: "contract IERC721", type: "address" }],
stateMutability: "view",
},
{
type: "function",
inputs: [],
- name: "proxiableUUID",
- outputs: [{ name: "", internalType: "bytes32", type: "bytes32" }],
+ name: "jurorProsecutionModule",
+ outputs: [{ name: "", internalType: "address", type: "address" }],
stateMutability: "view",
},
{
type: "function",
- inputs: [
- {
- name: "arbitrable",
- internalType: "contract IArbitrableV2",
- type: "address",
- },
- ],
- name: "rulers",
- outputs: [{ name: "ruler", internalType: "address", type: "address" }],
+ inputs: [{ name: "_disputeID", internalType: "uint256", type: "uint256" }],
+ name: "passPeriod",
+ outputs: [],
+ stateMutability: "nonpayable",
+ },
+ {
+ type: "function",
+ inputs: [],
+ name: "pause",
+ outputs: [],
+ stateMutability: "nonpayable",
+ },
+ {
+ type: "function",
+ inputs: [],
+ name: "paused",
+ outputs: [{ name: "", internalType: "bool", type: "bool" }],
stateMutability: "view",
},
{
type: "function",
- inputs: [{ name: "disputeID", internalType: "uint256", type: "uint256" }],
- name: "rulingResults",
- outputs: [
- { name: "ruling", internalType: "uint256", type: "uint256" },
- { name: "tied", internalType: "bool", type: "bool" },
- { name: "overridden", internalType: "bool", type: "bool" },
- ],
+ inputs: [],
+ name: "pinakion",
+ outputs: [{ name: "", internalType: "contract IERC20", type: "address" }],
stateMutability: "view",
},
{
type: "function",
- inputs: [
- {
- name: "arbitrable",
- internalType: "contract IArbitrableV2",
- type: "address",
- },
- ],
- name: "settings",
- outputs: [
- {
- name: "rulingMode",
- internalType: "enum KlerosCoreRuler.RulingMode",
- type: "uint8",
- },
- { name: "presetRuling", internalType: "uint256", type: "uint256" },
- { name: "presetTied", internalType: "bool", type: "bool" },
- { name: "presetOverridden", internalType: "bool", type: "bool" },
- ],
+ inputs: [],
+ name: "proxiableUUID",
+ outputs: [{ name: "", internalType: "bytes32", type: "bytes32" }],
stateMutability: "view",
},
{
type: "function",
- inputs: [
- { name: "newImplementation", internalType: "address", type: "address" },
- { name: "data", internalType: "bytes", type: "bytes" },
- ],
- name: "upgradeToAndCall",
+ inputs: [{ name: "_wNative", internalType: "address", type: "address" }],
+ name: "reinitialize",
outputs: [],
- stateMutability: "payable",
+ stateMutability: "nonpayable",
},
-] as const;
-
-/**
- * [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0x85093b5EDa4F2e2E2fEDae34Da91239D6a08e324)
- */
-export const klerosCoreRulerNeoImplementationAddress = {
- 42161: "0x85093b5EDa4F2e2E2fEDae34Da91239D6a08e324",
-} as const;
-
-/**
- * [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0x85093b5EDa4F2e2E2fEDae34Da91239D6a08e324)
- */
-export const klerosCoreRulerNeoImplementationConfig = {
- address: klerosCoreRulerNeoImplementationAddress,
- abi: klerosCoreRulerNeoImplementationAbi,
-} as const;
-
-//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// KlerosCoreRulerNeo_Proxy
-//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-/**
- * [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0xc0169e0B19aE02ac4fADD689260CF038726DFE13)
- */
-export const klerosCoreRulerNeoProxyAbi = [
{
- type: "constructor",
+ type: "function",
inputs: [
- { name: "_implementation", internalType: "address", type: "address" },
- { name: "_data", internalType: "bytes", type: "bytes" },
+ { name: "_courtID", internalType: "uint96", type: "uint96" },
+ { name: "_newStake", internalType: "uint256", type: "uint256" },
],
+ name: "setStake",
+ outputs: [],
stateMutability: "nonpayable",
},
- { type: "fallback", stateMutability: "payable" },
- { type: "receive", stateMutability: "payable" },
-] as const;
-
-/**
- * [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0xc0169e0B19aE02ac4fADD689260CF038726DFE13)
- */
-export const klerosCoreRulerNeoProxyAddress = {
- 42161: "0xc0169e0B19aE02ac4fADD689260CF038726DFE13",
-} as const;
-
-/**
- * [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0xc0169e0B19aE02ac4fADD689260CF038726DFE13)
- */
-export const klerosCoreRulerNeoProxyConfig = {
- address: klerosCoreRulerNeoProxyAddress,
- abi: klerosCoreRulerNeoProxyAbi,
-} as const;
-
-//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// KlerosCoreSnapshotProxy
-//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-/**
- * [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0xEF719a5B3352F607e6C4E17b7e0cDAd8322fEC95)
- */
-export const klerosCoreSnapshotProxyAbi = [
{
- type: "constructor",
+ type: "function",
inputs: [
- { name: "_governor", internalType: "address", type: "address" },
- { name: "_core", internalType: "contract IKlerosCore", type: "address" },
+ { name: "_account", internalType: "address", type: "address" },
+ { name: "_courtID", internalType: "uint96", type: "uint96" },
+ { name: "_newStake", internalType: "uint256", type: "uint256" },
],
+ name: "setStakeBySortitionModule",
+ outputs: [],
stateMutability: "nonpayable",
},
{
type: "function",
- inputs: [{ name: "_account", internalType: "address", type: "address" }],
- name: "balanceOf",
- outputs: [{ name: "totalStaked", internalType: "uint256", type: "uint256" }],
+ inputs: [],
+ name: "sortitionModule",
+ outputs: [{ name: "", internalType: "contract ISortitionModule", type: "address" }],
stateMutability: "view",
},
{
type: "function",
- inputs: [{ name: "_core", internalType: "contract IKlerosCore", type: "address" }],
- name: "changeCore",
+ inputs: [
+ { name: "_account", internalType: "address", type: "address" },
+ { name: "_amount", internalType: "uint256", type: "uint256" },
+ ],
+ name: "transferBySortitionModule",
outputs: [],
stateMutability: "nonpayable",
},
{
type: "function",
- inputs: [{ name: "_governor", internalType: "address", type: "address" }],
- name: "changeGovernor",
+ inputs: [],
+ name: "unpause",
outputs: [],
stateMutability: "nonpayable",
},
{
type: "function",
- inputs: [],
- name: "core",
- outputs: [{ name: "", internalType: "contract IKlerosCore", type: "address" }],
- stateMutability: "view",
+ inputs: [
+ { name: "newImplementation", internalType: "address", type: "address" },
+ { name: "data", internalType: "bytes", type: "bytes" },
+ ],
+ name: "upgradeToAndCall",
+ outputs: [],
+ stateMutability: "payable",
},
{
type: "function",
inputs: [],
- name: "decimals",
- outputs: [{ name: "", internalType: "uint8", type: "uint8" }],
+ name: "version",
+ outputs: [{ name: "", internalType: "string", type: "string" }],
stateMutability: "view",
},
{
type: "function",
inputs: [],
- name: "governor",
+ name: "wNative",
outputs: [{ name: "", internalType: "address", type: "address" }],
stateMutability: "view",
},
+] as const;
+
+/**
+ * [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0xC1210493804eEF123096F9581Ee82B915150E54c)
+ */
+export const klerosCoreImplementationAddress = {
+ 42161: "0xC1210493804eEF123096F9581Ee82B915150E54c",
+} as const;
+
+/**
+ * [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0xC1210493804eEF123096F9581Ee82B915150E54c)
+ */
+export const klerosCoreImplementationConfig = {
+ address: klerosCoreImplementationAddress,
+ abi: klerosCoreImplementationAbi,
+} as const;
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// KlerosCore_Proxy
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0x991d2df165670b9cac3B022f4B68D65b664222ea)
+ */
+export const klerosCoreProxyAbi = [
{
- type: "function",
- inputs: [],
- name: "name",
- outputs: [{ name: "", internalType: "string", type: "string" }],
- stateMutability: "view",
- },
- {
- type: "function",
- inputs: [],
- name: "symbol",
- outputs: [{ name: "", internalType: "string", type: "string" }],
- stateMutability: "view",
+ type: "constructor",
+ inputs: [
+ { name: "_implementation", internalType: "address", type: "address" },
+ { name: "_data", internalType: "bytes", type: "bytes" },
+ ],
+ stateMutability: "nonpayable",
},
+ { type: "fallback", stateMutability: "payable" },
+ { type: "receive", stateMutability: "payable" },
] as const;
/**
- * [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0xEF719a5B3352F607e6C4E17b7e0cDAd8322fEC95)
+ * [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0x991d2df165670b9cac3B022f4B68D65b664222ea)
*/
-export const klerosCoreSnapshotProxyAddress = {
- 42161: "0xEF719a5B3352F607e6C4E17b7e0cDAd8322fEC95",
+export const klerosCoreProxyAddress = {
+ 42161: "0x991d2df165670b9cac3B022f4B68D65b664222ea",
} as const;
/**
- * [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0xEF719a5B3352F607e6C4E17b7e0cDAd8322fEC95)
+ * [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0x991d2df165670b9cac3B022f4B68D65b664222ea)
*/
-export const klerosCoreSnapshotProxyConfig = {
- address: klerosCoreSnapshotProxyAddress,
- abi: klerosCoreSnapshotProxyAbi,
+export const klerosCoreProxyConfig = {
+ address: klerosCoreProxyAddress,
+ abi: klerosCoreProxyAbi,
} as const;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -14783,13 +14783,13 @@ export const randomizerRngProxyConfig = {
} as const;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// SortitionModuleNeo
+// SortitionModule
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0x21A9402aDb818744B296e1d1BE58C804118DC03D)
*/
-export const sortitionModuleNeoAbi = [
+export const sortitionModuleAbi = [
{ type: "fallback", stateMutability: "payable" },
{ type: "receive", stateMutability: "payable" },
{ type: "error", inputs: [], name: "AlreadyInitialized" },
@@ -15405,26 +15405,26 @@ export const sortitionModuleNeoAbi = [
/**
* [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0x21A9402aDb818744B296e1d1BE58C804118DC03D)
*/
-export const sortitionModuleNeoAddress = {
+export const sortitionModuleAddress = {
42161: "0x21A9402aDb818744B296e1d1BE58C804118DC03D",
} as const;
/**
* [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0x21A9402aDb818744B296e1d1BE58C804118DC03D)
*/
-export const sortitionModuleNeoConfig = {
- address: sortitionModuleNeoAddress,
- abi: sortitionModuleNeoAbi,
+export const sortitionModuleConfig = {
+ address: sortitionModuleAddress,
+ abi: sortitionModuleAbi,
} as const;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// SortitionModuleNeo_Implementation
+// SortitionModule_Implementation
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0x3f6D0daeD166b64FCfBb9bc7c9E26423c6C08eEE)
*/
-export const sortitionModuleNeoImplementationAbi = [
+export const sortitionModuleImplementationAbi = [
{ type: "constructor", inputs: [], stateMutability: "nonpayable" },
{ type: "error", inputs: [], name: "AlreadyInitialized" },
{ type: "error", inputs: [], name: "FailedDelegateCall" },
@@ -16031,26 +16031,26 @@ export const sortitionModuleNeoImplementationAbi = [
/**
* [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0x3f6D0daeD166b64FCfBb9bc7c9E26423c6C08eEE)
*/
-export const sortitionModuleNeoImplementationAddress = {
+export const sortitionModuleImplementationAddress = {
42161: "0x3f6D0daeD166b64FCfBb9bc7c9E26423c6C08eEE",
} as const;
/**
* [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0x3f6D0daeD166b64FCfBb9bc7c9E26423c6C08eEE)
*/
-export const sortitionModuleNeoImplementationConfig = {
- address: sortitionModuleNeoImplementationAddress,
- abi: sortitionModuleNeoImplementationAbi,
+export const sortitionModuleImplementationConfig = {
+ address: sortitionModuleImplementationAddress,
+ abi: sortitionModuleImplementationAbi,
} as const;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// SortitionModuleNeo_Proxy
+// SortitionModule_Proxy
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0x21A9402aDb818744B296e1d1BE58C804118DC03D)
*/
-export const sortitionModuleNeoProxyAbi = [
+export const sortitionModuleProxyAbi = [
{
type: "constructor",
inputs: [
@@ -16066,16 +16066,16 @@ export const sortitionModuleNeoProxyAbi = [
/**
* [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0x21A9402aDb818744B296e1d1BE58C804118DC03D)
*/
-export const sortitionModuleNeoProxyAddress = {
+export const sortitionModuleProxyAddress = {
42161: "0x21A9402aDb818744B296e1d1BE58C804118DC03D",
} as const;
/**
* [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0x21A9402aDb818744B296e1d1BE58C804118DC03D)
*/
-export const sortitionModuleNeoProxyConfig = {
- address: sortitionModuleNeoProxyAddress,
- abi: sortitionModuleNeoProxyAbi,
+export const sortitionModuleProxyConfig = {
+ address: sortitionModuleProxyAddress,
+ abi: sortitionModuleProxyAbi,
} as const;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/contracts/deployments/utils.ts b/contracts/deployments/utils.ts
index e2711a377..a876fbd5a 100644
--- a/contracts/deployments/utils.ts
+++ b/contracts/deployments/utils.ts
@@ -10,7 +10,7 @@ export const deployments = {
testnet: {
chainId: arbitrumSepolia.id,
},
- mainnetNeo: {
+ mainnet: {
chainId: arbitrum.id,
},
} as const;
diff --git a/contracts/foundry.toml b/contracts/foundry.toml
index a8c6351ec..7c2d48987 100644
--- a/contracts/foundry.toml
+++ b/contracts/foundry.toml
@@ -1,15 +1,22 @@
[profile.default]
+solc = "0.8.30"
+evm_version = "cancun"
+via_ir = true
+optimizer = true
+optimizer_runs = 10000
+
src = 'src'
out = 'out'
libs = ['../node_modules', 'lib']
+[lint]
+severity = ['high', 'medium']
+
[rpc_endpoints]
arbitrumSepolia = "https://sepolia-rollup.arbitrum.io/rpc"
-arbitrumGoerli = "https://goerli-rollup.arbitrum.io/rpc"
arbitrum = "https://arb1.arbitrum.io/rpc"
sepolia = "https://sepolia.infura.io/v3/${INFURA_API_KEY}"
-goerli = "https://goerli.infura.io/v3/${INFURA_API_KEY}"
mainnet = "https://mainnet.infura.io/v3/${INFURA_API_KEY}"
chiado = "https://rpc.chiado.gnosis.gateway.fm"
gnosischain = "https://rpc.gnosis.gateway.fm"
diff --git a/contracts/hardhat.config.ts b/contracts/hardhat.config.ts
index 75379d0b9..21a62a310 100644
--- a/contracts/hardhat.config.ts
+++ b/contracts/hardhat.config.ts
@@ -15,7 +15,7 @@ import "hardhat-contract-sizer";
import "hardhat-tracer";
require("./scripts/populatePolicyRegistry");
require("./scripts/populateCourts");
-require("./scripts/changeGovernor");
+require("./scripts/changeOwner");
require("./scripts/getDisputeTemplate");
require("./scripts/compareStorageLayout");
require("./scripts/storage-layout");
@@ -26,28 +26,13 @@ const config: HardhatUserConfig = {
solidity: {
compilers: [
{
- version: "0.8.28",
+ version: "0.8.30",
settings: {
- // viaIR: true,
+ evmVersion: "cancun",
+ viaIR: process.env.VIA_IR !== "false", // Defaults to true
optimizer: {
enabled: true,
- runs: 100,
- },
- outputSelection: {
- "*": {
- "*": ["storageLayout"],
- },
- },
- },
- },
- {
- // For Vea
- version: "0.8.24",
- settings: {
- // viaIR: true,
- optimizer: {
- enabled: true,
- runs: 100,
+ runs: 800, // Constrained by the size of the KlerosCore contract
},
outputSelection: {
"*": {
diff --git a/contracts/package.json b/contracts/package.json
index fc719eb7f..4f6014d53 100644
--- a/contracts/package.json
+++ b/contracts/package.json
@@ -1,6 +1,6 @@
{
"name": "@kleros/kleros-v2-contracts",
- "version": "0.11.0",
+ "version": "0.12.0",
"description": "Smart contracts for Kleros version 2",
"main": "./cjs/deployments/index.js",
"module": "./esm/deployments/index.js",
@@ -87,15 +87,13 @@
"watch": "hardhat watch",
"natspec-smells": "natspec-smells",
"docgen": "hardhat docgen",
- "docserve": "scripts/docPreprocess.sh && forge doc --serve",
- "docbuild": "scripts/docPreprocess.sh && forge doc --build --out dist && scripts/docPostprocess.sh",
"populate:courts:devnet": "hardhat populate:courts --from v2_devnet --network arbitrumSepoliaDevnet",
"populate:courts:testnet": "hardhat populate:courts --from v2_testnet --network arbitrumSepolia",
- "populate:courts:mainnetNeo": "hardhat populate:courts --core-type neo --from v2_mainnet_neo --network arbitrum",
- "populate:policiesUris": "scripts/setPoliciesURIs.sh config/policies.v2.{devnet,testnet,mainnet-neo}.json",
+ "populate:courts:mainnet": "hardhat populate:courts --from v2_mainnet --network arbitrum",
+ "populate:policiesUris": "scripts/setPoliciesURIs.sh config/policies.v2.{devnet,testnet,mainnet}.json",
"populate:policies:devnet": "hardhat populate:policy-registry --from v2_devnet --network arbitrumSepoliaDevnet",
"populate:policies:testnet": "hardhat populate:policy-registry --from v2_testnet --network arbitrumSepolia",
- "populate:policies:mainnetNeo": "hardhat populate:policy-registry --from v2_mainnet_neo --network arbitrum",
+ "populate:policies:mainnet": "hardhat populate:policy-registry --from v2_mainnet --network arbitrum",
"release:patch": "scripts/publish.sh patch",
"release:minor": "scripts/publish.sh minor",
"release:major": "scripts/publish.sh major",
@@ -121,7 +119,7 @@
"@types/mocha": "^10.0.10",
"@types/node": "^20.17.6",
"@types/sinon": "^17.0.4",
- "@wagmi/cli": "^2.2.0",
+ "@wagmi/cli": "^2.3.2",
"abitype": "^0.10.3",
"chai": "^4.5.0",
"dotenv": "^16.6.1",
@@ -131,14 +129,14 @@
"gluegun": "^5.2.0",
"graphql": "^16.9.0",
"graphql-request": "^7.1.2",
- "hardhat": "2.25.0",
- "hardhat-contract-sizer": "^2.10.0",
+ "hardhat": "2.26.3",
+ "hardhat-contract-sizer": "^2.10.1",
"hardhat-deploy": "^1.0.4",
"hardhat-deploy-ethers": "^0.4.2",
"hardhat-deploy-tenderly": "^0.2.1",
"hardhat-docgen": "^1.3.0",
"hardhat-gas-reporter": "^2.3.0",
- "hardhat-tracer": "^3.2.1",
+ "hardhat-tracer": "^3.4.0",
"hardhat-watcher": "^2.5.0",
"pino": "^8.21.0",
"pino-pretty": "^10.3.1",
@@ -154,10 +152,17 @@
},
"dependencies": {
"@chainlink/contracts": "^1.4.0",
- "@kleros/vea-contracts": "^0.6.0",
+ "@kleros/vea-contracts": "^0.7.0",
"@openzeppelin/contracts": "^5.4.0",
"@shutter-network/shutter-sdk": "0.0.2",
- "isomorphic-fetch": "^3.0.0",
+ "isomorphic-fetch": "^3.0.0"
+ },
+ "peerDependencies": {
"viem": "^2.24.1"
+ },
+ "peerDependenciesMeta": {
+ "viem": {
+ "optional": false
+ }
}
}
diff --git a/contracts/scripts/changeGovernor.ts b/contracts/scripts/changeGovernor.ts
deleted file mode 100644
index e9a9cd01c..000000000
--- a/contracts/scripts/changeGovernor.ts
+++ /dev/null
@@ -1,77 +0,0 @@
-import { task } from "hardhat/config";
-import { prompt, print } from "gluegun";
-import { Cores, getContracts } from "./utils/contracts";
-import { isAddress } from "viem";
-
-const { bold } = print.colors;
-
-task("change-governor", "Changes the governor for all the contracts")
- .addPositionalParam("newGovernor", "The address of the new governor")
- .addOptionalParam("coreType", "The type of core to use between base, neo, university (default: base)", Cores.BASE)
- .setAction(async (taskArgs, hre) => {
- const newGovernor = taskArgs.newGovernor;
- if (!isAddress(newGovernor)) {
- throw new Error("Invalid governor address provided");
- }
- print.highlight(`💣 Changing governor to ${bold(newGovernor)}`);
-
- const { confirm } = await prompt.ask({
- type: "confirm",
- name: "confirm",
- message: "Are you sure you want to proceed?",
- });
- if (!confirm) {
- console.log("Operation cancelled by user.");
- return;
- }
-
- const coreType = Cores[taskArgs.coreType.toUpperCase() as keyof typeof Cores];
- if (coreType === undefined) {
- console.error("Invalid core type, must be one of base, neo, university");
- return;
- }
- console.log("Using core type %s", coreType);
-
- const {
- core,
- disputeKitClassic,
- disputeResolver,
- disputeTemplateRegistry,
- policyRegistry,
- chainlinkRng,
- randomizerRng,
- snapshotProxy,
- sortition,
- evidence,
- } = await getContracts(hre, coreType);
-
- const updateGovernor = async (contractName: string, contractInstance: any) => {
- print.info(`Changing governor for ${contractName}`);
-
- const spinner = print.spin(`Executing transaction for ${contractName}...`);
- try {
- const tx = await contractInstance.changeGovernor(newGovernor);
- await tx.wait();
- spinner.succeed(`Governor changed for ${contractName}, tx hash: ${tx.hash}`);
- } catch (error) {
- if (error instanceof Error) {
- spinner.fail(`Failed to change governor for ${contractName}: ${error.message}`);
- } else {
- spinner.fail(`Failed to change governor for ${contractName}: ${String(error)}`);
- }
- }
- };
-
- await updateGovernor("KlerosCore", core);
- await updateGovernor("DisputeKitClassic", disputeKitClassic);
- await updateGovernor("DisputeResolver", disputeResolver);
- await updateGovernor("DisputeTemplateRegistry", disputeTemplateRegistry);
- await updateGovernor("PolicyRegistry", policyRegistry);
- await updateGovernor("KlerosCoreSnapshotProxy", snapshotProxy);
- await updateGovernor("SortitionModule", sortition);
- await updateGovernor("EvidenceModule", evidence);
- if (chainlinkRng) await updateGovernor("ChainlinkRNG", chainlinkRng);
- if (randomizerRng) await updateGovernor("RandomizerRNG", randomizerRng);
-
- print.success("Governor changed successfully");
- });
diff --git a/contracts/scripts/changeOwner.ts b/contracts/scripts/changeOwner.ts
new file mode 100644
index 000000000..fcb64137b
--- /dev/null
+++ b/contracts/scripts/changeOwner.ts
@@ -0,0 +1,77 @@
+import { task } from "hardhat/config";
+import { prompt, print } from "gluegun";
+import { Cores, getContracts } from "./utils/contracts";
+import { isAddress } from "viem";
+
+const { bold } = print.colors;
+
+task("change-owner", "Changes the owner for all the contracts")
+ .addPositionalParam("newOwner", "The address of the new owner")
+ .addOptionalParam("coreType", "The type of core to use between base, university (default: base)", Cores.BASE)
+ .setAction(async (taskArgs, hre) => {
+ const newOwner = taskArgs.newOwner;
+ if (!isAddress(newOwner)) {
+ throw new Error("Invalid owner address provided");
+ }
+ print.highlight(`💣 Changing owner to ${bold(newOwner)}`);
+
+ const { confirm } = await prompt.ask({
+ type: "confirm",
+ name: "confirm",
+ message: "Are you sure you want to proceed?",
+ });
+ if (!confirm) {
+ console.log("Operation cancelled by user.");
+ return;
+ }
+
+ const coreType = Cores[taskArgs.coreType.toUpperCase() as keyof typeof Cores];
+ if (coreType === undefined) {
+ console.error("Invalid core type, must be one of base, university");
+ return;
+ }
+ console.log("Using core type %s", coreType);
+
+ const {
+ core,
+ disputeKitClassic,
+ disputeResolver,
+ disputeTemplateRegistry,
+ policyRegistry,
+ chainlinkRng,
+ randomizerRng,
+ snapshotProxy,
+ sortition,
+ evidence,
+ } = await getContracts(hre, coreType);
+
+ const updateOwner = async (contractName: string, contractInstance: any) => {
+ print.info(`Changing owner for ${contractName}`);
+
+ const spinner = print.spin(`Executing transaction for ${contractName}...`);
+ try {
+ const tx = await contractInstance.changeOwner(newOwner);
+ await tx.wait();
+ spinner.succeed(`Owner changed for ${contractName}, tx hash: ${tx.hash}`);
+ } catch (error) {
+ if (error instanceof Error) {
+ spinner.fail(`Failed to change owner for ${contractName}: ${error.message}`);
+ } else {
+ spinner.fail(`Failed to change owner for ${contractName}: ${String(error)}`);
+ }
+ }
+ };
+
+ await updateOwner("KlerosCore", core);
+ await updateOwner("DisputeKitClassic", disputeKitClassic);
+ await updateOwner("DisputeResolver", disputeResolver);
+ await updateOwner("DisputeTemplateRegistry", disputeTemplateRegistry);
+ await updateOwner("PolicyRegistry", policyRegistry);
+ await updateOwner("KlerosCoreSnapshotProxy", snapshotProxy);
+ await updateOwner("SortitionModule", sortition);
+ await updateOwner("EvidenceModule", evidence);
+ if (chainlinkRng) await updateOwner("ChainlinkRNG", chainlinkRng);
+ if (randomizerRng) await updateOwner("RandomizerRNG", randomizerRng);
+
+ print.success("Owner changed successfully");
+ });
diff --git a/contracts/scripts/coverage.sh b/contracts/scripts/coverage.sh
index c228fbae5..9a1fc24eb 100755
--- a/contracts/scripts/coverage.sh
+++ b/contracts/scripts/coverage.sh
@@ -21,6 +21,7 @@ fi
# Generate the Hardhat coverage report
yarn clean
echo "Building contracts with Hardhat..."
+export VIA_IR=false
yarn build
echo "Running Hardhat coverage..."
yarn hardhat coverage --solcoverjs ./.solcover.js --temp artifacts --show-stack-traces --testfiles "test/**/*.ts"
diff --git a/contracts/scripts/disputeRelayerBot.ts b/contracts/scripts/disputeRelayerBot.ts
index 9437bdf52..87848993a 100644
--- a/contracts/scripts/disputeRelayerBot.ts
+++ b/contracts/scripts/disputeRelayerBot.ts
@@ -33,9 +33,9 @@ export default async function main(
homeGatewayArtifact: string,
feeTokenArtifact?: string
) {
- const core = (await ethers.getContract("KlerosCore")) as KlerosCore;
- const homeGateway = (await ethers.getContract(homeGatewayArtifact)) as HomeGateway;
- const feeToken = feeTokenArtifact ? ((await ethers.getContract(feeTokenArtifact)) as TestERC20) : undefined;
+ const core = await ethers.getContract("KlerosCore");
+ const homeGateway = await ethers.getContract(homeGatewayArtifact);
+ const feeToken = feeTokenArtifact ? await ethers.getContract(feeTokenArtifact) : undefined;
const foreignChainProvider = new ethers.providers.JsonRpcProvider(foreignNetwork.url);
const foreignGatewayDeployment = await foreignDeployments.get(foreignGatewayArtifact);
diff --git a/contracts/scripts/generateDeploymentArtifact.sh b/contracts/scripts/generateDeploymentArtifact.sh
index dedcf1c0b..6daf2a585 100755
--- a/contracts/scripts/generateDeploymentArtifact.sh
+++ b/contracts/scripts/generateDeploymentArtifact.sh
@@ -2,7 +2,7 @@
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
-if [[ $# < 2 ]]
+if [[ $# -lt 2 ]]
then
echo "usage: $(basename $0) network address"
exit 1
diff --git a/contracts/scripts/generateDeploymentsMarkdown.sh b/contracts/scripts/generateDeploymentsMarkdown.sh
index 6fa3c2932..5ae9dbf7f 100755
--- a/contracts/scripts/generateDeploymentsMarkdown.sh
+++ b/contracts/scripts/generateDeploymentsMarkdown.sh
@@ -15,6 +15,7 @@ IGNORED_ARTIFACTS=(
function generate() { #deploymentDir #explorerUrl
deploymentDir=$1
explorerUrl=$2
+ # shellcheck disable=SC2068
for f in $(ls -1 $deploymentDir/*.json 2>/dev/null | grep -v ${IGNORED_ARTIFACTS[@]/#/-e } | sort); do
contractName=$(basename $f .json)
address=$(cat $f | jq -r .address)
@@ -28,12 +29,12 @@ function generate() { #deploymentDir #explorerUrl
done
}
-echo "### V2 Neo (prelaunch)"
+echo "### V2 Mainnet"
echo "#### Arbitrum One"
echo
generate "$SCRIPT_DIR/../deployments/arbitrum" "https://arbiscan.io/address/" | grep -v 'DAI\|WETH\|PNKFaucet'
echo
-echo "### Official Testnet"
+echo "### V2 Testnet"
echo "#### Arbitrum Sepolia"
echo
generate "$SCRIPT_DIR/../deployments/arbitrumSepolia" "https://sepolia.arbiscan.io/address/"
@@ -47,7 +48,7 @@ echo
generate "$SCRIPT_DIR/../deployments/chiado" "https://gnosis-chiado.blockscout.com/address/"
echo
-echo "### Devnet"
+echo "### V2 Devnet (unstable)"
echo "#### Arbitrum Sepolia"
echo
generate "$SCRIPT_DIR/../deployments/arbitrumSepoliaDevnet" "https://sepolia.arbiscan.io/address/"
diff --git a/contracts/scripts/generateMetrics.sh b/contracts/scripts/generateMetrics.sh
new file mode 100755
index 000000000..52c56d8f7
--- /dev/null
+++ b/contracts/scripts/generateMetrics.sh
@@ -0,0 +1,24 @@
+#!/usr/bin/env bash
+
+SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
+
+SOURCE_DIR="src"
+
+yarn dlx solidity-code-metrics \
+ "$SOURCE_DIR"/arbitration/KlerosCore* \
+ "$SOURCE_DIR"/arbitration/PolicyRegistry.sol \
+ "$SOURCE_DIR"/arbitration/SortitionModule* \
+ "$SOURCE_DIR"/arbitration/arbitrables/DisputeResolver.sol \
+ "$SOURCE_DIR"/arbitration/DisputeTemplateRegistry.sol \
+ "$SOURCE_DIR"/arbitration/dispute-kits/* \
+ "$SOURCE_DIR"/arbitration/evidence/EvidenceModule.sol \
+ "$SOURCE_DIR"/arbitration/interfaces/* \
+ "$SOURCE_DIR"/libraries/Constants.sol \
+ "$SOURCE_DIR"/libraries/SortitionTrees.sol \
+ "$SOURCE_DIR"/libraries/Safe* \
+ "$SOURCE_DIR"/rng/RNGWithFallback.sol \
+ "$SOURCE_DIR"/rng/ChainlinkRNG.sol \
+ "$SOURCE_DIR"/rng/IRNG.sol \
+ "$SOURCE_DIR"/proxy/UUPSProx* \
+ "$SOURCE_DIR"/proxy/Initializable.sol \
+--html >METRICS.html
diff --git a/contracts/scripts/getDisputeKits.ts b/contracts/scripts/getDisputeKits.ts
new file mode 100644
index 000000000..32f2b18eb
--- /dev/null
+++ b/contracts/scripts/getDisputeKits.ts
@@ -0,0 +1,33 @@
+import { getDisputeKits } from "../deployments/disputeKitsViem";
+import { createPublicClient, http } from "viem";
+import { arbitrumSepolia } from "viem/chains";
+
+const rpc = process.env.ARBITRUM_SEPOLIA_RPC;
+if (!rpc) {
+ throw new Error("ARBITRUM_SEPOLIA_RPC is not set");
+}
+
+const client = createPublicClient({
+ chain: arbitrumSepolia,
+ transport: http(rpc),
+});
+
+async function main() {
+ try {
+ console.log("Fetching DisputeKitCreated events...");
+ const disputeKitResult = await getDisputeKits(client, "devnet");
+ console.log(disputeKitResult);
+ } catch (error) {
+ console.error("Error fetching events:", error);
+ throw error;
+ }
+}
+
+if (require.main === module) {
+ main()
+ .then(() => process.exit(0))
+ .catch((error) => {
+ console.error(error);
+ process.exit(1);
+ });
+}
diff --git a/contracts/scripts/keeperBot.ts b/contracts/scripts/keeperBot.ts
index 593d97e4a..5d1b2751f 100644
--- a/contracts/scripts/keeperBot.ts
+++ b/contracts/scripts/keeperBot.ts
@@ -6,7 +6,6 @@ import {
DisputeKitGatedShutter,
DisputeKitShutter,
SortitionModule,
- SortitionModuleNeo,
} from "../typechain-types";
import env from "./utils/env";
import loggerFactory from "./utils/logger";
@@ -49,7 +48,7 @@ const getContracts = async () => {
throw new Error("University is not supported yet");
}
const contracts = await getContractsForCoreType(hre, coreType);
- return { ...contracts, sortition: contracts.sortition as SortitionModule | SortitionModuleNeo };
+ return { ...contracts, sortition: contracts.sortition as SortitionModule };
};
type Contribution = {
@@ -277,9 +276,7 @@ const isRngReady = async () => {
return true;
}
} else if (currentRng === blockHashRNG?.target && blockHashRNG !== null) {
- const requestBlock = await sortition.randomNumberRequestBlock();
- const lookahead = await sortition.rngLookahead();
- const n = await blockHashRNG.receiveRandomness.staticCall(requestBlock + lookahead);
+ const n = await blockHashRNG.receiveRandomness.staticCall();
if (Number(n) === 0) {
logger.info("BlockHashRNG is NOT ready yet");
return false;
diff --git a/contracts/scripts/keeperBotShutter.ts b/contracts/scripts/keeperBotShutter.ts
index 0b9724cae..fff463513 100644
--- a/contracts/scripts/keeperBotShutter.ts
+++ b/contracts/scripts/keeperBotShutter.ts
@@ -1,6 +1,6 @@
import hre from "hardhat";
import { getBytes } from "ethers";
-import { DisputeKitGatedShutter, DisputeKitShutter, SortitionModule, SortitionModuleNeo } from "../typechain-types";
+import { DisputeKitGatedShutter, DisputeKitShutter } from "../typechain-types";
import { decrypt } from "./shutter";
import env from "./utils/env";
import loggerFactory from "./utils/logger";
@@ -312,8 +312,7 @@ const getContracts = async () => {
if (coreType === Cores.UNIVERSITY) {
throw new Error("University is not supported yet");
}
- const contracts = await getContractsForCoreType(hre, coreType);
- return { ...contracts, sortition: contracts.sortition as SortitionModule | SortitionModuleNeo };
+ return await getContractsForCoreType(hre, coreType);
};
async function main() {
diff --git a/contracts/scripts/populateCourts.ts b/contracts/scripts/populateCourts.ts
index ee95dee71..cf86c9cbb 100644
--- a/contracts/scripts/populateCourts.ts
+++ b/contracts/scripts/populateCourts.ts
@@ -1,11 +1,11 @@
import { task, types } from "hardhat/config";
-import { KlerosCore, KlerosCoreNeo, KlerosCoreUniversity } from "../typechain-types";
+import { KlerosCore, KlerosCoreUniversity } from "../typechain-types";
import { BigNumberish, toBigInt, toNumber } from "ethers";
import courtsV1Mainnet from "../config/courts.v1.mainnet.json";
import courtsV1GnosisChain from "../config/courts.v1.gnosischain.json";
import courtsV2ArbitrumTestnet from "../config/courts.v2.testnet.json";
import courtsV2ArbitrumDevnet from "../config/courts.v2.devnet.json";
-import courtsV2MainnetNeo from "../config/courts.v2.mainnet-neo.json";
+import courtsV2Mainnet from "../config/courts.v2.mainnet.json";
import { isDevnet } from "../deploy/utils";
import { execute, writeTransactionBatch } from "./utils/execution";
import { getContracts, Cores } from "./utils/contracts";
@@ -21,7 +21,7 @@ enum Sources {
V1_GNOSIS,
V2_DEVNET,
V2_TESTNET,
- V2_MAINNET_NEO,
+ V2_MAINNET,
}
type Court = {
@@ -43,7 +43,7 @@ const TEN_THOUSAND_GWEI = 10n ** 13n;
task("populate:courts", "Populates the courts and their parameters")
.addOptionalParam(
"from",
- "The source of the policies between v1_mainnet, v1_gnosis, v2_devnet, v2_testnet, v2_mainnet_neo (default: auto depending on the network)",
+ "The source of the policies between v1_mainnet, v1_gnosis, v2_devnet, v2_testnet, v2_mainnet (default: auto depending on the network)",
undefined
)
.addOptionalParam("start", "The starting index for the courts to populate (default: 0)", 0, types.int)
@@ -53,7 +53,7 @@ task("populate:courts", "Populates the courts and their parameters")
undefined,
types.int
)
- .addOptionalParam("coreType", "The type of core to use between base, neo, university (default: base)", Cores.BASE)
+ .addOptionalParam("coreType", "The type of core to use between base, university (default: base)", Cores.BASE)
.addFlag("reverse", "Iterates the courts in reverse order, useful to increase minStake in the child courts first")
.addFlag("forceV1ParametersToDev", "Use development values for the v1 courts parameters")
.setAction(async (taskArgs, hre) => {
@@ -74,7 +74,7 @@ task("populate:courts", "Populates the courts and their parameters")
if (taskArgs.from) {
from = Sources[taskArgs.from.toUpperCase() as keyof typeof Sources];
if (from === undefined) {
- console.error("Invalid source, must be one of v1_mainnet, v1_gnosis, v2_devnet, v2_testnet, v2_mainnet_neo");
+ console.error("Invalid source, must be one of v1_mainnet, v1_gnosis, v2_devnet, v2_testnet, v2_mainnet");
return;
}
} else {
@@ -84,7 +84,7 @@ task("populate:courts", "Populates the courts and their parameters")
const coreType = Cores[taskArgs.coreType.toUpperCase() as keyof typeof Cores];
if (coreType === undefined) {
- console.error("Invalid core type, must be one of base, neo, university");
+ console.error("Invalid core type, must be one of base, university");
return;
}
console.log("Using core type %s", coreType);
@@ -133,8 +133,8 @@ task("populate:courts", "Populates the courts and their parameters")
courtsV2 = courtsV2ArbitrumTestnet;
break;
}
- case Sources.V2_MAINNET_NEO: {
- courtsV2 = courtsV2MainnetNeo;
+ case Sources.V2_MAINNET: {
+ courtsV2 = courtsV2Mainnet;
break;
}
default:
diff --git a/contracts/scripts/populatePolicyRegistry.ts b/contracts/scripts/populatePolicyRegistry.ts
index 6ffdacd8e..43087268a 100644
--- a/contracts/scripts/populatePolicyRegistry.ts
+++ b/contracts/scripts/populatePolicyRegistry.ts
@@ -4,7 +4,7 @@ import policiesV1Mainnet from "../config/policies.v1.mainnet.json";
import policiesV1GnosisChain from "../config/policies.v1.gnosischain.json";
import policiesV2ArbitrumTestnet from "../config/policies.v2.testnet.json";
import policiesV2ArbitrumDevnet from "../config/policies.v2.devnet.json";
-import policiesV2MainnetNeo from "../config/policies.v2.mainnet-neo.json";
+import policiesV2Mainnet from "../config/policies.v2.mainnet.json";
import { isDevnet } from "../deploy/utils";
import { execute, writeTransactionBatch } from "./utils/execution";
@@ -19,13 +19,13 @@ enum Sources {
V1_GNOSIS,
V2_DEVNET,
V2_TESTNET,
- V2_MAINNET_NEO,
+ V2_MAINNET,
}
task("populate:policy-registry", "Populates the policy registry for each court")
.addOptionalParam(
"from",
- "The source of the policies between v1_mainnet, v1_gnosis, v2_devnet, v2_testnet, v2_mainnet_neo (default: auto depending on the network)",
+ "The source of the policies between v1_mainnet, v1_gnosis, v2_devnet, v2_testnet, v2_mainnet (default: auto depending on the network)",
undefined
)
.addOptionalParam("start", "The starting index for the courts to populate (default: 0)", 0, types.int)
@@ -53,7 +53,7 @@ task("populate:policy-registry", "Populates the policy registry for each court")
if (taskArgs.from) {
from = Sources[taskArgs.from.toUpperCase() as keyof typeof Sources];
if (from === undefined) {
- console.error("Invalid source, must be one of v1_mainnet, v1_gnosis, v2_devnet, v2_testnet, v2_mainnet_neo");
+ console.error("Invalid source, must be one of v1_mainnet, v1_gnosis, v2_devnet, v2_testnet, v2_mainnet");
return;
}
} else {
@@ -88,8 +88,8 @@ task("populate:policy-registry", "Populates the policy registry for each court")
policiesV2 = policiesV2ArbitrumTestnet;
break;
}
- case Sources.V2_MAINNET_NEO: {
- policiesV2 = policiesV2MainnetNeo;
+ case Sources.V2_MAINNET: {
+ policiesV2 = policiesV2Mainnet;
break;
}
default:
diff --git a/contracts/scripts/storage-layout.ts b/contracts/scripts/storage-layout.ts
index 697b7d48f..70cf166e7 100644
--- a/contracts/scripts/storage-layout.ts
+++ b/contracts/scripts/storage-layout.ts
@@ -4,7 +4,7 @@ import { HardhatRuntimeEnvironment } from "hardhat/types";
task("storage-layout", "Prints the storage layout of a contract").setAction(
async ({}, hre: HardhatRuntimeEnvironment) => {
await hre.run("compile");
- const buildInfo = await hre.artifacts.getBuildInfo(`src/arbitration/KlerosCoreNeo.sol:KlerosCoreNeo`);
- console.log(buildInfo.output.contracts["src/arbitration/KlerosCoreNeo.sol"]["KlerosCoreNeo"].storageLayout);
+ const buildInfo = await hre.artifacts.getBuildInfo(`src/arbitration/KlerosCore.sol:KlerosCore`);
+ console.log(buildInfo.output.contracts["src/arbitration/KlerosCore.sol"]["KlerosCore"].storageLayout);
}
);
diff --git a/contracts/scripts/utils/contracts.ts b/contracts/scripts/utils/contracts.ts
index cc7bf2429..fcfb91ac8 100644
--- a/contracts/scripts/utils/contracts.ts
+++ b/contracts/scripts/utils/contracts.ts
@@ -7,13 +7,11 @@ import {
DisputeResolver,
DisputeTemplateRegistry,
KlerosCore,
- KlerosCoreNeo,
KlerosCoreUniversity,
PNK,
PolicyRegistry,
RandomizerRNG,
SortitionModule,
- SortitionModuleNeo,
SortitionModuleUniversity,
TransactionBatcher,
KlerosCoreSnapshotProxy,
@@ -24,28 +22,18 @@ import {
export const Cores = {
BASE: "BASE",
- NEO: "NEO",
UNIVERSITY: "UNIVERSITY",
} as const;
export type Core = (typeof Cores)[keyof typeof Cores];
/**
- * Get contract names by specifying the coreType (BASE, NEO, UNIVERSITY).
+ * Get contract names by specifying the coreType (BASE, UNIVERSITY).
* @param coreType - Core type
* @returns Contract names
*/
export const getContractNames = (coreType: Core) => {
const coreSpecificNames = {
- [Cores.NEO]: {
- core: "KlerosCoreNeo",
- sortition: "SortitionModuleNeo",
- disputeKitClassic: "DisputeKitClassicNeo",
- disputeKitShutter: "DisputeKitShutterNeo",
- disputeKitGated: "DisputeKitGatedNeo",
- disputeKitGatedShutter: "DisputeKitGatedShutterNeo",
- disputeResolver: "DisputeResolverNeo",
- },
[Cores.BASE]: {
core: "KlerosCore",
sortition: "SortitionModule",
@@ -53,6 +41,7 @@ export const getContractNames = (coreType: Core) => {
disputeKitShutter: "DisputeKitShutter",
disputeKitGated: "DisputeKitGated",
disputeKitGatedShutter: "DisputeKitGatedShutter",
+ disputeTemplateRegistry: "DisputeTemplateRegistry",
disputeResolver: "DisputeResolver",
},
[Cores.UNIVERSITY]: {
@@ -62,16 +51,16 @@ export const getContractNames = (coreType: Core) => {
disputeKitShutter: "DisputeKitShutterUniversity",
disputeKitGated: "DisputeKitGatedUniversity",
disputeKitGatedShutter: "DisputeKitGatedShutterUniversity",
+ disputeTemplateRegistry: "DisputeTemplateRegistryUniversity",
disputeResolver: "DisputeResolverUniversity",
},
};
- if (!(coreType in coreSpecificNames)) throw new Error("Invalid core type, must be one of BASE, NEO, or UNIVERSITY");
+ if (!(coreType in coreSpecificNames)) throw new Error("Invalid core type, must be one of BASE, or UNIVERSITY");
return {
...coreSpecificNames[coreType],
evidence: "EvidenceModule",
- disputeTemplateRegistry: "DisputeTemplateRegistry",
policyRegistry: "PolicyRegistry",
batcher: "TransactionBatcher",
chainlinkRng: "ChainlinkRNG",
@@ -83,20 +72,16 @@ export const getContractNames = (coreType: Core) => {
};
/**
- * Get contracts by specifying the coreType (BASE, NEO, UNIVERSITY).
+ * Get contracts by specifying the coreType (BASE, UNIVERSITY).
* @param hre - Hardhat runtime environment
* @param coreType - Core type
* @returns Contracts
*/
export const getContracts = async (hre: HardhatRuntimeEnvironment, coreType: Core) => {
const { ethers } = hre;
- let core: KlerosCore | KlerosCoreNeo | KlerosCoreUniversity;
- let sortition: SortitionModule | SortitionModuleNeo | SortitionModuleUniversity;
+ let core: KlerosCore | KlerosCoreUniversity;
+ let sortition: SortitionModule | SortitionModuleUniversity;
switch (coreType) {
- case Cores.NEO:
- core = await ethers.getContract(getContractNames(coreType).core);
- sortition = await ethers.getContract(getContractNames(coreType).sortition);
- break;
case Cores.BASE:
core = await ethers.getContract(getContractNames(coreType).core);
sortition = await ethers.getContract(getContractNames(coreType).sortition);
@@ -106,7 +91,7 @@ export const getContracts = async (hre: HardhatRuntimeEnvironment, coreType: Cor
sortition = await ethers.getContract(getContractNames(coreType).sortition);
break;
default:
- throw new Error("Invalid core type, must be one of BASE, NEO, or UNIVERSITY");
+ throw new Error("Invalid core type, must be one of BASE, or UNIVERSITY");
}
const disputeKitClassic = await ethers.getContract(getContractNames(coreType).disputeKitClassic);
const disputeKitShutter = await ethers.getContractOrNull(
@@ -151,32 +136,28 @@ export const getContracts = async (hre: HardhatRuntimeEnvironment, coreType: Cor
};
/**
- * Get contracts by inferring the coreType (BASE, NEO, UNIVERSITY) from the network, most convenient for most cases.
+ * Get contracts by inferring the coreType (BASE, UNIVERSITY) from the network, most convenient for most cases.
* @param hre - Hardhat runtime environment
* @returns Contracts
*/
export const getContractsFromNetwork = async (hre: HardhatRuntimeEnvironment) => {
const { network } = hre;
- if (network.name === "arbitrumSepoliaDevnet" || network.name === "arbitrumSepolia") {
+ if (["arbitrumSepoliaDevnet", "arbitrumSepolia", "arbitrum"].includes(network.name)) {
return getContracts(hre, Cores.BASE);
- } else if (network.name === "arbitrum") {
- return getContracts(hre, Cores.NEO);
} else {
throw new Error("Invalid network");
}
};
/**
- * Get contract names by inferring the coreType (BASE, NEO, UNIVERSITY) from the network, most convenient for most cases.
+ * Get contract names by inferring the coreType (BASE, UNIVERSITY) from the network, most convenient for most cases.
* @param hre - Hardhat runtime environment
* @returns Contract names
*/
export const getContractNamesFromNetwork = async (hre: HardhatRuntimeEnvironment) => {
const { network } = hre;
- if (network.name === "arbitrumSepoliaDevnet" || network.name === "arbitrumSepolia") {
+ if (["arbitrumSepoliaDevnet", "arbitrumSepolia", "arbitrum"].includes(network.name)) {
return getContractNames(Cores.BASE);
- } else if (network.name === "arbitrum") {
- return getContractNames(Cores.NEO);
} else {
throw new Error("Invalid network");
}
diff --git a/contracts/scripts/utils/execution.ts b/contracts/scripts/utils/execution.ts
index f8fab0207..763eb9191 100644
--- a/contracts/scripts/utils/execution.ts
+++ b/contracts/scripts/utils/execution.ts
@@ -25,8 +25,8 @@ export const execute = async (tx: ContractTransaction) => {
const { ethers } = hre;
const contract = await ethers.getContractAt(governableAbi, tx.to);
- const governor = await contract.governor();
- const isContract = (await ethers.provider.getCode(governor)).length > 2;
+ const owner = await contract.governor();
+ const isContract = (await ethers.provider.getCode(owner)).length > 2;
if (isContract) {
// Don't execute, just log the tx. It must be submitted for execution separately.
const { to, value, data } = tx;
diff --git a/contracts/scripts/utils/tx-builder.ts b/contracts/scripts/utils/tx-builder.ts
index 06c7e65ab..fd0b52367 100644
--- a/contracts/scripts/utils/tx-builder.ts
+++ b/contracts/scripts/utils/tx-builder.ts
@@ -1,6 +1,6 @@
import { arbitrum } from "viem/chains";
-const governor = "0x66e8DE9B42308c6Ca913D1EE041d6F6fD037A57e";
+const owner = "0x66e8DE9B42308c6Ca913D1EE041d6F6fD037A57e";
const deployer = "0xf1C7c037891525E360C59f708739Ac09A7670c59";
// Transaction batch example: https://github.com/safe-global/safe-wallet-monorepo/blob/8bbf3b82edc347b70a038629cd9afd45eb1ed38a/apps/web/cypress/fixtures/test-working-batch.json
@@ -12,7 +12,7 @@ export const template = ({ name, transactions }: { name: string; transactions: B
name,
description: "", // Not used because the Safe app doesn't show it
txBuilderVersion: "1.18.0",
- createdFromSafeAddress: governor,
+ createdFromSafeAddress: owner,
createdFromOwnerAddress: deployer,
},
transactions,
@@ -42,4 +42,4 @@ export interface BuilderTransaction {
contractInputsValues: null;
}
-export const transactionBuilderUrl = `https://app.safe.global/apps/open?safe=arb1:${governor}&appUrl=https%3A%2F%2Fapps-portal.safe.global%2Ftx-builder`;
+export const transactionBuilderUrl = `https://app.safe.global/apps/open?safe=arb1:${owner}&appUrl=https%3A%2F%2Fapps-portal.safe.global%2Ftx-builder`;
diff --git a/contracts/scripts/viemTest.ts b/contracts/scripts/viemTest.ts
index bbd08d68f..0346ec900 100644
--- a/contracts/scripts/viemTest.ts
+++ b/contracts/scripts/viemTest.ts
@@ -15,7 +15,7 @@ const main = async () => {
client: client,
});
- await disputeKit.read.governor().then(console.log);
+ await disputeKit.read.owner().then(console.log);
// --------------------------------------------------
diff --git a/contracts/src/arbitration/DisputeTemplateRegistry.sol b/contracts/src/arbitration/DisputeTemplateRegistry.sol
index 2ea0a71f6..2abbe1911 100644
--- a/contracts/src/arbitration/DisputeTemplateRegistry.sol
+++ b/contracts/src/arbitration/DisputeTemplateRegistry.sol
@@ -6,26 +6,26 @@ import "../proxy/Initializable.sol";
import "./interfaces/IDisputeTemplateRegistry.sol";
/// @title Dispute Template Registry
-/// @dev A contract to maintain a registry of dispute templates.
+/// @notice A contract to maintain a registry of dispute templates.
contract DisputeTemplateRegistry is IDisputeTemplateRegistry, UUPSProxiable, Initializable {
- string public constant override version = "0.8.0";
+ string public constant override version = "2.0.0";
// ************************************* //
// * Storage * //
// ************************************* //
- /// @dev The governor of the contract.
- address public governor;
+ /// @notice The owner of the contract.
+ address public owner;
- /// @dev The number of templates.
+ /// @notice The number of templates.
uint256 public templates;
// ************************************* //
// * Function Modifiers * //
// ************************************* //
- modifier onlyByGovernor() {
- require(governor == msg.sender, "Governor only");
+ modifier onlyByOwner() {
+ if (owner != msg.sender) revert OwnerOnly();
_;
}
@@ -38,14 +38,10 @@ contract DisputeTemplateRegistry is IDisputeTemplateRegistry, UUPSProxiable, Ini
_disableInitializers();
}
- /// @dev Initializer
- /// @param _governor Governor of the contract.
- function initialize(address _governor) external reinitializer(1) {
- governor = _governor;
- }
-
- function initialize2() external reinitializer(2) {
- // NOP
+ /// @notice Initializer
+ /// @param _owner Owner of the contract.
+ function initialize(address _owner) external initializer {
+ owner = _owner;
}
// ************************ //
@@ -53,25 +49,22 @@ contract DisputeTemplateRegistry is IDisputeTemplateRegistry, UUPSProxiable, Ini
// ************************ //
/// @dev Access Control to perform implementation upgrades (UUPS Proxiable)
- /// Only the governor can perform upgrades (`onlyByGovernor`)
- function _authorizeUpgrade(address) internal view override onlyByGovernor {
+ /// Only the owner can perform upgrades (`onlyByOwner`)
+ function _authorizeUpgrade(address) internal view override onlyByOwner {
// NOP
}
- /// @dev Changes the governor of the contract.
- /// @param _governor The new governor.
- function changeGovernor(address _governor) external onlyByGovernor {
- governor = _governor;
+ /// @notice Changes the owner of the contract.
+ /// @param _owner The new owner.
+ function changeOwner(address _owner) external onlyByOwner {
+ owner = _owner;
}
// ************************************* //
// * State Modifiers * //
// ************************************* //
- /// @dev Registers a new dispute template.
- /// @param _templateTag The tag of the template (optional).
- /// @param _templateData The data of the template.
- /// @param _templateDataMappings The data mappings of the template.
+ /// @inheritdoc IDisputeTemplateRegistry
function setDisputeTemplate(
string memory _templateTag,
string memory _templateData,
@@ -80,4 +73,10 @@ contract DisputeTemplateRegistry is IDisputeTemplateRegistry, UUPSProxiable, Ini
templateId = templates++;
emit DisputeTemplate(templateId, _templateTag, _templateData, _templateDataMappings);
}
+
+ // ************************************* //
+ // * Errors * //
+ // ************************************* //
+
+ error OwnerOnly();
}
diff --git a/contracts/src/arbitration/KlerosCore.sol b/contracts/src/arbitration/KlerosCore.sol
index 3853c6b47..deb46afd8 100644
--- a/contracts/src/arbitration/KlerosCore.sol
+++ b/contracts/src/arbitration/KlerosCore.sol
@@ -2,13 +2,279 @@
pragma solidity ^0.8.24;
-import {KlerosCoreBase, IDisputeKit, ISortitionModule, IERC20} from "./KlerosCoreBase.sol";
+import {IArbitrableV2, IArbitratorV2} from "./interfaces/IArbitratorV2.sol";
+import {IDisputeKit} from "./interfaces/IDisputeKit.sol";
+import {ISortitionModule} from "./interfaces/ISortitionModule.sol";
+import {Initializable} from "../proxy/Initializable.sol";
+import {UUPSProxiable} from "../proxy/UUPSProxiable.sol";
+import {SafeERC20, IERC20} from "../libraries/SafeERC20.sol";
+import {SafeSend} from "../libraries/SafeSend.sol";
+import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol";
+import "../libraries/Constants.sol";
/// @title KlerosCore
-/// Core arbitrator contract for Kleros v2.
-/// Note that this contract trusts the PNK token, the dispute kit and the sortition module contracts.
-contract KlerosCore is KlerosCoreBase {
- string public constant override version = "0.10.0";
+/// @notice Core arbitrator contract for Kleros v2.
+/// @dev This contract trusts the PNK token, the dispute kits and the sortition module contracts.
+contract KlerosCore is IArbitratorV2, Initializable, UUPSProxiable {
+ using SafeERC20 for IERC20;
+ using SafeSend for address payable;
+
+ string public constant override version = "2.0.0";
+
+ // ************************************* //
+ // * Enums / Structs * //
+ // ************************************* //
+
+ enum Period {
+ evidence, // Evidence can be submitted. This is also when drawing has to take place.
+ commit, // Jurors commit a hashed vote. This is skipped for courts without hidden votes.
+ vote, // Jurors reveal/cast their vote depending on whether the court has hidden votes or not.
+ appeal, // The dispute can be appealed.
+ execution // Tokens are redistributed and the ruling is executed.
+ }
+
+ struct Court {
+ uint96 parent; // The parent court.
+ bool hiddenVotes; // Whether to use commit and reveal or not.
+ uint256[] children; // List of child courts.
+ uint256 minStake; // Minimum PNKs needed to stake in the court.
+ uint256 alpha; // Basis point of PNKs that are lost when incoherent.
+ uint256 feeForJuror; // Arbitration fee paid per juror.
+ uint256 jurorsForCourtJump; // The appeal after the one that reaches this number of jurors will go to the parent court if any.
+ uint256[4] timesPerPeriod; // The time allotted to each dispute period in the form `timesPerPeriod[period]`.
+ mapping(uint256 disputeKitId => bool) supportedDisputeKits; // True if DK with this ID is supported by the court. Note that each court must support classic dispute kit.
+ uint256[10] __gap; // Reserved slots for future upgrades.
+ }
+
+ struct Dispute {
+ uint96 courtID; // The ID of the court the dispute is in.
+ IArbitrableV2 arbitrated; // The arbitrable contract.
+ Period period; // The current period of the dispute.
+ bool ruled; // True if the ruling has been executed, false otherwise.
+ uint256 lastPeriodChange; // The last time the period was changed.
+ Round[] rounds; // Rounds of the dispute.
+ uint256[10] __gap; // Reserved slots for future upgrades.
+ }
+
+ struct Round {
+ uint256 disputeKitID; // Index of the dispute kit in the array.
+ uint256 pnkAtStakePerJuror; // The amount of PNKs at stake for each juror in this round.
+ uint256 totalFeesForJurors; // The total juror fees paid in this round.
+ uint256 nbVotes; // The total number of votes the dispute can possibly have in the current round. Former votes[_round].length.
+ uint256 repartitions; // A counter of reward repartitions made in this round.
+ uint256 pnkPenalties; // The amount of PNKs collected from penalties in this round.
+ address[] drawnJurors; // Addresses of the jurors that were drawn in this round.
+ uint96[] drawnJurorFromCourtIDs; // The courtIDs where the juror was drawn from, possibly their stake in a subcourt.
+ uint256 sumFeeRewardPaid; // Total sum of arbitration fees paid to coherent jurors as a reward in this round.
+ uint256 sumPnkRewardPaid; // Total sum of PNK paid to coherent jurors as a reward in this round.
+ IERC20 feeToken; // The token used for paying fees in this round.
+ uint256 drawIterations; // The number of iterations passed drawing the jurors for this round.
+ uint256[10] __gap; // Reserved slots for future upgrades.
+ }
+
+ // Workaround "stack too deep" errors
+ struct ExecuteParams {
+ uint256 disputeID; // The ID of the dispute to execute.
+ uint256 round; // The round to execute.
+ uint256 coherentCount; // The number of coherent votes in the round.
+ uint256 numberOfVotesInRound; // The number of votes in the round.
+ uint256 feePerJurorInRound; // The fee per juror in the round.
+ uint256 pnkAtStakePerJurorInRound; // The amount of PNKs at stake for each juror in the round.
+ uint256 pnkPenaltiesInRound; // The amount of PNKs collected from penalties in the round.
+ uint256 repartition; // The index of the repartition to execute.
+ }
+
+ struct CurrencyRate {
+ bool feePaymentAccepted; // True if this token is supported as payment method.
+ uint64 rateInEth; // Rate of the fee token in ETH.
+ uint8 rateDecimals; // Decimals of the fee token rate.
+ }
+
+ // ************************************* //
+ // * Storage * //
+ // ************************************* //
+
+ uint256 private constant NON_PAYABLE_AMOUNT = (2 ** 256 - 2) / 2; // An amount higher than the supply of ETH.
+
+ address public owner; // The owner of the contract.
+ address public guardian; // The guardian able to pause asset withdrawals.
+ IERC20 public pinakion; // The Pinakion token contract.
+ address public jurorProsecutionModule; // The module for juror's prosecution.
+ ISortitionModule public sortitionModule; // Sortition module for drawing.
+ Court[] public courts; // The courts.
+ IDisputeKit[] public disputeKits; // Array of dispute kits.
+ Dispute[] public disputes; // The disputes.
+ mapping(IERC20 => CurrencyRate) public currencyRates; // The price of each token in ETH.
+ bool public paused; // Whether asset withdrawals are paused.
+ address public wNative; // The wrapped native token for safeSend().
+ mapping(address => bool) public arbitrableWhitelist; // Arbitrable whitelist.
+ bool public arbitrableWhitelistEnabled; // Whether the arbitrable whitelist is enabled.
+ IERC721 public jurorNft; // Eligible jurors NFT.
+
+ // ************************************* //
+ // * Events * //
+ // ************************************* //
+
+ /// @notice Emitted when period is passed.
+ /// @param _disputeID ID of the related dispute.
+ /// @param _period The new period.
+ event NewPeriod(uint256 indexed _disputeID, Period _period);
+
+ /// @notice Emitted when appeal period starts.
+ /// @param _disputeID ID of the related dispute.
+ /// @param _arbitrable The arbitrable contract.
+ event AppealPossible(uint256 indexed _disputeID, IArbitrableV2 indexed _arbitrable);
+
+ /// @notice Emitted when the dispute is successfully appealed.
+ /// @param _disputeID ID of the related dispute.
+ /// @param _arbitrable The arbitrable contract.
+ event AppealDecision(uint256 indexed _disputeID, IArbitrableV2 indexed _arbitrable);
+
+ /// @notice Emitted when an address is successfully drawn.
+ /// @param _address The drawn address.
+ /// @param _disputeID ID of the related dispute.
+ /// @param _roundID ID of the related round.
+ /// @param _voteID ID of the vote given to the drawn juror.
+ event Draw(address indexed _address, uint256 indexed _disputeID, uint256 _roundID, uint256 _voteID);
+
+ /// @notice Emitted when a new court is created.
+ /// @param _courtID ID of the new court.
+ /// @param _parent ID of the parent court.
+ /// @param _hiddenVotes Whether the court has hidden votes or not.
+ /// @param _minStake The `minStake` property value of the court.
+ /// @param _alpha The `alpha` property value of the court.
+ /// @param _feeForJuror The `feeForJuror` property value of the court.
+ /// @param _jurorsForCourtJump The `jurorsForCourtJump` property value of the court.
+ /// @param _timesPerPeriod The `timesPerPeriod` property value of the court.
+ /// @param _supportedDisputeKits Indexes of dispute kits that this court will support.
+ event CourtCreated(
+ uint96 indexed _courtID,
+ uint96 indexed _parent,
+ bool _hiddenVotes,
+ uint256 _minStake,
+ uint256 _alpha,
+ uint256 _feeForJuror,
+ uint256 _jurorsForCourtJump,
+ uint256[4] _timesPerPeriod,
+ uint256[] _supportedDisputeKits
+ );
+
+ /// @notice Emitted when court's parameters are changed.
+ /// @param _courtID ID of the court.
+ /// @param _hiddenVotes Whether the court has hidden votes or not.
+ /// @param _minStake The `minStake` property value of the court.
+ /// @param _alpha The `alpha` property value of the court.
+ /// @param _feeForJuror The `feeForJuror` property value of the court.
+ /// @param _jurorsForCourtJump The `jurorsForCourtJump` property value of the court.
+ /// @param _timesPerPeriod The `timesPerPeriod` property value of the court.
+ event CourtModified(
+ uint96 indexed _courtID,
+ bool _hiddenVotes,
+ uint256 _minStake,
+ uint256 _alpha,
+ uint256 _feeForJuror,
+ uint256 _jurorsForCourtJump,
+ uint256[4] _timesPerPeriod
+ );
+
+ /// @notice Emitted when a dispute kit is created.
+ /// @param _disputeKitID ID of the new dispute kit.
+ /// @param _disputeKitAddress Address of the new dispute kit.
+ event DisputeKitCreated(uint256 indexed _disputeKitID, IDisputeKit indexed _disputeKitAddress);
+
+ /// @notice Emitted when a dispute kit is enabled/disabled in a court.
+ /// @param _courtID ID of the related court.
+ /// @param _disputeKitID ID of the dispute kit.
+ /// @param _enable Whether the dispute kit has been enabled or disabled.
+ event DisputeKitEnabled(uint96 indexed _courtID, uint256 indexed _disputeKitID, bool indexed _enable);
+
+ /// @notice Emitted when a dispute jumps to a new court.
+ /// @param _disputeID ID of the dispute.
+ /// @param _roundID ID of the round.
+ /// @param _fromCourtID ID of the previous court.
+ /// @param _toCourtID ID of the new court.
+ event CourtJump(
+ uint256 indexed _disputeID,
+ uint256 indexed _roundID,
+ uint96 indexed _fromCourtID,
+ uint96 _toCourtID
+ );
+
+ /// @notice Emitted when a dispute jumps to a new dispute kit.
+ /// @param _disputeID ID of the dispute.
+ /// @param _roundID ID of the round.
+ /// @param _fromDisputeKitID ID of the previous dispute kit.
+ /// @param _toDisputeKitID ID of the new dispute kit.
+ event DisputeKitJump(
+ uint256 indexed _disputeID,
+ uint256 indexed _roundID,
+ uint256 indexed _fromDisputeKitID,
+ uint256 _toDisputeKitID
+ );
+
+ /// @notice Emitted when juror's balance shifts after penalties/rewards has been processed.
+ /// @param _account Juror's address.
+ /// @param _disputeID ID of the dispute.
+ /// @param _roundID ID of the round.
+ /// @param _degreeOfCoherencyPnk Juror's degree of coherency in this round applied to PNK.
+ /// @param _degreeOfCoherencyFee Juror's degree of coherency in this round applied to the dispute fee.
+ /// @param _amountPnk Amount of PNK shifted.
+ /// @param _amountFee Amount of fee shifted.
+ /// @param _feeToken Address of the fee token.
+ event JurorRewardPenalty(
+ address indexed _account,
+ uint256 indexed _disputeID,
+ uint256 indexed _roundID,
+ uint256 _degreeOfCoherencyPnk,
+ uint256 _degreeOfCoherencyFee,
+ int256 _amountPnk,
+ int256 _amountFee,
+ IERC20 _feeToken
+ );
+
+ /// @notice Emitted when leftover reward sent to owner.
+ /// @param _disputeID ID of the dispute.
+ /// @param _roundID ID of the round.
+ /// @param _amountPnk Amount of PNK sent.
+ /// @param _amountFee Amount of fee sent.
+ /// @param _feeToken Address of the fee token.
+ event LeftoverRewardSent(
+ uint256 indexed _disputeID,
+ uint256 indexed _roundID,
+ uint256 _amountPnk,
+ uint256 _amountFee,
+ IERC20 _feeToken
+ );
+
+ /// @notice Emitted when this contract is paused.
+ event Paused();
+
+ /// @notice Emitted when this contract is unpaused.
+ event Unpaused();
+
+ // ************************************* //
+ // * Function Modifiers * //
+ // ************************************* //
+
+ modifier onlyByOwner() {
+ if (owner != msg.sender) revert OwnerOnly();
+ _;
+ }
+
+ modifier onlyByGuardianOrOwner() {
+ if (guardian != msg.sender && owner != msg.sender) revert GuardianOrOwnerOnly();
+ _;
+ }
+
+ modifier whenPaused() {
+ if (!paused) revert WhenPausedOnly();
+ _;
+ }
+
+ modifier whenNotPaused() {
+ if (paused) revert WhenNotPausedOnly();
+ _;
+ }
// ************************************* //
// * Constructor * //
@@ -19,8 +285,8 @@ contract KlerosCore is KlerosCoreBase {
_disableInitializers();
}
- /// @dev Initializer (constructor equivalent for upgradable contracts).
- /// @param _governor The governor's address.
+ /// @notice Initializer (constructor equivalent for upgradable contracts).
+ /// @param _owner The owner's address.
/// @param _guardian The guardian's address.
/// @param _pinakion The address of the token contract.
/// @param _jurorProsecutionModule The address of the juror prosecution module.
@@ -31,8 +297,9 @@ contract KlerosCore is KlerosCoreBase {
/// @param _sortitionExtraData The extra data for sortition module.
/// @param _sortitionModuleAddress The sortition module responsible for sortition of the jurors.
/// @param _wNative The wrapped native token address, typically wETH.
+ /// @param _jurorNft NFT contract to vet the jurors.
function initialize(
- address _governor,
+ address _owner,
address _guardian,
IERC20 _pinakion,
address _jurorProsecutionModule,
@@ -42,25 +309,57 @@ contract KlerosCore is KlerosCoreBase {
uint256[4] memory _timesPerPeriod,
bytes memory _sortitionExtraData,
ISortitionModule _sortitionModuleAddress,
- address _wNative
- ) external reinitializer(1) {
- __KlerosCoreBase_initialize(
- _governor,
- _guardian,
- _pinakion,
- _jurorProsecutionModule,
- _disputeKit,
+ address _wNative,
+ IERC721 _jurorNft
+ ) external initializer {
+ owner = _owner;
+ guardian = _guardian;
+ pinakion = _pinakion;
+ jurorProsecutionModule = _jurorProsecutionModule;
+ sortitionModule = _sortitionModuleAddress;
+ wNative = _wNative;
+ jurorNft = _jurorNft;
+
+ // NULL_DISPUTE_KIT: an empty element at index 0 to indicate when a dispute kit is not supported.
+ disputeKits.push();
+
+ // DISPUTE_KIT_CLASSIC
+ disputeKits.push(_disputeKit);
+
+ emit DisputeKitCreated(DISPUTE_KIT_CLASSIC, _disputeKit);
+
+ // FORKING_COURT
+ // TODO: Fill the properties for the Forking court, emit CourtCreated.
+ courts.push();
+ sortitionModule.createTree(FORKING_COURT, _sortitionExtraData);
+
+ // GENERAL_COURT
+ Court storage court = courts.push();
+ court.parent = FORKING_COURT;
+ court.children = new uint256[](0);
+ court.hiddenVotes = _hiddenVotes;
+ court.minStake = _courtParameters[0];
+ court.alpha = _courtParameters[1];
+ court.feeForJuror = _courtParameters[2];
+ court.jurorsForCourtJump = _courtParameters[3];
+ court.timesPerPeriod = _timesPerPeriod;
+
+ sortitionModule.createTree(GENERAL_COURT, _sortitionExtraData);
+
+ uint256[] memory supportedDisputeKits = new uint256[](1);
+ supportedDisputeKits[0] = DISPUTE_KIT_CLASSIC;
+ emit CourtCreated(
+ GENERAL_COURT,
+ court.parent,
_hiddenVotes,
- _courtParameters,
+ _courtParameters[0],
+ _courtParameters[1],
+ _courtParameters[2],
+ _courtParameters[3],
_timesPerPeriod,
- _sortitionExtraData,
- _sortitionModuleAddress,
- _wNative
+ supportedDisputeKits
);
- }
-
- function reinitialize(address _wNative) external reinitializer(6) {
- wNative = _wNative;
+ _enableDisputeKit(GENERAL_COURT, DISPUTE_KIT_CLASSIC, true);
}
// ************************************* //
@@ -68,8 +367,1077 @@ contract KlerosCore is KlerosCoreBase {
// ************************************* //
/// @dev Access Control to perform implementation upgrades (UUPS Proxiable)
- /// Only the governor can perform upgrades (`onlyByGovernor`)
- function _authorizeUpgrade(address) internal view override onlyByGovernor {
+ /// Only the owner can perform upgrades (`onlyByOwner`)
+ function _authorizeUpgrade(address) internal view override onlyByOwner {
// NOP
}
+
+ /// @notice Pause staking and reward execution. Can only be done by guardian or owner.
+ function pause() external onlyByGuardianOrOwner whenNotPaused {
+ paused = true;
+ emit Paused();
+ }
+
+ /// @notice Unpause staking and reward execution. Can only be done by owner.
+ function unpause() external onlyByOwner whenPaused {
+ paused = false;
+ emit Unpaused();
+ }
+
+ /// @notice Allows the owner to call anything on behalf of the contract.
+ /// @param _destination The destination of the call.
+ /// @param _amount The value sent with the call.
+ /// @param _data The data sent with the call.
+ function executeOwnerProposal(address _destination, uint256 _amount, bytes memory _data) external onlyByOwner {
+ (bool success, ) = _destination.call{value: _amount}(_data);
+ if (!success) revert UnsuccessfulCall();
+ }
+
+ /// @notice Changes the `owner` storage variable.
+ /// @param _owner The new value for the `owner` storage variable.
+ function changeOwner(address payable _owner) external onlyByOwner {
+ owner = _owner;
+ }
+
+ /// @notice Changes the `guardian` storage variable.
+ /// @param _guardian The new value for the `guardian` storage variable.
+ function changeGuardian(address _guardian) external onlyByOwner {
+ guardian = _guardian;
+ }
+
+ /// @notice Changes the `pinakion` storage variable.
+ /// @param _pinakion The new value for the `pinakion` storage variable.
+ function changePinakion(IERC20 _pinakion) external onlyByOwner {
+ pinakion = _pinakion;
+ }
+
+ /// @notice Changes the `jurorProsecutionModule` storage variable.
+ /// @param _jurorProsecutionModule The new value for the `jurorProsecutionModule` storage variable.
+ function changeJurorProsecutionModule(address _jurorProsecutionModule) external onlyByOwner {
+ jurorProsecutionModule = _jurorProsecutionModule;
+ }
+
+ /// @notice Changes the `_sortitionModule` storage variable.
+ /// Note that the new module should be initialized for all courts.
+ /// @param _sortitionModule The new value for the `sortitionModule` storage variable.
+ function changeSortitionModule(ISortitionModule _sortitionModule) external onlyByOwner {
+ sortitionModule = _sortitionModule;
+ }
+
+ /// @notice Add a new supported dispute kit, without enabling it.
+ /// Use `enableDisputeKits()` to enable the dispute kit for a specific court.
+ /// @param _disputeKitAddress The address of the dispute kit contract.
+ function addNewDisputeKit(IDisputeKit _disputeKitAddress) external onlyByOwner {
+ uint256 disputeKitID = disputeKits.length;
+ disputeKits.push(_disputeKitAddress);
+ emit DisputeKitCreated(disputeKitID, _disputeKitAddress);
+ }
+
+ /// @notice Creates a court under a specified parent court.
+ /// @param _parent The `parent` property value of the court.
+ /// @param _hiddenVotes The `hiddenVotes` property value of the court.
+ /// @param _minStake The `minStake` property value of the court.
+ /// @param _alpha The `alpha` property value of the court.
+ /// @param _feeForJuror The `feeForJuror` property value of the court.
+ /// @param _jurorsForCourtJump The `jurorsForCourtJump` property value of the court.
+ /// @param _timesPerPeriod The `timesPerPeriod` property value of the court.
+ /// @param _sortitionExtraData Extra data for sortition module.
+ /// @param _supportedDisputeKits Indexes of dispute kits that this court will support.
+ function createCourt(
+ uint96 _parent,
+ bool _hiddenVotes,
+ uint256 _minStake,
+ uint256 _alpha,
+ uint256 _feeForJuror,
+ uint256 _jurorsForCourtJump,
+ uint256[4] memory _timesPerPeriod,
+ bytes memory _sortitionExtraData,
+ uint256[] memory _supportedDisputeKits
+ ) external onlyByOwner {
+ if (courts[_parent].minStake > _minStake) revert MinStakeLowerThanParentCourt();
+ if (_supportedDisputeKits.length == 0) revert UnsupportedDisputeKit();
+ if (_parent == FORKING_COURT) revert InvalidForkingCourtAsParent();
+
+ uint96 courtID = uint96(courts.length);
+ Court storage court = courts.push();
+
+ for (uint256 i = 0; i < _supportedDisputeKits.length; i++) {
+ if (_supportedDisputeKits[i] == NULL_DISPUTE_KIT || _supportedDisputeKits[i] >= disputeKits.length) {
+ revert WrongDisputeKitIndex();
+ }
+ _enableDisputeKit(uint96(courtID), _supportedDisputeKits[i], true);
+ }
+ // Check that Classic DK support was added.
+ if (!court.supportedDisputeKits[DISPUTE_KIT_CLASSIC]) revert MustSupportDisputeKitClassic();
+
+ court.parent = _parent;
+ court.children = new uint256[](0);
+ court.hiddenVotes = _hiddenVotes;
+ court.minStake = _minStake;
+ court.alpha = _alpha;
+ court.feeForJuror = _feeForJuror;
+ court.jurorsForCourtJump = _jurorsForCourtJump;
+ court.timesPerPeriod = _timesPerPeriod;
+
+ sortitionModule.createTree(courtID, _sortitionExtraData);
+
+ // Update the parent.
+ courts[_parent].children.push(courtID);
+ emit CourtCreated(
+ courtID,
+ _parent,
+ _hiddenVotes,
+ _minStake,
+ _alpha,
+ _feeForJuror,
+ _jurorsForCourtJump,
+ _timesPerPeriod,
+ _supportedDisputeKits
+ );
+ }
+
+ /// @notice Changes the parameters of the court.
+ /// @param _courtID ID of the court.
+ /// @param _hiddenVotes The `hiddenVotes` property value of the court.
+ /// @param _minStake The `minStake` property value of the court.
+ /// @param _alpha The `alpha` property value of the court.
+ /// @param _feeForJuror The `feeForJuror` property value of the court.
+ /// @param _jurorsForCourtJump The `jurorsForCourtJump` property value of the court.
+ /// @param _timesPerPeriod The `timesPerPeriod` property value of the court.
+ function changeCourtParameters(
+ uint96 _courtID,
+ bool _hiddenVotes,
+ uint256 _minStake,
+ uint256 _alpha,
+ uint256 _feeForJuror,
+ uint256 _jurorsForCourtJump,
+ uint256[4] memory _timesPerPeriod
+ ) external onlyByOwner {
+ Court storage court = courts[_courtID];
+ if (_courtID != GENERAL_COURT && courts[court.parent].minStake > _minStake) {
+ revert MinStakeLowerThanParentCourt();
+ }
+ for (uint256 i = 0; i < court.children.length; i++) {
+ if (courts[court.children[i]].minStake < _minStake) {
+ revert MinStakeHigherThanChildCourt(court.children[i]);
+ }
+ }
+ court.minStake = _minStake;
+ court.hiddenVotes = _hiddenVotes;
+ court.alpha = _alpha;
+ court.feeForJuror = _feeForJuror;
+ court.jurorsForCourtJump = _jurorsForCourtJump;
+ court.timesPerPeriod = _timesPerPeriod;
+ emit CourtModified(
+ _courtID,
+ _hiddenVotes,
+ _minStake,
+ _alpha,
+ _feeForJuror,
+ _jurorsForCourtJump,
+ _timesPerPeriod
+ );
+ }
+
+ /// @notice Adds/removes court's support for specified dispute kits.
+ /// @param _courtID The ID of the court.
+ /// @param _disputeKitIDs The IDs of dispute kits which support should be added/removed.
+ /// @param _enable Whether add or remove the dispute kits from the court.
+ function enableDisputeKits(uint96 _courtID, uint256[] memory _disputeKitIDs, bool _enable) external onlyByOwner {
+ for (uint256 i = 0; i < _disputeKitIDs.length; i++) {
+ if (_disputeKitIDs[i] == NULL_DISPUTE_KIT || _disputeKitIDs[i] >= disputeKits.length) {
+ revert WrongDisputeKitIndex();
+ }
+ if (_enable) {
+ _enableDisputeKit(_courtID, _disputeKitIDs[i], true);
+ } else {
+ // Classic dispute kit must be supported by all courts.
+ if (_disputeKitIDs[i] == DISPUTE_KIT_CLASSIC) {
+ revert CannotDisableClassicDK();
+ }
+ _enableDisputeKit(_courtID, _disputeKitIDs[i], false);
+ }
+ }
+ }
+
+ /// @notice Changes the supported fee tokens.
+ /// @param _feeToken The fee token.
+ /// @param _accepted Whether the token is supported or not as a method of fee payment.
+ function changeAcceptedFeeTokens(IERC20 _feeToken, bool _accepted) external onlyByOwner {
+ currencyRates[_feeToken].feePaymentAccepted = _accepted;
+ emit AcceptedFeeToken(_feeToken, _accepted);
+ }
+
+ /// @notice Changes the currency rate of a fee token.
+ /// @param _feeToken The fee token.
+ /// @param _rateInEth The new rate of the fee token in ETH.
+ /// @param _rateDecimals The new decimals of the fee token rate.
+ function changeCurrencyRates(IERC20 _feeToken, uint64 _rateInEth, uint8 _rateDecimals) external onlyByOwner {
+ currencyRates[_feeToken].rateInEth = _rateInEth;
+ currencyRates[_feeToken].rateDecimals = _rateDecimals;
+ emit NewCurrencyRate(_feeToken, _rateInEth, _rateDecimals);
+ }
+
+ /// @notice Changes the `jurorNft` storage variable.
+ /// @param _jurorNft The new value for the `jurorNft` storage variable.
+ function changeJurorNft(IERC721 _jurorNft) external onlyByOwner {
+ jurorNft = _jurorNft;
+ }
+
+ /// @notice Adds or removes an arbitrable from whitelist.
+ /// @param _arbitrable Arbitrable address.
+ /// @param _allowed Whether add or remove permission.
+ function changeArbitrableWhitelist(address _arbitrable, bool _allowed) external onlyByOwner {
+ arbitrableWhitelist[_arbitrable] = _allowed;
+ }
+
+ /// @notice Enables or disables the arbitrable whitelist.
+ function changeArbitrableWhitelistEnabled(bool _enabled) external onlyByOwner {
+ arbitrableWhitelistEnabled = _enabled;
+ }
+
+ // ************************************* //
+ // * State Modifiers * //
+ // ************************************* //
+
+ /// @notice Sets the caller's stake in a court.
+ /// @param _courtID The ID of the court.
+ /// @param _newStake The new stake.
+ /// Note that the existing delayed stake will be nullified as non-relevant.
+ function setStake(uint96 _courtID, uint256 _newStake) external whenNotPaused {
+ if (address(jurorNft) != address(0) && jurorNft.balanceOf(msg.sender) == 0) revert NotEligibleForStaking();
+ _setStake(msg.sender, _courtID, _newStake, false, OnError.Revert);
+ }
+
+ /// @notice Sets the stake of a specified account in a court without delaying stake changes, typically to apply a delayed stake or unstake inactive jurors.
+ /// @param _account The account whose stake is being set.
+ /// @param _courtID The ID of the court.
+ /// @param _newStake The new stake.
+ /// @return True if the stake was set successfully.
+ function setStakeBySortitionModule(address _account, uint96 _courtID, uint256 _newStake) external returns (bool) {
+ if (msg.sender != address(sortitionModule)) revert SortitionModuleOnly();
+ return _setStake(_account, _courtID, _newStake, true, OnError.Return);
+ }
+
+ /// @notice Transfers PNK to the juror by SortitionModule.
+ /// @param _account The account of the juror whose PNK to transfer.
+ /// @param _amount The amount to transfer.
+ function transferBySortitionModule(address _account, uint256 _amount) external {
+ if (msg.sender != address(sortitionModule)) revert SortitionModuleOnly();
+ // Note eligibility is checked in SortitionModule.
+ pinakion.safeTransfer(_account, _amount);
+ }
+
+ /// @inheritdoc IArbitratorV2
+ function createDispute(
+ uint256 _numberOfChoices,
+ bytes memory _extraData
+ ) external payable override returns (uint256 disputeID) {
+ if (msg.value < arbitrationCost(_extraData)) revert ArbitrationFeesNotEnough();
+
+ return _createDispute(_numberOfChoices, _extraData, NATIVE_CURRENCY, msg.value);
+ }
+
+ /// @inheritdoc IArbitratorV2
+ function createDispute(
+ uint256 _numberOfChoices,
+ bytes calldata _extraData,
+ IERC20 _feeToken,
+ uint256 _feeAmount
+ ) external override returns (uint256 disputeID) {
+ if (!currencyRates[_feeToken].feePaymentAccepted) revert TokenNotAccepted();
+ if (_feeAmount < arbitrationCost(_extraData, _feeToken)) revert ArbitrationFeesNotEnough();
+
+ if (!_feeToken.safeTransferFrom(msg.sender, address(this), _feeAmount)) revert TransferFailed();
+ return _createDispute(_numberOfChoices, _extraData, _feeToken, _feeAmount);
+ }
+
+ function _createDispute(
+ uint256 _numberOfChoices,
+ bytes memory _extraData,
+ IERC20 _feeToken,
+ uint256 _feeAmount
+ ) internal returns (uint256 disputeID) {
+ if (arbitrableWhitelistEnabled && !arbitrableWhitelist[msg.sender]) revert ArbitrableNotWhitelisted();
+ (uint96 courtID, , uint256 disputeKitID) = _extraDataToCourtIDMinJurorsDisputeKit(_extraData);
+ if (!courts[courtID].supportedDisputeKits[disputeKitID]) revert DisputeKitNotSupportedByCourt();
+
+ disputeID = disputes.length;
+ Dispute storage dispute = disputes.push();
+ dispute.courtID = courtID;
+ dispute.arbitrated = IArbitrableV2(msg.sender);
+ dispute.lastPeriodChange = block.timestamp;
+
+ IDisputeKit disputeKit = disputeKits[disputeKitID];
+ Court storage court = courts[courtID];
+ Round storage round = dispute.rounds.push();
+
+ // Obtain the feeForJuror in the same currency as the _feeAmount
+ uint256 feeForJuror = (_feeToken == NATIVE_CURRENCY)
+ ? court.feeForJuror
+ : convertEthToTokenAmount(_feeToken, court.feeForJuror);
+ round.nbVotes = _feeAmount / feeForJuror;
+ round.disputeKitID = disputeKitID;
+ round.pnkAtStakePerJuror = _calculatePnkAtStake(court.minStake, court.alpha);
+ round.totalFeesForJurors = _feeAmount;
+ round.feeToken = IERC20(_feeToken);
+
+ sortitionModule.createDisputeHook(disputeID, 0); // Default round ID.
+
+ disputeKit.createDispute(disputeID, 0, _numberOfChoices, _extraData, round.nbVotes);
+ emit DisputeCreation(disputeID, IArbitrableV2(msg.sender));
+ }
+
+ /// @notice Passes the period of a specified dispute.
+ /// @param _disputeID The ID of the dispute.
+ function passPeriod(uint256 _disputeID) external {
+ Dispute storage dispute = disputes[_disputeID];
+ Court storage court = courts[dispute.courtID];
+
+ uint256 currentRound = dispute.rounds.length - 1;
+ Round storage round = dispute.rounds[currentRound];
+ if (dispute.period == Period.evidence) {
+ if (
+ currentRound == 0 &&
+ block.timestamp - dispute.lastPeriodChange < court.timesPerPeriod[uint256(dispute.period)]
+ ) {
+ revert EvidenceNotPassedAndNotAppeal();
+ }
+ if (round.drawnJurors.length != round.nbVotes) revert DisputeStillDrawing();
+ dispute.period = court.hiddenVotes ? Period.commit : Period.vote;
+ } else if (dispute.period == Period.commit) {
+ // Note that we do not want to pass to Voting period if all the commits are cast because it breaks the Shutter auto-reveal currently.
+ if (block.timestamp - dispute.lastPeriodChange < court.timesPerPeriod[uint256(dispute.period)]) {
+ revert CommitPeriodNotPassed();
+ }
+ dispute.period = Period.vote;
+ } else if (dispute.period == Period.vote) {
+ if (
+ block.timestamp - dispute.lastPeriodChange < court.timesPerPeriod[uint256(dispute.period)] &&
+ !disputeKits[round.disputeKitID].areVotesAllCast(_disputeID)
+ ) {
+ revert VotePeriodNotPassed();
+ }
+ dispute.period = Period.appeal;
+ emit AppealPossible(_disputeID, dispute.arbitrated);
+ } else if (dispute.period == Period.appeal) {
+ if (
+ block.timestamp - dispute.lastPeriodChange < court.timesPerPeriod[uint256(dispute.period)] &&
+ !disputeKits[round.disputeKitID].isAppealFunded(_disputeID)
+ ) {
+ revert AppealPeriodNotPassed();
+ }
+ dispute.period = Period.execution;
+ } else if (dispute.period == Period.execution) {
+ revert DisputePeriodIsFinal();
+ }
+
+ dispute.lastPeriodChange = block.timestamp;
+ emit NewPeriod(_disputeID, dispute.period);
+ }
+
+ /// @notice Draws jurors for the dispute. Can be called in parts.
+ /// @param _disputeID The ID of the dispute.
+ /// @param _iterations The number of iterations to run.
+ /// @return nbDrawnJurors The total number of jurors drawn in the round.
+ function draw(uint256 _disputeID, uint256 _iterations) external returns (uint256 nbDrawnJurors) {
+ Dispute storage dispute = disputes[_disputeID];
+ uint256 currentRound = dispute.rounds.length - 1;
+ Round storage round = dispute.rounds[currentRound];
+ if (dispute.period != Period.evidence) revert NotEvidencePeriod();
+
+ IDisputeKit disputeKit = disputeKits[round.disputeKitID];
+
+ uint256 startIndex = round.drawIterations; // for gas: less storage reads
+ uint256 i;
+ while (i < _iterations && round.drawnJurors.length < round.nbVotes) {
+ (address drawnAddress, uint96 fromSubcourtID) = disputeKit.draw(_disputeID, startIndex + i++);
+ if (drawnAddress == address(0)) {
+ continue;
+ }
+ sortitionModule.lockStake(drawnAddress, round.pnkAtStakePerJuror);
+ emit Draw(drawnAddress, _disputeID, currentRound, round.drawnJurors.length);
+ round.drawnJurors.push(drawnAddress);
+ round.drawnJurorFromCourtIDs.push(fromSubcourtID != 0 ? fromSubcourtID : dispute.courtID);
+ if (round.drawnJurors.length == round.nbVotes) {
+ sortitionModule.postDrawHook(_disputeID, currentRound);
+ }
+ }
+ round.drawIterations += i;
+ return round.drawnJurors.length;
+ }
+
+ /// @notice Appeals the ruling of a specified dispute.
+ /// @dev Access restricted to the Dispute Kit for this `_disputeID`.
+ /// @param _disputeID The ID of the dispute.
+ /// @param _numberOfChoices Number of choices for the dispute. Can be required during court jump.
+ /// @param _extraData Extradata for the dispute. Can be required during court jump.
+ function appeal(uint256 _disputeID, uint256 _numberOfChoices, bytes memory _extraData) external payable {
+ if (msg.value < appealCost(_disputeID)) revert AppealFeesNotEnough();
+
+ Dispute storage dispute = disputes[_disputeID];
+ if (dispute.period != Period.appeal) revert DisputeNotAppealable();
+
+ Round storage round = dispute.rounds[dispute.rounds.length - 1];
+ if (msg.sender != address(disputeKits[round.disputeKitID])) revert DisputeKitOnly();
+
+ // Warning: the extra round must be created before calling disputeKit.createDispute()
+ Round storage extraRound = dispute.rounds.push();
+ uint256 extraRoundID = dispute.rounds.length - 1;
+
+ (uint96 newCourtID, uint256 newDisputeKitID, bool courtJump, ) = _getCourtAndDisputeKitJumps(
+ dispute,
+ round,
+ courts[dispute.courtID],
+ _disputeID
+ );
+ if (courtJump) {
+ emit CourtJump(_disputeID, extraRoundID, dispute.courtID, newCourtID);
+ }
+
+ dispute.courtID = newCourtID;
+ dispute.period = Period.evidence;
+ dispute.lastPeriodChange = block.timestamp;
+
+ Court storage court = courts[newCourtID];
+ extraRound.nbVotes = msg.value / court.feeForJuror; // As many votes that can be afforded by the provided funds.
+ extraRound.pnkAtStakePerJuror = _calculatePnkAtStake(court.minStake, court.alpha);
+ extraRound.totalFeesForJurors = msg.value;
+ extraRound.disputeKitID = newDisputeKitID;
+
+ sortitionModule.createDisputeHook(_disputeID, extraRoundID);
+
+ // Dispute kit was changed, so create a dispute in the new DK contract.
+ if (extraRound.disputeKitID != round.disputeKitID) {
+ emit DisputeKitJump(_disputeID, dispute.rounds.length - 1, round.disputeKitID, extraRound.disputeKitID);
+ disputeKits[extraRound.disputeKitID].createDispute(
+ _disputeID,
+ extraRoundID,
+ _numberOfChoices,
+ _extraData,
+ extraRound.nbVotes
+ );
+ }
+
+ emit AppealDecision(_disputeID, dispute.arbitrated);
+ emit NewPeriod(_disputeID, Period.evidence);
+ }
+
+ /// @notice Distribute the PNKs at stake and the dispute fees for the specific round of the dispute. Can be called in parts.
+ /// @dev Reward distributions are forbidden during pause.
+ /// @param _disputeID The ID of the dispute.
+ /// @param _round The appeal round.
+ /// @param _iterations The number of iterations to run.
+ function execute(uint256 _disputeID, uint256 _round, uint256 _iterations) external whenNotPaused {
+ Round storage round;
+ {
+ Dispute storage dispute = disputes[_disputeID];
+ if (dispute.period != Period.execution) revert NotExecutionPeriod();
+
+ round = dispute.rounds[_round];
+ } // stack too deep workaround
+
+ uint256 start = round.repartitions;
+ uint256 end = round.repartitions + _iterations;
+
+ uint256 pnkPenaltiesInRound = round.pnkPenalties; // Keep in memory to save gas.
+ uint256 numberOfVotesInRound = round.drawnJurors.length;
+ uint256 feePerJurorInRound = round.totalFeesForJurors / numberOfVotesInRound;
+ uint256 pnkAtStakePerJurorInRound = round.pnkAtStakePerJuror;
+ uint256 coherentCount;
+ {
+ IDisputeKit disputeKit = disputeKits[round.disputeKitID];
+ coherentCount = disputeKit.getCoherentCount(_disputeID, _round); // Total number of jurors that are eligible to a reward in this round.
+ } // stack too deep workaround
+
+ if (coherentCount == 0) {
+ // We loop over the votes once as there are no rewards because it is not a tie and no one in this round is coherent with the final outcome.
+ if (end > numberOfVotesInRound) end = numberOfVotesInRound;
+ } else {
+ // We loop over the votes twice, first to collect the PNK penalties, and second to distribute them as rewards along with arbitration fees.
+ if (end > numberOfVotesInRound * 2) end = numberOfVotesInRound * 2;
+ }
+ round.repartitions = end;
+
+ for (uint256 i = start; i < end; i++) {
+ if (i < numberOfVotesInRound) {
+ pnkPenaltiesInRound = _executePenalties(
+ ExecuteParams({
+ disputeID: _disputeID,
+ round: _round,
+ coherentCount: coherentCount,
+ numberOfVotesInRound: numberOfVotesInRound,
+ feePerJurorInRound: feePerJurorInRound,
+ pnkAtStakePerJurorInRound: pnkAtStakePerJurorInRound,
+ pnkPenaltiesInRound: pnkPenaltiesInRound,
+ repartition: i
+ })
+ );
+ } else {
+ _executeRewards(
+ ExecuteParams({
+ disputeID: _disputeID,
+ round: _round,
+ coherentCount: coherentCount,
+ numberOfVotesInRound: numberOfVotesInRound,
+ feePerJurorInRound: feePerJurorInRound,
+ pnkAtStakePerJurorInRound: pnkAtStakePerJurorInRound,
+ pnkPenaltiesInRound: pnkPenaltiesInRound,
+ repartition: i
+ })
+ );
+ }
+ }
+ if (round.pnkPenalties != pnkPenaltiesInRound) {
+ round.pnkPenalties = pnkPenaltiesInRound; // Note: Check-Effect-Interaction pattern is compromised here, but in the current state it doesn't cause any issues.
+ }
+ }
+
+ /// @notice Distribute the PNKs at stake and the dispute fees for the specific round of the dispute, penalties only.
+ /// @param _params The parameters for the execution, see `ExecuteParams`.
+ /// @return pnkPenaltiesInRoundCache The updated penalties in round cache.
+ function _executePenalties(ExecuteParams memory _params) internal returns (uint256) {
+ Dispute storage dispute = disputes[_params.disputeID];
+ Round storage round = dispute.rounds[_params.round];
+ IDisputeKit disputeKit = disputeKits[round.disputeKitID];
+
+ // [0, 1] value that determines how coherent the juror was in this round, in basis points.
+ uint256 coherence = disputeKit.getDegreeOfCoherencePenalty(
+ _params.disputeID,
+ _params.round,
+ _params.repartition,
+ _params.feePerJurorInRound,
+ _params.pnkAtStakePerJurorInRound
+ );
+
+ // Extra check to guard against degree exceeding 1, though it should be ensured by the dispute kit.
+ if (coherence > ONE_BASIS_POINT) {
+ coherence = ONE_BASIS_POINT;
+ }
+
+ // Fully coherent jurors won't be penalized.
+ uint256 penalty = (round.pnkAtStakePerJuror * (ONE_BASIS_POINT - coherence)) / ONE_BASIS_POINT;
+
+ // Unlock the PNKs affected by the penalty
+ address account = round.drawnJurors[_params.repartition];
+ sortitionModule.unlockStake(account, penalty);
+
+ // Apply the penalty to the staked PNKs.
+ uint96 penalizedInCourtID = round.drawnJurorFromCourtIDs[_params.repartition];
+ (uint256 pnkBalance, uint256 newCourtStake, uint256 availablePenalty) = sortitionModule.setStakePenalty(
+ account,
+ penalizedInCourtID,
+ penalty
+ );
+ if (availablePenalty != 0) {
+ _params.pnkPenaltiesInRound += availablePenalty;
+ emit JurorRewardPenalty(
+ account,
+ _params.disputeID,
+ _params.round,
+ coherence,
+ 0,
+ -int256(availablePenalty),
+ 0,
+ round.feeToken
+ );
+ }
+
+ if (pnkBalance == 0 || !disputeKit.isVoteActive(_params.disputeID, _params.round, _params.repartition)) {
+ // The juror is inactive or their balance can't cover penalties anymore, unstake them from all courts.
+ sortitionModule.forcedUnstakeAllCourts(account);
+ } else if (newCourtStake < courts[penalizedInCourtID].minStake) {
+ // The juror's balance fell below the court minStake, unstake them from the court.
+ sortitionModule.forcedUnstake(account, penalizedInCourtID);
+ }
+
+ if (_params.repartition == _params.numberOfVotesInRound - 1 && _params.coherentCount == 0) {
+ // No one was coherent, send the rewards to the owner.
+ _transferFeeToken(round.feeToken, payable(owner), round.totalFeesForJurors);
+ pinakion.safeTransfer(owner, _params.pnkPenaltiesInRound);
+ emit LeftoverRewardSent(
+ _params.disputeID,
+ _params.round,
+ _params.pnkPenaltiesInRound,
+ round.totalFeesForJurors,
+ round.feeToken
+ );
+ }
+ return _params.pnkPenaltiesInRound;
+ }
+
+ /// @notice Distribute the PNKs at stake and the dispute fees for the specific round of the dispute, rewards only.
+ /// @param _params The parameters for the execution, see `ExecuteParams`.
+ function _executeRewards(ExecuteParams memory _params) internal {
+ Dispute storage dispute = disputes[_params.disputeID];
+ Round storage round = dispute.rounds[_params.round];
+ IDisputeKit disputeKit = disputeKits[round.disputeKitID];
+ uint256 repartition = _params.repartition % _params.numberOfVotesInRound;
+
+ // [0, 1] value that determines how coherent the juror was in this round, in basis points.
+ (uint256 pnkCoherence, uint256 feeCoherence) = disputeKit.getDegreeOfCoherenceReward(
+ _params.disputeID,
+ _params.round,
+ repartition,
+ _params.feePerJurorInRound,
+ _params.pnkAtStakePerJurorInRound
+ );
+
+ // Extra check to guard against degree exceeding 1, though it should be ensured by the dispute kit.
+ if (pnkCoherence > ONE_BASIS_POINT) {
+ pnkCoherence = ONE_BASIS_POINT;
+ }
+ if (feeCoherence > ONE_BASIS_POINT) {
+ feeCoherence = ONE_BASIS_POINT;
+ }
+
+ address account = round.drawnJurors[repartition];
+ uint256 pnkLocked = _applyCoherence(round.pnkAtStakePerJuror, pnkCoherence);
+
+ // Release the rest of the PNKs of the juror for this round.
+ sortitionModule.unlockStake(account, pnkLocked);
+
+ // Compute the rewards
+ uint256 pnkReward = _applyCoherence(_params.pnkPenaltiesInRound / _params.coherentCount, pnkCoherence);
+ round.sumPnkRewardPaid += pnkReward;
+ uint256 feeReward = _applyCoherence(round.totalFeesForJurors / _params.coherentCount, feeCoherence);
+ round.sumFeeRewardPaid += feeReward;
+
+ if (feeReward != 0) {
+ // Transfer the fee reward
+ _transferFeeToken(round.feeToken, payable(account), feeReward);
+ }
+ if (pnkReward != 0) {
+ uint96 rewardedInCourtID = round.drawnJurorFromCourtIDs[repartition];
+
+ // Stake the PNK reward if possible, bypasses delayed stakes and other checks done by validateStake()
+ if (!sortitionModule.setStakeReward(account, rewardedInCourtID, pnkReward)) {
+ pinakion.safeTransfer(account, pnkReward);
+ }
+ }
+ if (pnkReward != 0 || feeReward != 0) {
+ emit JurorRewardPenalty(
+ account,
+ _params.disputeID,
+ _params.round,
+ pnkCoherence,
+ feeCoherence,
+ int256(pnkReward),
+ int256(feeReward),
+ round.feeToken
+ );
+ }
+
+ // Transfer any residual rewards to the owner. It may happen due to partial coherence of the jurors.
+ if (_params.repartition == _params.numberOfVotesInRound * 2 - 1) {
+ uint256 leftoverPnkReward = _params.pnkPenaltiesInRound - round.sumPnkRewardPaid;
+ uint256 leftoverFeeReward = round.totalFeesForJurors - round.sumFeeRewardPaid;
+ if (leftoverPnkReward != 0 || leftoverFeeReward != 0) {
+ if (leftoverPnkReward != 0) {
+ pinakion.safeTransfer(owner, leftoverPnkReward);
+ }
+ if (leftoverFeeReward != 0) {
+ _transferFeeToken(round.feeToken, payable(owner), leftoverFeeReward);
+ }
+ emit LeftoverRewardSent(
+ _params.disputeID,
+ _params.round,
+ leftoverPnkReward,
+ leftoverFeeReward,
+ round.feeToken
+ );
+ }
+ }
+ }
+
+ /// @notice Executes a specified dispute's ruling.
+ /// @param _disputeID The ID of the dispute.
+ function executeRuling(uint256 _disputeID) external {
+ Dispute storage dispute = disputes[_disputeID];
+ if (dispute.period != Period.execution) revert NotExecutionPeriod();
+ if (dispute.ruled) revert RulingAlreadyExecuted();
+
+ (uint256 winningChoice, , ) = currentRuling(_disputeID);
+ dispute.ruled = true;
+ emit Ruling(dispute.arbitrated, _disputeID, winningChoice);
+ dispute.arbitrated.rule(_disputeID, winningChoice);
+ }
+
+ // ************************************* //
+ // * Public Views * //
+ // ************************************* //
+
+ /// @inheritdoc IArbitratorV2
+ function arbitrationCost(bytes memory _extraData) public view override returns (uint256 cost) {
+ (uint96 courtID, uint256 minJurors, ) = _extraDataToCourtIDMinJurorsDisputeKit(_extraData);
+ cost = courts[courtID].feeForJuror * minJurors;
+ }
+
+ /// @inheritdoc IArbitratorV2
+ function arbitrationCost(bytes calldata _extraData, IERC20 _feeToken) public view override returns (uint256 cost) {
+ cost = convertEthToTokenAmount(_feeToken, arbitrationCost(_extraData));
+ }
+
+ /// @notice Gets the cost of appealing a specified dispute.
+ /// @param _disputeID The ID of the dispute.
+ /// @return cost The appeal cost.
+ function appealCost(uint256 _disputeID) public view returns (uint256 cost) {
+ Dispute storage dispute = disputes[_disputeID];
+ Round storage round = dispute.rounds[dispute.rounds.length - 1];
+ Court storage court = courts[dispute.courtID];
+
+ (, uint256 newDisputeKitID, bool courtJump, ) = _getCourtAndDisputeKitJumps(dispute, round, court, _disputeID);
+
+ uint256 nbVotesAfterAppeal = disputeKits[newDisputeKitID].getNbVotesAfterAppeal(
+ disputeKits[round.disputeKitID],
+ round.nbVotes
+ );
+
+ if (courtJump) {
+ // Jump to parent court.
+ if (dispute.courtID == GENERAL_COURT) {
+ // TODO: Handle the forking when appealed in General court.
+ cost = NON_PAYABLE_AMOUNT; // Get the cost of the parent court.
+ } else {
+ cost = courts[court.parent].feeForJuror * nbVotesAfterAppeal;
+ }
+ } else {
+ // Stay in current court.
+ cost = court.feeForJuror * nbVotesAfterAppeal;
+ }
+ }
+
+ /// @notice Gets the start and the end of a specified dispute's current appeal period.
+ /// @param _disputeID The ID of the dispute.
+ /// @return start The start of the appeal period.
+ /// @return end The end of the appeal period.
+ function appealPeriod(uint256 _disputeID) external view returns (uint256 start, uint256 end) {
+ Dispute storage dispute = disputes[_disputeID];
+ if (dispute.period == Period.appeal) {
+ start = dispute.lastPeriodChange;
+ end = dispute.lastPeriodChange + courts[dispute.courtID].timesPerPeriod[uint256(Period.appeal)];
+ } else {
+ start = 0;
+ end = 0;
+ }
+ }
+
+ /// @inheritdoc IArbitratorV2
+ function currentRuling(uint256 _disputeID) public view returns (uint256 ruling, bool tied, bool overridden) {
+ Dispute storage dispute = disputes[_disputeID];
+ Round storage round = dispute.rounds[dispute.rounds.length - 1];
+ IDisputeKit disputeKit = disputeKits[round.disputeKitID];
+ (ruling, tied, overridden) = disputeKit.currentRuling(_disputeID);
+ }
+
+ /// @notice Gets the round info for a specified dispute and round.
+ /// @dev This function must not be called from a non-view function because it returns a dynamic array which might be very large, theoretically exceeding the block gas limit.
+ /// @param _disputeID The ID of the dispute.
+ /// @param _round The round to get the info for.
+ /// @return round The round info.
+ function getRoundInfo(uint256 _disputeID, uint256 _round) external view returns (Round memory) {
+ return disputes[_disputeID].rounds[_round];
+ }
+
+ /// @notice Gets the PNK at stake per juror for a specified dispute and round.
+ /// @param _disputeID The ID of the dispute.
+ /// @param _round The round to get the info for.
+ /// @return pnkAtStakePerJuror The PNK at stake per juror.
+ function getPnkAtStakePerJuror(uint256 _disputeID, uint256 _round) external view returns (uint256) {
+ return disputes[_disputeID].rounds[_round].pnkAtStakePerJuror;
+ }
+
+ /// @notice Gets the number of rounds for a specified dispute.
+ /// @param _disputeID The ID of the dispute.
+ /// @return The number of rounds.
+ function getNumberOfRounds(uint256 _disputeID) external view returns (uint256) {
+ return disputes[_disputeID].rounds.length;
+ }
+
+ /// @notice Checks if a given dispute kit is supported by a given court.
+ /// @param _courtID The ID of the court to check the support for.
+ /// @param _disputeKitID The ID of the dispute kit to check the support for.
+ /// @return Whether the dispute kit is supported or not.
+ function isSupported(uint96 _courtID, uint256 _disputeKitID) external view returns (bool) {
+ return courts[_courtID].supportedDisputeKits[_disputeKitID];
+ }
+
+ /// @notice Gets the timesPerPeriod array for a given court.
+ /// @param _courtID The ID of the court to get the times from.
+ /// @return timesPerPeriod The timesPerPeriod array for the given court.
+ function getTimesPerPeriod(uint96 _courtID) external view returns (uint256[4] memory timesPerPeriod) {
+ timesPerPeriod = courts[_courtID].timesPerPeriod;
+ }
+
+ // ************************************* //
+ // * Public Views for Dispute Kits * //
+ // ************************************* //
+
+ /// @notice Gets the number of votes permitted for the specified dispute in the latest round.
+ /// @param _disputeID The ID of the dispute.
+ function getNumberOfVotes(uint256 _disputeID) external view returns (uint256) {
+ Dispute storage dispute = disputes[_disputeID];
+ return dispute.rounds[dispute.rounds.length - 1].nbVotes;
+ }
+
+ /// @notice Returns true if the dispute kit will be switched to a parent DK.
+ /// @param _disputeID The ID of the dispute.
+ /// @return Whether DK will be switched or not.
+ function isDisputeKitJumping(uint256 _disputeID) external view returns (bool) {
+ Dispute storage dispute = disputes[_disputeID];
+ Round storage round = dispute.rounds[dispute.rounds.length - 1];
+ Court storage court = courts[dispute.courtID];
+
+ if (!_isCourtJumping(round, court, _disputeID)) {
+ return false;
+ }
+
+ // Jump if the parent court doesn't support the current DK.
+ return !courts[court.parent].supportedDisputeKits[round.disputeKitID];
+ }
+
+ /// @notice Returns the length of disputeKits array.
+ /// @return disputeKits length.
+ function getDisputeKitsLength() external view returns (uint256) {
+ return disputeKits.length;
+ }
+
+ /// @notice Converts ETH into tokens.
+ /// @param _toToken The token to convert ETH into.
+ /// @param _amountInEth ETH amount.
+ /// @return Amount of tokens.
+ function convertEthToTokenAmount(IERC20 _toToken, uint256 _amountInEth) public view returns (uint256) {
+ return (_amountInEth * 10 ** currencyRates[_toToken].rateDecimals) / currencyRates[_toToken].rateInEth;
+ }
+
+ // ************************************* //
+ // * Internal * //
+ // ************************************* //
+
+ /// @notice Returns true if the round is jumping to a parent court.
+ /// @param _round The round to check.
+ /// @param _court The court to check.
+ /// @return Whether the round is jumping to a parent court or not.
+ function _isCourtJumping(
+ Round storage _round,
+ Court storage _court,
+ uint256 _disputeID
+ ) internal view returns (bool) {
+ return
+ disputeKits[_round.disputeKitID].earlyCourtJump(_disputeID) || _round.nbVotes >= _court.jurorsForCourtJump;
+ }
+
+ /// @notice Checks whether a dispute will jump to new court/DK, and returns new court and DK.
+ /// @param _dispute Dispute data.
+ /// @param _round Round ID.
+ /// @param _court Current court ID.
+ /// @param _disputeID Dispute ID.
+ /// @return newCourtID Court ID after jump.
+ /// @return newDisputeKitID Dispute kit ID after jump.
+ /// @return courtJump Whether the dispute jumps to a new court or not.
+ /// @return disputeKitJump Whether the dispute jumps to a new dispute kit or not.
+ function _getCourtAndDisputeKitJumps(
+ Dispute storage _dispute,
+ Round storage _round,
+ Court storage _court,
+ uint256 _disputeID
+ ) internal view returns (uint96 newCourtID, uint256 newDisputeKitID, bool courtJump, bool disputeKitJump) {
+ newCourtID = _dispute.courtID;
+ newDisputeKitID = _round.disputeKitID;
+
+ if (!_isCourtJumping(_round, _court, _disputeID)) return (newCourtID, newDisputeKitID, false, false);
+
+ // Jump to parent court.
+ newCourtID = courts[newCourtID].parent;
+ courtJump = true;
+
+ if (!courts[newCourtID].supportedDisputeKits[newDisputeKitID]) {
+ // The current Dispute Kit is not compatible with the new court, jump to another Dispute Kit.
+ newDisputeKitID = disputeKits[_round.disputeKitID].getJumpDisputeKitID();
+ if (newDisputeKitID == NULL_DISPUTE_KIT || !courts[newCourtID].supportedDisputeKits[newDisputeKitID]) {
+ // The new Dispute Kit is not defined or still not compatible, fall back to `DisputeKitClassic` which is always supported.
+ newDisputeKitID = DISPUTE_KIT_CLASSIC;
+ }
+ disputeKitJump = true;
+ }
+ }
+
+ /// @notice Internal function to transfer fee tokens (ETH or ERC20)
+ /// @param _feeToken The token to transfer (NATIVE_CURRENCY for ETH).
+ /// @param _recipient The recipient address.
+ /// @param _amount The amount to transfer.
+ function _transferFeeToken(IERC20 _feeToken, address payable _recipient, uint256 _amount) internal {
+ if (_feeToken == NATIVE_CURRENCY) {
+ _recipient.safeSend(_amount, wNative);
+ } else {
+ _feeToken.safeTransfer(_recipient, _amount);
+ }
+ }
+
+ /// @notice Applies degree of coherence to an amount
+ /// @param _amount The base amount to apply coherence to.
+ /// @param _coherence The degree of coherence in basis points.
+ /// @return The amount after applying the degree of coherence.
+ function _applyCoherence(uint256 _amount, uint256 _coherence) internal pure returns (uint256) {
+ return (_amount * _coherence) / ONE_BASIS_POINT;
+ }
+
+ /// @notice Calculates PNK at stake per juror based on court parameters
+ /// @param _minStake The minimum stake for the court.
+ /// @param _alpha The alpha parameter for the court in basis points.
+ /// @return The amount of PNK at stake per juror.
+ function _calculatePnkAtStake(uint256 _minStake, uint256 _alpha) internal pure returns (uint256) {
+ return (_minStake * _alpha) / ONE_BASIS_POINT;
+ }
+
+ /// @notice Toggles the dispute kit support for a given court.
+ /// @param _courtID The ID of the court to toggle the support for.
+ /// @param _disputeKitID The ID of the dispute kit to toggle the support for.
+ /// @param _enable Whether to enable or disable the support. Note that classic dispute kit should always be enabled.
+ function _enableDisputeKit(uint96 _courtID, uint256 _disputeKitID, bool _enable) internal {
+ courts[_courtID].supportedDisputeKits[_disputeKitID] = _enable;
+ emit DisputeKitEnabled(_courtID, _disputeKitID, _enable);
+ }
+
+ /// @notice If called only once then set _onError to Revert, otherwise set it to Return
+ /// @param _account The account to set the stake for.
+ /// @param _courtID The ID of the court to set the stake for.
+ /// @param _newStake The new stake.
+ /// @param _noDelay True if the stake change should not be delayed.
+ /// @param _onError Whether to revert or return false on error.
+ /// @return Whether the stake was successfully set or not.
+ function _setStake(
+ address _account,
+ uint96 _courtID,
+ uint256 _newStake,
+ bool _noDelay,
+ OnError _onError
+ ) internal returns (bool) {
+ if (_courtID == FORKING_COURT || _courtID >= courts.length) {
+ _stakingFailed(_onError, StakingResult.CannotStakeInThisCourt); // Staking directly into the forking court is not allowed.
+ return false;
+ }
+ if (_newStake != 0 && _newStake < courts[_courtID].minStake) {
+ _stakingFailed(_onError, StakingResult.CannotStakeLessThanMinStake); // Staking less than the minimum stake is not allowed.
+ return false;
+ }
+ (uint256 pnkDeposit, uint256 pnkWithdrawal, StakingResult stakingResult) = sortitionModule.validateStake(
+ _account,
+ _courtID,
+ _newStake,
+ _noDelay
+ );
+ if (stakingResult != StakingResult.Successful && stakingResult != StakingResult.Delayed) {
+ _stakingFailed(_onError, stakingResult);
+ return false;
+ } else if (stakingResult == StakingResult.Delayed) {
+ return true;
+ }
+ if (pnkDeposit > 0) {
+ if (!pinakion.safeTransferFrom(_account, address(this), pnkDeposit)) {
+ _stakingFailed(_onError, StakingResult.StakingTransferFailed);
+ return false;
+ }
+ }
+ if (pnkWithdrawal > 0) {
+ if (!pinakion.safeTransfer(_account, pnkWithdrawal)) {
+ _stakingFailed(_onError, StakingResult.UnstakingTransferFailed);
+ return false;
+ }
+ }
+ sortitionModule.setStake(_account, _courtID, pnkDeposit, pnkWithdrawal, _newStake);
+
+ return true;
+ }
+
+ /// @notice It may revert depending on the _onError parameter.
+ function _stakingFailed(OnError _onError, StakingResult _result) internal pure {
+ if (_onError == OnError.Return) return;
+ if (_result == StakingResult.StakingTransferFailed) revert StakingTransferFailed();
+ if (_result == StakingResult.UnstakingTransferFailed) revert UnstakingTransferFailed();
+ if (_result == StakingResult.CannotStakeInMoreCourts) revert StakingInTooManyCourts();
+ if (_result == StakingResult.CannotStakeInThisCourt) revert StakingNotPossibleInThisCourt();
+ if (_result == StakingResult.CannotStakeLessThanMinStake) revert StakingLessThanCourtMinStake();
+ if (_result == StakingResult.CannotStakeZeroWhenNoStake) revert StakingZeroWhenNoStake();
+ if (_result == StakingResult.CannotStakeMoreThanMaxStakePerJuror) revert StakingMoreThanMaxStakePerJuror();
+ if (_result == StakingResult.CannotStakeMoreThanMaxTotalStaked) revert StakingMoreThanMaxTotalStaked();
+ }
+
+ /// @notice Gets a court ID, the minimum number of jurors and an ID of a dispute kit from a specified extra data bytes array.
+ /// @dev If `_extraData` contains an incorrect value then this value will be switched to default.
+ /// @param _extraData The extra data bytes array. The first 32 bytes are the court ID, the next are the minimum number of jurors and the last are the dispute kit ID.
+ /// @return courtID The court ID.
+ /// @return minJurors The minimum number of jurors required.
+ /// @return disputeKitID The ID of the dispute kit.
+ function _extraDataToCourtIDMinJurorsDisputeKit(
+ bytes memory _extraData
+ ) internal view returns (uint96 courtID, uint256 minJurors, uint256 disputeKitID) {
+ // Note that if the _extraData doesn't contain 32 bytes, default values are used.
+ if (_extraData.length >= 64) {
+ assembly {
+ // solium-disable-line security/no-inline-assembly
+ courtID := mload(add(_extraData, 0x20))
+ minJurors := mload(add(_extraData, 0x40))
+ disputeKitID := mload(add(_extraData, 0x60))
+ }
+ if (courtID == FORKING_COURT || courtID >= courts.length) {
+ courtID = GENERAL_COURT;
+ }
+ if (minJurors == 0) {
+ minJurors = DEFAULT_NB_OF_JURORS;
+ }
+ if (disputeKitID == NULL_DISPUTE_KIT || disputeKitID >= disputeKits.length) {
+ disputeKitID = DISPUTE_KIT_CLASSIC;
+ }
+ } else {
+ courtID = GENERAL_COURT;
+ minJurors = DEFAULT_NB_OF_JURORS;
+ disputeKitID = DISPUTE_KIT_CLASSIC;
+ }
+ }
+
+ // ************************************* //
+ // * Errors * //
+ // ************************************* //
+
+ error OwnerOnly();
+ error GuardianOrOwnerOnly();
+ error DisputeKitOnly();
+ error SortitionModuleOnly();
+ error UnsuccessfulCall();
+ error InvalidDisputeKitParent();
+ error MinStakeLowerThanParentCourt();
+ error MinStakeHigherThanChildCourt(uint256 _childCourtID);
+ error UnsupportedDisputeKit();
+ error InvalidForkingCourtAsParent();
+ error WrongDisputeKitIndex();
+ error CannotDisableClassicDK();
+ error NotEligibleForStaking();
+ error StakingMoreThanMaxStakePerJuror();
+ error StakingMoreThanMaxTotalStaked();
+ error StakingInTooManyCourts();
+ error StakingNotPossibleInThisCourt();
+ error StakingLessThanCourtMinStake();
+ error StakingTransferFailed();
+ error UnstakingTransferFailed();
+ error ArbitrableNotWhitelisted();
+ error ArbitrationFeesNotEnough();
+ error DisputeKitNotSupportedByCourt();
+ error MustSupportDisputeKitClassic();
+ error TokenNotAccepted();
+ error EvidenceNotPassedAndNotAppeal();
+ error DisputeStillDrawing();
+ error CommitPeriodNotPassed();
+ error VotePeriodNotPassed();
+ error AppealPeriodNotPassed();
+ error NotEvidencePeriod();
+ error AppealFeesNotEnough();
+ error DisputeNotAppealable();
+ error NotExecutionPeriod();
+ error RulingAlreadyExecuted();
+ error DisputePeriodIsFinal();
+ error TransferFailed();
+ error WhenNotPausedOnly();
+ error WhenPausedOnly();
+ error StakingZeroWhenNoStake();
}
diff --git a/contracts/src/arbitration/KlerosCoreBase.sol b/contracts/src/arbitration/KlerosCoreBase.sol
deleted file mode 100644
index 2b9998bda..000000000
--- a/contracts/src/arbitration/KlerosCoreBase.sol
+++ /dev/null
@@ -1,1211 +0,0 @@
-// SPDX-License-Identifier: MIT
-
-pragma solidity ^0.8.24;
-
-import {IArbitrableV2, IArbitratorV2} from "./interfaces/IArbitratorV2.sol";
-import {IDisputeKit} from "./interfaces/IDisputeKit.sol";
-import {ISortitionModule} from "./interfaces/ISortitionModule.sol";
-import {Initializable} from "../proxy/Initializable.sol";
-import {UUPSProxiable} from "../proxy/UUPSProxiable.sol";
-import {SafeERC20, IERC20} from "../libraries/SafeERC20.sol";
-import {SafeSend} from "../libraries/SafeSend.sol";
-import "../libraries/Constants.sol";
-
-/// @title KlerosCoreBase
-/// Core arbitrator contract for Kleros v2.
-/// Note that this contract trusts the PNK token, the dispute kit and the sortition module contracts.
-abstract contract KlerosCoreBase is IArbitratorV2, Initializable, UUPSProxiable {
- using SafeERC20 for IERC20;
- using SafeSend for address payable;
-
- // ************************************* //
- // * Enums / Structs * //
- // ************************************* //
-
- enum Period {
- evidence, // Evidence can be submitted. This is also when drawing has to take place.
- commit, // Jurors commit a hashed vote. This is skipped for courts without hidden votes.
- vote, // Jurors reveal/cast their vote depending on whether the court has hidden votes or not.
- appeal, // The dispute can be appealed.
- execution // Tokens are redistributed and the ruling is executed.
- }
-
- struct Court {
- uint96 parent; // The parent court.
- bool hiddenVotes; // Whether to use commit and reveal or not.
- uint256[] children; // List of child courts.
- uint256 minStake; // Minimum PNKs needed to stake in the court.
- uint256 alpha; // Basis point of PNKs that are lost when incoherent.
- uint256 feeForJuror; // Arbitration fee paid per juror.
- uint256 jurorsForCourtJump; // The appeal after the one that reaches this number of jurors will go to the parent court if any.
- uint256[4] timesPerPeriod; // The time allotted to each dispute period in the form `timesPerPeriod[period]`.
- mapping(uint256 disputeKitId => bool) supportedDisputeKits; // True if DK with this ID is supported by the court. Note that each court must support classic dispute kit.
- bool disabled; // True if the court is disabled. Unused for now, will be implemented later.
- }
-
- struct Dispute {
- uint96 courtID; // The ID of the court the dispute is in.
- IArbitrableV2 arbitrated; // The arbitrable contract.
- Period period; // The current period of the dispute.
- bool ruled; // True if the ruling has been executed, false otherwise.
- uint256 lastPeriodChange; // The last time the period was changed.
- Round[] rounds;
- }
-
- struct Round {
- uint256 disputeKitID; // Index of the dispute kit in the array.
- uint256 pnkAtStakePerJuror; // The amount of PNKs at stake for each juror in this round.
- uint256 totalFeesForJurors; // The total juror fees paid in this round.
- uint256 nbVotes; // The total number of votes the dispute can possibly have in the current round. Former votes[_round].length.
- uint256 repartitions; // A counter of reward repartitions made in this round.
- uint256 pnkPenalties; // The amount of PNKs collected from penalties in this round.
- address[] drawnJurors; // Addresses of the jurors that were drawn in this round.
- uint256 sumFeeRewardPaid; // Total sum of arbitration fees paid to coherent jurors as a reward in this round.
- uint256 sumPnkRewardPaid; // Total sum of PNK paid to coherent jurors as a reward in this round.
- IERC20 feeToken; // The token used for paying fees in this round.
- uint256 drawIterations; // The number of iterations passed drawing the jurors for this round.
- }
-
- // Workaround "stack too deep" errors
- struct ExecuteParams {
- uint256 disputeID; // The ID of the dispute to execute.
- uint256 round; // The round to execute.
- uint256 coherentCount; // The number of coherent votes in the round.
- uint256 numberOfVotesInRound; // The number of votes in the round.
- uint256 feePerJurorInRound; // The fee per juror in the round.
- uint256 pnkAtStakePerJurorInRound; // The amount of PNKs at stake for each juror in the round.
- uint256 pnkPenaltiesInRound; // The amount of PNKs collected from penalties in the round.
- uint256 repartition; // The index of the repartition to execute.
- }
-
- struct CurrencyRate {
- bool feePaymentAccepted;
- uint64 rateInEth;
- uint8 rateDecimals;
- }
-
- // ************************************* //
- // * Storage * //
- // ************************************* //
-
- uint256 private constant ALPHA_DIVISOR = 1e4; // The number to divide `Court.alpha` by.
- uint256 private constant NON_PAYABLE_AMOUNT = (2 ** 256 - 2) / 2; // An amount higher than the supply of ETH.
-
- address public governor; // The governor of the contract.
- address public guardian; // The guardian able to pause asset withdrawals.
- IERC20 public pinakion; // The Pinakion token contract.
- address public jurorProsecutionModule; // The module for juror's prosecution.
- ISortitionModule public sortitionModule; // Sortition module for drawing.
- Court[] public courts; // The courts.
- IDisputeKit[] public disputeKits; // Array of dispute kits.
- Dispute[] public disputes; // The disputes.
- mapping(IERC20 => CurrencyRate) public currencyRates; // The price of each token in ETH.
- bool public paused; // Whether asset withdrawals are paused.
- address public wNative; // The wrapped native token for safeSend().
-
- // ************************************* //
- // * Events * //
- // ************************************* //
-
- event NewPeriod(uint256 indexed _disputeID, Period _period);
- event AppealPossible(uint256 indexed _disputeID, IArbitrableV2 indexed _arbitrable);
- event AppealDecision(uint256 indexed _disputeID, IArbitrableV2 indexed _arbitrable);
- event Draw(address indexed _address, uint256 indexed _disputeID, uint256 _roundID, uint256 _voteID);
- event CourtCreated(
- uint96 indexed _courtID,
- uint96 indexed _parent,
- bool _hiddenVotes,
- uint256 _minStake,
- uint256 _alpha,
- uint256 _feeForJuror,
- uint256 _jurorsForCourtJump,
- uint256[4] _timesPerPeriod,
- uint256[] _supportedDisputeKits
- );
- event CourtModified(
- uint96 indexed _courtID,
- bool _hiddenVotes,
- uint256 _minStake,
- uint256 _alpha,
- uint256 _feeForJuror,
- uint256 _jurorsForCourtJump,
- uint256[4] _timesPerPeriod
- );
- event DisputeKitCreated(uint256 indexed _disputeKitID, IDisputeKit indexed _disputeKitAddress);
- event DisputeKitEnabled(uint96 indexed _courtID, uint256 indexed _disputeKitID, bool indexed _enable);
- event CourtJump(
- uint256 indexed _disputeID,
- uint256 indexed _roundID,
- uint96 indexed _fromCourtID,
- uint96 _toCourtID
- );
- event DisputeKitJump(
- uint256 indexed _disputeID,
- uint256 indexed _roundID,
- uint256 indexed _fromDisputeKitID,
- uint256 _toDisputeKitID
- );
- event TokenAndETHShift(
- address indexed _account,
- uint256 indexed _disputeID,
- uint256 indexed _roundID,
- uint256 _degreeOfCoherency,
- int256 _pnkAmount,
- int256 _feeAmount,
- IERC20 _feeToken
- );
- event LeftoverRewardSent(
- uint256 indexed _disputeID,
- uint256 indexed _roundID,
- uint256 _pnkAmount,
- uint256 _feeAmount,
- IERC20 _feeToken
- );
- event Paused();
- event Unpaused();
-
- // ************************************* //
- // * Function Modifiers * //
- // ************************************* //
-
- modifier onlyByGovernor() {
- if (governor != msg.sender) revert GovernorOnly();
- _;
- }
-
- modifier onlyByGuardianOrGovernor() {
- if (guardian != msg.sender && governor != msg.sender) revert GuardianOrGovernorOnly();
- _;
- }
-
- modifier whenPaused() {
- if (!paused) revert WhenPausedOnly();
- _;
- }
-
- modifier whenNotPaused() {
- if (paused) revert WhenNotPausedOnly();
- _;
- }
-
- // ************************************* //
- // * Constructor * //
- // ************************************* //
-
- function __KlerosCoreBase_initialize(
- address _governor,
- address _guardian,
- IERC20 _pinakion,
- address _jurorProsecutionModule,
- IDisputeKit _disputeKit,
- bool _hiddenVotes,
- uint256[4] memory _courtParameters,
- uint256[4] memory _timesPerPeriod,
- bytes memory _sortitionExtraData,
- ISortitionModule _sortitionModuleAddress,
- address _wNative
- ) internal onlyInitializing {
- governor = _governor;
- guardian = _guardian;
- pinakion = _pinakion;
- jurorProsecutionModule = _jurorProsecutionModule;
- sortitionModule = _sortitionModuleAddress;
- wNative = _wNative;
-
- // NULL_DISPUTE_KIT: an empty element at index 0 to indicate when a dispute kit is not supported.
- disputeKits.push();
-
- // DISPUTE_KIT_CLASSIC
- disputeKits.push(_disputeKit);
-
- emit DisputeKitCreated(DISPUTE_KIT_CLASSIC, _disputeKit);
-
- // FORKING_COURT
- // TODO: Fill the properties for the Forking court, emit CourtCreated.
- courts.push();
- sortitionModule.createTree(bytes32(uint256(FORKING_COURT)), _sortitionExtraData);
-
- // GENERAL_COURT
- Court storage court = courts.push();
- court.parent = FORKING_COURT;
- court.children = new uint256[](0);
- court.hiddenVotes = _hiddenVotes;
- court.minStake = _courtParameters[0];
- court.alpha = _courtParameters[1];
- court.feeForJuror = _courtParameters[2];
- court.jurorsForCourtJump = _courtParameters[3];
- court.timesPerPeriod = _timesPerPeriod;
-
- sortitionModule.createTree(bytes32(uint256(GENERAL_COURT)), _sortitionExtraData);
-
- uint256[] memory supportedDisputeKits = new uint256[](1);
- supportedDisputeKits[0] = DISPUTE_KIT_CLASSIC;
- emit CourtCreated(
- GENERAL_COURT,
- court.parent,
- _hiddenVotes,
- _courtParameters[0],
- _courtParameters[1],
- _courtParameters[2],
- _courtParameters[3],
- _timesPerPeriod,
- supportedDisputeKits
- );
- _enableDisputeKit(GENERAL_COURT, DISPUTE_KIT_CLASSIC, true);
- }
-
- // ************************************* //
- // * Governance * //
- // ************************************* //
-
- /// @dev Pause staking and reward execution. Can only be done by guardian or governor.
- function pause() external onlyByGuardianOrGovernor whenNotPaused {
- paused = true;
- emit Paused();
- }
-
- /// @dev Unpause staking and reward execution. Can only be done by governor.
- function unpause() external onlyByGovernor whenPaused {
- paused = false;
- emit Unpaused();
- }
-
- /// @dev Allows the governor to call anything on behalf of the contract.
- /// @param _destination The destination of the call.
- /// @param _amount The value sent with the call.
- /// @param _data The data sent with the call.
- function executeGovernorProposal(
- address _destination,
- uint256 _amount,
- bytes memory _data
- ) external onlyByGovernor {
- (bool success, ) = _destination.call{value: _amount}(_data);
- if (!success) revert UnsuccessfulCall();
- }
-
- /// @dev Changes the `governor` storage variable.
- /// @param _governor The new value for the `governor` storage variable.
- function changeGovernor(address payable _governor) external onlyByGovernor {
- governor = _governor;
- }
-
- /// @dev Changes the `guardian` storage variable.
- /// @param _guardian The new value for the `guardian` storage variable.
- function changeGuardian(address _guardian) external onlyByGovernor {
- guardian = _guardian;
- }
-
- /// @dev Changes the `pinakion` storage variable.
- /// @param _pinakion The new value for the `pinakion` storage variable.
- function changePinakion(IERC20 _pinakion) external onlyByGovernor {
- pinakion = _pinakion;
- }
-
- /// @dev Changes the `jurorProsecutionModule` storage variable.
- /// @param _jurorProsecutionModule The new value for the `jurorProsecutionModule` storage variable.
- function changeJurorProsecutionModule(address _jurorProsecutionModule) external onlyByGovernor {
- jurorProsecutionModule = _jurorProsecutionModule;
- }
-
- /// @dev Changes the `_sortitionModule` storage variable.
- /// Note that the new module should be initialized for all courts.
- /// @param _sortitionModule The new value for the `sortitionModule` storage variable.
- function changeSortitionModule(ISortitionModule _sortitionModule) external onlyByGovernor {
- sortitionModule = _sortitionModule;
- }
-
- /// @dev Add a new supported dispute kit module to the court.
- /// @param _disputeKitAddress The address of the dispute kit contract.
- function addNewDisputeKit(IDisputeKit _disputeKitAddress) external onlyByGovernor {
- uint256 disputeKitID = disputeKits.length;
- disputeKits.push(_disputeKitAddress);
- emit DisputeKitCreated(disputeKitID, _disputeKitAddress);
- }
-
- /// @dev Creates a court under a specified parent court.
- /// @param _parent The `parent` property value of the court.
- /// @param _hiddenVotes The `hiddenVotes` property value of the court.
- /// @param _minStake The `minStake` property value of the court.
- /// @param _alpha The `alpha` property value of the court.
- /// @param _feeForJuror The `feeForJuror` property value of the court.
- /// @param _jurorsForCourtJump The `jurorsForCourtJump` property value of the court.
- /// @param _timesPerPeriod The `timesPerPeriod` property value of the court.
- /// @param _sortitionExtraData Extra data for sortition module.
- /// @param _supportedDisputeKits Indexes of dispute kits that this court will support.
- function createCourt(
- uint96 _parent,
- bool _hiddenVotes,
- uint256 _minStake,
- uint256 _alpha,
- uint256 _feeForJuror,
- uint256 _jurorsForCourtJump,
- uint256[4] memory _timesPerPeriod,
- bytes memory _sortitionExtraData,
- uint256[] memory _supportedDisputeKits
- ) external onlyByGovernor {
- if (courts[_parent].minStake > _minStake) revert MinStakeLowerThanParentCourt();
- if (_supportedDisputeKits.length == 0) revert UnsupportedDisputeKit();
- if (_parent == FORKING_COURT) revert InvalidForkingCourtAsParent();
-
- uint256 courtID = courts.length;
- Court storage court = courts.push();
-
- for (uint256 i = 0; i < _supportedDisputeKits.length; i++) {
- if (_supportedDisputeKits[i] == 0 || _supportedDisputeKits[i] >= disputeKits.length) {
- revert WrongDisputeKitIndex();
- }
- _enableDisputeKit(uint96(courtID), _supportedDisputeKits[i], true);
- }
- // Check that Classic DK support was added.
- if (!court.supportedDisputeKits[DISPUTE_KIT_CLASSIC]) revert MustSupportDisputeKitClassic();
-
- court.parent = _parent;
- court.children = new uint256[](0);
- court.hiddenVotes = _hiddenVotes;
- court.minStake = _minStake;
- court.alpha = _alpha;
- court.feeForJuror = _feeForJuror;
- court.jurorsForCourtJump = _jurorsForCourtJump;
- court.timesPerPeriod = _timesPerPeriod;
-
- sortitionModule.createTree(bytes32(courtID), _sortitionExtraData);
-
- // Update the parent.
- courts[_parent].children.push(courtID);
- emit CourtCreated(
- uint96(courtID),
- _parent,
- _hiddenVotes,
- _minStake,
- _alpha,
- _feeForJuror,
- _jurorsForCourtJump,
- _timesPerPeriod,
- _supportedDisputeKits
- );
- }
-
- function changeCourtParameters(
- uint96 _courtID,
- bool _hiddenVotes,
- uint256 _minStake,
- uint256 _alpha,
- uint256 _feeForJuror,
- uint256 _jurorsForCourtJump,
- uint256[4] memory _timesPerPeriod
- ) external onlyByGovernor {
- Court storage court = courts[_courtID];
- if (_courtID != GENERAL_COURT && courts[court.parent].minStake > _minStake) {
- revert MinStakeLowerThanParentCourt();
- }
- for (uint256 i = 0; i < court.children.length; i++) {
- if (courts[court.children[i]].minStake < _minStake) {
- revert MinStakeLowerThanParentCourt();
- }
- }
- court.minStake = _minStake;
- court.hiddenVotes = _hiddenVotes;
- court.alpha = _alpha;
- court.feeForJuror = _feeForJuror;
- court.jurorsForCourtJump = _jurorsForCourtJump;
- court.timesPerPeriod = _timesPerPeriod;
- emit CourtModified(
- _courtID,
- _hiddenVotes,
- _minStake,
- _alpha,
- _feeForJuror,
- _jurorsForCourtJump,
- _timesPerPeriod
- );
- }
-
- /// @dev Adds/removes court's support for specified dispute kits.
- /// @param _courtID The ID of the court.
- /// @param _disputeKitIDs The IDs of dispute kits which support should be added/removed.
- /// @param _enable Whether add or remove the dispute kits from the court.
- function enableDisputeKits(uint96 _courtID, uint256[] memory _disputeKitIDs, bool _enable) external onlyByGovernor {
- for (uint256 i = 0; i < _disputeKitIDs.length; i++) {
- if (_enable) {
- if (_disputeKitIDs[i] == 0 || _disputeKitIDs[i] >= disputeKits.length) {
- revert WrongDisputeKitIndex();
- }
- _enableDisputeKit(_courtID, _disputeKitIDs[i], true);
- } else {
- // Classic dispute kit must be supported by all courts.
- if (_disputeKitIDs[i] == DISPUTE_KIT_CLASSIC) {
- revert CannotDisableClassicDK();
- }
- _enableDisputeKit(_courtID, _disputeKitIDs[i], false);
- }
- }
- }
-
- /// @dev Changes the supported fee tokens.
- /// @param _feeToken The fee token.
- /// @param _accepted Whether the token is supported or not as a method of fee payment.
- function changeAcceptedFeeTokens(IERC20 _feeToken, bool _accepted) external onlyByGovernor {
- currencyRates[_feeToken].feePaymentAccepted = _accepted;
- emit AcceptedFeeToken(_feeToken, _accepted);
- }
-
- /// @dev Changes the currency rate of a fee token.
- /// @param _feeToken The fee token.
- /// @param _rateInEth The new rate of the fee token in ETH.
- /// @param _rateDecimals The new decimals of the fee token rate.
- function changeCurrencyRates(IERC20 _feeToken, uint64 _rateInEth, uint8 _rateDecimals) external onlyByGovernor {
- currencyRates[_feeToken].rateInEth = _rateInEth;
- currencyRates[_feeToken].rateDecimals = _rateDecimals;
- emit NewCurrencyRate(_feeToken, _rateInEth, _rateDecimals);
- }
-
- // ************************************* //
- // * State Modifiers * //
- // ************************************* //
-
- /// @dev Sets the caller's stake in a court.
- /// @param _courtID The ID of the court.
- /// @param _newStake The new stake.
- /// Note that the existing delayed stake will be nullified as non-relevant.
- function setStake(uint96 _courtID, uint256 _newStake) external virtual whenNotPaused {
- _setStake(msg.sender, _courtID, _newStake, OnError.Revert);
- }
-
- /// @dev Sets the stake of a specified account in a court, typically to apply a delayed stake or unstake inactive jurors.
- /// @param _account The account whose stake is being set.
- /// @param _courtID The ID of the court.
- /// @param _newStake The new stake.
- function setStakeBySortitionModule(address _account, uint96 _courtID, uint256 _newStake) external {
- if (msg.sender != address(sortitionModule)) revert SortitionModuleOnly();
- _setStake(_account, _courtID, _newStake, OnError.Return);
- }
-
- /// @dev Transfers PNK to the juror by SortitionModule.
- /// @param _account The account of the juror whose PNK to transfer.
- /// @param _amount The amount to transfer.
- function transferBySortitionModule(address _account, uint256 _amount) external {
- if (msg.sender != address(sortitionModule)) revert SortitionModuleOnly();
- // Note eligibility is checked in SortitionModule.
- pinakion.safeTransfer(_account, _amount);
- }
-
- /// @inheritdoc IArbitratorV2
- function createDispute(
- uint256 _numberOfChoices,
- bytes memory _extraData
- ) external payable override returns (uint256 disputeID) {
- if (msg.value < arbitrationCost(_extraData)) revert ArbitrationFeesNotEnough();
-
- return _createDispute(_numberOfChoices, _extraData, NATIVE_CURRENCY, msg.value);
- }
-
- /// @inheritdoc IArbitratorV2
- function createDispute(
- uint256 _numberOfChoices,
- bytes calldata _extraData,
- IERC20 _feeToken,
- uint256 _feeAmount
- ) external override returns (uint256 disputeID) {
- if (!currencyRates[_feeToken].feePaymentAccepted) revert TokenNotAccepted();
- if (_feeAmount < arbitrationCost(_extraData, _feeToken)) revert ArbitrationFeesNotEnough();
-
- if (!_feeToken.safeTransferFrom(msg.sender, address(this), _feeAmount)) revert TransferFailed();
- return _createDispute(_numberOfChoices, _extraData, _feeToken, _feeAmount);
- }
-
- function _createDispute(
- uint256 _numberOfChoices,
- bytes memory _extraData,
- IERC20 _feeToken,
- uint256 _feeAmount
- ) internal virtual returns (uint256 disputeID) {
- (uint96 courtID, , uint256 disputeKitID) = _extraDataToCourtIDMinJurorsDisputeKit(_extraData);
- if (!courts[courtID].supportedDisputeKits[disputeKitID]) revert DisputeKitNotSupportedByCourt();
-
- disputeID = disputes.length;
- Dispute storage dispute = disputes.push();
- dispute.courtID = courtID;
- dispute.arbitrated = IArbitrableV2(msg.sender);
- dispute.lastPeriodChange = block.timestamp;
-
- IDisputeKit disputeKit = disputeKits[disputeKitID];
- Court storage court = courts[courtID];
- Round storage round = dispute.rounds.push();
-
- // Obtain the feeForJuror in the same currency as the _feeAmount
- uint256 feeForJuror = (_feeToken == NATIVE_CURRENCY)
- ? court.feeForJuror
- : convertEthToTokenAmount(_feeToken, court.feeForJuror);
- round.nbVotes = _feeAmount / feeForJuror;
- round.disputeKitID = disputeKitID;
- round.pnkAtStakePerJuror = _calculatePnkAtStake(court.minStake, court.alpha);
- round.totalFeesForJurors = _feeAmount;
- round.feeToken = IERC20(_feeToken);
-
- sortitionModule.createDisputeHook(disputeID, 0); // Default round ID.
-
- disputeKit.createDispute(disputeID, _numberOfChoices, _extraData, round.nbVotes);
- emit DisputeCreation(disputeID, IArbitrableV2(msg.sender));
- }
-
- /// @dev Passes the period of a specified dispute.
- /// @param _disputeID The ID of the dispute.
- function passPeriod(uint256 _disputeID) external {
- Dispute storage dispute = disputes[_disputeID];
- Court storage court = courts[dispute.courtID];
-
- uint256 currentRound = dispute.rounds.length - 1;
- Round storage round = dispute.rounds[currentRound];
- if (dispute.period == Period.evidence) {
- if (
- currentRound == 0 &&
- block.timestamp - dispute.lastPeriodChange < court.timesPerPeriod[uint256(dispute.period)]
- ) {
- revert EvidenceNotPassedAndNotAppeal();
- }
- if (round.drawnJurors.length != round.nbVotes) revert DisputeStillDrawing();
- dispute.period = court.hiddenVotes ? Period.commit : Period.vote;
- } else if (dispute.period == Period.commit) {
- if (
- block.timestamp - dispute.lastPeriodChange < court.timesPerPeriod[uint256(dispute.period)] &&
- !disputeKits[round.disputeKitID].areCommitsAllCast(_disputeID)
- ) {
- revert CommitPeriodNotPassed();
- }
- dispute.period = Period.vote;
- } else if (dispute.period == Period.vote) {
- if (
- block.timestamp - dispute.lastPeriodChange < court.timesPerPeriod[uint256(dispute.period)] &&
- !disputeKits[round.disputeKitID].areVotesAllCast(_disputeID)
- ) {
- revert VotePeriodNotPassed();
- }
- dispute.period = Period.appeal;
- emit AppealPossible(_disputeID, dispute.arbitrated);
- } else if (dispute.period == Period.appeal) {
- if (
- block.timestamp - dispute.lastPeriodChange < court.timesPerPeriod[uint256(dispute.period)] &&
- !disputeKits[round.disputeKitID].isAppealFunded(_disputeID)
- ) {
- revert AppealPeriodNotPassed();
- }
- dispute.period = Period.execution;
- } else if (dispute.period == Period.execution) {
- revert DisputePeriodIsFinal();
- }
-
- dispute.lastPeriodChange = block.timestamp;
- emit NewPeriod(_disputeID, dispute.period);
- }
-
- /// @dev Draws jurors for the dispute. Can be called in parts.
- /// @param _disputeID The ID of the dispute.
- /// @param _iterations The number of iterations to run.
- /// @return nbDrawnJurors The total number of jurors drawn in the round.
- function draw(uint256 _disputeID, uint256 _iterations) external returns (uint256 nbDrawnJurors) {
- Dispute storage dispute = disputes[_disputeID];
- uint256 currentRound = dispute.rounds.length - 1;
- Round storage round = dispute.rounds[currentRound];
- if (dispute.period != Period.evidence) revert NotEvidencePeriod();
-
- IDisputeKit disputeKit = disputeKits[round.disputeKitID];
-
- uint256 startIndex = round.drawIterations; // for gas: less storage reads
- uint256 i;
- while (i < _iterations && round.drawnJurors.length < round.nbVotes) {
- address drawnAddress = disputeKit.draw(_disputeID, startIndex + i++);
- if (drawnAddress == address(0)) {
- continue;
- }
- sortitionModule.lockStake(drawnAddress, round.pnkAtStakePerJuror);
- emit Draw(drawnAddress, _disputeID, currentRound, round.drawnJurors.length);
- round.drawnJurors.push(drawnAddress);
- if (round.drawnJurors.length == round.nbVotes) {
- sortitionModule.postDrawHook(_disputeID, currentRound);
- }
- }
- round.drawIterations += i;
- return round.drawnJurors.length;
- }
-
- /// @dev Appeals the ruling of a specified dispute.
- /// Note: Access restricted to the Dispute Kit for this `disputeID`.
- /// @param _disputeID The ID of the dispute.
- /// @param _numberOfChoices Number of choices for the dispute. Can be required during court jump.
- /// @param _extraData Extradata for the dispute. Can be required during court jump.
- function appeal(uint256 _disputeID, uint256 _numberOfChoices, bytes memory _extraData) external payable {
- if (msg.value < appealCost(_disputeID)) revert AppealFeesNotEnough();
-
- Dispute storage dispute = disputes[_disputeID];
- if (dispute.period != Period.appeal) revert DisputeNotAppealable();
-
- Round storage round = dispute.rounds[dispute.rounds.length - 1];
- if (msg.sender != address(disputeKits[round.disputeKitID])) revert DisputeKitOnly();
-
- uint96 newCourtID = dispute.courtID;
- uint256 newDisputeKitID = round.disputeKitID;
-
- // Warning: the extra round must be created before calling disputeKit.createDispute()
- Round storage extraRound = dispute.rounds.push();
-
- if (round.nbVotes >= courts[newCourtID].jurorsForCourtJump) {
- // Jump to parent court.
- newCourtID = courts[newCourtID].parent;
-
- if (!courts[newCourtID].supportedDisputeKits[newDisputeKitID]) {
- // Switch to classic dispute kit if parent court doesn't support the current one.
- newDisputeKitID = DISPUTE_KIT_CLASSIC;
- }
-
- if (newCourtID != dispute.courtID) {
- emit CourtJump(_disputeID, dispute.rounds.length - 1, dispute.courtID, newCourtID);
- }
- }
-
- dispute.courtID = newCourtID;
- dispute.period = Period.evidence;
- dispute.lastPeriodChange = block.timestamp;
-
- Court storage court = courts[newCourtID];
- extraRound.nbVotes = msg.value / court.feeForJuror; // As many votes that can be afforded by the provided funds.
- extraRound.pnkAtStakePerJuror = _calculatePnkAtStake(court.minStake, court.alpha);
- extraRound.totalFeesForJurors = msg.value;
- extraRound.disputeKitID = newDisputeKitID;
-
- sortitionModule.createDisputeHook(_disputeID, dispute.rounds.length - 1);
-
- // Dispute kit was changed, so create a dispute in the new DK contract.
- if (extraRound.disputeKitID != round.disputeKitID) {
- emit DisputeKitJump(_disputeID, dispute.rounds.length - 1, round.disputeKitID, extraRound.disputeKitID);
- disputeKits[extraRound.disputeKitID].createDispute(
- _disputeID,
- _numberOfChoices,
- _extraData,
- extraRound.nbVotes
- );
- }
-
- emit AppealDecision(_disputeID, dispute.arbitrated);
- emit NewPeriod(_disputeID, Period.evidence);
- }
-
- /// @dev Distribute the PNKs at stake and the dispute fees for the specific round of the dispute. Can be called in parts.
- /// Note: Reward distributions are forbidden during pause.
- /// @param _disputeID The ID of the dispute.
- /// @param _round The appeal round.
- /// @param _iterations The number of iterations to run.
- function execute(uint256 _disputeID, uint256 _round, uint256 _iterations) external whenNotPaused {
- Round storage round;
- {
- Dispute storage dispute = disputes[_disputeID];
- if (dispute.period != Period.execution) revert NotExecutionPeriod();
-
- round = dispute.rounds[_round];
- } // stack too deep workaround
-
- uint256 start = round.repartitions;
- uint256 end = round.repartitions + _iterations;
-
- uint256 pnkPenaltiesInRound = round.pnkPenalties; // Keep in memory to save gas.
- uint256 numberOfVotesInRound = round.drawnJurors.length;
- uint256 feePerJurorInRound = round.totalFeesForJurors / numberOfVotesInRound;
- uint256 pnkAtStakePerJurorInRound = round.pnkAtStakePerJuror;
- uint256 coherentCount;
- {
- IDisputeKit disputeKit = disputeKits[round.disputeKitID];
- coherentCount = disputeKit.getCoherentCount(_disputeID, _round); // Total number of jurors that are eligible to a reward in this round.
- } // stack too deep workaround
-
- if (coherentCount == 0) {
- // We loop over the votes once as there are no rewards because it is not a tie and no one in this round is coherent with the final outcome.
- if (end > numberOfVotesInRound) end = numberOfVotesInRound;
- } else {
- // We loop over the votes twice, first to collect the PNK penalties, and second to distribute them as rewards along with arbitration fees.
- if (end > numberOfVotesInRound * 2) end = numberOfVotesInRound * 2;
- }
- round.repartitions = end;
-
- for (uint256 i = start; i < end; i++) {
- if (i < numberOfVotesInRound) {
- pnkPenaltiesInRound = _executePenalties(
- ExecuteParams({
- disputeID: _disputeID,
- round: _round,
- coherentCount: coherentCount,
- numberOfVotesInRound: numberOfVotesInRound,
- feePerJurorInRound: feePerJurorInRound,
- pnkAtStakePerJurorInRound: pnkAtStakePerJurorInRound,
- pnkPenaltiesInRound: pnkPenaltiesInRound,
- repartition: i
- })
- );
- } else {
- _executeRewards(
- ExecuteParams({
- disputeID: _disputeID,
- round: _round,
- coherentCount: coherentCount,
- numberOfVotesInRound: numberOfVotesInRound,
- feePerJurorInRound: feePerJurorInRound,
- pnkAtStakePerJurorInRound: pnkAtStakePerJurorInRound,
- pnkPenaltiesInRound: pnkPenaltiesInRound,
- repartition: i
- })
- );
- }
- }
- if (round.pnkPenalties != pnkPenaltiesInRound) {
- round.pnkPenalties = pnkPenaltiesInRound; // Reentrancy risk: breaks Check-Effect-Interact
- }
- }
-
- /// @dev Distribute the PNKs at stake and the dispute fees for the specific round of the dispute, penalties only.
- /// @param _params The parameters for the execution, see `ExecuteParams`.
- /// @return pnkPenaltiesInRoundCache The updated penalties in round cache.
- function _executePenalties(ExecuteParams memory _params) internal returns (uint256) {
- Dispute storage dispute = disputes[_params.disputeID];
- Round storage round = dispute.rounds[_params.round];
- IDisputeKit disputeKit = disputeKits[round.disputeKitID];
-
- // [0, 1] value that determines how coherent the juror was in this round, in basis points.
- uint256 degreeOfCoherence = disputeKit.getDegreeOfCoherence(
- _params.disputeID,
- _params.round,
- _params.repartition,
- _params.feePerJurorInRound,
- _params.pnkAtStakePerJurorInRound
- );
- if (degreeOfCoherence > ALPHA_DIVISOR) {
- // Make sure the degree doesn't exceed 1, though it should be ensured by the dispute kit.
- degreeOfCoherence = ALPHA_DIVISOR;
- }
-
- // Fully coherent jurors won't be penalized.
- uint256 penalty = (round.pnkAtStakePerJuror * (ALPHA_DIVISOR - degreeOfCoherence)) / ALPHA_DIVISOR;
-
- // Unlock the PNKs affected by the penalty
- address account = round.drawnJurors[_params.repartition];
- sortitionModule.unlockStake(account, penalty);
-
- // Apply the penalty to the staked PNKs.
- (uint256 pnkBalance, uint256 availablePenalty) = sortitionModule.penalizeStake(account, penalty);
- _params.pnkPenaltiesInRound += availablePenalty;
- emit TokenAndETHShift(
- account,
- _params.disputeID,
- _params.round,
- degreeOfCoherence,
- -int256(availablePenalty),
- 0,
- round.feeToken
- );
- // Unstake the juror from all courts if he was inactive or his balance can't cover penalties anymore.
- if (pnkBalance == 0 || !disputeKit.isVoteActive(_params.disputeID, _params.round, _params.repartition)) {
- sortitionModule.setJurorInactive(account);
- }
- if (_params.repartition == _params.numberOfVotesInRound - 1 && _params.coherentCount == 0) {
- // No one was coherent, send the rewards to the governor.
- _transferFeeToken(round.feeToken, payable(governor), round.totalFeesForJurors);
- pinakion.safeTransfer(governor, _params.pnkPenaltiesInRound);
- emit LeftoverRewardSent(
- _params.disputeID,
- _params.round,
- _params.pnkPenaltiesInRound,
- round.totalFeesForJurors,
- round.feeToken
- );
- }
- return _params.pnkPenaltiesInRound;
- }
-
- /// @dev Distribute the PNKs at stake and the dispute fees for the specific round of the dispute, rewards only.
- /// @param _params The parameters for the execution, see `ExecuteParams`.
- function _executeRewards(ExecuteParams memory _params) internal {
- Dispute storage dispute = disputes[_params.disputeID];
- Round storage round = dispute.rounds[_params.round];
- IDisputeKit disputeKit = disputeKits[round.disputeKitID];
-
- // [0, 1] value that determines how coherent the juror was in this round, in basis points.
- uint256 degreeOfCoherence = disputeKit.getDegreeOfCoherence(
- _params.disputeID,
- _params.round,
- _params.repartition % _params.numberOfVotesInRound,
- _params.feePerJurorInRound,
- _params.pnkAtStakePerJurorInRound
- );
-
- // Make sure the degree doesn't exceed 1, though it should be ensured by the dispute kit.
- if (degreeOfCoherence > ALPHA_DIVISOR) {
- degreeOfCoherence = ALPHA_DIVISOR;
- }
-
- address account = round.drawnJurors[_params.repartition % _params.numberOfVotesInRound];
- uint256 pnkLocked = _applyCoherence(round.pnkAtStakePerJuror, degreeOfCoherence);
-
- // Release the rest of the PNKs of the juror for this round.
- sortitionModule.unlockStake(account, pnkLocked);
-
- // Transfer the rewards
- uint256 pnkReward = _applyCoherence(_params.pnkPenaltiesInRound / _params.coherentCount, degreeOfCoherence);
- round.sumPnkRewardPaid += pnkReward;
- uint256 feeReward = _applyCoherence(round.totalFeesForJurors / _params.coherentCount, degreeOfCoherence);
- round.sumFeeRewardPaid += feeReward;
- pinakion.safeTransfer(account, pnkReward);
- _transferFeeToken(round.feeToken, payable(account), feeReward);
- emit TokenAndETHShift(
- account,
- _params.disputeID,
- _params.round,
- degreeOfCoherence,
- int256(pnkReward),
- int256(feeReward),
- round.feeToken
- );
-
- // Transfer any residual rewards to the governor. It may happen due to partial coherence of the jurors.
- if (_params.repartition == _params.numberOfVotesInRound * 2 - 1) {
- uint256 leftoverPnkReward = _params.pnkPenaltiesInRound - round.sumPnkRewardPaid;
- uint256 leftoverFeeReward = round.totalFeesForJurors - round.sumFeeRewardPaid;
- if (leftoverPnkReward != 0 || leftoverFeeReward != 0) {
- if (leftoverPnkReward != 0) {
- pinakion.safeTransfer(governor, leftoverPnkReward);
- }
- if (leftoverFeeReward != 0) {
- _transferFeeToken(round.feeToken, payable(governor), leftoverFeeReward);
- }
- emit LeftoverRewardSent(
- _params.disputeID,
- _params.round,
- leftoverPnkReward,
- leftoverFeeReward,
- round.feeToken
- );
- }
- }
- }
-
- /// @dev Executes a specified dispute's ruling.
- /// @param _disputeID The ID of the dispute.
- function executeRuling(uint256 _disputeID) external {
- Dispute storage dispute = disputes[_disputeID];
- if (dispute.period != Period.execution) revert NotExecutionPeriod();
- if (dispute.ruled) revert RulingAlreadyExecuted();
-
- (uint256 winningChoice, , ) = currentRuling(_disputeID);
- dispute.ruled = true;
- emit Ruling(dispute.arbitrated, _disputeID, winningChoice);
- dispute.arbitrated.rule(_disputeID, winningChoice);
- }
-
- // ************************************* //
- // * Public Views * //
- // ************************************* //
-
- /// @dev Compute the cost of arbitration denominated in ETH.
- /// It is recommended not to increase it often, as it can be highly time and gas consuming for the arbitrated contracts to cope with fee augmentation.
- /// @param _extraData Additional info about the dispute. We use it to pass the ID of the dispute's court (first 32 bytes), the minimum number of jurors required (next 32 bytes) and the ID of the specific dispute kit (last 32 bytes).
- /// @return cost The arbitration cost in ETH.
- function arbitrationCost(bytes memory _extraData) public view override returns (uint256 cost) {
- (uint96 courtID, uint256 minJurors, ) = _extraDataToCourtIDMinJurorsDisputeKit(_extraData);
- cost = courts[courtID].feeForJuror * minJurors;
- }
-
- /// @dev Compute the cost of arbitration denominated in `_feeToken`.
- /// It is recommended not to increase it often, as it can be highly time and gas consuming for the arbitrated contracts to cope with fee augmentation.
- /// @param _extraData Additional info about the dispute. We use it to pass the ID of the dispute's court (first 32 bytes), the minimum number of jurors required (next 32 bytes) and the ID of the specific dispute kit (last 32 bytes).
- /// @param _feeToken The ERC20 token used to pay fees.
- /// @return cost The arbitration cost in `_feeToken`.
- function arbitrationCost(bytes calldata _extraData, IERC20 _feeToken) public view override returns (uint256 cost) {
- cost = convertEthToTokenAmount(_feeToken, arbitrationCost(_extraData));
- }
-
- /// @dev Gets the cost of appealing a specified dispute.
- /// @param _disputeID The ID of the dispute.
- /// @return cost The appeal cost.
- function appealCost(uint256 _disputeID) public view returns (uint256 cost) {
- Dispute storage dispute = disputes[_disputeID];
- Round storage round = dispute.rounds[dispute.rounds.length - 1];
- Court storage court = courts[dispute.courtID];
- if (round.nbVotes >= court.jurorsForCourtJump) {
- // Jump to parent court.
- if (dispute.courtID == GENERAL_COURT) {
- // TODO: Handle the forking when appealed in General court.
- cost = NON_PAYABLE_AMOUNT; // Get the cost of the parent court.
- } else {
- cost = courts[court.parent].feeForJuror * ((round.nbVotes * 2) + 1);
- }
- } else {
- // Stay in current court.
- cost = court.feeForJuror * ((round.nbVotes * 2) + 1);
- }
- }
-
- /// @dev Gets the start and the end of a specified dispute's current appeal period.
- /// @param _disputeID The ID of the dispute.
- /// @return start The start of the appeal period.
- /// @return end The end of the appeal period.
- function appealPeriod(uint256 _disputeID) external view returns (uint256 start, uint256 end) {
- Dispute storage dispute = disputes[_disputeID];
- if (dispute.period == Period.appeal) {
- start = dispute.lastPeriodChange;
- end = dispute.lastPeriodChange + courts[dispute.courtID].timesPerPeriod[uint256(Period.appeal)];
- } else {
- start = 0;
- end = 0;
- }
- }
-
- /// @dev Gets the current ruling of a specified dispute.
- /// @param _disputeID The ID of the dispute.
- /// @return ruling The current ruling.
- /// @return tied Whether it's a tie or not.
- /// @return overridden Whether the ruling was overridden by appeal funding or not.
- function currentRuling(uint256 _disputeID) public view returns (uint256 ruling, bool tied, bool overridden) {
- Dispute storage dispute = disputes[_disputeID];
- Round storage round = dispute.rounds[dispute.rounds.length - 1];
- IDisputeKit disputeKit = disputeKits[round.disputeKitID];
- (ruling, tied, overridden) = disputeKit.currentRuling(_disputeID);
- }
-
- /// @dev Gets the round info for a specified dispute and round.
- /// @dev This function must not be called from a non-view function because it returns a dynamic array which might be very large, theoretically exceeding the block gas limit.
- /// @param _disputeID The ID of the dispute.
- /// @param _round The round to get the info for.
- /// @return round The round info.
- function getRoundInfo(uint256 _disputeID, uint256 _round) external view returns (Round memory) {
- return disputes[_disputeID].rounds[_round];
- }
-
- /// @dev Gets the PNK at stake per juror for a specified dispute and round.
- /// @param _disputeID The ID of the dispute.
- /// @param _round The round to get the info for.
- /// @return pnkAtStakePerJuror The PNK at stake per juror.
- function getPnkAtStakePerJuror(uint256 _disputeID, uint256 _round) external view returns (uint256) {
- return disputes[_disputeID].rounds[_round].pnkAtStakePerJuror;
- }
-
- /// @dev Gets the number of rounds for a specified dispute.
- /// @param _disputeID The ID of the dispute.
- /// @return The number of rounds.
- function getNumberOfRounds(uint256 _disputeID) external view returns (uint256) {
- return disputes[_disputeID].rounds.length;
- }
-
- /// @dev Checks if a given dispute kit is supported by a given court.
- /// @param _courtID The ID of the court to check the support for.
- /// @param _disputeKitID The ID of the dispute kit to check the support for.
- /// @return Whether the dispute kit is supported or not.
- function isSupported(uint96 _courtID, uint256 _disputeKitID) external view returns (bool) {
- return courts[_courtID].supportedDisputeKits[_disputeKitID];
- }
-
- /// @dev Gets the timesPerPeriod array for a given court.
- /// @param _courtID The ID of the court to get the times from.
- /// @return timesPerPeriod The timesPerPeriod array for the given court.
- function getTimesPerPeriod(uint96 _courtID) external view returns (uint256[4] memory timesPerPeriod) {
- timesPerPeriod = courts[_courtID].timesPerPeriod;
- }
-
- // ************************************* //
- // * Public Views for Dispute Kits * //
- // ************************************* //
-
- /// @dev Gets the number of votes permitted for the specified dispute in the latest round.
- /// @param _disputeID The ID of the dispute.
- function getNumberOfVotes(uint256 _disputeID) external view returns (uint256) {
- Dispute storage dispute = disputes[_disputeID];
- return dispute.rounds[dispute.rounds.length - 1].nbVotes;
- }
-
- /// @dev Returns true if the dispute kit will be switched to a parent DK.
- /// @param _disputeID The ID of the dispute.
- /// @return Whether DK will be switched or not.
- function isDisputeKitJumping(uint256 _disputeID) external view returns (bool) {
- Dispute storage dispute = disputes[_disputeID];
- Round storage round = dispute.rounds[dispute.rounds.length - 1];
- Court storage court = courts[dispute.courtID];
-
- if (round.nbVotes < court.jurorsForCourtJump) {
- return false;
- }
-
- // Jump if the parent court doesn't support the current DK.
- return !courts[court.parent].supportedDisputeKits[round.disputeKitID];
- }
-
- function getDisputeKitsLength() external view returns (uint256) {
- return disputeKits.length;
- }
-
- function convertEthToTokenAmount(IERC20 _toToken, uint256 _amountInEth) public view returns (uint256) {
- return (_amountInEth * 10 ** currencyRates[_toToken].rateDecimals) / currencyRates[_toToken].rateInEth;
- }
-
- // ************************************* //
- // * Internal * //
- // ************************************* //
-
- /// @dev Internal function to transfer fee tokens (ETH or ERC20)
- /// @param _feeToken The token to transfer (NATIVE_CURRENCY for ETH).
- /// @param _recipient The recipient address.
- /// @param _amount The amount to transfer.
- function _transferFeeToken(IERC20 _feeToken, address payable _recipient, uint256 _amount) internal {
- if (_feeToken == NATIVE_CURRENCY) {
- _recipient.safeSend(_amount, wNative);
- } else {
- _feeToken.safeTransfer(_recipient, _amount);
- }
- }
-
- /// @dev Applies degree of coherence to an amount
- /// @param _amount The base amount to apply coherence to.
- /// @param _degreeOfCoherence The degree of coherence in basis points.
- /// @return The amount after applying the degree of coherence.
- function _applyCoherence(uint256 _amount, uint256 _degreeOfCoherence) internal pure returns (uint256) {
- return (_amount * _degreeOfCoherence) / ALPHA_DIVISOR;
- }
-
- /// @dev Calculates PNK at stake per juror based on court parameters
- /// @param _minStake The minimum stake for the court.
- /// @param _alpha The alpha parameter for the court in basis points.
- /// @return The amount of PNK at stake per juror.
- function _calculatePnkAtStake(uint256 _minStake, uint256 _alpha) internal pure returns (uint256) {
- return (_minStake * _alpha) / ALPHA_DIVISOR;
- }
-
- /// @dev Toggles the dispute kit support for a given court.
- /// @param _courtID The ID of the court to toggle the support for.
- /// @param _disputeKitID The ID of the dispute kit to toggle the support for.
- /// @param _enable Whether to enable or disable the support. Note that classic dispute kit should always be enabled.
- function _enableDisputeKit(uint96 _courtID, uint256 _disputeKitID, bool _enable) internal {
- courts[_courtID].supportedDisputeKits[_disputeKitID] = _enable;
- emit DisputeKitEnabled(_courtID, _disputeKitID, _enable);
- }
-
- /// @dev If called only once then set _onError to Revert, otherwise set it to Return
- /// @param _account The account to set the stake for.
- /// @param _courtID The ID of the court to set the stake for.
- /// @param _newStake The new stake.
- /// @param _onError Whether to revert or return false on error.
- /// @return Whether the stake was successfully set or not.
- function _setStake(address _account, uint96 _courtID, uint256 _newStake, OnError _onError) internal returns (bool) {
- if (_courtID == FORKING_COURT || _courtID >= courts.length) {
- _stakingFailed(_onError, StakingResult.CannotStakeInThisCourt); // Staking directly into the forking court is not allowed.
- return false;
- }
- if (_newStake != 0 && _newStake < courts[_courtID].minStake) {
- _stakingFailed(_onError, StakingResult.CannotStakeLessThanMinStake); // Staking less than the minimum stake is not allowed.
- return false;
- }
- (uint256 pnkDeposit, uint256 pnkWithdrawal, StakingResult stakingResult) = sortitionModule.validateStake(
- _account,
- _courtID,
- _newStake
- );
- if (stakingResult != StakingResult.Successful && stakingResult != StakingResult.Delayed) {
- _stakingFailed(_onError, stakingResult);
- return false;
- } else if (stakingResult == StakingResult.Delayed) {
- return true;
- }
- if (pnkDeposit > 0) {
- if (!pinakion.safeTransferFrom(_account, address(this), pnkDeposit)) {
- _stakingFailed(_onError, StakingResult.StakingTransferFailed);
- return false;
- }
- }
- if (pnkWithdrawal > 0) {
- if (!pinakion.safeTransfer(_account, pnkWithdrawal)) {
- _stakingFailed(_onError, StakingResult.UnstakingTransferFailed);
- return false;
- }
- }
- sortitionModule.setStake(_account, _courtID, pnkDeposit, pnkWithdrawal, _newStake);
-
- return true;
- }
-
- /// @dev It may revert depending on the _onError parameter.
- function _stakingFailed(OnError _onError, StakingResult _result) internal pure virtual {
- if (_onError == OnError.Return) return;
- if (_result == StakingResult.StakingTransferFailed) revert StakingTransferFailed();
- if (_result == StakingResult.UnstakingTransferFailed) revert UnstakingTransferFailed();
- if (_result == StakingResult.CannotStakeInMoreCourts) revert StakingInTooManyCourts();
- if (_result == StakingResult.CannotStakeInThisCourt) revert StakingNotPossibleInThisCourt();
- if (_result == StakingResult.CannotStakeLessThanMinStake) revert StakingLessThanCourtMinStake();
- if (_result == StakingResult.CannotStakeZeroWhenNoStake) revert StakingZeroWhenNoStake();
- }
-
- /// @dev Gets a court ID, the minimum number of jurors and an ID of a dispute kit from a specified extra data bytes array.
- /// Note that if extradata contains an incorrect value then this value will be switched to default.
- /// @param _extraData The extra data bytes array. The first 32 bytes are the court ID, the next are the minimum number of jurors and the last are the dispute kit ID.
- /// @return courtID The court ID.
- /// @return minJurors The minimum number of jurors required.
- /// @return disputeKitID The ID of the dispute kit.
- function _extraDataToCourtIDMinJurorsDisputeKit(
- bytes memory _extraData
- ) internal view returns (uint96 courtID, uint256 minJurors, uint256 disputeKitID) {
- // Note that if the extradata doesn't contain 32 bytes for the dispute kit ID it'll return the default 0 index.
- if (_extraData.length >= 64) {
- assembly {
- // solium-disable-line security/no-inline-assembly
- courtID := mload(add(_extraData, 0x20))
- minJurors := mload(add(_extraData, 0x40))
- disputeKitID := mload(add(_extraData, 0x60))
- }
- if (courtID == FORKING_COURT || courtID >= courts.length) {
- courtID = GENERAL_COURT;
- }
- if (minJurors == 0) {
- minJurors = DEFAULT_NB_OF_JURORS;
- }
- if (disputeKitID == NULL_DISPUTE_KIT || disputeKitID >= disputeKits.length) {
- disputeKitID = DISPUTE_KIT_CLASSIC; // 0 index is not used.
- }
- } else {
- courtID = GENERAL_COURT;
- minJurors = DEFAULT_NB_OF_JURORS;
- disputeKitID = DISPUTE_KIT_CLASSIC;
- }
- }
-
- // ************************************* //
- // * Errors * //
- // ************************************* //
-
- error GovernorOnly();
- error GuardianOrGovernorOnly();
- error DisputeKitOnly();
- error SortitionModuleOnly();
- error UnsuccessfulCall();
- error InvalidDisputKitParent();
- error MinStakeLowerThanParentCourt();
- error UnsupportedDisputeKit();
- error InvalidForkingCourtAsParent();
- error WrongDisputeKitIndex();
- error CannotDisableClassicDK();
- error StakingInTooManyCourts();
- error StakingNotPossibleInThisCourt();
- error StakingLessThanCourtMinStake();
- error StakingTransferFailed();
- error UnstakingTransferFailed();
- error ArbitrationFeesNotEnough();
- error DisputeKitNotSupportedByCourt();
- error MustSupportDisputeKitClassic();
- error TokenNotAccepted();
- error EvidenceNotPassedAndNotAppeal();
- error DisputeStillDrawing();
- error CommitPeriodNotPassed();
- error VotePeriodNotPassed();
- error AppealPeriodNotPassed();
- error NotEvidencePeriod();
- error AppealFeesNotEnough();
- error DisputeNotAppealable();
- error NotExecutionPeriod();
- error RulingAlreadyExecuted();
- error DisputePeriodIsFinal();
- error TransferFailed();
- error WhenNotPausedOnly();
- error WhenPausedOnly();
- error StakingZeroWhenNoStake();
-}
diff --git a/contracts/src/arbitration/KlerosCoreNeo.sol b/contracts/src/arbitration/KlerosCoreNeo.sol
deleted file mode 100644
index 1d09c2964..000000000
--- a/contracts/src/arbitration/KlerosCoreNeo.sol
+++ /dev/null
@@ -1,142 +0,0 @@
-// SPDX-License-Identifier: MIT
-
-pragma solidity ^0.8.24;
-
-import {KlerosCoreBase, IDisputeKit, ISortitionModule, IERC20, OnError, StakingResult} from "./KlerosCoreBase.sol";
-import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
-
-/// @title KlerosCoreNeo
-/// Core arbitrator contract for Kleros v2.
-/// Note that this contract trusts the PNK token, the dispute kit and the sortition module contracts.
-contract KlerosCoreNeo is KlerosCoreBase {
- string public constant override version = "0.10.0";
-
- // ************************************* //
- // * Storage * //
- // ************************************* //
-
- mapping(address => bool) public arbitrableWhitelist; // Arbitrable whitelist.
- IERC721 public jurorNft; // Eligible jurors NFT.
-
- // ************************************* //
- // * Constructor * //
- // ************************************* //
-
- /// @custom:oz-upgrades-unsafe-allow constructor
- constructor() {
- _disableInitializers();
- }
-
- /// @dev Initializer (constructor equivalent for upgradable contracts).
- /// @param _governor The governor's address.
- /// @param _guardian The guardian's address.
- /// @param _pinakion The address of the token contract.
- /// @param _jurorProsecutionModule The address of the juror prosecution module.
- /// @param _disputeKit The address of the default dispute kit.
- /// @param _hiddenVotes The `hiddenVotes` property value of the general court.
- /// @param _courtParameters Numeric parameters of General court (minStake, alpha, feeForJuror and jurorsForCourtJump respectively).
- /// @param _timesPerPeriod The `timesPerPeriod` property value of the general court.
- /// @param _sortitionExtraData The extra data for sortition module.
- /// @param _sortitionModuleAddress The sortition module responsible for sortition of the jurors.
- /// @param _jurorNft NFT contract to vet the jurors.
- /// @param _wNative The wrapped native token address, typically wETH.
- function initialize(
- address _governor,
- address _guardian,
- IERC20 _pinakion,
- address _jurorProsecutionModule,
- IDisputeKit _disputeKit,
- bool _hiddenVotes,
- uint256[4] memory _courtParameters,
- uint256[4] memory _timesPerPeriod,
- bytes memory _sortitionExtraData,
- ISortitionModule _sortitionModuleAddress,
- IERC721 _jurorNft,
- address _wNative
- ) external reinitializer(2) {
- __KlerosCoreBase_initialize(
- _governor,
- _guardian,
- _pinakion,
- _jurorProsecutionModule,
- _disputeKit,
- _hiddenVotes,
- _courtParameters,
- _timesPerPeriod,
- _sortitionExtraData,
- _sortitionModuleAddress,
- _wNative
- );
- jurorNft = _jurorNft;
- }
-
- function reinitialize(address _wNative) external reinitializer(6) {
- wNative = _wNative;
- }
-
- // ************************************* //
- // * Governance * //
- // ************************************* //
-
- /// @dev Access Control to perform implementation upgrades (UUPS Proxiable)
- /// Only the governor can perform upgrades (`onlyByGovernor`)
- function _authorizeUpgrade(address) internal view override onlyByGovernor {
- // NOP
- }
-
- /// @dev Changes the `jurorNft` storage variable.
- /// @param _jurorNft The new value for the `jurorNft` storage variable.
- function changeJurorNft(IERC721 _jurorNft) external onlyByGovernor {
- jurorNft = _jurorNft;
- }
-
- /// @dev Adds or removes an arbitrable from whitelist.
- /// @param _arbitrable Arbitrable address.
- /// @param _allowed Whether add or remove permission.
- function changeArbitrableWhitelist(address _arbitrable, bool _allowed) external onlyByGovernor {
- arbitrableWhitelist[_arbitrable] = _allowed;
- }
-
- // ************************************* //
- // * State Modifiers * //
- // ************************************* //
-
- /// @dev Sets the caller's stake in a court.
- /// Note: Staking and unstaking is forbidden during pause.
- /// @param _courtID The ID of the court.
- /// @param _newStake The new stake.
- /// Note that the existing delayed stake will be nullified as non-relevant.
- function setStake(uint96 _courtID, uint256 _newStake) external override whenNotPaused {
- if (jurorNft.balanceOf(msg.sender) == 0) revert NotEligibleForStaking();
- super._setStake(msg.sender, _courtID, _newStake, OnError.Revert);
- }
-
- // ************************************* //
- // * Internal * //
- // ************************************* //
-
- function _createDispute(
- uint256 _numberOfChoices,
- bytes memory _extraData,
- IERC20 _feeToken,
- uint256 _feeAmount
- ) internal override returns (uint256 disputeID) {
- if (!arbitrableWhitelist[msg.sender]) revert ArbitrableNotWhitelisted();
- return super._createDispute(_numberOfChoices, _extraData, _feeToken, _feeAmount);
- }
-
- function _stakingFailed(OnError _onError, StakingResult _result) internal pure override {
- super._stakingFailed(_onError, _result);
- if (_result == StakingResult.CannotStakeMoreThanMaxStakePerJuror) revert StakingMoreThanMaxStakePerJuror();
- if (_result == StakingResult.CannotStakeMoreThanMaxTotalStaked) revert StakingMoreThanMaxTotalStaked();
- }
-
- // ************************************* //
- // * Errors * //
- // ************************************* //
-
- error NotEligibleForStaking();
- error StakingMoreThanMaxStakePerJuror();
- error StakingMoreThanMaxTotalStaked();
- error ArbitrableNotWhitelisted();
-}
diff --git a/contracts/src/arbitration/KlerosGovernor.sol b/contracts/src/arbitration/KlerosGovernor.sol
index 7e9415a7b..783a65164 100644
--- a/contracts/src/arbitration/KlerosGovernor.sol
+++ b/contracts/src/arbitration/KlerosGovernor.sol
@@ -6,7 +6,8 @@ import {IArbitrableV2, IArbitratorV2} from "./interfaces/IArbitrableV2.sol";
import {SafeSend} from "../libraries/SafeSend.sol";
import "./interfaces/IDisputeTemplateRegistry.sol";
-/// @title KlerosGovernor for V2. Note that appeal functionality and evidence submission will be handled by the court.
+/// @title KlerosGovernor for V2.
+/// @dev Appeal and evidence submission is handled by the court.
contract KlerosGovernor is IArbitrableV2 {
using SafeSend for address payable;
@@ -70,18 +71,18 @@ contract KlerosGovernor is IArbitrableV2 {
modifier duringSubmissionPeriod() {
uint256 offset = sessions[sessions.length - 1].durationOffset;
- require(block.timestamp - lastApprovalTime <= submissionTimeout + offset, "Submission time has ended.");
+ if (block.timestamp - lastApprovalTime > submissionTimeout + offset) revert SubmissionTimeHasEnded();
_;
}
modifier duringApprovalPeriod() {
uint256 offset = sessions[sessions.length - 1].durationOffset;
- require(block.timestamp - lastApprovalTime > submissionTimeout + offset, "Approval time not started yet.");
+ if (block.timestamp - lastApprovalTime <= submissionTimeout + offset) revert ApprovalTimeNotStarted();
_;
}
- modifier onlyByGovernor() {
- require(address(this) == msg.sender, "Only the governor allowed.");
+ modifier onlyByOwner() {
+ if (address(this) != msg.sender) revert OwnerOnly();
_;
}
@@ -89,7 +90,7 @@ contract KlerosGovernor is IArbitrableV2 {
// * Events * //
// ************************************* //
- /// @dev Emitted when a new list is submitted.
+ /// @notice Emitted when a new list is submitted.
/// @param _listID The index of the transaction list in the array of lists.
/// @param _submitter The address that submitted the list.
/// @param _session The number of the current session.
@@ -106,7 +107,7 @@ contract KlerosGovernor is IArbitrableV2 {
// * Constructor * //
// ************************************* //
- /// @dev Constructor.
+ /// @notice Constructor.
/// @param _arbitrator The arbitrator of the contract.
/// @param _arbitratorExtraData Extra data for the arbitrator.
/// @param _templateData The dispute template data.
@@ -145,49 +146,51 @@ contract KlerosGovernor is IArbitrableV2 {
// * Governance * //
// ************************************* //
- /// @dev Changes the value of the base deposit required for submitting a list.
+ /// @notice Changes the value of the base deposit required for submitting a list.
/// @param _submissionBaseDeposit The new value of the base deposit, in wei.
- function changeSubmissionDeposit(uint256 _submissionBaseDeposit) external onlyByGovernor {
+ function changeSubmissionDeposit(uint256 _submissionBaseDeposit) external onlyByOwner {
submissionBaseDeposit = _submissionBaseDeposit;
}
- /// @dev Changes the time allocated for submission. Note that it can't be changed during approval period because there can be an active dispute in the old arbitrator contract
+ /// @notice Changes the time allocated for submission.
+ /// @dev It cannot be changed during approval period because there can be an active dispute in the old arbitrator contract
/// and prolonging submission timeout might switch it back to submission period.
/// @param _submissionTimeout The new duration of the submission period, in seconds.
- function changeSubmissionTimeout(uint256 _submissionTimeout) external onlyByGovernor duringSubmissionPeriod {
+ function changeSubmissionTimeout(uint256 _submissionTimeout) external onlyByOwner duringSubmissionPeriod {
submissionTimeout = _submissionTimeout;
}
- /// @dev Changes the time allocated for list's execution.
+ /// @notice Changes the time allocated for list's execution.
/// @param _executionTimeout The new duration of the execution timeout, in seconds.
- function changeExecutionTimeout(uint256 _executionTimeout) external onlyByGovernor {
+ function changeExecutionTimeout(uint256 _executionTimeout) external onlyByOwner {
executionTimeout = _executionTimeout;
}
- /// @dev Changes list withdrawal timeout. Note that withdrawals are only possible in the first half of the submission period.
+ /// @notice Changes list withdrawal timeout. Note that withdrawals are only possible in the first half of the submission period.
/// @param _withdrawTimeout The new duration of withdraw period, in seconds.
- function changeWithdrawTimeout(uint256 _withdrawTimeout) external onlyByGovernor {
+ function changeWithdrawTimeout(uint256 _withdrawTimeout) external onlyByOwner {
withdrawTimeout = _withdrawTimeout;
}
- /// @dev Changes the arbitrator of the contract. Note that it can't be changed during approval period because there can be an active dispute in the old arbitrator contract.
+ /// @notice Changes the arbitrator of the contract.
+ /// @dev It cannot be changed during approval period because there can be an active dispute in the old arbitrator contract.
/// @param _arbitrator The new trusted arbitrator.
/// @param _arbitratorExtraData The extra data used by the new arbitrator.
function changeArbitrator(
IArbitratorV2 _arbitrator,
bytes memory _arbitratorExtraData
- ) external onlyByGovernor duringSubmissionPeriod {
+ ) external onlyByOwner duringSubmissionPeriod {
arbitrator = _arbitrator;
arbitratorExtraData = _arbitratorExtraData;
}
- /// @dev Update the dispute template data.
+ /// @notice Update the dispute template data.
/// @param _templateData The new dispute template data.
/// @param _templateDataMappings The new dispute template data mappings.
function changeDisputeTemplate(
string memory _templateData,
string memory _templateDataMappings
- ) external onlyByGovernor {
+ ) external onlyByOwner {
templateId = templateRegistry.setDisputeTemplate("", _templateData, _templateDataMappings);
}
@@ -195,7 +198,7 @@ contract KlerosGovernor is IArbitrableV2 {
// * State Modifiers * //
// ************************************* //
- /// @dev Creates transaction list based on input parameters and submits it for potential approval and execution.
+ /// @notice Creates transaction list based on input parameters and submits it for potential approval and execution.
/// @param _target List of addresses to call.
/// @param _value List of values required for respective addresses.
/// @param _data Concatenated calldata of all transactions of this list.
@@ -208,14 +211,14 @@ contract KlerosGovernor is IArbitrableV2 {
uint256[] memory _dataSize,
string memory _description
) external payable duringSubmissionPeriod {
- require(_target.length == _value.length, "Wrong input: target and value");
- require(_target.length == _dataSize.length, "Wrong input: target and datasize");
+ if (_target.length != _value.length) revert WrongInputTargetAndValue();
+ if (_target.length != _dataSize.length) revert WrongInputTargetAndDatasize();
Session storage session = sessions[sessions.length - 1];
Submission storage submission = submissions.push();
submission.submitter = payable(msg.sender);
// Do the assignment first to avoid creating a new variable and bypass a 'stack too deep' error.
submission.deposit = submissionBaseDeposit + arbitrator.arbitrationCost(arbitratorExtraData);
- require(msg.value >= submission.deposit, "Not enough ETH to cover deposit");
+ if (msg.value < submission.deposit) revert InsufficientDeposit();
bytes32 listHash;
bytes32 currentTxHash;
@@ -233,7 +236,7 @@ contract KlerosGovernor is IArbitrableV2 {
currentTxHash = keccak256(abi.encodePacked(transaction.target, transaction.value, transaction.data));
listHash = keccak256(abi.encodePacked(currentTxHash, listHash));
}
- require(!session.alreadySubmitted[listHash], "List already submitted");
+ if (session.alreadySubmitted[listHash]) revert ListAlreadySubmitted();
session.alreadySubmitted[listHash] = true;
submission.listHash = listHash;
submission.submissionTime = block.timestamp;
@@ -249,18 +252,18 @@ contract KlerosGovernor is IArbitrableV2 {
reservedETH += submission.deposit;
}
- /// @dev Withdraws submitted transaction list. Reimburses submission deposit.
- /// Withdrawal is only possible during the first half of the submission period and during withdrawTimeout after the submission is made.
+ /// @notice Withdraws submitted transaction list. Reimburses submission deposit.
+ /// @dev Withdrawal is only possible during the first half of the submission period and during withdrawTimeout after the submission is made.
/// @param _submissionID Submission's index in the array of submitted lists of the current sesssion.
/// @param _listHash Hash of a withdrawing list.
function withdrawTransactionList(uint256 _submissionID, bytes32 _listHash) external {
Session storage session = sessions[sessions.length - 1];
Submission storage submission = submissions[session.submittedLists[_submissionID]];
- require(block.timestamp - lastApprovalTime <= submissionTimeout / 2, "Should be in first half");
- // This require statement is an extra check to prevent _submissionID linking to the wrong list because of index swap during withdrawal.
- require(submission.listHash == _listHash, "Wrong list hash");
- require(submission.submitter == msg.sender, "Only submitter can withdraw");
- require(block.timestamp - submission.submissionTime <= withdrawTimeout, "Withdrawing time has passed.");
+ if (block.timestamp - lastApprovalTime > submissionTimeout / 2) revert ShouldOnlyWithdrawInFirstHalf();
+ // This is an extra check to prevent _submissionID linking to the wrong list because of index swap during withdrawal.
+ if (submission.listHash != _listHash) revert WrongListHash();
+ if (submission.submitter != msg.sender) revert OnlySubmitterCanWithdraw();
+ if (block.timestamp - submission.submissionTime > withdrawTimeout) revert WithdrawingTimeHasPassed();
session.submittedLists[_submissionID] = session.submittedLists[session.submittedLists.length - 1];
session.alreadySubmitted[_listHash] = false;
session.submittedLists.pop();
@@ -269,11 +272,11 @@ contract KlerosGovernor is IArbitrableV2 {
payable(msg.sender).transfer(submission.deposit);
}
- /// @dev Approves a transaction list or creates a dispute if more than one list was submitted.
- /// If nothing was submitted changes session.
+ /// @notice Approves a transaction list or creates a dispute if more than one list was submitted.
+ /// @dev If nothing was submitted changes session.
function executeSubmissions() external duringApprovalPeriod {
Session storage session = sessions[sessions.length - 1];
- require(session.status == Status.NoDispute, "Already disputed");
+ if (session.status != Status.NoDispute) revert AlreadyDisputed();
if (session.submittedLists.length == 0) {
lastApprovalTime = block.timestamp;
session.status = Status.Resolved;
@@ -300,19 +303,20 @@ contract KlerosGovernor is IArbitrableV2 {
// Check in case arbitration cost increased after the submission. It's unlikely that its increase won't be covered by the base deposit, but technically possible.
session.sumDeposit = session.sumDeposit > arbitrationCost ? session.sumDeposit - arbitrationCost : 0;
reservedETH = reservedETH > arbitrationCost ? reservedETH - arbitrationCost : 0;
- emit DisputeRequest(arbitrator, session.disputeID, sessions.length - 1, templateId, "");
+ emit DisputeRequest(arbitrator, session.disputeID, templateId);
}
}
- /// @dev Gives a ruling for a dispute. Must be called by the arbitrator.
+ /// @notice Gives a ruling for a dispute.
+ /// @dev Must be called by the arbitrator.
/// @param _disputeID ID of the dispute in the Arbitrator contract.
/// @param _ruling Ruling given by the arbitrator. Note that 0 is reserved for "Refuse to arbitrate".
/// Note If the final ruling is "0" nothing is approved and deposits will stay locked in the contract.
function rule(uint256 _disputeID, uint256 _ruling) external override {
Session storage session = sessions[sessions.length - 1];
- require(msg.sender == address(arbitrator), "Only arbitrator allowed");
- require(session.status == Status.DisputeCreated, "Wrong status");
- require(_ruling <= session.submittedLists.length, "Ruling is out of bounds.");
+ if (msg.sender != address(arbitrator)) revert OnlyArbitratorAllowed();
+ if (session.status != Status.DisputeCreated) revert NotDisputed();
+ if (_ruling > session.submittedLists.length) revert RulingOutOfBounds();
if (_ruling != 0) {
Submission storage submission = submissions[session.submittedLists[_ruling - 1]];
@@ -332,14 +336,14 @@ contract KlerosGovernor is IArbitrableV2 {
emit Ruling(IArbitratorV2(msg.sender), _disputeID, _ruling);
}
- /// @dev Executes selected transactions of the list.
+ /// @notice Executes selected transactions of the list.
/// @param _listID The index of the transaction list in the array of lists.
/// @param _cursor Index of the transaction from which to start executing.
/// @param _count Number of transactions to execute. Executes until the end if set to "0" or number higher than number of transactions in the list.
function executeTransactionList(uint256 _listID, uint256 _cursor, uint256 _count) external {
Submission storage submission = submissions[_listID];
- require(submission.approved, "Should be approved");
- require(block.timestamp - submission.approvalTime <= executionTimeout, "Time to execute has passed");
+ if (!submission.approved) revert SubmissionNotApproved();
+ if (block.timestamp - submission.approvalTime > executionTimeout) revert TimeToExecuteHasPassed();
for (uint256 i = _cursor; i < submission.txs.length && (_count == 0 || i < _cursor + _count); i++) {
Transaction storage transaction = submission.txs[i];
uint256 expendableFunds = getExpendableFunds();
@@ -347,23 +351,23 @@ contract KlerosGovernor is IArbitrableV2 {
(bool callResult, ) = transaction.target.call{value: transaction.value}(transaction.data);
// An extra check to prevent re-entrancy through target call.
if (callResult == true) {
- require(!transaction.executed, "Already executed");
+ if (transaction.executed) revert AlreadyExecuted();
transaction.executed = true;
}
}
}
}
- /// @dev Receive function to receive funds for the execution of transactions.
+ /// @notice Receive function to receive funds for the execution of transactions.
receive() external payable {}
- /// @dev Gets the sum of contract funds that are used for the execution of transactions.
+ /// @notice Gets the sum of contract funds that are used for the execution of transactions.
/// @return Contract balance without reserved ETH.
function getExpendableFunds() public view returns (uint256) {
return address(this).balance - reservedETH;
}
- /// @dev Gets the info of the specific transaction in the specific list.
+ /// @notice Gets the info of the specific transaction in the specific list.
/// @param _listID The index of the transaction list in the array of lists.
/// @param _transactionIndex The index of the transaction.
/// @return target The target of the transaction.
@@ -379,8 +383,11 @@ contract KlerosGovernor is IArbitrableV2 {
return (transaction.target, transaction.value, transaction.data, transaction.executed);
}
- /// @dev Gets the array of submitted lists in the session.
- /// Note that this function is O(n), where n is the number of submissions in the session. This could exceed the gas limit, therefore this function should only be used for interface display and not by other contracts.
+ /// @notice Gets the array of submitted lists in the session.
+ ///
+ /// @dev This function is O(n), where `n` is the number of submissions in the session.
+ /// This could exceed the gas limit, therefore this function should only be used for interface display and not by other contracts.
+ ///
/// @param _session The ID of the session.
/// @return submittedLists Indexes of lists that were submitted during the session.
function getSubmittedLists(uint256 _session) external view returns (uint256[] memory submittedLists) {
@@ -388,7 +395,7 @@ contract KlerosGovernor is IArbitrableV2 {
submittedLists = session.submittedLists;
}
- /// @dev Gets the number of transactions in the list.
+ /// @notice Gets the number of transactions in the list.
/// @param _listID The index of the transaction list in the array of lists.
/// @return txCount The number of transactions in the list.
function getNumberOfTransactions(uint256 _listID) external view returns (uint256 txCount) {
@@ -396,15 +403,38 @@ contract KlerosGovernor is IArbitrableV2 {
return submission.txs.length;
}
- /// @dev Gets the number of lists created in contract's lifetime.
+ /// @notice Gets the number of lists created in contract's lifetime.
/// @return The number of created lists.
function getNumberOfCreatedLists() external view returns (uint256) {
return submissions.length;
}
- /// @dev Gets the number of the ongoing session.
+ /// @notice Gets the number of the ongoing session.
/// @return The number of the ongoing session.
function getCurrentSessionNumber() external view returns (uint256) {
return sessions.length - 1;
}
+
+ // ************************************* //
+ // * Errors * //
+ // ************************************* //
+
+ error SubmissionTimeHasEnded();
+ error ApprovalTimeNotStarted();
+ error OwnerOnly();
+ error WrongInputTargetAndValue();
+ error WrongInputTargetAndDatasize();
+ error InsufficientDeposit();
+ error ListAlreadySubmitted();
+ error ShouldOnlyWithdrawInFirstHalf();
+ error WrongListHash();
+ error OnlySubmitterCanWithdraw();
+ error WithdrawingTimeHasPassed();
+ error AlreadyDisputed();
+ error OnlyArbitratorAllowed();
+ error NotDisputed();
+ error RulingOutOfBounds();
+ error SubmissionNotApproved();
+ error TimeToExecuteHasPassed();
+ error AlreadyExecuted();
}
diff --git a/contracts/src/arbitration/PolicyRegistry.sol b/contracts/src/arbitration/PolicyRegistry.sol
index eb32476d6..ac8e6f44c 100644
--- a/contracts/src/arbitration/PolicyRegistry.sol
+++ b/contracts/src/arbitration/PolicyRegistry.sol
@@ -5,15 +5,15 @@ import "../proxy/UUPSProxiable.sol";
import "../proxy/Initializable.sol";
/// @title PolicyRegistry
-/// @dev A contract to maintain a policy for each court.
+/// @notice A contract to maintain a policy for each court.
contract PolicyRegistry is UUPSProxiable, Initializable {
- string public constant override version = "0.8.0";
+ string public constant override version = "2.0.0";
// ************************************* //
// * Events * //
// ************************************* //
- /// @dev Emitted when a policy is updated.
+ /// @notice Emitted when a policy is updated.
/// @param _courtID The ID of the policy's court.
/// @param _courtName The name of the policy's court.
/// @param _policy The URI of the policy JSON.
@@ -23,16 +23,16 @@ contract PolicyRegistry is UUPSProxiable, Initializable {
// * Storage * //
// ************************************* //
- address public governor;
+ address public owner;
mapping(uint256 => string) public policies;
// ************************************* //
// * Function Modifiers * //
// ************************************* //
- /// @dev Requires that the sender is the governor.
- modifier onlyByGovernor() {
- require(governor == msg.sender, "No allowed: governor only");
+ /// @notice Requires that the sender is the owner.
+ modifier onlyByOwner() {
+ if (owner != msg.sender) revert OwnerOnly();
_;
}
@@ -45,14 +45,10 @@ contract PolicyRegistry is UUPSProxiable, Initializable {
_disableInitializers();
}
- /// @dev Constructs the `PolicyRegistry` contract.
- /// @param _governor The governor's address.
- function initialize(address _governor) external reinitializer(1) {
- governor = _governor;
- }
-
- function initialize2() external reinitializer(2) {
- // NOP
+ /// @notice Constructs the `PolicyRegistry` contract.
+ /// @param _owner The owner's address.
+ function initialize(address _owner) external initializer {
+ owner = _owner;
}
// ************************************* //
@@ -61,28 +57,34 @@ contract PolicyRegistry is UUPSProxiable, Initializable {
/**
* @dev Access Control to perform implementation upgrades (UUPS Proxiable)
- * @dev Only the governor can perform upgrades (`onlyByGovernor`)
+ * @dev Only the owner can perform upgrades (`onlyByOwner`)
*/
- function _authorizeUpgrade(address) internal view override onlyByGovernor {
+ function _authorizeUpgrade(address) internal view override onlyByOwner {
// NOP
}
- /// @dev Changes the `governor` storage variable.
- /// @param _governor The new value for the `governor` storage variable.
- function changeGovernor(address _governor) external onlyByGovernor {
- governor = _governor;
+ /// @notice Changes the `owner` storage variable.
+ /// @param _owner The new value for the `owner` storage variable.
+ function changeOwner(address _owner) external onlyByOwner {
+ owner = _owner;
}
// ************************************* //
// * State Modifiers * //
// ************************************* //
- /// @dev Sets the policy for the specified court.
+ /// @notice Sets the policy for the specified court.
/// @param _courtID The ID of the specified court.
/// @param _courtName The name of the specified court.
/// @param _policy The URI of the policy JSON.
- function setPolicy(uint256 _courtID, string calldata _courtName, string calldata _policy) external onlyByGovernor {
+ function setPolicy(uint256 _courtID, string calldata _courtName, string calldata _policy) external onlyByOwner {
policies[_courtID] = _policy;
emit PolicyUpdate(_courtID, _courtName, policies[_courtID]);
}
+
+ // ************************************* //
+ // * Errors * //
+ // ************************************* //
+
+ error OwnerOnly();
}
diff --git a/contracts/src/arbitration/SortitionModule.sol b/contracts/src/arbitration/SortitionModule.sol
index cb4f14c58..8a73ac76e 100644
--- a/contracts/src/arbitration/SortitionModule.sol
+++ b/contracts/src/arbitration/SortitionModule.sol
@@ -2,12 +2,99 @@
pragma solidity ^0.8.24;
-import {SortitionModuleBase, KlerosCore, RNG} from "./SortitionModuleBase.sol";
+import {KlerosCore} from "./KlerosCore.sol";
+import {ISortitionModule} from "./interfaces/ISortitionModule.sol";
+import {IDisputeKit} from "./interfaces/IDisputeKit.sol";
+import {Initializable} from "../proxy/Initializable.sol";
+import {UUPSProxiable} from "../proxy/UUPSProxiable.sol";
+import {SortitionTrees, TreeKey, CourtID} from "../libraries/SortitionTrees.sol";
+import {IRNG} from "../rng/IRNG.sol";
+import "../libraries/Constants.sol";
/// @title SortitionModule
-/// @dev A factory of trees that keeps track of staked values for sortition.
-contract SortitionModule is SortitionModuleBase {
- string public constant override version = "0.9.0";
+/// @notice A factory of trees that keeps track of staked values for sortition.
+contract SortitionModule is ISortitionModule, Initializable, UUPSProxiable {
+ using SortitionTrees for SortitionTrees.Tree;
+ using SortitionTrees for mapping(TreeKey key => SortitionTrees.Tree);
+
+ string public constant override version = "2.0.0";
+
+ // ************************************* //
+ // * Enums / Structs * //
+ // ************************************* //
+
+ struct DelayedStake {
+ address account; // The address of the juror.
+ uint96 courtID; // The ID of the court.
+ uint256 stake; // The new stake.
+ }
+
+ struct Juror {
+ uint96[] courtIDs; // The IDs of courts where the juror's stake path ends. A stake path is a path from the general court to a court the juror directly staked in using `_setStake`.
+ uint256 stakedPnk; // The juror's total amount of tokens staked in subcourts. PNK balance including locked PNK and penalty deductions.
+ uint256 lockedPnk; // The juror's total amount of tokens locked in disputes.
+ }
+
+ // ************************************* //
+ // * Storage * //
+ // ************************************* //
+
+ address public owner; // The owner of the contract.
+ KlerosCore public core; // The core arbitrator contract.
+ Phase public phase; // The current phase.
+ uint256 public minStakingTime; // The time after which the phase can be switched to Drawing if there are open disputes.
+ uint256 public maxDrawingTime; // The time after which the phase can be switched back to Staking.
+ uint256 public lastPhaseChange; // The last time the phase was changed.
+ uint256 public disputesWithoutJurors; // The number of disputes that have not finished drawing jurors.
+ IRNG public rng; // The random number generator.
+ uint256 public randomNumber; // Random number returned by RNG.
+ uint256 public delayedStakeWriteIndex; // The index of the last `delayedStake` item that was written to the array. 0 index is skipped.
+ uint256 public delayedStakeReadIndex; // The index of the next `delayedStake` item that should be processed. Starts at 1 because 0 index is skipped.
+ mapping(TreeKey key => SortitionTrees.Tree) sortitionSumTrees; // The mapping of sortition trees by keys.
+ mapping(address account => Juror) public jurors; // The jurors.
+ mapping(uint256 => DelayedStake) public delayedStakes; // Stores the stakes that were changed during Drawing phase, to update them when the phase is switched to Staking.
+ uint256 public maxStakePerJuror; // The maximum amount of PNK that a juror can stake across the courts.
+ uint256 public maxTotalStaked; // The maximum amount of PNK that all the jurors can stake across the courts.
+ uint256 public totalStaked; // The amount of PNK that is currently staked across the courts.
+
+ // ************************************* //
+ // * Events * //
+ // ************************************* //
+
+ /// @notice Emitted when a juror stakes in a court.
+ /// @param _address The address of the juror.
+ /// @param _courtID The ID of the court.
+ /// @param _amount The amount of tokens staked in the court.
+ /// @param _amountAllCourts The amount of tokens staked in all courts.
+ event StakeSet(address indexed _address, uint256 _courtID, uint256 _amount, uint256 _amountAllCourts);
+
+ /// @notice Emitted when a juror's stake is delayed.
+ /// @param _address The address of the juror.
+ /// @param _courtID The ID of the court.
+ /// @param _amount The amount of tokens staked in the court.
+ event StakeDelayed(address indexed _address, uint96 indexed _courtID, uint256 _amount);
+
+ /// @notice Emitted when a juror's stake is delayed execution fails.
+ /// @param _address The address of the juror.
+ /// @param _courtID The ID of the court.
+ /// @param _amount The amount of tokens staked in the court.
+ event StakeDelayedExecutionFailed(address indexed _address, uint96 indexed _courtID, uint256 _amount);
+
+ /// @notice Emitted when a juror's stake is locked.
+ /// @param _address The address of the juror.
+ /// @param _relativeAmount The amount of tokens locked.
+ /// @param _unlock Whether the stake is locked or unlocked.
+ event StakeLocked(address indexed _address, uint256 _relativeAmount, bool _unlock);
+
+ /// @notice Emitted when leftover PNK is available.
+ /// @param _account The account of the juror.
+ /// @param _amount The amount of PNK available.
+ event LeftoverPNK(address indexed _account, uint256 _amount);
+
+ /// @notice Emitted when leftover PNK is withdrawn.
+ /// @param _account The account of the juror withdrawing PNK.
+ /// @param _amount The amount of PNK withdrawn.
+ event LeftoverPNKWithdrawn(address indexed _account, uint256 _amount);
// ************************************* //
// * Constructor * //
@@ -18,26 +105,46 @@ contract SortitionModule is SortitionModuleBase {
_disableInitializers();
}
- /// @dev Initializer (constructor equivalent for upgradable contracts).
- /// @param _governor The governor.
+ /// @notice Initializer (constructor equivalent for upgradable contracts).
+ /// @param _owner The owner.
/// @param _core The KlerosCore.
/// @param _minStakingTime Minimal time to stake
/// @param _maxDrawingTime Time after which the drawing phase can be switched
/// @param _rng The random number generator.
- /// @param _rngLookahead Lookahead value for rng.
+ /// @param _maxStakePerJuror The maximum amount of PNK a juror can stake across the courts.
+ /// @param _maxTotalStaked The maximum amount of PNK that all the jurors can stake across the courts.
function initialize(
- address _governor,
+ address _owner,
KlerosCore _core,
uint256 _minStakingTime,
uint256 _maxDrawingTime,
- RNG _rng,
- uint256 _rngLookahead
- ) external reinitializer(1) {
- __SortitionModuleBase_initialize(_governor, _core, _minStakingTime, _maxDrawingTime, _rng, _rngLookahead);
+ IRNG _rng,
+ uint256 _maxStakePerJuror,
+ uint256 _maxTotalStaked
+ ) external initializer {
+ owner = _owner;
+ core = _core;
+ minStakingTime = _minStakingTime;
+ maxDrawingTime = _maxDrawingTime;
+ lastPhaseChange = block.timestamp;
+ rng = _rng;
+ maxStakePerJuror = _maxStakePerJuror;
+ maxTotalStaked = _maxTotalStaked;
+ delayedStakeReadIndex = 1;
}
- function initialize4() external reinitializer(4) {
- // NOP
+ // ************************************* //
+ // * Function Modifiers * //
+ // ************************************* //
+
+ modifier onlyByOwner() {
+ if (owner != msg.sender) revert OwnerOnly();
+ _;
+ }
+
+ modifier onlyByCore() {
+ if (address(core) != msg.sender) revert KlerosCoreOnly();
+ _;
}
// ************************************* //
@@ -45,8 +152,412 @@ contract SortitionModule is SortitionModuleBase {
// ************************************* //
/// @dev Access Control to perform implementation upgrades (UUPS Proxiable)
- /// Only the governor can perform upgrades (`onlyByGovernor`)
- function _authorizeUpgrade(address) internal view virtual override onlyByGovernor {
+ /// Only the owner can perform upgrades (`onlyByOwner`)
+ function _authorizeUpgrade(address) internal view override onlyByOwner {
// NOP
}
+
+ /// @notice Changes the owner of the contract.
+ /// @param _owner The new owner.
+ function changeOwner(address _owner) external onlyByOwner {
+ owner = _owner;
+ }
+
+ /// @notice Changes the `minStakingTime` storage variable.
+ /// @param _minStakingTime The new value for the `minStakingTime` storage variable.
+ function changeMinStakingTime(uint256 _minStakingTime) external onlyByOwner {
+ minStakingTime = _minStakingTime;
+ }
+
+ /// @notice Changes the `maxDrawingTime` storage variable.
+ /// @param _maxDrawingTime The new value for the `maxDrawingTime` storage variable.
+ function changeMaxDrawingTime(uint256 _maxDrawingTime) external onlyByOwner {
+ maxDrawingTime = _maxDrawingTime;
+ }
+
+ /// @notice Changes the `rng` storage variable.
+ /// @param _rng The new random number generator.
+ function changeRandomNumberGenerator(IRNG _rng) external onlyByOwner {
+ rng = _rng;
+ if (phase == Phase.generating) {
+ rng.requestRandomness();
+ }
+ }
+
+ /// @notice Changes the `maxStakePerJuror` storage variable.
+ /// @param _maxStakePerJuror The new `maxStakePerJuror` storage variable.
+ function changeMaxStakePerJuror(uint256 _maxStakePerJuror) external onlyByOwner {
+ maxStakePerJuror = _maxStakePerJuror;
+ }
+
+ /// @notice Changes the `maxTotalStaked` storage variable.
+ /// @param _maxTotalStaked The new `maxTotalStaked` storage variable.
+ function changeMaxTotalStaked(uint256 _maxTotalStaked) external onlyByOwner {
+ maxTotalStaked = _maxTotalStaked;
+ }
+
+ // ************************************* //
+ // * State Modifiers * //
+ // ************************************* //
+
+ /// @inheritdoc ISortitionModule
+ function passPhase() external override {
+ if (phase == Phase.staking) {
+ if (block.timestamp - lastPhaseChange < minStakingTime) revert MinStakingTimeNotPassed();
+ if (disputesWithoutJurors == 0) revert NoDisputesThatNeedJurors();
+ rng.requestRandomness();
+ phase = Phase.generating;
+ } else if (phase == Phase.generating) {
+ randomNumber = rng.receiveRandomness();
+ if (randomNumber == 0) revert RandomNumberNotReady();
+ phase = Phase.drawing;
+ } else if (phase == Phase.drawing) {
+ if (disputesWithoutJurors > 0 && block.timestamp - lastPhaseChange < maxDrawingTime) {
+ revert DisputesWithoutJurorsAndMaxDrawingTimeNotPassed();
+ }
+ phase = Phase.staking;
+ }
+
+ lastPhaseChange = block.timestamp;
+ emit NewPhase(phase);
+ }
+
+ /// @inheritdoc ISortitionModule
+ function createTree(uint96 _courtID, bytes memory _extraData) external override onlyByCore {
+ TreeKey key = CourtID.wrap(_courtID).toTreeKey();
+ uint256 K = _extraDataToTreeK(_extraData);
+ sortitionSumTrees.createTree(key, K);
+ }
+
+ /// @inheritdoc ISortitionModule
+ function executeDelayedStakes(uint256 _iterations) external override {
+ if (phase != Phase.staking) revert NotStakingPhase();
+ if (delayedStakeWriteIndex < delayedStakeReadIndex) revert NoDelayedStakeToExecute();
+
+ uint256 actualIterations = (delayedStakeReadIndex + _iterations) - 1 > delayedStakeWriteIndex
+ ? (delayedStakeWriteIndex - delayedStakeReadIndex) + 1
+ : _iterations;
+ uint256 newDelayedStakeReadIndex = delayedStakeReadIndex + actualIterations;
+
+ for (uint256 i = delayedStakeReadIndex; i < newDelayedStakeReadIndex; i++) {
+ DelayedStake storage delayedStake = delayedStakes[i];
+ if (!core.setStakeBySortitionModule(delayedStake.account, delayedStake.courtID, delayedStake.stake)) {
+ emit StakeDelayedExecutionFailed(delayedStake.account, delayedStake.courtID, delayedStake.stake);
+ }
+ delete delayedStakes[i];
+ }
+ delayedStakeReadIndex = newDelayedStakeReadIndex;
+ }
+
+ /// @inheritdoc ISortitionModule
+ function createDisputeHook(uint256 /*_disputeID*/, uint256 /*_roundID*/) external override onlyByCore {
+ disputesWithoutJurors++;
+ }
+
+ /// @inheritdoc ISortitionModule
+ function postDrawHook(uint256 /*_disputeID*/, uint256 /*_roundID*/) external override onlyByCore {
+ disputesWithoutJurors--;
+ }
+
+ /// @inheritdoc ISortitionModule
+ function validateStake(
+ address _account,
+ uint96 _courtID,
+ uint256 _newStake,
+ bool _noDelay
+ ) external override onlyByCore returns (uint256 pnkDeposit, uint256 pnkWithdrawal, StakingResult stakingResult) {
+ (pnkDeposit, pnkWithdrawal, stakingResult) = _validateStake(_account, _courtID, _newStake, _noDelay);
+ }
+
+ function _validateStake(
+ address _account,
+ uint96 _courtID,
+ uint256 _newStake,
+ bool _noDelay
+ ) internal returns (uint256 pnkDeposit, uint256 pnkWithdrawal, StakingResult stakingResult) {
+ Juror storage juror = jurors[_account];
+ uint256 currentStake = _stakeOf(_account, _courtID);
+ bool stakeIncrease = _newStake > currentStake;
+ uint256 stakeChange = stakeIncrease ? _newStake - currentStake : currentStake - _newStake;
+
+ uint256 nbCourts = juror.courtIDs.length;
+ if (currentStake == 0 && nbCourts >= MAX_STAKE_PATHS) {
+ return (0, 0, StakingResult.CannotStakeInMoreCourts); // Prevent staking beyond MAX_STAKE_PATHS but unstaking is always allowed.
+ }
+
+ if (currentStake == 0 && _newStake == 0) {
+ return (0, 0, StakingResult.CannotStakeZeroWhenNoStake); // Forbid staking 0 amount when current stake is 0 to avoid flaky behaviour.
+ }
+
+ if (stakeIncrease) {
+ // Check if the stake increase is within the limits.
+ if (juror.stakedPnk + stakeChange > maxStakePerJuror || currentStake + stakeChange > maxStakePerJuror) {
+ return (0, 0, StakingResult.CannotStakeMoreThanMaxStakePerJuror);
+ }
+ if (totalStaked + stakeChange > maxTotalStaked) {
+ return (0, 0, StakingResult.CannotStakeMoreThanMaxTotalStaked);
+ }
+ }
+
+ if (phase != Phase.staking && !_noDelay) {
+ // Store the stake change as delayed, to be applied when the phase switches back to Staking.
+ DelayedStake storage delayedStake = delayedStakes[++delayedStakeWriteIndex];
+ delayedStake.account = _account;
+ delayedStake.courtID = _courtID;
+ delayedStake.stake = _newStake;
+ emit StakeDelayed(_account, _courtID, _newStake);
+ return (pnkDeposit, pnkWithdrawal, StakingResult.Delayed);
+ }
+
+ // Current phase is Staking: set stakes.
+ if (stakeIncrease) {
+ pnkDeposit = stakeChange;
+ totalStaked += stakeChange;
+ } else {
+ pnkWithdrawal = stakeChange;
+ uint256 possibleWithdrawal = juror.stakedPnk > juror.lockedPnk ? juror.stakedPnk - juror.lockedPnk : 0;
+ if (pnkWithdrawal > possibleWithdrawal) {
+ // Ensure locked tokens remain in the contract. They can only be released during Execution.
+ pnkWithdrawal = possibleWithdrawal;
+ }
+ totalStaked -= pnkWithdrawal;
+ }
+ return (pnkDeposit, pnkWithdrawal, StakingResult.Successful);
+ }
+
+ /// @inheritdoc ISortitionModule
+ function setStake(
+ address _account,
+ uint96 _courtID,
+ uint256 _pnkDeposit,
+ uint256 _pnkWithdrawal,
+ uint256 _newStake
+ ) external override onlyByCore {
+ _setStake(_account, _courtID, _pnkDeposit, _pnkWithdrawal, _newStake);
+ }
+
+ /// @inheritdoc ISortitionModule
+ function setStakePenalty(
+ address _account,
+ uint96 _courtID,
+ uint256 _penalty
+ ) external override onlyByCore returns (uint256 pnkBalance, uint256 newCourtStake, uint256 availablePenalty) {
+ Juror storage juror = jurors[_account];
+ availablePenalty = _penalty;
+ newCourtStake = _stakeOf(_account, _courtID);
+ if (juror.stakedPnk < _penalty) {
+ availablePenalty = juror.stakedPnk;
+ }
+
+ if (availablePenalty == 0) return (juror.stakedPnk, newCourtStake, 0); // No penalty to apply.
+
+ uint256 currentStake = newCourtStake;
+ uint256 newStake = 0;
+ if (currentStake >= availablePenalty) {
+ newStake = currentStake - availablePenalty;
+ }
+ _setStake(_account, _courtID, 0, availablePenalty, newStake);
+ pnkBalance = juror.stakedPnk; // updated by _setStake()
+ newCourtStake = newStake;
+ }
+
+ /// @inheritdoc ISortitionModule
+ function setStakeReward(
+ address _account,
+ uint96 _courtID,
+ uint256 _reward
+ ) external override onlyByCore returns (bool success) {
+ if (_reward == 0) return true; // No reward to add.
+
+ uint256 currentStake = _stakeOf(_account, _courtID);
+ if (currentStake == 0) return false; // Juror has been unstaked, don't increase their stake.
+
+ uint256 newStake = currentStake + _reward;
+ _setStake(_account, _courtID, _reward, 0, newStake);
+ return true;
+ }
+
+ function _setStake(
+ address _account,
+ uint96 _courtID,
+ uint256 _pnkDeposit,
+ uint256 _pnkWithdrawal,
+ uint256 _newStake
+ ) internal {
+ Juror storage juror = jurors[_account];
+ if (_pnkDeposit > 0) {
+ uint256 currentStake = _stakeOf(_account, _courtID);
+ if (currentStake == 0) {
+ juror.courtIDs.push(_courtID);
+ }
+ // Increase juror's balance by deposited amount.
+ juror.stakedPnk += _pnkDeposit;
+ } else {
+ juror.stakedPnk -= _pnkWithdrawal;
+ if (_newStake == 0) {
+ // Cleanup
+ for (uint256 i = juror.courtIDs.length; i > 0; i--) {
+ if (juror.courtIDs[i - 1] == _courtID) {
+ juror.courtIDs[i - 1] = juror.courtIDs[juror.courtIDs.length - 1];
+ juror.courtIDs.pop();
+ break;
+ }
+ }
+ }
+ }
+
+ // Update the sortition sum tree.
+ bytes32 stakePathID = SortitionTrees.toStakePathID(_account, _courtID);
+ bool finished = false;
+ uint96 currentCourtID = _courtID;
+ while (!finished) {
+ // Tokens are also implicitly staked in parent courts through sortition module to increase the chance of being drawn.
+ TreeKey key = CourtID.wrap(currentCourtID).toTreeKey();
+ sortitionSumTrees[key].set(_newStake, stakePathID);
+ if (currentCourtID == GENERAL_COURT) {
+ finished = true;
+ } else {
+ (currentCourtID, , , , , ) = core.courts(currentCourtID); // Get the parent court.
+ }
+ }
+ emit StakeSet(_account, _courtID, _newStake, juror.stakedPnk);
+ }
+
+ /// @inheritdoc ISortitionModule
+ function lockStake(address _account, uint256 _relativeAmount) external override onlyByCore {
+ jurors[_account].lockedPnk += _relativeAmount;
+ emit StakeLocked(_account, _relativeAmount, false);
+ }
+
+ /// @inheritdoc ISortitionModule
+ function unlockStake(address _account, uint256 _relativeAmount) external override onlyByCore {
+ Juror storage juror = jurors[_account];
+ juror.lockedPnk -= _relativeAmount;
+ emit StakeLocked(_account, _relativeAmount, true);
+
+ uint256 amount = getJurorLeftoverPNK(_account);
+ if (amount > 0) {
+ emit LeftoverPNK(_account, amount);
+ }
+ }
+
+ /// @inheritdoc ISortitionModule
+ function forcedUnstakeAllCourts(address _account) external override onlyByCore {
+ uint96[] memory courtIDs = getJurorCourtIDs(_account);
+ for (uint256 j = courtIDs.length; j > 0; j--) {
+ core.setStakeBySortitionModule(_account, courtIDs[j - 1], 0);
+ }
+ }
+
+ /// @inheritdoc ISortitionModule
+ function forcedUnstake(address _account, uint96 _courtID) external override onlyByCore {
+ core.setStakeBySortitionModule(_account, _courtID, 0);
+ }
+
+ /// @inheritdoc ISortitionModule
+ function withdrawLeftoverPNK(address _account) external override {
+ // Can withdraw the leftover PNK if fully unstaked, has no tokens locked and has positive balance.
+ // This withdrawal can't be triggered by calling setStake() in KlerosCore because current stake is technically 0, thus it is done via separate function.
+ uint256 amount = getJurorLeftoverPNK(_account);
+ if (amount == 0) revert NotEligibleForWithdrawal();
+ jurors[_account].stakedPnk = 0;
+ core.transferBySortitionModule(_account, amount);
+ emit LeftoverPNKWithdrawn(_account, amount);
+ }
+
+ // ************************************* //
+ // * Public Views * //
+ // ************************************* //
+
+ /// @inheritdoc ISortitionModule
+ function draw(
+ uint96 _courtID,
+ uint256 _coreDisputeID,
+ uint256 _nonce
+ ) public view override returns (address drawnAddress, uint96 fromSubcourtID) {
+ if (phase != Phase.drawing) revert NotDrawingPhase();
+
+ TreeKey key = CourtID.wrap(_courtID).toTreeKey();
+ (drawnAddress, fromSubcourtID) = sortitionSumTrees[key].draw(_coreDisputeID, _nonce, randomNumber);
+ }
+
+ /// @inheritdoc ISortitionModule
+ function getJurorBalance(
+ address _juror,
+ uint96 _courtID
+ )
+ external
+ view
+ override
+ returns (uint256 totalStakedPnk, uint256 totalLocked, uint256 stakedInCourt, uint256 nbCourts)
+ {
+ Juror storage juror = jurors[_juror];
+ totalStakedPnk = juror.stakedPnk;
+ totalLocked = juror.lockedPnk;
+ stakedInCourt = _stakeOf(_juror, _courtID);
+ nbCourts = juror.courtIDs.length;
+ }
+
+ /// @inheritdoc ISortitionModule
+ function getJurorCourtIDs(address _juror) public view override returns (uint96[] memory) {
+ return jurors[_juror].courtIDs;
+ }
+
+ /// @inheritdoc ISortitionModule
+ function isJurorStaked(address _juror) external view override returns (bool) {
+ return jurors[_juror].stakedPnk > 0;
+ }
+
+ /// @inheritdoc ISortitionModule
+ function getJurorLeftoverPNK(address _juror) public view override returns (uint256) {
+ Juror storage juror = jurors[_juror];
+ if (juror.courtIDs.length == 0 && juror.lockedPnk == 0) {
+ return juror.stakedPnk;
+ } else {
+ return 0;
+ }
+ }
+
+ // ************************************* //
+ // * Internal * //
+ // ************************************* //
+
+ /// @notice Get the stake of a juror in a court.
+ /// @param _juror The address of the juror.
+ /// @param _courtID The ID of the court.
+ /// @return value The stake of the juror in the court.
+ function _stakeOf(address _juror, uint96 _courtID) internal view returns (uint256) {
+ bytes32 stakePathID = SortitionTrees.toStakePathID(_juror, _courtID);
+ TreeKey key = CourtID.wrap(_courtID).toTreeKey();
+ return sortitionSumTrees[key].stakeOf(stakePathID);
+ }
+
+ /// @notice Converts sortition extradata into K value of sortition tree.
+ /// @param _extraData Sortition extra data.
+ /// @return K The value of K.
+ function _extraDataToTreeK(bytes memory _extraData) internal pure returns (uint256 K) {
+ if (_extraData.length >= 32) {
+ assembly {
+ // solium-disable-line security/no-inline-assembly
+ K := mload(add(_extraData, 0x20))
+ }
+ } else {
+ K = DEFAULT_K;
+ }
+ }
+
+ // ************************************* //
+ // * Errors * //
+ // ************************************* //
+
+ error OwnerOnly();
+ error KlerosCoreOnly();
+ error MinStakingTimeNotPassed();
+ error NoDisputesThatNeedJurors();
+ error RandomNumberNotReady();
+ error DisputesWithoutJurorsAndMaxDrawingTimeNotPassed();
+ error NotStakingPhase();
+ error NoDelayedStakeToExecute();
+ error NotEligibleForWithdrawal();
+ error NotDrawingPhase();
}
diff --git a/contracts/src/arbitration/SortitionModuleBase.sol b/contracts/src/arbitration/SortitionModuleBase.sol
deleted file mode 100644
index 577d9fd22..000000000
--- a/contracts/src/arbitration/SortitionModuleBase.sol
+++ /dev/null
@@ -1,695 +0,0 @@
-// SPDX-License-Identifier: MIT
-
-pragma solidity ^0.8.24;
-
-import {KlerosCore} from "./KlerosCore.sol";
-import {ISortitionModule} from "./interfaces/ISortitionModule.sol";
-import {IDisputeKit} from "./interfaces/IDisputeKit.sol";
-import {Initializable} from "../proxy/Initializable.sol";
-import {UUPSProxiable} from "../proxy/UUPSProxiable.sol";
-import {RNG} from "../rng/RNG.sol";
-import "../libraries/Constants.sol";
-
-/// @title SortitionModuleBase
-/// @dev A factory of trees that keeps track of staked values for sortition.
-abstract contract SortitionModuleBase is ISortitionModule, Initializable, UUPSProxiable {
- // ************************************* //
- // * Enums / Structs * //
- // ************************************* //
-
- struct SortitionSumTree {
- uint256 K; // The maximum number of children per node.
- // We use this to keep track of vacant positions in the tree after removing a leaf. This is for keeping the tree as balanced as possible without spending gas on moving nodes around.
- uint256[] stack;
- uint256[] nodes;
- // Two-way mapping of IDs to node indexes. Note that node index 0 is reserved for the root node, and means the ID does not have a node.
- mapping(bytes32 => uint256) IDsToNodeIndexes;
- mapping(uint256 => bytes32) nodeIndexesToIDs;
- }
-
- struct DelayedStake {
- address account; // The address of the juror.
- uint96 courtID; // The ID of the court.
- uint256 stake; // The new stake.
- bool alreadyTransferred; // DEPRECATED. True if tokens were already transferred before delayed stake's execution.
- }
-
- struct Juror {
- uint96[] courtIDs; // The IDs of courts where the juror's stake path ends. A stake path is a path from the general court to a court the juror directly staked in using `_setStake`.
- uint256 stakedPnk; // The juror's total amount of tokens staked in subcourts. Reflects actual pnk balance.
- uint256 lockedPnk; // The juror's total amount of tokens locked in disputes.
- }
-
- // ************************************* //
- // * Storage * //
- // ************************************* //
-
- address public governor; // The governor of the contract.
- KlerosCore public core; // The core arbitrator contract.
- Phase public phase; // The current phase.
- uint256 public minStakingTime; // The time after which the phase can be switched to Drawing if there are open disputes.
- uint256 public maxDrawingTime; // The time after which the phase can be switched back to Staking.
- uint256 public lastPhaseChange; // The last time the phase was changed.
- uint256 public randomNumberRequestBlock; // Number of the block when RNG request was made.
- uint256 public disputesWithoutJurors; // The number of disputes that have not finished drawing jurors.
- RNG public rng; // The random number generator.
- uint256 public randomNumber; // Random number returned by RNG.
- uint256 public rngLookahead; // Minimal block distance between requesting and obtaining a random number.
- uint256 public delayedStakeWriteIndex; // The index of the last `delayedStake` item that was written to the array. 0 index is skipped.
- uint256 public delayedStakeReadIndex; // The index of the next `delayedStake` item that should be processed. Starts at 1 because 0 index is skipped.
- mapping(bytes32 treeHash => SortitionSumTree) sortitionSumTrees; // The mapping trees by keys.
- mapping(address account => Juror) public jurors; // The jurors.
- mapping(uint256 => DelayedStake) public delayedStakes; // Stores the stakes that were changed during Drawing phase, to update them when the phase is switched to Staking.
- mapping(address jurorAccount => mapping(uint96 courtId => uint256)) public latestDelayedStakeIndex; // DEPRECATED. Maps the juror to its latest delayed stake. If there is already a delayed stake for this juror then it'll be replaced. latestDelayedStakeIndex[juror][courtID].
-
- // ************************************* //
- // * Events * //
- // ************************************* //
-
- /// @notice Emitted when a juror stakes in a court.
- /// @param _address The address of the juror.
- /// @param _courtID The ID of the court.
- /// @param _amount The amount of tokens staked in the court.
- /// @param _amountAllCourts The amount of tokens staked in all courts.
- event StakeSet(address indexed _address, uint256 _courtID, uint256 _amount, uint256 _amountAllCourts);
-
- /// @notice Emitted when a juror's stake is delayed.
- /// @param _address The address of the juror.
- /// @param _courtID The ID of the court.
- /// @param _amount The amount of tokens staked in the court.
- event StakeDelayed(address indexed _address, uint96 indexed _courtID, uint256 _amount);
-
- /// @notice Emitted when a juror's stake is locked.
- /// @param _address The address of the juror.
- /// @param _relativeAmount The amount of tokens locked.
- /// @param _unlock Whether the stake is locked or unlocked.
- event StakeLocked(address indexed _address, uint256 _relativeAmount, bool _unlock);
-
- /// @dev Emitted when leftover PNK is available.
- /// @param _account The account of the juror.
- /// @param _amount The amount of PNK available.
- event LeftoverPNK(address indexed _account, uint256 _amount);
-
- /// @dev Emitted when leftover PNK is withdrawn.
- /// @param _account The account of the juror withdrawing PNK.
- /// @param _amount The amount of PNK withdrawn.
- event LeftoverPNKWithdrawn(address indexed _account, uint256 _amount);
-
- // ************************************* //
- // * Constructor * //
- // ************************************* //
-
- function __SortitionModuleBase_initialize(
- address _governor,
- KlerosCore _core,
- uint256 _minStakingTime,
- uint256 _maxDrawingTime,
- RNG _rng,
- uint256 _rngLookahead
- ) internal onlyInitializing {
- governor = _governor;
- core = _core;
- minStakingTime = _minStakingTime;
- maxDrawingTime = _maxDrawingTime;
- lastPhaseChange = block.timestamp;
- rng = _rng;
- rngLookahead = _rngLookahead;
- delayedStakeReadIndex = 1;
- }
-
- // ************************************* //
- // * Function Modifiers * //
- // ************************************* //
-
- modifier onlyByGovernor() {
- require(address(governor) == msg.sender, "Access not allowed: Governor only.");
- _;
- }
-
- modifier onlyByCore() {
- require(address(core) == msg.sender, "Access not allowed: KlerosCore only.");
- _;
- }
-
- // ************************************* //
- // * Governance * //
- // ************************************* //
-
- /// @dev Changes the governor of the contract.
- /// @param _governor The new governor.
- function changeGovernor(address _governor) external onlyByGovernor {
- governor = _governor;
- }
-
- /// @dev Changes the `minStakingTime` storage variable.
- /// @param _minStakingTime The new value for the `minStakingTime` storage variable.
- function changeMinStakingTime(uint256 _minStakingTime) external onlyByGovernor {
- minStakingTime = _minStakingTime;
- }
-
- /// @dev Changes the `maxDrawingTime` storage variable.
- /// @param _maxDrawingTime The new value for the `maxDrawingTime` storage variable.
- function changeMaxDrawingTime(uint256 _maxDrawingTime) external onlyByGovernor {
- maxDrawingTime = _maxDrawingTime;
- }
-
- /// @dev Changes the `_rng` and `_rngLookahead` storage variables.
- /// @param _rng The new value for the `RNGenerator` storage variable.
- /// @param _rngLookahead The new value for the `rngLookahead` storage variable.
- function changeRandomNumberGenerator(RNG _rng, uint256 _rngLookahead) external onlyByGovernor {
- rng = _rng;
- rngLookahead = _rngLookahead;
- if (phase == Phase.generating) {
- rng.requestRandomness(block.number + rngLookahead);
- randomNumberRequestBlock = block.number;
- }
- }
-
- // ************************************* //
- // * State Modifiers * //
- // ************************************* //
-
- function passPhase() external {
- if (phase == Phase.staking) {
- require(
- block.timestamp - lastPhaseChange >= minStakingTime,
- "The minimum staking time has not passed yet."
- );
- require(disputesWithoutJurors > 0, "There are no disputes that need jurors.");
- rng.requestRandomness(block.number + rngLookahead);
- randomNumberRequestBlock = block.number;
- phase = Phase.generating;
- } else if (phase == Phase.generating) {
- randomNumber = rng.receiveRandomness(randomNumberRequestBlock + rngLookahead);
- require(randomNumber != 0, "Random number is not ready yet");
- phase = Phase.drawing;
- } else if (phase == Phase.drawing) {
- require(
- disputesWithoutJurors == 0 || block.timestamp - lastPhaseChange >= maxDrawingTime,
- "There are still disputes without jurors and the maximum drawing time has not passed yet."
- );
- phase = Phase.staking;
- }
-
- lastPhaseChange = block.timestamp;
- emit NewPhase(phase);
- }
-
- /// @dev Create a sortition sum tree at the specified key.
- /// @param _key The key of the new tree.
- /// @param _extraData Extra data that contains the number of children each node in the tree should have.
- function createTree(bytes32 _key, bytes memory _extraData) external override onlyByCore {
- SortitionSumTree storage tree = sortitionSumTrees[_key];
- uint256 K = _extraDataToTreeK(_extraData);
- require(tree.K == 0, "Tree already exists.");
- require(K > 1, "K must be greater than one.");
- tree.K = K;
- tree.nodes.push(0);
- }
-
- /// @dev Executes the next delayed stakes.
- /// @param _iterations The number of delayed stakes to execute.
- function executeDelayedStakes(uint256 _iterations) external {
- require(phase == Phase.staking, "Should be in Staking phase.");
- require(delayedStakeWriteIndex >= delayedStakeReadIndex, "No delayed stake to execute.");
-
- uint256 actualIterations = (delayedStakeReadIndex + _iterations) - 1 > delayedStakeWriteIndex
- ? (delayedStakeWriteIndex - delayedStakeReadIndex) + 1
- : _iterations;
- uint256 newDelayedStakeReadIndex = delayedStakeReadIndex + actualIterations;
-
- for (uint256 i = delayedStakeReadIndex; i < newDelayedStakeReadIndex; i++) {
- DelayedStake storage delayedStake = delayedStakes[i];
- core.setStakeBySortitionModule(delayedStake.account, delayedStake.courtID, delayedStake.stake);
- delete delayedStakes[i];
- }
- delayedStakeReadIndex = newDelayedStakeReadIndex;
- }
-
- function createDisputeHook(uint256 /*_disputeID*/, uint256 /*_roundID*/) external override onlyByCore {
- disputesWithoutJurors++;
- }
-
- function postDrawHook(uint256 /*_disputeID*/, uint256 /*_roundID*/) external override onlyByCore {
- disputesWithoutJurors--;
- }
-
- /// @dev Saves the random number to use it in sortition. Not used by this contract because the storing of the number is inlined in passPhase().
- /// @param _randomNumber Random number returned by RNG contract.
- function notifyRandomNumber(uint256 _randomNumber) public override {}
-
- /// @dev Validate the specified juror's new stake for a court.
- /// Note: no state changes should be made when returning stakingResult != Successful, otherwise delayed stakes might break invariants.
- /// @param _account The address of the juror.
- /// @param _courtID The ID of the court.
- /// @param _newStake The new stake.
- /// @return pnkDeposit The amount of PNK to be deposited.
- /// @return pnkWithdrawal The amount of PNK to be withdrawn.
- /// @return stakingResult The result of the staking operation.
- function validateStake(
- address _account,
- uint96 _courtID,
- uint256 _newStake
- ) external override onlyByCore returns (uint256 pnkDeposit, uint256 pnkWithdrawal, StakingResult stakingResult) {
- (pnkDeposit, pnkWithdrawal, stakingResult) = _validateStake(_account, _courtID, _newStake);
- }
-
- function _validateStake(
- address _account,
- uint96 _courtID,
- uint256 _newStake
- ) internal virtual returns (uint256 pnkDeposit, uint256 pnkWithdrawal, StakingResult stakingResult) {
- Juror storage juror = jurors[_account];
- uint256 currentStake = stakeOf(_account, _courtID);
-
- uint256 nbCourts = juror.courtIDs.length;
- if (currentStake == 0 && nbCourts >= MAX_STAKE_PATHS) {
- return (0, 0, StakingResult.CannotStakeInMoreCourts); // Prevent staking beyond MAX_STAKE_PATHS but unstaking is always allowed.
- }
-
- if (currentStake == 0 && _newStake == 0) {
- return (0, 0, StakingResult.CannotStakeZeroWhenNoStake); // Forbid staking 0 amount when current stake is 0 to avoid flaky behaviour.
- }
-
- if (phase != Phase.staking) {
- // Store the stake change as delayed, to be applied when the phase switches back to Staking.
- DelayedStake storage delayedStake = delayedStakes[++delayedStakeWriteIndex];
- delayedStake.account = _account;
- delayedStake.courtID = _courtID;
- delayedStake.stake = _newStake;
- emit StakeDelayed(_account, _courtID, _newStake);
- return (pnkDeposit, pnkWithdrawal, StakingResult.Delayed);
- }
-
- // Current phase is Staking: set stakes.
- if (_newStake >= currentStake) {
- pnkDeposit = _newStake - currentStake;
- } else {
- pnkWithdrawal = currentStake - _newStake;
- // Ensure locked tokens remain in the contract. They can only be released during Execution.
- uint256 possibleWithdrawal = juror.stakedPnk > juror.lockedPnk ? juror.stakedPnk - juror.lockedPnk : 0;
- if (pnkWithdrawal > possibleWithdrawal) {
- pnkWithdrawal = possibleWithdrawal;
- }
- }
- return (pnkDeposit, pnkWithdrawal, StakingResult.Successful);
- }
-
- /// @dev Update the state of the stakes, called by KC at the end of setStake flow.
- /// `O(n + p * log_k(j))` where
- /// `n` is the number of courts the juror has staked in,
- /// `p` is the depth of the court tree,
- /// `k` is the minimum number of children per node of one of these courts' sortition sum tree,
- /// and `j` is the maximum number of jurors that ever staked in one of these courts simultaneously.
- /// @param _account The address of the juror.
- /// @param _courtID The ID of the court.
- /// @param _pnkDeposit The amount of PNK to be deposited.
- /// @param _pnkWithdrawal The amount of PNK to be withdrawn.
- /// @param _newStake The new stake.
- function setStake(
- address _account,
- uint96 _courtID,
- uint256 _pnkDeposit,
- uint256 _pnkWithdrawal,
- uint256 _newStake
- ) external override onlyByCore {
- _setStake(_account, _courtID, _pnkDeposit, _pnkWithdrawal, _newStake);
- }
-
- function _setStake(
- address _account,
- uint96 _courtID,
- uint256 _pnkDeposit,
- uint256 _pnkWithdrawal,
- uint256 _newStake
- ) internal virtual {
- Juror storage juror = jurors[_account];
- if (_pnkDeposit > 0) {
- uint256 currentStake = stakeOf(_account, _courtID);
- if (currentStake == 0) {
- juror.courtIDs.push(_courtID);
- }
- // Increase juror's balance by deposited amount.
- juror.stakedPnk += _pnkDeposit;
- } else {
- juror.stakedPnk -= _pnkWithdrawal;
- if (_newStake == 0) {
- // Cleanup
- for (uint256 i = juror.courtIDs.length; i > 0; i--) {
- if (juror.courtIDs[i - 1] == _courtID) {
- juror.courtIDs[i - 1] = juror.courtIDs[juror.courtIDs.length - 1];
- juror.courtIDs.pop();
- break;
- }
- }
- }
- }
-
- // Update the sortition sum tree.
- bytes32 stakePathID = _accountAndCourtIDToStakePathID(_account, _courtID);
- bool finished = false;
- uint96 currenCourtID = _courtID;
- while (!finished) {
- // Tokens are also implicitly staked in parent courts through sortition module to increase the chance of being drawn.
- _set(bytes32(uint256(currenCourtID)), _newStake, stakePathID);
- if (currenCourtID == GENERAL_COURT) {
- finished = true;
- } else {
- (currenCourtID, , , , , , ) = core.courts(currenCourtID); // Get the parent court.
- }
- }
- emit StakeSet(_account, _courtID, _newStake, juror.stakedPnk);
- }
-
- function lockStake(address _account, uint256 _relativeAmount) external override onlyByCore {
- jurors[_account].lockedPnk += _relativeAmount;
- emit StakeLocked(_account, _relativeAmount, false);
- }
-
- function unlockStake(address _account, uint256 _relativeAmount) external override onlyByCore {
- Juror storage juror = jurors[_account];
- juror.lockedPnk -= _relativeAmount;
- emit StakeLocked(_account, _relativeAmount, true);
-
- uint256 amount = getJurorLeftoverPNK(_account);
- if (amount > 0) {
- emit LeftoverPNK(_account, amount);
- }
- }
-
- function penalizeStake(
- address _account,
- uint256 _relativeAmount
- ) external override onlyByCore returns (uint256 pnkBalance, uint256 availablePenalty) {
- Juror storage juror = jurors[_account];
- uint256 stakedPnk = juror.stakedPnk;
-
- if (stakedPnk >= _relativeAmount) {
- availablePenalty = _relativeAmount;
- juror.stakedPnk -= _relativeAmount;
- } else {
- availablePenalty = stakedPnk;
- juror.stakedPnk = 0;
- }
-
- pnkBalance = juror.stakedPnk;
- return (pnkBalance, availablePenalty);
- }
-
- /// @dev Unstakes the inactive juror from all courts.
- /// `O(n * (p * log_k(j)) )` where
- /// `n` is the number of courts the juror has staked in,
- /// `p` is the depth of the court tree,
- /// `k` is the minimum number of children per node of one of these courts' sortition sum tree,
- /// and `j` is the maximum number of jurors that ever staked in one of these courts simultaneously.
- /// @param _account The juror to unstake.
- function setJurorInactive(address _account) external override onlyByCore {
- uint96[] memory courtIDs = getJurorCourtIDs(_account);
- for (uint256 j = courtIDs.length; j > 0; j--) {
- core.setStakeBySortitionModule(_account, courtIDs[j - 1], 0);
- }
- }
-
- /// @dev Gives back the locked PNKs in case the juror fully unstaked earlier.
- /// Note that since locked and staked PNK are async it is possible for the juror to have positive staked PNK balance
- /// while having 0 stake in courts and 0 locked tokens (eg. when the juror fully unstaked during dispute and later got his tokens unlocked).
- /// In this case the juror can use this function to withdraw the leftover tokens.
- /// Also note that if the juror has some leftover PNK while not fully unstaked he'll have to manually unstake from all courts to trigger this function.
- /// @param _account The juror whose PNK to withdraw.
- function withdrawLeftoverPNK(address _account) external override {
- // Can withdraw the leftover PNK if fully unstaked, has no tokens locked and has positive balance.
- // This withdrawal can't be triggered by calling setStake() in KlerosCore because current stake is technically 0, thus it is done via separate function.
- uint256 amount = getJurorLeftoverPNK(_account);
- require(amount > 0, "Not eligible for withdrawal.");
- jurors[_account].stakedPnk = 0;
- core.transferBySortitionModule(_account, amount);
- emit LeftoverPNKWithdrawn(_account, amount);
- }
-
- // ************************************* //
- // * Public Views * //
- // ************************************* //
-
- /// @dev Draw an ID from a tree using a number.
- /// Note that this function reverts if the sum of all values in the tree is 0.
- /// @param _key The key of the tree.
- /// @param _coreDisputeID Index of the dispute in Kleros Core.
- /// @param _nonce Nonce to hash with random number.
- /// @return drawnAddress The drawn address.
- /// `O(k * log_k(n))` where
- /// `k` is the maximum number of children per node in the tree,
- /// and `n` is the maximum number of nodes ever appended.
- function draw(
- bytes32 _key,
- uint256 _coreDisputeID,
- uint256 _nonce
- ) public view override returns (address drawnAddress) {
- require(phase == Phase.drawing, "Wrong phase.");
- SortitionSumTree storage tree = sortitionSumTrees[_key];
-
- if (tree.nodes[0] == 0) {
- return address(0); // No jurors staked.
- }
-
- uint256 currentDrawnNumber = uint256(keccak256(abi.encodePacked(randomNumber, _coreDisputeID, _nonce))) %
- tree.nodes[0];
-
- // While it still has children
- uint256 treeIndex = 0;
- while ((tree.K * treeIndex) + 1 < tree.nodes.length) {
- for (uint256 i = 1; i <= tree.K; i++) {
- // Loop over children.
- uint256 nodeIndex = (tree.K * treeIndex) + i;
- uint256 nodeValue = tree.nodes[nodeIndex];
-
- if (currentDrawnNumber >= nodeValue) {
- // Go to the next child.
- currentDrawnNumber -= nodeValue;
- } else {
- // Pick this child.
- treeIndex = nodeIndex;
- break;
- }
- }
- }
- drawnAddress = _stakePathIDToAccount(tree.nodeIndexesToIDs[treeIndex]);
- }
-
- /// @dev Get the stake of a juror in a court.
- /// @param _juror The address of the juror.
- /// @param _courtID The ID of the court.
- /// @return value The stake of the juror in the court.
- function stakeOf(address _juror, uint96 _courtID) public view returns (uint256) {
- bytes32 stakePathID = _accountAndCourtIDToStakePathID(_juror, _courtID);
- return stakeOf(bytes32(uint256(_courtID)), stakePathID);
- }
-
- /// @dev Get the stake of a juror in a court.
- /// @param _key The key of the tree, corresponding to a court.
- /// @param _ID The stake path ID, corresponding to a juror.
- /// @return The stake of the juror in the court.
- function stakeOf(bytes32 _key, bytes32 _ID) public view returns (uint256) {
- SortitionSumTree storage tree = sortitionSumTrees[_key];
- uint treeIndex = tree.IDsToNodeIndexes[_ID];
- if (treeIndex == 0) {
- return 0;
- }
- return tree.nodes[treeIndex];
- }
-
- function getJurorBalance(
- address _juror,
- uint96 _courtID
- )
- external
- view
- override
- returns (uint256 totalStaked, uint256 totalLocked, uint256 stakedInCourt, uint256 nbCourts)
- {
- Juror storage juror = jurors[_juror];
- totalStaked = juror.stakedPnk;
- totalLocked = juror.lockedPnk;
- stakedInCourt = stakeOf(_juror, _courtID);
- nbCourts = juror.courtIDs.length;
- }
-
- /// @dev Gets the court identifiers where a specific `_juror` has staked.
- /// @param _juror The address of the juror.
- function getJurorCourtIDs(address _juror) public view override returns (uint96[] memory) {
- return jurors[_juror].courtIDs;
- }
-
- function isJurorStaked(address _juror) external view override returns (bool) {
- return jurors[_juror].stakedPnk > 0;
- }
-
- function getJurorLeftoverPNK(address _juror) public view override returns (uint256) {
- Juror storage juror = jurors[_juror];
- if (juror.courtIDs.length == 0 && juror.lockedPnk == 0) {
- return juror.stakedPnk;
- } else {
- return 0;
- }
- }
-
- // ************************************* //
- // * Internal * //
- // ************************************* //
-
- /// @dev Update all the parents of a node.
- /// @param _key The key of the tree to update.
- /// @param _treeIndex The index of the node to start from.
- /// @param _plusOrMinus Whether to add (true) or substract (false).
- /// @param _value The value to add or substract.
- /// `O(log_k(n))` where
- /// `k` is the maximum number of children per node in the tree,
- /// and `n` is the maximum number of nodes ever appended.
- function _updateParents(bytes32 _key, uint256 _treeIndex, bool _plusOrMinus, uint256 _value) private {
- SortitionSumTree storage tree = sortitionSumTrees[_key];
-
- uint256 parentIndex = _treeIndex;
- while (parentIndex != 0) {
- parentIndex = (parentIndex - 1) / tree.K;
- tree.nodes[parentIndex] = _plusOrMinus
- ? tree.nodes[parentIndex] + _value
- : tree.nodes[parentIndex] - _value;
- }
- }
-
- /// @dev Retrieves a juror's address from the stake path ID.
- /// @param _stakePathID The stake path ID to unpack.
- /// @return account The account.
- function _stakePathIDToAccount(bytes32 _stakePathID) internal pure returns (address account) {
- assembly {
- // solium-disable-line security/no-inline-assembly
- let ptr := mload(0x40)
- for {
- let i := 0x00
- } lt(i, 0x14) {
- i := add(i, 0x01)
- } {
- mstore8(add(add(ptr, 0x0c), i), byte(i, _stakePathID))
- }
- account := mload(ptr)
- }
- }
-
- function _extraDataToTreeK(bytes memory _extraData) internal pure returns (uint256 K) {
- if (_extraData.length >= 32) {
- assembly {
- // solium-disable-line security/no-inline-assembly
- K := mload(add(_extraData, 0x20))
- }
- } else {
- K = DEFAULT_K;
- }
- }
-
- /// @dev Set a value in a tree.
- /// @param _key The key of the tree.
- /// @param _value The new value.
- /// @param _ID The ID of the value.
- /// `O(log_k(n))` where
- /// `k` is the maximum number of children per node in the tree,
- /// and `n` is the maximum number of nodes ever appended.
- function _set(bytes32 _key, uint256 _value, bytes32 _ID) internal {
- SortitionSumTree storage tree = sortitionSumTrees[_key];
- uint256 treeIndex = tree.IDsToNodeIndexes[_ID];
-
- if (treeIndex == 0) {
- // No existing node.
- if (_value != 0) {
- // Non zero value.
- // Append.
- // Add node.
- if (tree.stack.length == 0) {
- // No vacant spots.
- // Get the index and append the value.
- treeIndex = tree.nodes.length;
- tree.nodes.push(_value);
-
- // Potentially append a new node and make the parent a sum node.
- if (treeIndex != 1 && (treeIndex - 1) % tree.K == 0) {
- // Is first child.
- uint256 parentIndex = treeIndex / tree.K;
- bytes32 parentID = tree.nodeIndexesToIDs[parentIndex];
- uint256 newIndex = treeIndex + 1;
- tree.nodes.push(tree.nodes[parentIndex]);
- delete tree.nodeIndexesToIDs[parentIndex];
- tree.IDsToNodeIndexes[parentID] = newIndex;
- tree.nodeIndexesToIDs[newIndex] = parentID;
- }
- } else {
- // Some vacant spot.
- // Pop the stack and append the value.
- treeIndex = tree.stack[tree.stack.length - 1];
- tree.stack.pop();
- tree.nodes[treeIndex] = _value;
- }
-
- // Add label.
- tree.IDsToNodeIndexes[_ID] = treeIndex;
- tree.nodeIndexesToIDs[treeIndex] = _ID;
-
- _updateParents(_key, treeIndex, true, _value);
- }
- } else {
- // Existing node.
- if (_value == 0) {
- // Zero value.
- // Remove.
- // Remember value and set to 0.
- uint256 value = tree.nodes[treeIndex];
- tree.nodes[treeIndex] = 0;
-
- // Push to stack.
- tree.stack.push(treeIndex);
-
- // Clear label.
- delete tree.IDsToNodeIndexes[_ID];
- delete tree.nodeIndexesToIDs[treeIndex];
-
- _updateParents(_key, treeIndex, false, value);
- } else if (_value != tree.nodes[treeIndex]) {
- // New, non zero value.
- // Set.
- bool plusOrMinus = tree.nodes[treeIndex] <= _value;
- uint256 plusOrMinusValue = plusOrMinus
- ? _value - tree.nodes[treeIndex]
- : tree.nodes[treeIndex] - _value;
- tree.nodes[treeIndex] = _value;
-
- _updateParents(_key, treeIndex, plusOrMinus, plusOrMinusValue);
- }
- }
- }
-
- /// @dev Packs an account and a court ID into a stake path ID.
- /// @param _account The address of the juror to pack.
- /// @param _courtID The court ID to pack.
- /// @return stakePathID The stake path ID.
- function _accountAndCourtIDToStakePathID(
- address _account,
- uint96 _courtID
- ) internal pure returns (bytes32 stakePathID) {
- assembly {
- // solium-disable-line security/no-inline-assembly
- let ptr := mload(0x40)
- for {
- let i := 0x00
- } lt(i, 0x14) {
- i := add(i, 0x01)
- } {
- mstore8(add(ptr, i), byte(add(0x0c, i), _account))
- }
- for {
- let i := 0x14
- } lt(i, 0x20) {
- i := add(i, 0x01)
- } {
- mstore8(add(ptr, i), byte(i, _courtID))
- }
- stakePathID := mload(ptr)
- }
- }
-}
diff --git a/contracts/src/arbitration/SortitionModuleNeo.sol b/contracts/src/arbitration/SortitionModuleNeo.sol
deleted file mode 100644
index b966c9379..000000000
--- a/contracts/src/arbitration/SortitionModuleNeo.sol
+++ /dev/null
@@ -1,105 +0,0 @@
-// SPDX-License-Identifier: MIT
-
-pragma solidity ^0.8.24;
-
-import {SortitionModuleBase, KlerosCore, RNG, StakingResult} from "./SortitionModuleBase.sol";
-
-/// @title SortitionModuleNeo
-/// @dev A factory of trees that keeps track of staked values for sortition.
-contract SortitionModuleNeo is SortitionModuleBase {
- string public constant override version = "0.9.0";
-
- // ************************************* //
- // * Storage * //
- // ************************************* //
-
- uint256 public maxStakePerJuror;
- uint256 public maxTotalStaked;
- uint256 public totalStaked;
-
- // ************************************* //
- // * Constructor * //
- // ************************************* //
-
- /// @custom:oz-upgrades-unsafe-allow constructor
- constructor() {
- _disableInitializers();
- }
-
- /// @dev Initializer (constructor equivalent for upgradable contracts).
- /// @param _governor The governor.
- /// @param _core The KlerosCore.
- /// @param _minStakingTime Minimal time to stake
- /// @param _maxDrawingTime Time after which the drawing phase can be switched
- /// @param _rng The random number generator.
- /// @param _rngLookahead Lookahead value for rng.
- /// @param _maxStakePerJuror The maximum amount of PNK a juror can stake in a court.
- /// @param _maxTotalStaked The maximum amount of PNK that can be staked in all courts.
- function initialize(
- address _governor,
- KlerosCore _core,
- uint256 _minStakingTime,
- uint256 _maxDrawingTime,
- RNG _rng,
- uint256 _rngLookahead,
- uint256 _maxStakePerJuror,
- uint256 _maxTotalStaked
- ) external reinitializer(2) {
- __SortitionModuleBase_initialize(_governor, _core, _minStakingTime, _maxDrawingTime, _rng, _rngLookahead);
- maxStakePerJuror = _maxStakePerJuror;
- maxTotalStaked = _maxTotalStaked;
- }
-
- function initialize4() external reinitializer(4) {
- // NOP
- }
-
- // ************************************* //
- // * Governance * //
- // ************************************* //
-
- /// @dev Access Control to perform implementation upgrades (UUPS Proxiable)
- /// Only the governor can perform upgrades (`onlyByGovernor`)
- function _authorizeUpgrade(address) internal view override onlyByGovernor {
- // NOP
- }
-
- function changeMaxStakePerJuror(uint256 _maxStakePerJuror) external onlyByGovernor {
- maxStakePerJuror = _maxStakePerJuror;
- }
-
- function changeMaxTotalStaked(uint256 _maxTotalStaked) external onlyByGovernor {
- maxTotalStaked = _maxTotalStaked;
- }
-
- // ************************************* //
- // * State Modifiers * //
- // ************************************* //
-
- function _validateStake(
- address _account,
- uint96 _courtID,
- uint256 _newStake
- ) internal override onlyByCore returns (uint256 pnkDeposit, uint256 pnkWithdrawal, StakingResult stakingResult) {
- uint256 currentStake = stakeOf(_account, _courtID);
- bool stakeIncrease = _newStake > currentStake;
- uint256 stakeChange = stakeIncrease ? _newStake - currentStake : currentStake - _newStake;
- Juror storage juror = jurors[_account];
- if (stakeIncrease) {
- if (juror.stakedPnk + stakeChange > maxStakePerJuror) {
- return (0, 0, StakingResult.CannotStakeMoreThanMaxStakePerJuror);
- }
- if (totalStaked + stakeChange > maxTotalStaked) {
- return (0, 0, StakingResult.CannotStakeMoreThanMaxTotalStaked);
- }
- }
- if (phase == Phase.staking) {
- if (stakeIncrease) {
- totalStaked += stakeChange;
- } else {
- totalStaked -= stakeChange;
- }
- }
- (pnkDeposit, pnkWithdrawal, stakingResult) = super._validateStake(_account, _courtID, _newStake);
- }
-}
diff --git a/contracts/src/arbitration/arbitrables/ArbitrableExample.sol b/contracts/src/arbitration/arbitrables/ArbitrableExample.sol
index 810688788..ff4b49932 100644
--- a/contracts/src/arbitration/arbitrables/ArbitrableExample.sol
+++ b/contracts/src/arbitration/arbitrables/ArbitrableExample.sol
@@ -7,7 +7,7 @@ import "../interfaces/IDisputeTemplateRegistry.sol";
import "../../libraries/SafeERC20.sol";
/// @title ArbitrableExample
-/// An example of an arbitrable contract which connects to the arbitator that implements the updated interface.
+/// @notice An example of an arbitrable contract which connects to the arbitator that implements the updated interface.
contract ArbitrableExample is IArbitrableV2 {
using SafeERC20 for IERC20;
@@ -21,9 +21,17 @@ contract ArbitrableExample is IArbitrableV2 {
uint256 numberOfRulingOptions; // The number of choices the arbitrator can give.
}
+ // ************************************* //
+ // * Events * //
+ // ************************************* //
+
event Action(string indexed _action);
- address public immutable governor;
+ // ************************************* //
+ // * Storage * //
+ // ************************************* //
+
+ address public immutable owner;
IArbitratorV2 public arbitrator; // Arbitrator is set in constructor.
IDisputeTemplateRegistry public templateRegistry; // The dispute template registry.
uint256 public templateId; // The current dispute template identifier.
@@ -32,12 +40,14 @@ contract ArbitrableExample is IArbitrableV2 {
mapping(uint256 => uint256) public externalIDtoLocalID; // Maps external (arbitrator side) dispute IDs to local dispute IDs.
DisputeStruct[] public disputes; // Stores the disputes' info. disputes[disputeID].
+ uint256 public numberOfRulingOptions = 2;
+
// ************************************* //
// * Function Modifiers * //
// ************************************* //
- modifier onlyByGovernor() {
- require(msg.sender == governor, "Only the governor allowed.");
+ modifier onlyByOwner() {
+ if (owner != msg.sender) revert OwnerOnly();
_;
}
@@ -45,7 +55,7 @@ contract ArbitrableExample is IArbitrableV2 {
// * Constructor * //
// ************************************* //
- /// @dev Constructor
+ /// @notice Constructor
/// @param _arbitrator The arbitrator to rule on created disputes.
/// @param _templateData The dispute template data.
/// @param _templateDataMappings The dispute template data mappings.
@@ -60,7 +70,7 @@ contract ArbitrableExample is IArbitrableV2 {
IDisputeTemplateRegistry _templateRegistry,
IERC20 _weth
) {
- governor = msg.sender;
+ owner = msg.sender;
arbitrator = _arbitrator;
arbitratorExtraData = _arbitratorExtraData;
templateRegistry = _templateRegistry;
@@ -73,82 +83,91 @@ contract ArbitrableExample is IArbitrableV2 {
// * Governance * //
// ************************************* //
- function changeArbitrator(IArbitratorV2 _arbitrator) external onlyByGovernor {
+ function changeArbitrator(IArbitratorV2 _arbitrator) external onlyByOwner {
arbitrator = _arbitrator;
}
- function changeArbitratorExtraData(bytes calldata _arbitratorExtraData) external onlyByGovernor {
+ function changeArbitratorExtraData(bytes calldata _arbitratorExtraData) external onlyByOwner {
arbitratorExtraData = _arbitratorExtraData;
}
- function changeTemplateRegistry(IDisputeTemplateRegistry _templateRegistry) external onlyByGovernor {
+ function changeTemplateRegistry(IDisputeTemplateRegistry _templateRegistry) external onlyByOwner {
templateRegistry = _templateRegistry;
}
function changeDisputeTemplate(
string memory _templateData,
string memory _templateDataMappings
- ) external onlyByGovernor {
+ ) external onlyByOwner {
templateId = templateRegistry.setDisputeTemplate("", _templateData, _templateDataMappings);
}
+ function changeNumberOfRulingOptions(uint256 _numberOfRulingOptions) external onlyByOwner {
+ numberOfRulingOptions = _numberOfRulingOptions;
+ }
+
// ************************************* //
// * State Modifiers * //
// ************************************* //
- /// @dev Calls createDispute function of the specified arbitrator to create a dispute.
- /// Note that we don’t need to check that msg.value is enough to pay arbitration fees as it’s the responsibility of the arbitrator contract.
+ /// @notice Calls createDispute function of the specified arbitrator to create a dispute.
+ /// @dev No need to check that msg.value is enough to pay arbitration fees as it’s the responsibility of the arbitrator contract.
/// @param _action The action that requires arbitration.
/// @return disputeID Dispute id (on arbitrator side) of the dispute created.
function createDispute(string calldata _action) external payable returns (uint256 disputeID) {
emit Action(_action);
- uint256 numberOfRulingOptions = 2;
uint256 localDisputeID = disputes.length;
disputes.push(DisputeStruct({isRuled: false, ruling: 0, numberOfRulingOptions: numberOfRulingOptions}));
disputeID = arbitrator.createDispute{value: msg.value}(numberOfRulingOptions, arbitratorExtraData);
externalIDtoLocalID[disputeID] = localDisputeID;
- uint256 externalDisputeID = uint256(keccak256(abi.encodePacked(_action)));
- emit DisputeRequest(arbitrator, disputeID, externalDisputeID, templateId, "");
+ emit DisputeRequest(arbitrator, disputeID, templateId);
}
- /// @dev Calls createDispute function of the specified arbitrator to create a dispute.
- /// Note that we don’t need to check that msg.value is enough to pay arbitration fees as it’s the responsibility of the arbitrator contract.
+ /// @notice Calls createDispute function of the specified arbitrator to create a dispute.
+ /// @dev No need to check that msg.value is enough to pay arbitration fees as it’s the responsibility of the arbitrator contract.
/// @param _action The action that requires arbitration.
/// @param _feeInWeth Amount of fees in WETH for the arbitrator.
/// @return disputeID Dispute id (on arbitrator side) of the dispute created.
function createDispute(string calldata _action, uint256 _feeInWeth) external returns (uint256 disputeID) {
emit Action(_action);
- uint256 numberOfRulingOptions = 2;
uint256 localDisputeID = disputes.length;
disputes.push(DisputeStruct({isRuled: false, ruling: 0, numberOfRulingOptions: numberOfRulingOptions}));
- require(weth.safeTransferFrom(msg.sender, address(this), _feeInWeth), "Transfer failed");
- require(weth.increaseAllowance(address(arbitrator), _feeInWeth), "Allowance increase failed");
+ if (!weth.safeTransferFrom(msg.sender, address(this), _feeInWeth)) revert TransferFailed();
+ if (!weth.increaseAllowance(address(arbitrator), _feeInWeth)) revert AllowanceIncreaseFailed();
disputeID = arbitrator.createDispute(numberOfRulingOptions, arbitratorExtraData, weth, _feeInWeth);
externalIDtoLocalID[disputeID] = localDisputeID;
- uint256 externalDisputeID = uint256(keccak256(abi.encodePacked(_action)));
- emit DisputeRequest(arbitrator, disputeID, externalDisputeID, templateId, "");
+ emit DisputeRequest(arbitrator, disputeID, templateId);
}
- /// @dev To be called by the arbitrator of the dispute, to declare the winning ruling.
- /// @param _arbitratorDisputeID ID of the dispute in arbitrator contract.
- /// @param _ruling The ruling choice of the arbitration.
+ /// @inheritdoc IArbitrableV2
function rule(uint256 _arbitratorDisputeID, uint256 _ruling) external override {
uint256 localDisputeID = externalIDtoLocalID[_arbitratorDisputeID];
DisputeStruct storage dispute = disputes[localDisputeID];
- require(msg.sender == address(arbitrator), "Only the arbitrator can execute this.");
- require(_ruling <= dispute.numberOfRulingOptions, "Invalid ruling.");
- require(dispute.isRuled == false, "This dispute has been ruled already.");
+ if (msg.sender != address(arbitrator)) revert ArbitratorOnly();
+ if (_ruling > dispute.numberOfRulingOptions) revert RulingOutOfBounds();
+ if (dispute.isRuled) revert DisputeAlreadyRuled();
dispute.isRuled = true;
dispute.ruling = _ruling;
emit Ruling(IArbitratorV2(msg.sender), _arbitratorDisputeID, dispute.ruling);
}
+
+ // ************************************* //
+ // * Errors * //
+ // ************************************* //
+
+ error OwnerOnly();
+ error TransferFailed();
+ error AllowanceIncreaseFailed();
+ error ArbitratorOnly();
+ error RulingOutOfBounds();
+ error DisputeAlreadyRuled();
}
diff --git a/contracts/src/arbitration/arbitrables/DisputeResolver.sol b/contracts/src/arbitration/arbitrables/DisputeResolver.sol
index 8fa1da02f..282914883 100644
--- a/contracts/src/arbitration/arbitrables/DisputeResolver.sol
+++ b/contracts/src/arbitration/arbitrables/DisputeResolver.sol
@@ -6,7 +6,8 @@ import "../interfaces/IDisputeTemplateRegistry.sol";
pragma solidity ^0.8.24;
/// @title DisputeResolver
-/// DisputeResolver contract adapted for V2 from https://github.com/kleros/arbitrable-proxy-contracts/blob/master/contracts/ArbitrableProxy.sol.
+/// @notice DisputeResolver contract
+/// @dev Adapted for V2 from https://github.com/kleros/arbitrable-proxy-contracts/blob/master/contracts/ArbitrableProxy.sol.
contract DisputeResolver is IArbitrableV2 {
// ************************************* //
// * Enums / Structs * //
@@ -23,20 +24,30 @@ contract DisputeResolver is IArbitrableV2 {
// * Storage * //
// ************************************* //
- address public governor; // The governor.
+ address public owner; // The owner.
IArbitratorV2 public arbitrator; // The arbitrator.
IDisputeTemplateRegistry public templateRegistry; // The dispute template registry.
DisputeStruct[] public disputes; // Local disputes.
mapping(uint256 => uint256) public arbitratorDisputeIDToLocalID; // Maps arbitrator-side dispute IDs to local dispute IDs.
+ // ************************************* //
+ // * Function Modifiers * //
+ // ************************************* //
+
+ modifier onlyByOwner() {
+ if (owner != msg.sender) revert OwnerOnly();
+ _;
+ }
+
// ************************************* //
// * Constructor * //
// ************************************* //
- /// @dev Constructor
+ /// @notice Constructor
/// @param _arbitrator Target global arbitrator for any disputes.
+ /// @param _templateRegistry The dispute template registry.
constructor(IArbitratorV2 _arbitrator, IDisputeTemplateRegistry _templateRegistry) {
- governor = msg.sender;
+ owner = msg.sender;
arbitrator = _arbitrator;
templateRegistry = _templateRegistry;
}
@@ -45,20 +56,17 @@ contract DisputeResolver is IArbitrableV2 {
// * Governance * //
// ************************************* //
- /// @dev Changes the governor.
- /// @param _governor The address of the new governor.
- function changeGovernor(address _governor) external {
- require(governor == msg.sender, "Access not allowed: Governor only.");
- governor = _governor;
+ /// @notice Changes the owner.
+ /// @param _owner The address of the new owner.
+ function changeOwner(address _owner) external onlyByOwner {
+ owner = _owner;
}
- function changeArbitrator(IArbitratorV2 _arbitrator) external {
- require(governor == msg.sender, "Access not allowed: Governor only.");
+ function changeArbitrator(IArbitratorV2 _arbitrator) external onlyByOwner {
arbitrator = _arbitrator;
}
- function changeTemplateRegistry(IDisputeTemplateRegistry _templateRegistry) external {
- require(governor == msg.sender, "Access not allowed: Governor only.");
+ function changeTemplateRegistry(IDisputeTemplateRegistry _templateRegistry) external onlyByOwner {
templateRegistry = _templateRegistry;
}
@@ -66,8 +74,8 @@ contract DisputeResolver is IArbitrableV2 {
// * State Modifiers * //
// ************************************* //
- /// @dev Calls createDispute function of the specified arbitrator to create a dispute.
- /// Note that we don’t need to check that msg.value is enough to pay arbitration fees as it’s the responsibility of the arbitrator contract.
+ /// @notice Calls createDispute function of the specified arbitrator to create a dispute.
+ /// @dev No need to check that msg.value is enough to pay arbitration fees as it’s the responsibility of the arbitrator contract.
/// @param _arbitratorExtraData Extra data for the arbitrator of the dispute.
/// @param _disputeTemplate Dispute template.
/// @param _disputeTemplateDataMappings The data mappings.
@@ -84,34 +92,17 @@ contract DisputeResolver is IArbitrableV2 {
_arbitratorExtraData,
_disputeTemplate,
_disputeTemplateDataMappings,
- "",
_numberOfRulingOptions
);
}
- /// @dev Calls createDispute function of the specified arbitrator to create a dispute.
- /// Note that we don’t need to check that msg.value is enough to pay arbitration fees as it’s the responsibility of the arbitrator contract.
- /// @param _arbitratorExtraData Extra data for the arbitrator of the dispute.
- /// @param _disputeTemplateUri The URI to the dispute template. For example on IPFS: starting with '/ipfs/'.
- /// @param _numberOfRulingOptions Number of ruling options.
- /// @return disputeID Dispute id (on arbitrator side) of the created dispute.
- function createDisputeForTemplateUri(
- bytes calldata _arbitratorExtraData,
- string calldata _disputeTemplateUri,
- uint256 _numberOfRulingOptions
- ) external payable returns (uint256 disputeID) {
- return _createDispute(_arbitratorExtraData, "", "", _disputeTemplateUri, _numberOfRulingOptions);
- }
-
- /// @dev To be called by the arbitrator of the dispute, to declare the winning ruling.
- /// @param _arbitratorDisputeID ID of the dispute in arbitrator contract.
- /// @param _ruling The ruling choice of the arbitration.
+ /// @inheritdoc IArbitrableV2
function rule(uint256 _arbitratorDisputeID, uint256 _ruling) external override {
uint256 localDisputeID = arbitratorDisputeIDToLocalID[_arbitratorDisputeID];
DisputeStruct storage dispute = disputes[localDisputeID];
- require(msg.sender == address(arbitrator), "Only the arbitrator can execute this.");
- require(_ruling <= dispute.numberOfRulingOptions, "Invalid ruling.");
- require(!dispute.isRuled, "This dispute has been ruled already.");
+ if (msg.sender != address(arbitrator)) revert ArbitratorOnly();
+ if (_ruling > dispute.numberOfRulingOptions) revert RulingOutOfBounds();
+ if (dispute.isRuled) revert DisputeAlreadyRuled();
dispute.isRuled = true;
dispute.ruling = _ruling;
@@ -127,10 +118,9 @@ contract DisputeResolver is IArbitrableV2 {
bytes calldata _arbitratorExtraData,
string memory _disputeTemplate,
string memory _disputeTemplateDataMappings,
- string memory _disputeTemplateUri,
uint256 _numberOfRulingOptions
) internal virtual returns (uint256 arbitratorDisputeID) {
- require(_numberOfRulingOptions > 1, "Should be at least 2 ruling options.");
+ if (_numberOfRulingOptions <= 1) revert ShouldBeAtLeastTwoRulingOptions();
arbitratorDisputeID = arbitrator.createDispute{value: msg.value}(_numberOfRulingOptions, _arbitratorExtraData);
uint256 localDisputeID = disputes.length;
@@ -144,6 +134,16 @@ contract DisputeResolver is IArbitrableV2 {
);
arbitratorDisputeIDToLocalID[arbitratorDisputeID] = localDisputeID;
uint256 templateId = templateRegistry.setDisputeTemplate("", _disputeTemplate, _disputeTemplateDataMappings);
- emit DisputeRequest(arbitrator, arbitratorDisputeID, localDisputeID, templateId, _disputeTemplateUri);
+ emit DisputeRequest(arbitrator, arbitratorDisputeID, templateId);
}
+
+ // ************************************* //
+ // * Errors * //
+ // ************************************* //
+
+ error OwnerOnly();
+ error ArbitratorOnly();
+ error RulingOutOfBounds();
+ error DisputeAlreadyRuled();
+ error ShouldBeAtLeastTwoRulingOptions();
}
diff --git a/contracts/src/arbitration/devtools/DisputeResolverRuler.sol b/contracts/src/arbitration/devtools/DisputeResolverRuler.sol
index 85bede8bf..d3870dc71 100644
--- a/contracts/src/arbitration/devtools/DisputeResolverRuler.sol
+++ b/contracts/src/arbitration/devtools/DisputeResolverRuler.sol
@@ -9,20 +9,20 @@ interface IKlerosCoreRulerFragment {
}
/// @title DisputeResolverRuler
-/// It extends DisputeResolver for testing purposes of the automatic ruling modes.
-/// The arbitrator disputeID must be known before dispute creation, otherwise the dispute cannot be retrieved during the immediate call to rule().
+/// @notice Extension of the DisputeResolver for development tooling and testing of the automatic ruling modes.
+/// @dev The arbitrator disputeID must be known before dispute creation, otherwise the dispute cannot be retrieved during the immediate call to rule().
contract DisputeResolverRuler is DisputeResolver {
// ************************************* //
// * Constructor * //
// ************************************* //
- /// @dev Constructor
+ /// @notice Constructor
/// @param _arbitrator Target global arbitrator for any disputes.
constructor(
IArbitratorV2 _arbitrator,
IDisputeTemplateRegistry _templateRegistry
) DisputeResolver(_arbitrator, _templateRegistry) {
- governor = msg.sender;
+ owner = msg.sender;
}
// ************************************* //
@@ -33,10 +33,9 @@ contract DisputeResolverRuler is DisputeResolver {
bytes calldata _arbitratorExtraData,
string memory _disputeTemplate,
string memory _disputeTemplateDataMappings,
- string memory _disputeTemplateUri,
uint256 _numberOfRulingOptions
) internal override returns (uint256 arbitratorDisputeID) {
- require(_numberOfRulingOptions > 1, "Should be at least 2 ruling options.");
+ if (_numberOfRulingOptions <= 1) revert ShouldBeAtLeastTwoRulingOptions();
uint256 localDisputeID = disputes.length;
DisputeStruct storage dispute = disputes.push();
@@ -47,7 +46,7 @@ contract DisputeResolverRuler is DisputeResolver {
arbitratorDisputeID = IKlerosCoreRulerFragment(address(arbitrator)).getNextDisputeID();
arbitratorDisputeIDToLocalID[arbitratorDisputeID] = localDisputeID;
uint256 templateId = templateRegistry.setDisputeTemplate("", _disputeTemplate, _disputeTemplateDataMappings);
- emit DisputeRequest(arbitrator, arbitratorDisputeID, localDisputeID, templateId, _disputeTemplateUri);
+ emit DisputeRequest(arbitrator, arbitratorDisputeID, templateId);
arbitrator.createDispute{value: msg.value}(_numberOfRulingOptions, _arbitratorExtraData);
}
diff --git a/contracts/src/arbitration/devtools/KlerosCoreRuler.sol b/contracts/src/arbitration/devtools/KlerosCoreRuler.sol
index 2382970cf..a12a87972 100644
--- a/contracts/src/arbitration/devtools/KlerosCoreRuler.sol
+++ b/contracts/src/arbitration/devtools/KlerosCoreRuler.sol
@@ -13,7 +13,7 @@ import "../../libraries/Constants.sol";
contract KlerosCoreRuler is IArbitratorV2, UUPSProxiable, Initializable {
using SafeERC20 for IERC20;
- string public constant override version = "0.8.0";
+ string public constant override version = "2.0.0";
// ************************************* //
// * Enums / Structs * //
@@ -85,7 +85,7 @@ contract KlerosCoreRuler is IArbitratorV2, UUPSProxiable, Initializable {
uint256 private constant NON_PAYABLE_AMOUNT = (2 ** 256 - 2) / 2; // An amount higher than the supply of ETH.
- address public governor; // The governor of the contract.
+ address public owner; // The owner of the contract.
IERC20 public pinakion; // The Pinakion token contract.
Court[] public courts; // The courts.
Dispute[] public disputes; // The disputes.
@@ -126,20 +126,21 @@ contract KlerosCoreRuler is IArbitratorV2, UUPSProxiable, Initializable {
uint96 indexed _fromCourtID,
uint96 _toCourtID
);
- event TokenAndETHShift(
+ event JurorRewardPenalty(
address indexed _account,
uint256 indexed _disputeID,
uint256 indexed _roundID,
- uint256 _degreeOfCoherency,
- int256 _pnkAmount,
- int256 _feeAmount,
+ uint256 _degreeOfCoherencyPnk,
+ uint256 _degreeOfCoherencyFee,
+ int256 _amountPnk,
+ int256 _amountFee,
IERC20 _feeToken
);
event LeftoverRewardSent(
uint256 indexed _disputeID,
uint256 indexed _roundID,
- uint256 _pnkAmount,
- uint256 _feeAmount,
+ uint256 _amountPnk,
+ uint256 _amountFee,
IERC20 _feeToken
);
event AutoRuled(
@@ -157,8 +158,8 @@ contract KlerosCoreRuler is IArbitratorV2, UUPSProxiable, Initializable {
// * Function Modifiers * //
// ************************************* //
- modifier onlyByGovernor() {
- if (governor != msg.sender) revert GovernorOnly();
+ modifier onlyByOwner() {
+ if (owner != msg.sender) revert OwnerOnly();
_;
}
@@ -172,15 +173,11 @@ contract KlerosCoreRuler is IArbitratorV2, UUPSProxiable, Initializable {
}
/// @dev Initializer (constructor equivalent for upgradable contracts).
- /// @param _governor The governor's address.
+ /// @param _owner The owner's address.
/// @param _pinakion The address of the token contract.
/// @param _courtParameters Numeric parameters of General court (minStake, alpha, feeForJuror and jurorsForCourtJump respectively).
- function initialize(
- address _governor,
- IERC20 _pinakion,
- uint256[4] memory _courtParameters
- ) external reinitializer(1) {
- governor = _governor;
+ function initialize(address _owner, IERC20 _pinakion, uint256[4] memory _courtParameters) external initializer {
+ owner = _owner;
pinakion = _pinakion;
// FORKING_COURT
@@ -210,43 +207,35 @@ contract KlerosCoreRuler is IArbitratorV2, UUPSProxiable, Initializable {
);
}
- function initialize2() external reinitializer(2) {
- // NOP
- }
-
// ************************************* //
// * Governance * //
// ************************************* //
/* @dev Access Control to perform implementation upgrades (UUPS Proxiable)
- * @dev Only the governor can perform upgrades (`onlyByGovernor`)
+ * @dev Only the owner can perform upgrades (`onlyByOwner`)
*/
- function _authorizeUpgrade(address) internal view override onlyByGovernor {
+ function _authorizeUpgrade(address) internal view override onlyByOwner {
// NOP
}
- /// @dev Allows the governor to call anything on behalf of the contract.
+ /// @dev Allows the owner to call anything on behalf of the contract.
/// @param _destination The destination of the call.
/// @param _amount The value sent with the call.
/// @param _data The data sent with the call.
- function executeGovernorProposal(
- address _destination,
- uint256 _amount,
- bytes memory _data
- ) external onlyByGovernor {
+ function executeOwnerProposal(address _destination, uint256 _amount, bytes memory _data) external onlyByOwner {
(bool success, ) = _destination.call{value: _amount}(_data);
if (!success) revert UnsuccessfulCall();
}
- /// @dev Changes the `governor` storage variable.
- /// @param _governor The new value for the `governor` storage variable.
- function changeGovernor(address payable _governor) external onlyByGovernor {
- governor = _governor;
+ /// @dev Changes the `owner` storage variable.
+ /// @param _owner The new value for the `owner` storage variable.
+ function changeOwner(address payable _owner) external onlyByOwner {
+ owner = _owner;
}
/// @dev Changes the `pinakion` storage variable.
/// @param _pinakion The new value for the `pinakion` storage variable.
- function changePinakion(IERC20 _pinakion) external onlyByGovernor {
+ function changePinakion(IERC20 _pinakion) external onlyByOwner {
pinakion = _pinakion;
}
@@ -266,7 +255,7 @@ contract KlerosCoreRuler is IArbitratorV2, UUPSProxiable, Initializable {
uint256 _feeForJuror,
uint256 _jurorsForCourtJump,
uint256[4] memory _timesPerPeriod
- ) external onlyByGovernor {
+ ) external onlyByOwner {
if (_parent == FORKING_COURT) revert InvalidForkingCourtAsParent();
uint256 courtID = courts.length;
@@ -303,7 +292,7 @@ contract KlerosCoreRuler is IArbitratorV2, UUPSProxiable, Initializable {
uint256 _feeForJuror,
uint256 _jurorsForCourtJump,
uint256[4] memory _timesPerPeriod
- ) external onlyByGovernor {
+ ) external onlyByOwner {
Court storage court = courts[_courtID];
court.minStake = _minStake;
court.hiddenVotes = _hiddenVotes;
@@ -325,7 +314,7 @@ contract KlerosCoreRuler is IArbitratorV2, UUPSProxiable, Initializable {
/// @dev Changes the supported fee tokens.
/// @param _feeToken The fee token.
/// @param _accepted Whether the token is supported or not as a method of fee payment.
- function changeAcceptedFeeTokens(IERC20 _feeToken, bool _accepted) external onlyByGovernor {
+ function changeAcceptedFeeTokens(IERC20 _feeToken, bool _accepted) external onlyByOwner {
currencyRates[_feeToken].feePaymentAccepted = _accepted;
emit AcceptedFeeToken(_feeToken, _accepted);
}
@@ -334,7 +323,7 @@ contract KlerosCoreRuler is IArbitratorV2, UUPSProxiable, Initializable {
/// @param _feeToken The fee token.
/// @param _rateInEth The new rate of the fee token in ETH.
/// @param _rateDecimals The new decimals of the fee token rate.
- function changeCurrencyRates(IERC20 _feeToken, uint64 _rateInEth, uint8 _rateDecimals) external onlyByGovernor {
+ function changeCurrencyRates(IERC20 _feeToken, uint64 _rateInEth, uint8 _rateDecimals) external onlyByOwner {
currencyRates[_feeToken].rateInEth = _rateInEth;
currencyRates[_feeToken].rateDecimals = _rateDecimals;
emit NewCurrencyRate(_feeToken, _rateInEth, _rateDecimals);
@@ -530,7 +519,16 @@ contract KlerosCoreRuler is IArbitratorV2, UUPSProxiable, Initializable {
// The dispute fees were paid in ERC20
round.feeToken.safeTransfer(account, feeReward);
}
- emit TokenAndETHShift(account, _disputeID, _round, 1, int256(0), int256(feeReward), round.feeToken);
+ emit JurorRewardPenalty(
+ account,
+ _disputeID,
+ _round,
+ ONE_BASIS_POINT,
+ ONE_BASIS_POINT,
+ int256(0),
+ int256(feeReward),
+ round.feeToken
+ );
}
/// @dev Executes a specified dispute's ruling.
@@ -675,8 +673,7 @@ contract KlerosCoreRuler is IArbitratorV2, UUPSProxiable, Initializable {
// * Errors * //
// ************************************* //
- error GovernorOnly();
- error GovernorOrInstructorOnly();
+ error OwnerOnly();
error RulerOnly();
error NoRulerSet();
error RulingModeNotSet();
diff --git a/contracts/src/arbitration/dispute-kits/DisputeKitClassic.sol b/contracts/src/arbitration/dispute-kits/DisputeKitClassic.sol
index 2479ab07d..95f551a48 100644
--- a/contracts/src/arbitration/dispute-kits/DisputeKitClassic.sol
+++ b/contracts/src/arbitration/dispute-kits/DisputeKitClassic.sol
@@ -5,13 +5,13 @@ pragma solidity ^0.8.24;
import {DisputeKitClassicBase, KlerosCore} from "./DisputeKitClassicBase.sol";
/// @title DisputeKitClassic
-/// Dispute kit implementation of the Kleros v1 features including:
+/// @notice Dispute kit implementation of the Kleros v1 features including:
/// - a drawing system: proportional to staked PNK,
/// - a vote aggregation system: plurality,
/// - an incentive system: equal split between coherent votes,
/// - an appeal system: fund 2 choices only, vote on any choice.
contract DisputeKitClassic is DisputeKitClassicBase {
- string public constant override version = "0.12.0";
+ string public constant override version = "2.0.0";
// ************************************* //
// * Constructor * //
@@ -22,16 +22,18 @@ contract DisputeKitClassic is DisputeKitClassicBase {
_disableInitializers();
}
- /// @dev Initializer.
- /// @param _governor The governor's address.
+ /// @notice Initializer.
+ /// @param _owner The owner's address.
/// @param _core The KlerosCore arbitrator.
/// @param _wNative The wrapped native token address, typically wETH.
- function initialize(address _governor, KlerosCore _core, address _wNative) external reinitializer(1) {
- __DisputeKitClassicBase_initialize(_governor, _core, _wNative);
- }
-
- function reinitialize(address _wNative) external reinitializer(9) {
- wNative = _wNative;
+ /// @param _jumpDisputeKitID The ID of the dispute kit to switch to after the court jump.
+ function initialize(
+ address _owner,
+ KlerosCore _core,
+ address _wNative,
+ uint256 _jumpDisputeKitID
+ ) external initializer {
+ __DisputeKitClassicBase_initialize(_owner, _core, _wNative, _jumpDisputeKitID);
}
// ************************ //
@@ -39,8 +41,8 @@ contract DisputeKitClassic is DisputeKitClassicBase {
// ************************ //
/// @dev Access Control to perform implementation upgrades (UUPS Proxiable)
- /// Only the governor can perform upgrades (`onlyByGovernor`)
- function _authorizeUpgrade(address) internal view override onlyByGovernor {
+ /// Only the owner can perform upgrades (`onlyByOwner`)
+ function _authorizeUpgrade(address) internal view override onlyByOwner {
// NOP
}
}
diff --git a/contracts/src/arbitration/dispute-kits/DisputeKitClassicBase.sol b/contracts/src/arbitration/dispute-kits/DisputeKitClassicBase.sol
index 9b1968400..9ed66cdfe 100644
--- a/contracts/src/arbitration/dispute-kits/DisputeKitClassicBase.sol
+++ b/contracts/src/arbitration/dispute-kits/DisputeKitClassicBase.sol
@@ -2,13 +2,14 @@
pragma solidity ^0.8.24;
-import {KlerosCore, KlerosCoreBase, IDisputeKit, ISortitionModule} from "../KlerosCore.sol";
+import {KlerosCore, IDisputeKit, ISortitionModule} from "../KlerosCore.sol";
import {Initializable} from "../../proxy/Initializable.sol";
import {UUPSProxiable} from "../../proxy/UUPSProxiable.sol";
import {SafeSend} from "../../libraries/SafeSend.sol";
+import {ONE_BASIS_POINT, DISPUTE_KIT_CLASSIC} from "../../libraries/Constants.sol";
/// @title DisputeKitClassicBase
-/// Abstract Dispute kit classic implementation of the Kleros v1 features including:
+/// @notice Abstract Dispute kit classic implementation of the Kleros v1 features including:
/// - a drawing system: proportional to staked PNK,
/// - a vote aggregation system: plurality,
/// - an incentive system: equal split between coherent votes,
@@ -23,9 +24,9 @@ abstract contract DisputeKitClassicBase is IDisputeKit, Initializable, UUPSProxi
struct Dispute {
Round[] rounds; // Rounds of the dispute. 0 is the default round, and [1, ..n] are the appeal rounds.
uint256 numberOfChoices; // The number of choices jurors have when voting. This does not include choice `0` which is reserved for "refuse to arbitrate".
- bool jumped; // True if dispute jumped to a parent dispute kit and won't be handled by this DK anymore.
mapping(uint256 => uint256) coreRoundIDToLocal; // Maps id of the round in the core contract to the index of the round of related local dispute.
bytes extraData; // Extradata for the dispute.
+ uint256[10] __gap; // Reserved slots for future upgrades.
}
struct Round {
@@ -40,14 +41,21 @@ abstract contract DisputeKitClassicBase is IDisputeKit, Initializable, UUPSProxi
mapping(address account => mapping(uint256 choiceId => uint256)) contributions; // Maps contributors to their contributions for each choice.
uint256 feeRewards; // Sum of reimbursable appeal fees available to the parties that made contributions to the ruling that ultimately wins a dispute.
uint256[] fundedChoices; // Stores the choices that are fully funded.
- uint256 nbVotes; // Maximal number of votes this dispute can get.
+ mapping(address drawnAddress => bool) alreadyDrawn; // True if the address has already been drawn, false by default.
+ uint256[10] __gap; // Reserved slots for future upgrades.
}
struct Vote {
+ bool voted; // True if the vote has been cast.
address account; // The address of the juror.
bytes32 commit; // The commit of the juror. For courts with hidden votes.
uint256 choice; // The choice of the juror.
- bool voted; // True if the vote has been cast.
+ uint256[10] __gap; // Reserved slots for future upgrades.
+ }
+
+ struct Active {
+ bool dispute; // True if at least one round in the dispute has been active on this Dispute Kit. False if the dispute is unknown to this Dispute Kit.
+ bool currentRound; // True if the dispute's current round is active on this Dispute Kit. False if the dispute has jumped to another Dispute Kit.
}
// ************************************* //
@@ -57,36 +65,36 @@ abstract contract DisputeKitClassicBase is IDisputeKit, Initializable, UUPSProxi
uint256 public constant WINNER_STAKE_MULTIPLIER = 10000; // Multiplier of the appeal cost that the winner has to pay as fee stake for a round in basis points. Default is 1x of appeal fee.
uint256 public constant LOSER_STAKE_MULTIPLIER = 20000; // Multiplier of the appeal cost that the loser has to pay as fee stake for a round in basis points. Default is 2x of appeal fee.
uint256 public constant LOSER_APPEAL_PERIOD_MULTIPLIER = 5000; // Multiplier of the appeal period for the choice that wasn't voted for in the previous round, in basis points. Default is 1/2 of original appeal period.
- uint256 public constant ONE_BASIS_POINT = 10000; // One basis point, for scaling.
- address public governor; // The governor of the contract.
+ address public owner; // The owner of the contract.
KlerosCore public core; // The Kleros Core arbitrator
Dispute[] public disputes; // Array of the locally created disputes.
mapping(uint256 => uint256) public coreDisputeIDToLocal; // Maps the dispute ID in Kleros Core to the local dispute ID.
bool public singleDrawPerJuror; // Whether each juror can only draw once per dispute, false by default.
- mapping(uint256 localDisputeID => mapping(uint256 localRoundID => mapping(address drawnAddress => bool)))
- public alreadyDrawn; // True if the address has already been drawn, false by default. To be added to the Round struct when fully redeploying rather than upgrading.
- mapping(uint256 coreDisputeID => bool) public coreDisputeIDToActive; // True if this dispute kit is active for this core dispute ID.
+ mapping(uint256 coreDisputeID => Active) public coreDisputeIDToActive; // Active status of the dispute and the current round.
address public wNative; // The wrapped native token for safeSend().
+ uint256 public jumpDisputeKitID; // The ID of the dispute kit in Kleros Core disputeKits array that the dispute should switch to after the court jump, in case the new court doesn't support this dispute kit.
+
+ uint256[50] private __gap; // Reserved slots for future upgrades.
// ************************************* //
// * Events * //
// ************************************* //
- /// @dev To be emitted when a dispute is created.
+ /// @notice To be emitted when a dispute is created.
/// @param _coreDisputeID The identifier of the dispute in the Arbitrator contract.
/// @param _numberOfChoices The number of choices available in the dispute.
/// @param _extraData The extra data for the dispute.
event DisputeCreation(uint256 indexed _coreDisputeID, uint256 _numberOfChoices, bytes _extraData);
- /// @dev To be emitted when a vote commitment is cast.
+ /// @notice To be emitted when a vote commitment is cast.
/// @param _coreDisputeID The identifier of the dispute in the Arbitrator contract.
/// @param _juror The address of the juror casting the vote commitment.
/// @param _voteIDs The identifiers of the votes in the dispute.
/// @param _commit The commitment of the juror.
event CommitCast(uint256 indexed _coreDisputeID, address indexed _juror, uint256[] _voteIDs, bytes32 _commit);
- /// @dev To be emitted when a funding contribution is made.
+ /// @notice To be emitted when a funding contribution is made.
/// @param _coreDisputeID The identifier of the dispute in the Arbitrator contract.
/// @param _coreRoundID The identifier of the round in the Arbitrator contract.
/// @param _choice The choice that is being funded.
@@ -100,21 +108,14 @@ abstract contract DisputeKitClassicBase is IDisputeKit, Initializable, UUPSProxi
uint256 _amount
);
- /// @dev To be emitted when the contributed funds are withdrawn.
+ /// @notice To be emitted when the contributed funds are withdrawn.
/// @param _coreDisputeID The identifier of the dispute in the Arbitrator contract.
- /// @param _coreRoundID The identifier of the round in the Arbitrator contract.
/// @param _choice The choice that is being funded.
/// @param _contributor The address of the contributor.
/// @param _amount The amount withdrawn.
- event Withdrawal(
- uint256 indexed _coreDisputeID,
- uint256 indexed _coreRoundID,
- uint256 _choice,
- address indexed _contributor,
- uint256 _amount
- );
+ event Withdrawal(uint256 indexed _coreDisputeID, uint256 _choice, address indexed _contributor, uint256 _amount);
- /// @dev To be emitted when a choice is fully funded for an appeal.
+ /// @notice To be emitted when a choice is fully funded for an appeal.
/// @param _coreDisputeID The identifier of the dispute in the Arbitrator contract.
/// @param _coreRoundID The identifier of the round in the Arbitrator contract.
/// @param _choice The choice that is being funded.
@@ -124,18 +125,19 @@ abstract contract DisputeKitClassicBase is IDisputeKit, Initializable, UUPSProxi
// * Modifiers * //
// ************************************* //
- modifier onlyByGovernor() {
- require(governor == msg.sender, "Access not allowed: Governor only.");
+ modifier onlyByOwner() {
+ if (owner != msg.sender) revert OwnerOnly();
_;
}
modifier onlyByCore() {
- require(address(core) == msg.sender, "Access not allowed: KlerosCore only.");
+ if (address(core) != msg.sender) revert KlerosCoreOnly();
_;
}
- modifier notJumped(uint256 _coreDisputeID) {
- require(!disputes[coreDisputeIDToLocal[_coreDisputeID]].jumped, "Dispute jumped to a parent DK!");
+ modifier isActive(uint256 _coreDisputeID) {
+ if (!coreDisputeIDToActive[_coreDisputeID].dispute) revert DisputeUnknownInThisDisputeKit();
+ if (!coreDisputeIDToActive[_coreDisputeID].currentRound) revert DisputeJumpedToAnotherDisputeKit();
_;
}
@@ -143,92 +145,97 @@ abstract contract DisputeKitClassicBase is IDisputeKit, Initializable, UUPSProxi
// * Constructor * //
// ************************************* //
- /// @dev Initializer.
- /// @param _governor The governor's address.
+ /// @notice Initializer.
+ /// @param _owner The owner's address.
/// @param _core The KlerosCore arbitrator.
/// @param _wNative The wrapped native token address, typically wETH.
+ /// @param _jumpDisputeKitID The ID of the dispute kit to switch to after the court jump.
function __DisputeKitClassicBase_initialize(
- address _governor,
+ address _owner,
KlerosCore _core,
- address _wNative
+ address _wNative,
+ uint256 _jumpDisputeKitID
) internal onlyInitializing {
- governor = _governor;
+ owner = _owner;
core = _core;
wNative = _wNative;
+ jumpDisputeKitID = _jumpDisputeKitID;
}
// ************************ //
// * Governance * //
// ************************ //
- /// @dev Allows the governor to call anything on behalf of the contract.
+ /// @notice Allows the owner to call anything on behalf of the contract.
/// @param _destination The destination of the call.
/// @param _amount The value sent with the call.
/// @param _data The data sent with the call.
- function executeGovernorProposal(
- address _destination,
- uint256 _amount,
- bytes memory _data
- ) external onlyByGovernor {
+ function executeOwnerProposal(address _destination, uint256 _amount, bytes memory _data) external onlyByOwner {
(bool success, ) = _destination.call{value: _amount}(_data);
- require(success, "Unsuccessful call");
+ if (!success) revert UnsuccessfulCall();
}
- /// @dev Changes the `governor` storage variable.
- /// @param _governor The new value for the `governor` storage variable.
- function changeGovernor(address payable _governor) external onlyByGovernor {
- governor = _governor;
+ /// @notice Changes the `owner` storage variable.
+ /// @param _owner The new value for the `owner` storage variable.
+ function changeOwner(address payable _owner) external onlyByOwner {
+ owner = _owner;
}
- /// @dev Changes the `core` storage variable.
+ /// @notice Changes the `core` storage variable.
/// @param _core The new value for the `core` storage variable.
- function changeCore(address _core) external onlyByGovernor {
+ function changeCore(address _core) external onlyByOwner {
core = KlerosCore(_core);
}
+ /// @notice Changes the dispute kit ID used for the jump.
+ /// @param _jumpDisputeKitID The new value for the `jumpDisputeKitID` storage variable.
+ function changeJumpDisputeKitID(uint256 _jumpDisputeKitID) external onlyByOwner {
+ jumpDisputeKitID = _jumpDisputeKitID;
+ }
+
// ************************************* //
// * State Modifiers * //
// ************************************* //
- /// @dev Creates a local dispute and maps it to the dispute ID in the Core contract.
- /// Note: Access restricted to Kleros Core only.
- /// @param _coreDisputeID The ID of the dispute in Kleros Core.
- /// @param _numberOfChoices Number of choices of the dispute
- /// @param _extraData Additional info about the dispute, for possible use in future dispute kits.
- /// @param _nbVotes Number of votes for this dispute.
+ /// @inheritdoc IDisputeKit
function createDispute(
uint256 _coreDisputeID,
+ uint256 _coreRoundID,
uint256 _numberOfChoices,
bytes calldata _extraData,
- uint256 _nbVotes
- ) external override onlyByCore {
- uint256 localDisputeID = disputes.length;
- Dispute storage dispute = disputes.push();
+ uint256 /*_nbVotes*/
+ ) public virtual override onlyByCore {
+ uint256 localDisputeID;
+ Dispute storage dispute;
+ Active storage active = coreDisputeIDToActive[_coreDisputeID];
+ if (active.dispute) {
+ // The dispute has already been created in this DK in a previous round. E.g. if DK1 jumps to DK2 and then back to DK1.
+ localDisputeID = coreDisputeIDToLocal[_coreDisputeID];
+ dispute = disputes[localDisputeID];
+ } else {
+ // The dispute has not been created in this DK yet.
+ localDisputeID = disputes.length;
+ dispute = disputes.push();
+ coreDisputeIDToLocal[_coreDisputeID] = localDisputeID;
+ }
+
+ active.dispute = true;
+ active.currentRound = true;
dispute.numberOfChoices = _numberOfChoices;
dispute.extraData = _extraData;
- dispute.jumped = false; // Possibly true if this DK has jumped in a previous round.
- // New round in the Core should be created before the dispute creation in DK.
- dispute.coreRoundIDToLocal[core.getNumberOfRounds(_coreDisputeID) - 1] = dispute.rounds.length;
+ // KlerosCore.Round must have been already created.
+ dispute.coreRoundIDToLocal[_coreRoundID] = dispute.rounds.length;
+ dispute.rounds.push().tied = true;
- Round storage round = dispute.rounds.push();
- round.nbVotes = _nbVotes;
- round.tied = true;
-
- coreDisputeIDToLocal[_coreDisputeID] = localDisputeID;
- coreDisputeIDToActive[_coreDisputeID] = true;
emit DisputeCreation(_coreDisputeID, _numberOfChoices, _extraData);
}
- /// @dev Draws the juror from the sortition tree. The drawn address is picked up by Kleros Core.
- /// Note: Access restricted to Kleros Core only.
- /// @param _coreDisputeID The ID of the dispute in Kleros Core.
- /// @param _nonce Nonce of the drawing iteration.
- /// @return drawnAddress The drawn address.
+ /// @inheritdoc IDisputeKit
function draw(
uint256 _coreDisputeID,
uint256 _nonce
- ) external override onlyByCore notJumped(_coreDisputeID) returns (address drawnAddress) {
+ ) external override onlyByCore isActive(_coreDisputeID) returns (address drawnAddress, uint96 fromSubcourtID) {
uint256 localDisputeID = coreDisputeIDToLocal[_coreDisputeID];
Dispute storage dispute = disputes[localDisputeID];
uint256 localRoundID = dispute.rounds.length - 1;
@@ -236,26 +243,26 @@ abstract contract DisputeKitClassicBase is IDisputeKit, Initializable, UUPSProxi
ISortitionModule sortitionModule = core.sortitionModule();
(uint96 courtID, , , , ) = core.disputes(_coreDisputeID);
- bytes32 key = bytes32(uint256(courtID)); // Get the ID of the tree.
-
- drawnAddress = sortitionModule.draw(key, _coreDisputeID, _nonce);
+ (drawnAddress, fromSubcourtID) = sortitionModule.draw(courtID, _coreDisputeID, _nonce);
if (drawnAddress == address(0)) {
// Sortition can return 0 address if no one has staked yet.
- return drawnAddress;
+ return (drawnAddress, fromSubcourtID);
}
if (_postDrawCheck(round, _coreDisputeID, drawnAddress)) {
- round.votes.push(Vote({account: drawnAddress, commit: bytes32(0), choice: 0, voted: false}));
- alreadyDrawn[localDisputeID][localRoundID][drawnAddress] = true;
+ Vote storage vote = round.votes.push();
+ vote.account = drawnAddress;
+ round.alreadyDrawn[drawnAddress] = true;
} else {
drawnAddress = address(0);
}
}
- /// @dev Sets the caller's commit for the specified votes. It can be called multiple times during the
- /// commit period, each call overrides the commits of the previous one.
- /// `O(n)` where
- /// `n` is the number of votes.
+ /// @notice Sets the caller's commit for the specified votes.
+ ///
+ /// @dev It can be called multiple times during the commit period, each call overrides the commits of the previous one.
+ /// `O(n)` where `n` is the number of votes.
+ ///
/// @param _coreDisputeID The ID of the dispute in Kleros Core.
/// @param _voteIDs The IDs of the votes.
/// @param _commit The commitment hash.
@@ -267,25 +274,30 @@ abstract contract DisputeKitClassicBase is IDisputeKit, Initializable, UUPSProxi
uint256 _coreDisputeID,
uint256[] calldata _voteIDs,
bytes32 _commit
- ) internal notJumped(_coreDisputeID) {
+ ) internal isActive(_coreDisputeID) {
(, , KlerosCore.Period period, , ) = core.disputes(_coreDisputeID);
- require(period == KlerosCoreBase.Period.commit, "The dispute should be in Commit period.");
- require(_commit != bytes32(0), "Empty commit.");
- require(coreDisputeIDToActive[_coreDisputeID], "Not active for core dispute ID");
+ if (period != KlerosCore.Period.commit) revert NotCommitPeriod();
+ if (_commit == bytes32(0)) revert EmptyCommit();
Dispute storage dispute = disputes[coreDisputeIDToLocal[_coreDisputeID]];
Round storage round = dispute.rounds[dispute.rounds.length - 1];
+ // Introduce a counter so we don't count a re-commited votes.
+ uint256 commitCount;
for (uint256 i = 0; i < _voteIDs.length; i++) {
- require(round.votes[_voteIDs[i]].account == msg.sender, "The caller has to own the vote.");
+ if (round.votes[_voteIDs[i]].account != msg.sender) revert JurorHasToOwnTheVote();
+ if (round.votes[_voteIDs[i]].commit == bytes32(0)) {
+ commitCount++;
+ }
round.votes[_voteIDs[i]].commit = _commit;
}
- round.totalCommitted += _voteIDs.length;
+ round.totalCommitted += commitCount;
emit CommitCast(_coreDisputeID, msg.sender, _voteIDs, _commit);
}
- /// @dev Sets the caller's choices for the specified votes.
- /// `O(n)` where
- /// `n` is the number of votes.
+ /// @notice Sets the caller's choices for the specified votes.
+ ///
+ /// @dev `O(n)` where `n` is the number of votes.
+ ///
/// @param _coreDisputeID The ID of the dispute in Kleros Core.
/// @param _voteIDs The IDs of the votes.
/// @param _choice The choice.
@@ -308,29 +320,28 @@ abstract contract DisputeKitClassicBase is IDisputeKit, Initializable, UUPSProxi
uint256 _salt,
string memory _justification,
address _juror
- ) internal notJumped(_coreDisputeID) {
+ ) internal isActive(_coreDisputeID) {
(, , KlerosCore.Period period, , ) = core.disputes(_coreDisputeID);
- require(period == KlerosCoreBase.Period.vote, "The dispute should be in Vote period.");
- require(_voteIDs.length > 0, "No voteID provided");
- require(coreDisputeIDToActive[_coreDisputeID], "Not active for core dispute ID");
+ if (period != KlerosCore.Period.vote) revert NotVotePeriod();
+ if (_voteIDs.length == 0) revert EmptyVoteIDs();
- Dispute storage dispute = disputes[coreDisputeIDToLocal[_coreDisputeID]];
- require(_choice <= dispute.numberOfChoices, "Choice out of bounds");
+ uint256 localDisputeID = coreDisputeIDToLocal[_coreDisputeID];
+ Dispute storage dispute = disputes[localDisputeID];
+ if (_choice > dispute.numberOfChoices) revert ChoiceOutOfBounds();
- Round storage round = dispute.rounds[dispute.rounds.length - 1];
+ uint256 localRoundID = dispute.rounds.length - 1;
+ Round storage round = dispute.rounds[localRoundID];
{
(uint96 courtID, , , , ) = core.disputes(_coreDisputeID);
- (, bool hiddenVotes, , , , , ) = core.courts(courtID);
- bytes32 voteHash = hashVote(_choice, _salt, _justification);
+ (, bool hiddenVotes, , , , ) = core.courts(courtID);
+ if (hiddenVotes) {
+ _verifyHiddenVoteCommitments(localDisputeID, localRoundID, _voteIDs, _choice, _justification, _salt);
+ }
// Save the votes.
for (uint256 i = 0; i < _voteIDs.length; i++) {
- require(round.votes[_voteIDs[i]].account == _juror, "The juror has to own the vote.");
- require(
- !hiddenVotes || round.votes[_voteIDs[i]].commit == voteHash,
- "The vote hash must match the commitment in courts with hidden votes."
- );
- require(!round.votes[_voteIDs[i]].voted, "Vote already cast.");
+ if (round.votes[_voteIDs[i]].account != _juror) revert JurorHasToOwnTheVote();
+ if (round.votes[_voteIDs[i]].voted) revert VoteAlreadyCast();
round.votes[_voteIDs[i]].choice = _choice;
round.votes[_voteIDs[i]].voted = true;
}
@@ -355,35 +366,35 @@ abstract contract DisputeKitClassicBase is IDisputeKit, Initializable, UUPSProxi
emit VoteCast(_coreDisputeID, _juror, _voteIDs, _choice, _justification);
}
- /// @dev Manages contributions, and appeals a dispute if at least two choices are fully funded.
+ /// @notice Manages contributions, and appeals a dispute if at least two choices are fully funded.
/// Note that the surplus deposit will be reimbursed.
/// @param _coreDisputeID Index of the dispute in Kleros Core.
/// @param _choice A choice that receives funding.
- function fundAppeal(uint256 _coreDisputeID, uint256 _choice) external payable notJumped(_coreDisputeID) {
+ function fundAppeal(uint256 _coreDisputeID, uint256 _choice) external payable isActive(_coreDisputeID) {
Dispute storage dispute = disputes[coreDisputeIDToLocal[_coreDisputeID]];
- require(_choice <= dispute.numberOfChoices, "There is no such ruling to fund.");
- require(coreDisputeIDToActive[_coreDisputeID], "Not active for core dispute ID");
+ if (_choice > dispute.numberOfChoices) revert ChoiceOutOfBounds();
(uint256 appealPeriodStart, uint256 appealPeriodEnd) = core.appealPeriod(_coreDisputeID);
- require(block.timestamp >= appealPeriodStart && block.timestamp < appealPeriodEnd, "Appeal period is over.");
+ if (block.timestamp < appealPeriodStart || block.timestamp >= appealPeriodEnd) revert NotAppealPeriod();
uint256 multiplier;
(uint256 ruling, , ) = this.currentRuling(_coreDisputeID);
if (ruling == _choice) {
multiplier = WINNER_STAKE_MULTIPLIER;
} else {
- require(
- block.timestamp - appealPeriodStart <
- ((appealPeriodEnd - appealPeriodStart) * LOSER_APPEAL_PERIOD_MULTIPLIER) / ONE_BASIS_POINT,
- "Appeal period is over for loser"
- );
+ if (
+ block.timestamp - appealPeriodStart >=
+ ((appealPeriodEnd - appealPeriodStart) * LOSER_APPEAL_PERIOD_MULTIPLIER) / ONE_BASIS_POINT
+ ) {
+ revert NotAppealPeriodForLoser();
+ }
multiplier = LOSER_STAKE_MULTIPLIER;
}
Round storage round = dispute.rounds[dispute.rounds.length - 1];
uint256 coreRoundID = core.getNumberOfRounds(_coreDisputeID) - 1;
- require(!round.hasPaid[_choice], "Appeal fee is already paid.");
+ if (round.hasPaid[_choice]) revert AppealFeeIsAlreadyPaid();
uint256 appealCost = core.appealCost(_coreDisputeID);
uint256 totalCost = appealCost + (appealCost * multiplier) / ONE_BASIS_POINT;
@@ -411,13 +422,12 @@ abstract contract DisputeKitClassicBase is IDisputeKit, Initializable, UUPSProxi
if (core.isDisputeKitJumping(_coreDisputeID)) {
// Don't create a new round in case of a jump, and remove local dispute from the flow.
- dispute.jumped = true;
+ coreDisputeIDToActive[_coreDisputeID].currentRound = false;
} else {
// Don't subtract 1 from length since both round arrays haven't been updated yet.
dispute.coreRoundIDToLocal[coreRoundID + 1] = dispute.rounds.length;
Round storage newRound = dispute.rounds.push();
- newRound.nbVotes = core.getNumberOfVotes(_coreDisputeID);
newRound.tied = true;
}
core.appeal{value: appealCost}(_coreDisputeID, dispute.numberOfChoices, dispute.extraData);
@@ -426,50 +436,52 @@ abstract contract DisputeKitClassicBase is IDisputeKit, Initializable, UUPSProxi
if (msg.value > contribution) payable(msg.sender).safeSend(msg.value - contribution, wNative);
}
- /// @dev Allows those contributors who attempted to fund an appeal round to withdraw any reimbursable fees or rewards after the dispute gets resolved.
- /// Note that withdrawals are not possible if the core contract is paused.
+ /// @notice Allows those contributors who attempted to fund an appeal round to withdraw any reimbursable fees or rewards after the dispute gets resolved.
+ /// @dev Withdrawals are not possible if the core contract is paused.
+ /// @dev It can be called after the dispute has jumped to another dispute kit.
/// @param _coreDisputeID Index of the dispute in Kleros Core contract.
/// @param _beneficiary The address whose rewards to withdraw.
- /// @param _coreRoundID The round in the Kleros Core contract the caller wants to withdraw from.
/// @param _choice The ruling option that the caller wants to withdraw from.
/// @return amount The withdrawn amount.
function withdrawFeesAndRewards(
uint256 _coreDisputeID,
address payable _beneficiary,
- uint256 _coreRoundID,
uint256 _choice
) external returns (uint256 amount) {
(, , , bool isRuled, ) = core.disputes(_coreDisputeID);
- require(isRuled, "Dispute should be resolved.");
- require(!core.paused(), "Core is paused");
- require(coreDisputeIDToActive[_coreDisputeID], "Not active for core dispute ID");
+ if (!isRuled) revert DisputeNotResolved();
+ if (core.paused()) revert CoreIsPaused();
+ if (!coreDisputeIDToActive[_coreDisputeID].dispute) revert DisputeUnknownInThisDisputeKit();
Dispute storage dispute = disputes[coreDisputeIDToLocal[_coreDisputeID]];
- Round storage round = dispute.rounds[dispute.coreRoundIDToLocal[_coreRoundID]];
(uint256 finalRuling, , ) = core.currentRuling(_coreDisputeID);
- if (!round.hasPaid[_choice]) {
- // Allow to reimburse if funding was unsuccessful for this ruling option.
- amount = round.contributions[_beneficiary][_choice];
- } else {
- // Funding was successful for this ruling option.
- if (_choice == finalRuling) {
- // This ruling option is the ultimate winner.
- amount = round.paidFees[_choice] > 0
- ? (round.contributions[_beneficiary][_choice] * round.feeRewards) / round.paidFees[_choice]
- : 0;
- } else if (!round.hasPaid[finalRuling]) {
- // The ultimate winner was not funded in this round. In this case funded ruling option(s) are reimbursed.
- amount =
- (round.contributions[_beneficiary][_choice] * round.feeRewards) /
- (round.paidFees[round.fundedChoices[0]] + round.paidFees[round.fundedChoices[1]]);
+ for (uint256 i = 0; i < dispute.rounds.length; i++) {
+ Round storage round = dispute.rounds[i];
+
+ if (!round.hasPaid[_choice]) {
+ // Allow to reimburse if funding was unsuccessful for this ruling option.
+ amount += round.contributions[_beneficiary][_choice];
+ } else {
+ // Funding was successful for this ruling option.
+ if (_choice == finalRuling) {
+ // This ruling option is the ultimate winner.
+ amount += round.paidFees[_choice] > 0
+ ? (round.contributions[_beneficiary][_choice] * round.feeRewards) / round.paidFees[_choice]
+ : 0;
+ } else if (!round.hasPaid[finalRuling]) {
+ // The ultimate winner was not funded in this round. In this case funded ruling option(s) are reimbursed.
+ amount +=
+ (round.contributions[_beneficiary][_choice] * round.feeRewards) /
+ (round.paidFees[round.fundedChoices[0]] + round.paidFees[round.fundedChoices[1]]);
+ }
}
+ round.contributions[_beneficiary][_choice] = 0;
}
- round.contributions[_beneficiary][_choice] = 0;
if (amount != 0) {
_beneficiary.safeSend(amount, wNative);
- emit Withdrawal(_coreDisputeID, _coreRoundID, _choice, _beneficiary, amount);
+ emit Withdrawal(_coreDisputeID, _choice, _beneficiary, amount);
}
}
@@ -477,33 +489,29 @@ abstract contract DisputeKitClassicBase is IDisputeKit, Initializable, UUPSProxi
// * Public Views * //
// ************************************* //
- /**
- * @dev Computes the hash of a vote using ABI encoding
- * @dev The unused parameters may be used by overriding contracts.
- * @param _choice The choice being voted for
- * @param _justification The justification for the vote
- * @param _salt A random salt for commitment
- * @return bytes32 The hash of the encoded vote parameters
- */
+ /// @notice Computes the hash of a vote using ABI encoding
+ /// @dev The unused parameters may be used by overriding contracts.
+ /// @param _choice The choice being voted for
+ /// @param _salt A random salt for commitment
+ /// @return bytes32 The hash of the encoded vote parameters
function hashVote(
uint256 _choice,
uint256 _salt,
- string memory _justification
- ) public pure virtual returns (bytes32) {
+ string memory /*_justification*/
+ ) public view virtual returns (bytes32) {
return keccak256(abi.encodePacked(_choice, _salt));
}
+ /// @notice Returns the rulings that were fully funded in the latest appeal round.
+ /// @param _coreDisputeID The ID of the dispute in Kleros Core.
+ /// @return fundedChoices Fully funded rulings.
function getFundedChoices(uint256 _coreDisputeID) public view returns (uint256[] memory fundedChoices) {
Dispute storage dispute = disputes[coreDisputeIDToLocal[_coreDisputeID]];
Round storage lastRound = dispute.rounds[dispute.rounds.length - 1];
return lastRound.fundedChoices;
}
- /// @dev Gets the current ruling of a specified dispute.
- /// @param _coreDisputeID The ID of the dispute in Kleros Core.
- /// @return ruling The current ruling.
- /// @return tied Whether it's a tie or not.
- /// @return overridden Whether the ruling was overridden by appeal funding or not.
+ /// @inheritdoc IDisputeKit
function currentRuling(
uint256 _coreDisputeID
) external view override returns (uint256 ruling, bool tied, bool overridden) {
@@ -513,7 +521,7 @@ abstract contract DisputeKitClassicBase is IDisputeKit, Initializable, UUPSProxi
ruling = tied ? 0 : round.winningChoice;
(, , KlerosCore.Period period, , ) = core.disputes(_coreDisputeID);
// Override the final ruling if only one side funded the appeals.
- if (period == KlerosCoreBase.Period.execution) {
+ if (period == KlerosCore.Period.execution) {
uint256[] memory fundedChoices = getFundedChoices(_coreDisputeID);
if (fundedChoices.length == 1) {
ruling = fundedChoices[0];
@@ -523,18 +531,34 @@ abstract contract DisputeKitClassicBase is IDisputeKit, Initializable, UUPSProxi
}
}
- /// @dev Gets the degree of coherence of a particular voter. This function is called by Kleros Core in order to determine the amount of the reward.
- /// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.
- /// @param _coreRoundID The ID of the round in Kleros Core, not in the Dispute Kit.
- /// @param _voteID The ID of the vote.
- /// @return The degree of coherence in basis points.
- function getDegreeOfCoherence(
+ /// @inheritdoc IDisputeKit
+ function getDegreeOfCoherenceReward(
+ uint256 _coreDisputeID,
+ uint256 _coreRoundID,
+ uint256 _voteID,
+ uint256 /* _feePerJuror */,
+ uint256 /* _pnkAtStakePerJuror */
+ ) external view override returns (uint256 pnkCoherence, uint256 feeCoherence) {
+ uint256 coherence = _getDegreeOfCoherence(_coreDisputeID, _coreRoundID, _voteID);
+ return (coherence, coherence);
+ }
+
+ /// @inheritdoc IDisputeKit
+ function getDegreeOfCoherencePenalty(
uint256 _coreDisputeID,
uint256 _coreRoundID,
uint256 _voteID,
uint256 /* _feePerJuror */,
uint256 /* _pnkAtStakePerJuror */
- ) external view override returns (uint256) {
+ ) external view override returns (uint256 pnkCoherence) {
+ return _getDegreeOfCoherence(_coreDisputeID, _coreRoundID, _voteID);
+ }
+
+ function _getDegreeOfCoherence(
+ uint256 _coreDisputeID,
+ uint256 _coreRoundID,
+ uint256 _voteID
+ ) internal view returns (uint256 coherence) {
// In this contract this degree can be either 0 or 1, but in other dispute kits this value can be something in between.
Dispute storage dispute = disputes[coreDisputeIDToLocal[_coreDisputeID]];
Vote storage vote = dispute.rounds[dispute.coreRoundIDToLocal[_coreRoundID]].votes[_voteID];
@@ -547,10 +571,7 @@ abstract contract DisputeKitClassicBase is IDisputeKit, Initializable, UUPSProxi
}
}
- /// @dev Gets the number of jurors who are eligible to a reward in this round.
- /// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.
- /// @param _coreRoundID The ID of the round in Kleros Core, not in the Dispute Kit.
- /// @return The number of coherent jurors.
+ /// @inheritdoc IDisputeKit
function getCoherentCount(uint256 _coreDisputeID, uint256 _coreRoundID) external view override returns (uint256) {
Dispute storage dispute = disputes[coreDisputeIDToLocal[_coreDisputeID]];
Round storage currentRound = dispute.rounds[dispute.coreRoundIDToLocal[_coreRoundID]];
@@ -565,34 +586,26 @@ abstract contract DisputeKitClassicBase is IDisputeKit, Initializable, UUPSProxi
}
}
- /// @dev Returns true if all of the jurors have cast their commits for the last round.
- /// @param _coreDisputeID The ID of the dispute in Kleros Core.
- /// @return Whether all of the jurors have cast their commits for the last round.
+ /// @inheritdoc IDisputeKit
function areCommitsAllCast(uint256 _coreDisputeID) external view override returns (bool) {
Dispute storage dispute = disputes[coreDisputeIDToLocal[_coreDisputeID]];
Round storage round = dispute.rounds[dispute.rounds.length - 1];
return round.totalCommitted == round.votes.length;
}
- /// @dev Returns true if all of the jurors have cast their votes for the last round.
- /// Note that this function is to be called directly by the core contract and is not for off-chain usage.
- /// @param _coreDisputeID The ID of the dispute in Kleros Core.
- /// @return Whether all of the jurors have cast their votes for the last round.
+ /// @inheritdoc IDisputeKit
function areVotesAllCast(uint256 _coreDisputeID) external view override returns (bool) {
Dispute storage dispute = disputes[coreDisputeIDToLocal[_coreDisputeID]];
Round storage round = dispute.rounds[dispute.rounds.length - 1];
(uint96 courtID, , , , ) = core.disputes(_coreDisputeID);
- (, bool hiddenVotes, , , , , ) = core.courts(courtID);
+ (, bool hiddenVotes, , , , ) = core.courts(courtID);
uint256 expectedTotalVoted = hiddenVotes ? round.totalCommitted : round.votes.length;
return round.totalVoted == expectedTotalVoted;
}
- /// @dev Returns true if the appeal funding is finished prematurely (e.g. when losing side didn't fund).
- /// Note that this function is to be called directly by the core contract and is not for off-chain usage.
- /// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.
- /// @return Whether the appeal funding is finished.
+ /// @inheritdoc IDisputeKit
function isAppealFunded(uint256 _coreDisputeID) external view override returns (bool) {
(uint256 appealPeriodStart, uint256 appealPeriodEnd) = core.appealPeriod(_coreDisputeID);
@@ -603,11 +616,26 @@ abstract contract DisputeKitClassicBase is IDisputeKit, Initializable, UUPSProxi
((appealPeriodEnd - appealPeriodStart) * LOSER_APPEAL_PERIOD_MULTIPLIER) / ONE_BASIS_POINT);
}
- /// @dev Returns true if the specified voter was active in this round.
- /// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.
- /// @param _coreRoundID The ID of the round in Kleros Core, not in the Dispute Kit.
- /// @param _voteID The ID of the voter.
- /// @return Whether the voter was active or not.
+ /// @inheritdoc IDisputeKit
+ function earlyCourtJump(uint256 /* _coreDisputeID */) external pure override returns (bool) {
+ return false;
+ }
+
+ /// @inheritdoc IDisputeKit
+ function getNbVotesAfterAppeal(
+ IDisputeKit /* _previousDisputeKit */,
+ uint256 _currentNbVotes
+ ) external pure override returns (uint256) {
+ return (_currentNbVotes * 2) + 1;
+ }
+
+ /// @inheritdoc IDisputeKit
+ function getJumpDisputeKitID() external view override returns (uint256) {
+ // Fall back to classic DK in case the jump ID is not defined.
+ return jumpDisputeKitID == 0 ? DISPUTE_KIT_CLASSIC : jumpDisputeKitID;
+ }
+
+ /// @inheritdoc IDisputeKit
function isVoteActive(
uint256 _coreDisputeID,
uint256 _coreRoundID,
@@ -618,6 +646,7 @@ abstract contract DisputeKitClassicBase is IDisputeKit, Initializable, UUPSProxi
return vote.voted;
}
+ /// @inheritdoc IDisputeKit
function getRoundInfo(
uint256 _coreDisputeID,
uint256 _coreRoundID,
@@ -630,7 +659,7 @@ abstract contract DisputeKitClassicBase is IDisputeKit, Initializable, UUPSProxi
uint256 winningChoice,
bool tied,
uint256 totalVoted,
- uint256 totalCommited,
+ uint256 totalCommitted,
uint256 nbVoters,
uint256 choiceCount
)
@@ -647,14 +676,14 @@ abstract contract DisputeKitClassicBase is IDisputeKit, Initializable, UUPSProxi
);
}
- /// @dev Returns the number of rounds in a dispute.
+ /// @notice Returns the number of rounds in a dispute.
/// @param _localDisputeID The ID of the dispute in the Dispute Kit.
/// @return The number of rounds in the dispute.
function getNumberOfRounds(uint256 _localDisputeID) external view returns (uint256) {
return disputes[_localDisputeID].rounds.length;
}
- /// @dev Returns the local dispute ID and round ID for a given core dispute ID and core round ID.
+ /// @notice Returns the local dispute ID and round ID for a given core dispute ID and core round ID.
/// @param _coreDisputeID The ID of the dispute in Kleros Core.
/// @param _coreRoundID The ID of the round in Kleros Core.
/// @return localDisputeID The ID of the dispute in the Dispute Kit.
@@ -667,12 +696,7 @@ abstract contract DisputeKitClassicBase is IDisputeKit, Initializable, UUPSProxi
localRoundID = disputes[localDisputeID].coreRoundIDToLocal[_coreRoundID];
}
- /// @dev Returns the vote information for a given vote ID.
- /// @param _coreDisputeID The ID of the dispute in Kleros Core.
- /// @param _coreRoundID The ID of the round in Kleros Core.
- /// @param _voteID The ID of the vote.
- /// @return account The address of the juror who cast the vote.
- /// @return commit The commit of the vote.
+ /// @inheritdoc IDisputeKit
function getVoteInfo(
uint256 _coreDisputeID,
uint256 _coreRoundID,
@@ -687,27 +711,73 @@ abstract contract DisputeKitClassicBase is IDisputeKit, Initializable, UUPSProxi
// * Internal * //
// ************************************* //
- /// @dev Checks that the chosen address satisfies certain conditions for being drawn.
- /// Note that we don't check the minStake requirement here because of the implicit staking in parent courts.
+ /// @notice Verifies that revealed choice and justification match the hidden vote commitments.
+ /// @param _localDisputeID The ID of the dispute in the Dispute Kit.
+ /// @param _localRoundID The ID of the round in the Dispute Kit.
+ /// @param _voteIDs The IDs of the votes.
+ /// @param _choice The choice.
+ /// @param _justification The justification.
+ /// @param _salt The salt.
+ function _verifyHiddenVoteCommitments(
+ uint256 _localDisputeID,
+ uint256 _localRoundID,
+ uint256[] calldata _voteIDs,
+ uint256 _choice,
+ string memory _justification,
+ uint256 _salt
+ ) internal view virtual {
+ bytes32 actualVoteHash = hashVote(_choice, _salt, _justification);
+ for (uint256 i = 0; i < _voteIDs.length; i++) {
+ if (disputes[_localDisputeID].rounds[_localRoundID].votes[_voteIDs[i]].commit != actualVoteHash)
+ revert ChoiceCommitmentMismatch();
+ }
+ }
+
+ /// @notice Checks that the chosen address satisfies certain conditions for being drawn.
+ ///
+ /// @dev No need to check the minStake requirement here because of the implicit staking in parent courts.
/// minStake is checked directly during staking process however it's possible for the juror to get drawn
/// while having < minStake if it is later increased by governance.
/// This issue is expected and harmless.
- /// @param _round The round in which the juror is being drawn.
+ ///
/// @param _coreDisputeID ID of the dispute in the core contract.
/// @param _juror Chosen address.
/// @return result Whether the address passes the check or not.
function _postDrawCheck(
- Round storage _round,
+ Round storage /*_round*/,
uint256 _coreDisputeID,
address _juror
) internal view virtual returns (bool result) {
if (singleDrawPerJuror) {
uint256 localDisputeID = coreDisputeIDToLocal[_coreDisputeID];
Dispute storage dispute = disputes[localDisputeID];
- uint256 localRoundID = dispute.rounds.length - 1;
- result = !alreadyDrawn[localDisputeID][localRoundID][_juror];
+ Round storage round = dispute.rounds[dispute.rounds.length - 1];
+ result = !round.alreadyDrawn[_juror];
} else {
result = true;
}
}
+
+ // ************************************* //
+ // * Errors * //
+ // ************************************* //
+
+ error OwnerOnly();
+ error KlerosCoreOnly();
+ error DisputeJumpedToAnotherDisputeKit();
+ error DisputeUnknownInThisDisputeKit();
+ error UnsuccessfulCall();
+ error NotCommitPeriod();
+ error EmptyCommit();
+ error JurorHasToOwnTheVote();
+ error NotVotePeriod();
+ error EmptyVoteIDs();
+ error ChoiceOutOfBounds();
+ error ChoiceCommitmentMismatch();
+ error VoteAlreadyCast();
+ error NotAppealPeriod();
+ error NotAppealPeriodForLoser();
+ error AppealFeeIsAlreadyPaid();
+ error DisputeNotResolved();
+ error CoreIsPaused();
}
diff --git a/contracts/src/arbitration/dispute-kits/DisputeKitGated.sol b/contracts/src/arbitration/dispute-kits/DisputeKitGated.sol
index 037f79585..2b5131d81 100644
--- a/contracts/src/arbitration/dispute-kits/DisputeKitGated.sol
+++ b/contracts/src/arbitration/dispute-kits/DisputeKitGated.sol
@@ -5,7 +5,7 @@ pragma solidity ^0.8.24;
import {DisputeKitClassicBase, KlerosCore} from "./DisputeKitClassicBase.sol";
interface IBalanceHolder {
- /// @dev Returns the number of tokens in `owner` account.
+ /// @notice Returns the number of tokens in `owner` account.
/// @dev Compatible with ERC-20 and ERC-721.
/// @param owner The address of the owner.
/// @return balance The number of tokens in `owner` account.
@@ -13,7 +13,7 @@ interface IBalanceHolder {
}
interface IBalanceHolderERC1155 {
- /// @dev Returns the balance of an ERC-1155 token.
+ /// @notice Returns the balance of an ERC-1155 token.
/// @param account The address of the token holder
/// @param id ID of the token
/// @return The token balance
@@ -21,13 +21,21 @@ interface IBalanceHolderERC1155 {
}
/// @title DisputeKitGated
-/// Dispute kit implementation adapted from DisputeKitClassic
+/// @notice Dispute kit implementation adapted from DisputeKitClassic
/// - a drawing system: proportional to staked PNK with a non-zero balance of `tokenGate` where `tokenGate` is an ERC20, ERC721 or ERC1155
/// - a vote aggregation system: plurality,
/// - an incentive system: equal split between coherent votes,
/// - an appeal system: fund 2 choices only, vote on any choice.
contract DisputeKitGated is DisputeKitClassicBase {
- string public constant override version = "0.12.0";
+ string public constant override version = "2.0.0";
+
+ address private constant NO_TOKEN_GATE = address(0);
+
+ // ************************************* //
+ // * Storage * //
+ // ************************************* //
+
+ mapping(address token => bool supported) public supportedTokens; // Whether the token is supported or not.
// ************************************* //
// * Constructor * //
@@ -38,16 +46,19 @@ contract DisputeKitGated is DisputeKitClassicBase {
_disableInitializers();
}
- /// @dev Initializer.
- /// @param _governor The governor's address.
+ /// @notice Initializer.
+ /// @param _owner The owner's address.
/// @param _core The KlerosCore arbitrator.
/// @param _wNative The wrapped native token address, typically wETH.
- function initialize(address _governor, KlerosCore _core, address _wNative) external reinitializer(1) {
- __DisputeKitClassicBase_initialize(_governor, _core, _wNative);
- }
-
- function reinitialize(address _wNative) external reinitializer(9) {
- wNative = _wNative;
+ /// @param _jumpDisputeKitID The ID of the dispute kit to switch to after the court jump.
+ function initialize(
+ address _owner,
+ KlerosCore _core,
+ address _wNative,
+ uint256 _jumpDisputeKitID
+ ) external initializer {
+ __DisputeKitClassicBase_initialize(_owner, _core, _wNative, _jumpDisputeKitID);
+ supportedTokens[NO_TOKEN_GATE] = true; // Allows disputes without token gating
}
// ************************ //
@@ -55,28 +66,56 @@ contract DisputeKitGated is DisputeKitClassicBase {
// ************************ //
/// @dev Access Control to perform implementation upgrades (UUPS Proxiable)
- /// Only the governor can perform upgrades (`onlyByGovernor`)
- function _authorizeUpgrade(address) internal view override onlyByGovernor {
+ /// Only the owner can perform upgrades (`onlyByOwner`)
+ function _authorizeUpgrade(address) internal view override onlyByOwner {
// NOP
}
+ /// @notice Changes the supported tokens.
+ /// @param _tokens The tokens to support.
+ /// @param _supported Whether the tokens are supported or not.
+ function changeSupportedTokens(address[] memory _tokens, bool _supported) external onlyByOwner {
+ for (uint256 i = 0; i < _tokens.length; i++) {
+ supportedTokens[_tokens[i]] = _supported;
+ }
+ }
+
+ // ************************************* //
+ // * State Modifiers * //
+ // ************************************* //
+
+ /// @inheritdoc DisputeKitClassicBase
+ function createDispute(
+ uint256 _coreDisputeID,
+ uint256 _coreRoundID,
+ uint256 _numberOfChoices,
+ bytes calldata _extraData,
+ uint256 _nbVotes
+ ) public override {
+ (address tokenGate, , ) = _extraDataToTokenInfo(_extraData);
+ if (!supportedTokens[tokenGate]) revert TokenNotSupported(tokenGate);
+
+ // super.createDispute() ensures access control onlyByCore.
+ super.createDispute(_coreDisputeID, _coreRoundID, _numberOfChoices, _extraData, _nbVotes);
+ }
+
// ************************************* //
// * Internal * //
// ************************************* //
- /// @dev Extracts token gating information from the extra data.
+ /// @notice Extracts token gating information from the extra data.
/// @param _extraData The extra data bytes array with the following encoding:
- /// - bytes 0-31: uint96 courtID, not used here
- /// - bytes 32-63: uint256 minJurors, not used here
- /// - bytes 64-95: uint256 disputeKitID, not used here
- /// - bytes 96-127: uint256 packedTokenGateAndFlag (address tokenGate in bits 0-159, bool isERC1155 in bit 160)
- /// - bytes 128-159: uint256 tokenId
+ /// - bytes 0-31: uint96 courtID, not used here
+ /// - bytes 32-63: uint256 minJurors, not used here
+ /// - bytes 64-95: uint256 disputeKitID, not used here
+ /// - bytes 96-127: uint256 packedTokenGateAndFlag (address tokenGate in bits 0-159, bool isERC1155 in bit 160)
+ /// - bytes 128-159: uint256 tokenId
/// @return tokenGate The address of the token contract used for gating access.
/// @return isERC1155 True if the token is an ERC-1155, false for ERC-20/ERC-721.
/// @return tokenId The token ID for ERC-1155 tokens (ignored for ERC-20/ERC-721).
- function extraDataToTokenInfo(
+ function _extraDataToTokenInfo(
bytes memory _extraData
- ) public pure returns (address tokenGate, bool isERC1155, uint256 tokenId) {
+ ) internal pure returns (address tokenGate, bool isERC1155, uint256 tokenId) {
// Need at least 160 bytes to safely read the parameters
if (_extraData.length < 160) return (address(0), false, 0);
@@ -102,10 +141,10 @@ contract DisputeKitGated is DisputeKitClassicBase {
// Get the local dispute and extract token info from extraData
uint256 localDisputeID = coreDisputeIDToLocal[_coreDisputeID];
Dispute storage dispute = disputes[localDisputeID];
- (address tokenGate, bool isERC1155, uint256 tokenId) = extraDataToTokenInfo(dispute.extraData);
+ (address tokenGate, bool isERC1155, uint256 tokenId) = _extraDataToTokenInfo(dispute.extraData);
// If no token gate is specified, allow all jurors
- if (tokenGate == address(0)) return true;
+ if (tokenGate == NO_TOKEN_GATE) return true;
// Check juror's token balance
if (isERC1155) {
@@ -114,4 +153,10 @@ contract DisputeKitGated is DisputeKitClassicBase {
return IBalanceHolder(tokenGate).balanceOf(_juror) > 0;
}
}
+
+ // ************************************* //
+ // * Errors * //
+ // ************************************* //
+
+ error TokenNotSupported(address tokenGate);
}
diff --git a/contracts/src/arbitration/dispute-kits/DisputeKitGatedShutter.sol b/contracts/src/arbitration/dispute-kits/DisputeKitGatedShutter.sol
index 3ad37d56d..38b3a66e3 100644
--- a/contracts/src/arbitration/dispute-kits/DisputeKitGatedShutter.sol
+++ b/contracts/src/arbitration/dispute-kits/DisputeKitGatedShutter.sol
@@ -5,7 +5,7 @@ pragma solidity ^0.8.24;
import {DisputeKitClassicBase, KlerosCore} from "./DisputeKitClassicBase.sol";
interface IBalanceHolder {
- /// @dev Returns the number of tokens in `owner` account.
+ /// @notice Returns the number of tokens in `owner` account.
/// @dev Compatible with ERC-20 and ERC-721.
/// @param owner The address of the owner.
/// @return balance The number of tokens in `owner` account.
@@ -13,7 +13,7 @@ interface IBalanceHolder {
}
interface IBalanceHolderERC1155 {
- /// @dev Returns the balance of an ERC-1155 token.
+ /// @notice Returns the balance of an ERC-1155 token.
/// @param account The address of the token holder
/// @param id ID of the token
/// @return The token balance
@@ -21,14 +21,30 @@ interface IBalanceHolderERC1155 {
}
/// @title DisputeKitGatedShutter
-/// Added functionality: shielded voting.
+/// @notice Added functionality: shielded voting.
/// Dispute kit implementation adapted from DisputeKitClassic
/// - a drawing system: proportional to staked PNK with a non-zero balance of `tokenGate` where `tokenGate` is an ERC20, ERC721 or ERC1155
/// - a vote aggregation system: plurality,
/// - an incentive system: equal split between coherent votes,
/// - an appeal system: fund 2 choices only, vote on any choice.
contract DisputeKitGatedShutter is DisputeKitClassicBase {
- string public constant override version = "0.12.0";
+ string public constant override version = "2.0.0";
+
+ address private constant NO_TOKEN_GATE = address(0);
+
+ // ************************************* //
+ // * Storage * //
+ // ************************************* //
+
+ mapping(address token => bool supported) public supportedTokens; // Whether the token is supported or not.
+ mapping(uint256 localDisputeID => mapping(uint256 localRoundID => mapping(uint256 voteID => bytes32 justificationCommitment)))
+ public justificationCommitments;
+
+ // ************************************* //
+ // * Transient Storage * //
+ // ************************************* //
+
+ bool transient callerIsJuror;
// ************************************* //
// * Events * //
@@ -37,13 +53,15 @@ contract DisputeKitGatedShutter is DisputeKitClassicBase {
/// @dev Emitted when a vote is cast.
/// @param _coreDisputeID The identifier of the dispute in the Arbitrator contract.
/// @param _juror The address of the juror casting the vote commitment.
- /// @param _commit The commitment hash.
+ /// @param _choiceCommit The commitment hash without the justification.
+ /// @param _justificationCommit The commitment hash for the justification.
/// @param _identity The Shutter identity used for encryption.
/// @param _encryptedVote The Shutter encrypted vote.
event CommitCastShutter(
uint256 indexed _coreDisputeID,
address indexed _juror,
- bytes32 indexed _commit,
+ bytes32 indexed _choiceCommit,
+ bytes32 _justificationCommit,
bytes32 _identity,
bytes _encryptedVote
);
@@ -57,16 +75,19 @@ contract DisputeKitGatedShutter is DisputeKitClassicBase {
_disableInitializers();
}
- /// @dev Initializer.
- /// @param _governor The governor's address.
+ /// @notice Initializer.
+ /// @param _owner The owner's address.
/// @param _core The KlerosCore arbitrator.
/// @param _wNative The wrapped native token address, typically wETH.
- function initialize(address _governor, KlerosCore _core, address _wNative) external reinitializer(1) {
- __DisputeKitClassicBase_initialize(_governor, _core, _wNative);
- }
-
- function reinitialize(address _wNative) external reinitializer(9) {
- wNative = _wNative;
+ /// @param _jumpDisputeKitID The ID of the dispute kit to switch to after the court jump.
+ function initialize(
+ address _owner,
+ KlerosCore _core,
+ address _wNative,
+ uint256 _jumpDisputeKitID
+ ) external initializer {
+ __DisputeKitClassicBase_initialize(_owner, _core, _wNative, _jumpDisputeKitID);
+ supportedTokens[NO_TOKEN_GATE] = true; // Allows disputes without token gating
}
// ************************ //
@@ -74,35 +95,86 @@ contract DisputeKitGatedShutter is DisputeKitClassicBase {
// ************************ //
/// @dev Access Control to perform implementation upgrades (UUPS Proxiable)
- /// Only the governor can perform upgrades (`onlyByGovernor`)
- function _authorizeUpgrade(address) internal view override onlyByGovernor {
+ /// Only the owner can perform upgrades (`onlyByOwner`)
+ function _authorizeUpgrade(address) internal view override onlyByOwner {
// NOP
}
+ /// @notice Changes the supported tokens.
+ /// @param _tokens The tokens to support.
+ /// @param _supported Whether the tokens are supported or not.
+ function changeSupportedTokens(address[] memory _tokens, bool _supported) external onlyByOwner {
+ for (uint256 i = 0; i < _tokens.length; i++) {
+ supportedTokens[_tokens[i]] = _supported;
+ }
+ }
+
// ************************************* //
// * State Modifiers * //
// ************************************* //
- /// @dev Sets the caller's commit for the specified votes. It can be called multiple times during the
- /// commit period, each call overrides the commits of the previous one.
- /// `O(n)` where
- /// `n` is the number of votes.
+ /// @inheritdoc DisputeKitClassicBase
+ function createDispute(
+ uint256 _coreDisputeID,
+ uint256 _coreRoundID,
+ uint256 _numberOfChoices,
+ bytes calldata _extraData,
+ uint256 _nbVotes
+ ) public override {
+ (address tokenGate, , ) = _extraDataToTokenInfo(_extraData);
+ if (!supportedTokens[tokenGate]) revert TokenNotSupported(tokenGate);
+
+ // super.createDispute() ensures access control onlyByCore.
+ super.createDispute(_coreDisputeID, _coreRoundID, _numberOfChoices, _extraData, _nbVotes);
+ }
+
+ /// @notice Sets the caller's commit for the specified votes.
+ ///
+ /// @dev It can be called multiple times during the commit period, each call overrides the commits of the previous one.
+ /// `O(n)` where `n` is the number of votes.
+ ///
/// @param _coreDisputeID The ID of the dispute in Kleros Core.
/// @param _voteIDs The IDs of the votes.
- /// @param _commit The commitment hash including the justification.
+ /// @param _choiceCommit The commitment hash without the justification.
+ /// @param _justificationCommit The commitment hash for justification.
/// @param _identity The Shutter identity used for encryption.
/// @param _encryptedVote The Shutter encrypted vote.
function castCommitShutter(
uint256 _coreDisputeID,
uint256[] calldata _voteIDs,
- bytes32 _commit,
+ bytes32 _choiceCommit,
+ bytes32 _justificationCommit,
bytes32 _identity,
bytes calldata _encryptedVote
- ) external notJumped(_coreDisputeID) {
- _castCommit(_coreDisputeID, _voteIDs, _commit);
- emit CommitCastShutter(_coreDisputeID, msg.sender, _commit, _identity, _encryptedVote);
+ ) external {
+ if (_justificationCommit == bytes32(0)) revert EmptyJustificationCommit();
+
+ uint256 localDisputeID = coreDisputeIDToLocal[_coreDisputeID];
+ Dispute storage dispute = disputes[localDisputeID];
+ uint256 localRoundID = dispute.rounds.length - 1;
+ for (uint256 i = 0; i < _voteIDs.length; i++) {
+ justificationCommitments[localDisputeID][localRoundID][_voteIDs[i]] = _justificationCommit;
+ }
+
+ // `_castCommit()` ensures that the caller owns the vote and that dispute is active
+ _castCommit(_coreDisputeID, _voteIDs, _choiceCommit);
+ emit CommitCastShutter(
+ _coreDisputeID,
+ msg.sender,
+ _choiceCommit,
+ _justificationCommit,
+ _identity,
+ _encryptedVote
+ );
}
+ /// @notice Version of the `castVote` function designed specifically for Shutter.
+ /// @dev `O(n)` where `n` is the number of votes.
+ /// @param _coreDisputeID The ID of the dispute in Kleros Core.
+ /// @param _voteIDs The IDs of the votes.
+ /// @param _choice The choice.
+ /// @param _salt The salt for the commit if the votes were hidden.
+ /// @param _justification Justification of the choice.
function castVoteShutter(
uint256 _coreDisputeID,
uint256[] calldata _voteIDs,
@@ -113,41 +185,58 @@ contract DisputeKitGatedShutter is DisputeKitClassicBase {
Dispute storage dispute = disputes[coreDisputeIDToLocal[_coreDisputeID]];
address juror = dispute.rounds[dispute.rounds.length - 1].votes[_voteIDs[0]].account;
- // _castVote() ensures that all the _voteIDs do belong to `juror`
+ callerIsJuror = juror == msg.sender;
+
+ // `_castVote()` ensures that all the `_voteIDs` do belong to `juror`
_castVote(_coreDisputeID, _voteIDs, _choice, _salt, _justification, juror);
+
+ callerIsJuror = false;
}
// ************************************* //
// * Public Views * //
// ************************************* //
- /**
- * @dev Computes the hash of a vote using ABI encoding
- * @param _choice The choice being voted for
- * @param _justification The justification for the vote
- * @param _salt A random salt for commitment
- * @return bytes32 The hash of the encoded vote parameters
- */
- function hashVote(
- uint256 _choice,
- uint256 _salt,
- string memory _justification
- ) public pure override returns (bytes32) {
- bytes32 justificationHash = keccak256(bytes(_justification));
- return keccak256(abi.encode(_choice, _salt, justificationHash));
+ /// @notice Computes the hash of a justification using ABI encoding
+ /// @param _salt A random salt for commitment
+ /// @param _justification The justification for the vote
+ /// @return bytes32 The hash of the encoded justification
+ function hashJustification(uint256 _salt, string memory _justification) public pure returns (bytes32) {
+ return keccak256(abi.encode(_salt, keccak256(bytes(_justification))));
}
// ************************************* //
// * Internal * //
// ************************************* //
- /// @dev Extracts token gating information from the extra data.
+ /// @inheritdoc DisputeKitClassicBase
+ function _verifyHiddenVoteCommitments(
+ uint256 _localDisputeID,
+ uint256 _localRoundID,
+ uint256[] calldata _voteIDs,
+ uint256 _choice,
+ string memory _justification,
+ uint256 _salt
+ ) internal view override {
+ super._verifyHiddenVoteCommitments(_localDisputeID, _localRoundID, _voteIDs, _choice, _justification, _salt);
+
+ // The juror is allowed to reveal without verifying the justification commitment for recovery purposes.
+ if (callerIsJuror) return;
+
+ bytes32 actualJustificationHash = hashJustification(_salt, _justification);
+ for (uint256 i = 0; i < _voteIDs.length; i++) {
+ if (justificationCommitments[_localDisputeID][_localRoundID][_voteIDs[i]] != actualJustificationHash)
+ revert JustificationCommitmentMismatch();
+ }
+ }
+
+ /// @notice Extracts token gating information from the extra data.
/// @param _extraData The extra data bytes array with the following encoding:
- /// - bytes 0-31: uint96 courtID, not used here
- /// - bytes 32-63: uint256 minJurors, not used here
- /// - bytes 64-95: uint256 disputeKitID, not used here
- /// - bytes 96-127: uint256 packedTokenGateAndFlag (address tokenGate in bits 0-159, bool isERC1155 in bit 160)
- /// - bytes 128-159: uint256 tokenId
+ /// - bytes 0-31: uint96 courtID, not used here
+ /// - bytes 32-63: uint256 minJurors, not used here
+ /// - bytes 64-95: uint256 disputeKitID, not used here
+ /// - bytes 96-127: uint256 packedTokenGateAndFlag (address tokenGate in bits 0-159, bool isERC1155 in bit 160)
+ /// - bytes 128-159: uint256 tokenId
/// @return tokenGate The address of the token contract used for gating access.
/// @return isERC1155 True if the token is an ERC-1155, false for ERC-20/ERC-721.
/// @return tokenId The token ID for ERC-1155 tokens (ignored for ERC-20/ERC-721).
@@ -182,7 +271,7 @@ contract DisputeKitGatedShutter is DisputeKitClassicBase {
(address tokenGate, bool isERC1155, uint256 tokenId) = _extraDataToTokenInfo(dispute.extraData);
// If no token gate is specified, allow all jurors
- if (tokenGate == address(0)) return true;
+ if (tokenGate == NO_TOKEN_GATE) return true;
// Check juror's token balance
if (isERC1155) {
@@ -191,4 +280,12 @@ contract DisputeKitGatedShutter is DisputeKitClassicBase {
return IBalanceHolder(tokenGate).balanceOf(_juror) > 0;
}
}
+
+ // ************************************* //
+ // * Errors * //
+ // ************************************* //
+
+ error TokenNotSupported(address tokenGate);
+ error EmptyJustificationCommit();
+ error JustificationCommitmentMismatch();
}
diff --git a/contracts/src/arbitration/dispute-kits/DisputeKitShutter.sol b/contracts/src/arbitration/dispute-kits/DisputeKitShutter.sol
index 057a06921..53f89d895 100644
--- a/contracts/src/arbitration/dispute-kits/DisputeKitShutter.sol
+++ b/contracts/src/arbitration/dispute-kits/DisputeKitShutter.sol
@@ -1,33 +1,48 @@
// SPDX-License-Identifier: MIT
-pragma solidity ^0.8.24;
+pragma solidity ^0.8.28;
import {DisputeKitClassicBase, KlerosCore} from "./DisputeKitClassicBase.sol";
/// @title DisputeKitShutter
-/// Added functionality: shielded voting.
+/// @notice Added functionality: shielded voting.
/// Dispute kit implementation of the Kleros v1 features including:
/// - a drawing system: proportional to staked PNK,
/// - a vote aggregation system: plurality,
/// - an incentive system: equal split between coherent votes,
/// - an appeal system: fund 2 choices only, vote on any choice.
contract DisputeKitShutter is DisputeKitClassicBase {
- string public constant override version = "0.12.0";
+ string public constant override version = "2.0.0";
+
+ // ************************************* //
+ // * Storage * //
+ // ************************************* //
+
+ mapping(uint256 localDisputeID => mapping(uint256 localRoundID => mapping(uint256 voteID => bytes32 justificationCommitment)))
+ public justificationCommitments;
+
+ // ************************************* //
+ // * Transient Storage * //
+ // ************************************* //
+
+ bool transient callerIsJuror;
// ************************************* //
// * Events * //
// ************************************* //
- /// @dev Emitted when a vote is cast.
+ /// @notice Emitted when a vote is cast.
/// @param _coreDisputeID The identifier of the dispute in the Arbitrator contract.
/// @param _juror The address of the juror casting the vote commitment.
- /// @param _commit The commitment hash.
+ /// @param _choiceCommit The commitment hash without the justification.
+ /// @param _justificationCommit The commitment hash for the justification.
/// @param _identity The Shutter identity used for encryption.
/// @param _encryptedVote The Shutter encrypted vote.
event CommitCastShutter(
uint256 indexed _coreDisputeID,
address indexed _juror,
- bytes32 indexed _commit,
+ bytes32 indexed _choiceCommit,
+ bytes32 _justificationCommit,
bytes32 _identity,
bytes _encryptedVote
);
@@ -41,16 +56,18 @@ contract DisputeKitShutter is DisputeKitClassicBase {
_disableInitializers();
}
- /// @dev Initializer.
- /// @param _governor The governor's address.
+ /// @notice Initializer.
+ /// @param _owner The owner's address.
/// @param _core The KlerosCore arbitrator.
/// @param _wNative The wrapped native token address, typically wETH.
- function initialize(address _governor, KlerosCore _core, address _wNative) external reinitializer(1) {
- __DisputeKitClassicBase_initialize(_governor, _core, _wNative);
- }
-
- function reinitialize(address _wNative) external reinitializer(9) {
- wNative = _wNative;
+ /// @param _jumpDisputeKitID The ID of the dispute kit to switch to after the court jump.
+ function initialize(
+ address _owner,
+ KlerosCore _core,
+ address _wNative,
+ uint256 _jumpDisputeKitID
+ ) external initializer {
+ __DisputeKitClassicBase_initialize(_owner, _core, _wNative, _jumpDisputeKitID);
}
// ************************ //
@@ -58,8 +75,8 @@ contract DisputeKitShutter is DisputeKitClassicBase {
// ************************ //
/// @dev Access Control to perform implementation upgrades (UUPS Proxiable)
- /// Only the governor can perform upgrades (`onlyByGovernor`)
- function _authorizeUpgrade(address) internal view override onlyByGovernor {
+ /// Only the owner can perform upgrades (`onlyByOwner`)
+ function _authorizeUpgrade(address) internal view override onlyByOwner {
// NOP
}
@@ -67,26 +84,53 @@ contract DisputeKitShutter is DisputeKitClassicBase {
// * State Modifiers * //
// ************************************* //
- /// @dev Sets the caller's commit for the specified votes. It can be called multiple times during the
- /// commit period, each call overrides the commits of the previous one.
- /// `O(n)` where
- /// `n` is the number of votes.
+ /// @notice Sets the caller's commit for the specified votes.
+ ///
+ /// @dev It can be called multiple times during the commit period, each call overrides the commits of the previous one.
+ /// `O(n)` where `n` is the number of votes.
+ ///
/// @param _coreDisputeID The ID of the dispute in Kleros Core.
/// @param _voteIDs The IDs of the votes.
- /// @param _commit The commitment hash including the justification.
+ /// @param _choiceCommit The commitment hash without the justification.
+ /// @param _justificationCommit The commitment hash for justification.
/// @param _identity The Shutter identity used for encryption.
/// @param _encryptedVote The Shutter encrypted vote.
function castCommitShutter(
uint256 _coreDisputeID,
uint256[] calldata _voteIDs,
- bytes32 _commit,
+ bytes32 _choiceCommit,
+ bytes32 _justificationCommit,
bytes32 _identity,
bytes calldata _encryptedVote
- ) external notJumped(_coreDisputeID) {
- _castCommit(_coreDisputeID, _voteIDs, _commit);
- emit CommitCastShutter(_coreDisputeID, msg.sender, _commit, _identity, _encryptedVote);
+ ) external {
+ if (_justificationCommit == bytes32(0)) revert EmptyJustificationCommit();
+
+ uint256 localDisputeID = coreDisputeIDToLocal[_coreDisputeID];
+ Dispute storage dispute = disputes[localDisputeID];
+ uint256 localRoundID = dispute.rounds.length - 1;
+ for (uint256 i = 0; i < _voteIDs.length; i++) {
+ justificationCommitments[localDisputeID][localRoundID][_voteIDs[i]] = _justificationCommit;
+ }
+
+ // `_castCommit()` ensures that the caller owns the vote and that dispute is active
+ _castCommit(_coreDisputeID, _voteIDs, _choiceCommit);
+ emit CommitCastShutter(
+ _coreDisputeID,
+ msg.sender,
+ _choiceCommit,
+ _justificationCommit,
+ _identity,
+ _encryptedVote
+ );
}
+ /// @notice Version of `castVote` function designed specifically for Shutter.
+ /// @dev `O(n)` where `n` is the number of votes.
+ /// @param _coreDisputeID The ID of the dispute in Kleros Core.
+ /// @param _voteIDs The IDs of the votes.
+ /// @param _choice The choice.
+ /// @param _salt The salt for the commit if the votes were hidden.
+ /// @param _justification Justification of the choice.
function castVoteShutter(
uint256 _coreDisputeID,
uint256[] calldata _voteIDs,
@@ -97,27 +141,55 @@ contract DisputeKitShutter is DisputeKitClassicBase {
Dispute storage dispute = disputes[coreDisputeIDToLocal[_coreDisputeID]];
address juror = dispute.rounds[dispute.rounds.length - 1].votes[_voteIDs[0]].account;
- // _castVote() ensures that all the _voteIDs do belong to `juror`
+ callerIsJuror = juror == msg.sender;
+
+ // `_castVote()` ensures that all the `_voteIDs` do belong to `juror`
_castVote(_coreDisputeID, _voteIDs, _choice, _salt, _justification, juror);
+
+ callerIsJuror = false;
}
// ************************************* //
// * Public Views * //
// ************************************* //
- /**
- * @dev Computes the hash of a vote using ABI encoding
- * @param _choice The choice being voted for
- * @param _justification The justification for the vote
- * @param _salt A random salt for commitment
- * @return bytes32 The hash of the encoded vote parameters
- */
- function hashVote(
+ /// @notice Computes the hash of a justification using ABI encoding
+ /// @param _salt A random salt for commitment
+ /// @param _justification The justification for the vote
+ /// @return bytes32 The hash of the encoded justification
+ function hashJustification(uint256 _salt, string memory _justification) public pure returns (bytes32) {
+ return keccak256(abi.encode(_salt, keccak256(bytes(_justification))));
+ }
+
+ // ************************************* //
+ // * Internal * //
+ // ************************************* //
+
+ /// @inheritdoc DisputeKitClassicBase
+ function _verifyHiddenVoteCommitments(
+ uint256 _localDisputeID,
+ uint256 _localRoundID,
+ uint256[] calldata _voteIDs,
uint256 _choice,
- uint256 _salt,
- string memory _justification
- ) public pure override returns (bytes32) {
- bytes32 justificationHash = keccak256(bytes(_justification));
- return keccak256(abi.encode(_choice, _salt, justificationHash));
+ string memory _justification,
+ uint256 _salt
+ ) internal view override {
+ super._verifyHiddenVoteCommitments(_localDisputeID, _localRoundID, _voteIDs, _choice, _justification, _salt);
+
+ // The juror is allowed to reveal without verifying the justification commitment for recovery purposes.
+ if (callerIsJuror) return;
+
+ bytes32 actualJustificationHash = hashJustification(_salt, _justification);
+ for (uint256 i = 0; i < _voteIDs.length; i++) {
+ if (justificationCommitments[_localDisputeID][_localRoundID][_voteIDs[i]] != actualJustificationHash)
+ revert JustificationCommitmentMismatch();
+ }
}
+
+ // ************************************* //
+ // * Errors * //
+ // ************************************* //
+
+ error EmptyJustificationCommit();
+ error JustificationCommitmentMismatch();
}
diff --git a/contracts/src/arbitration/dispute-kits/DisputeKitSybilResistant.sol b/contracts/src/arbitration/dispute-kits/DisputeKitSybilResistant.sol
index 8568c55af..983fb63df 100644
--- a/contracts/src/arbitration/dispute-kits/DisputeKitSybilResistant.sol
+++ b/contracts/src/arbitration/dispute-kits/DisputeKitSybilResistant.sol
@@ -5,20 +5,20 @@ pragma solidity ^0.8.24;
import {DisputeKitClassicBase, KlerosCore} from "./DisputeKitClassicBase.sol";
interface IProofOfHumanity {
- /// @dev Return true if the submission is registered and not expired.
+ /// @notice Return true if the submission is registered and not expired.
/// @param _submissionID The address of the submission.
/// @return Whether the submission is registered or not.
function isRegistered(address _submissionID) external view returns (bool);
}
/// @title DisputeKitSybilResistant
-/// Dispute kit implementation adapted from DisputeKitClassic
+/// @notice Dispute kit implementation adapted from DisputeKitClassic
/// - a drawing system: at most 1 vote per juror registered on Proof of Humanity,
/// - a vote aggregation system: plurality,
/// - an incentive system: equal split between coherent votes,
/// - an appeal system: fund 2 choices only, vote on any choice.
contract DisputeKitSybilResistant is DisputeKitClassicBase {
- string public constant override version = "0.12.0";
+ string public constant override version = "2.0.0";
// ************************************* //
// * Storage * //
@@ -35,18 +35,20 @@ contract DisputeKitSybilResistant is DisputeKitClassicBase {
_disableInitializers();
}
- /// @dev Initializer.
- /// @param _governor The governor's address.
+ /// @notice Initializer.
+ /// @param _owner The owner's address.
/// @param _core The KlerosCore arbitrator.
/// @param _poh The Proof of Humanity registry.
/// @param _wNative The wrapped native token address, typically wETH.
+ /// @param _jumpDisputeKitID The ID of the dispute kit to switch to after the court jump.
function initialize(
- address _governor,
+ address _owner,
KlerosCore _core,
IProofOfHumanity _poh,
- address _wNative
- ) external reinitializer(1) {
- __DisputeKitClassicBase_initialize(_governor, _core, _wNative);
+ address _wNative,
+ uint256 _jumpDisputeKitID
+ ) external initializer {
+ __DisputeKitClassicBase_initialize(_owner, _core, _wNative, _jumpDisputeKitID);
poh = _poh;
singleDrawPerJuror = true;
}
@@ -56,8 +58,8 @@ contract DisputeKitSybilResistant is DisputeKitClassicBase {
// ************************ //
/// @dev Access Control to perform implementation upgrades (UUPS Proxiable)
- /// Only the governor can perform upgrades (`onlyByGovernor`)
- function _authorizeUpgrade(address) internal view override onlyByGovernor {
+ /// Only the owner can perform upgrades (`onlyByOwner`)
+ function _authorizeUpgrade(address) internal view override onlyByOwner {
// NOP
}
diff --git a/contracts/src/arbitration/evidence/EvidenceModule.sol b/contracts/src/arbitration/evidence/EvidenceModule.sol
index fe55122b9..489b6c704 100644
--- a/contracts/src/arbitration/evidence/EvidenceModule.sol
+++ b/contracts/src/arbitration/evidence/EvidenceModule.sol
@@ -9,20 +9,20 @@ import "../../proxy/Initializable.sol";
/// @title Evidence Module
contract EvidenceModule is IEvidence, Initializable, UUPSProxiable {
- string public constant override version = "0.8.0";
+ string public constant override version = "2.0.0";
// ************************************* //
// * Storage * //
// ************************************* //
- address public governor; // The governor of the contract.
+ address public owner; // The owner of the contract.
// ************************************* //
// * Modifiers * //
// ************************************* //
- modifier onlyByGovernor() {
- require(governor == msg.sender, "Access not allowed: Governor only.");
+ modifier onlyByOwner() {
+ if (owner != msg.sender) revert OwnerOnly();
_;
}
@@ -35,14 +35,10 @@ contract EvidenceModule is IEvidence, Initializable, UUPSProxiable {
_disableInitializers();
}
- /// @dev Initializer.
- /// @param _governor The governor's address.
- function initialize(address _governor) external reinitializer(1) {
- governor = _governor;
- }
-
- function initialize2() external reinitializer(2) {
- // NOP
+ /// @notice Initializer.
+ /// @param _owner The owner's address.
+ function initialize(address _owner) external initializer {
+ owner = _owner;
}
// ************************ //
@@ -51,9 +47,9 @@ contract EvidenceModule is IEvidence, Initializable, UUPSProxiable {
/**
* @dev Access Control to perform implementation upgrades (UUPS Proxiable)
- * @dev Only the governor can perform upgrades (`onlyByGovernor`)
+ * @dev Only the owner can perform upgrades (`onlyByOwner`)
*/
- function _authorizeUpgrade(address) internal view override onlyByGovernor {
+ function _authorizeUpgrade(address) internal view override onlyByOwner {
// NOP
}
@@ -61,10 +57,16 @@ contract EvidenceModule is IEvidence, Initializable, UUPSProxiable {
// * Function Modifiers * //
// ************************************* //
- /// @dev Submits evidence for a dispute.
- /// @param _externalDisputeID Unique identifier for this dispute outside Kleros. It's the submitter responsability to submit the right evidence group ID.
- /// @param _evidence Stringified evidence object, example: '{"name" : "Justification", "description" : "Description", "fileURI" : "/ipfs/QmWQV5ZFFhEJiW8Lm7ay2zLxC2XS4wx1b2W7FfdrLMyQQc"}'.
- function submitEvidence(uint256 _externalDisputeID, string calldata _evidence) external {
- emit Evidence(_externalDisputeID, msg.sender, _evidence);
+ /// @notice Submits evidence for a dispute.
+ /// @param _arbitratorDisputeID The identifier of the dispute in the Arbitrator contract.
+ /// @param _evidence Stringified evidence object, example: `{"name" : "Justification", "description" : "Description", "fileURI" : "/ipfs/QmWQV5ZFFhEJiW8Lm7ay2zLxC2XS4wx1b2W7FfdrLMyQQc"}`.
+ function submitEvidence(uint256 _arbitratorDisputeID, string calldata _evidence) external {
+ emit Evidence(_arbitratorDisputeID, msg.sender, _evidence);
}
+
+ // ************************************* //
+ // * Errors * //
+ // ************************************* //
+
+ error OwnerOnly();
}
diff --git a/contracts/src/arbitration/evidence/ModeratedEvidenceModule.sol b/contracts/src/arbitration/evidence/ModeratedEvidenceModule.sol
index dbfbd8adf..524f2ec3e 100644
--- a/contracts/src/arbitration/evidence/ModeratedEvidenceModule.sol
+++ b/contracts/src/arbitration/evidence/ModeratedEvidenceModule.sol
@@ -5,12 +5,9 @@ pragma solidity ^0.8.24;
// TODO: standard interfaces should be placed in a separated repo (?)
import {IArbitrableV2, IArbitratorV2} from "../interfaces/IArbitrableV2.sol";
import "../interfaces/IDisputeTemplateRegistry.sol";
-import "../../libraries/CappedMath.sol";
/// @title Implementation of the Evidence Standard with Moderated Submissions
contract ModeratedEvidenceModule is IArbitrableV2 {
- using CappedMath for uint256;
-
// ************************************* //
// * Enums / Structs * //
// ************************************* //
@@ -54,7 +51,7 @@ contract ModeratedEvidenceModule is IArbitrableV2 {
mapping(uint256 => bytes32) public disputeIDtoEvidenceID; // One-to-one relationship between the dispute and the evidence.
ArbitratorData[] public arbitratorDataList; // Stores the arbitrator data of the contract. Updated each time the data is changed.
IArbitratorV2 public immutable arbitrator; // The trusted arbitrator to resolve potential disputes. If it needs to be changed, a new contract can be deployed.
- address public governor; // The address that can make governance changes to the parameters of the contract.
+ address public owner; // The address that can make governance changes to the parameters of the contract.
IDisputeTemplateRegistry public templateRegistry; // The dispute template registry.
uint256 public bondTimeout; // The time in seconds during which the last moderation status can be challenged.
uint256 public totalCostMultiplier; // Multiplier of arbitration fees that must be ultimately paid as fee stake. In basis points.
@@ -64,8 +61,8 @@ contract ModeratedEvidenceModule is IArbitrableV2 {
// * Function Modifiers * //
// ************************************* //
- modifier onlyGovernor() {
- require(msg.sender == governor, "The caller must be the governor");
+ modifier onlyOwner() {
+ require(msg.sender == owner, "The caller must be the owner");
_;
}
@@ -73,19 +70,19 @@ contract ModeratedEvidenceModule is IArbitrableV2 {
// * Events * //
// ************************************* //
- /// @dev To be raised when a moderated evidence is submitted. Should point to the resource (evidences are not to be stored on chain due to gas considerations).
+ /// @notice To be raised when a moderated evidence is submitted. Should point to the resource (evidences are not to be stored on chain due to gas considerations).
/// @param _arbitrator The arbitrator of the contract.
- /// @param _externalDisputeID Unique identifier for this dispute outside Kleros. It's the submitter responsability to submit the right evidence group ID.
+ /// @param _arbitratorDisputeID The identifier of the dispute in the Arbitrator contract.
/// @param _party The address of the party submiting the evidence. Note that 0x0 refers to evidence not submitted by any party.
/// @param _evidence Stringified evidence object, example: '{"name" : "Justification", "description" : "Description", "fileURI" : "/ipfs/QmWQV5ZFFhEJiW8Lm7ay2zLxC2XS4wx1b2W7FfdrLMyQQc"}'.
event ModeratedEvidence(
IArbitratorV2 indexed _arbitrator,
- uint256 indexed _externalDisputeID,
+ uint256 indexed _arbitratorDisputeID,
address indexed _party,
string _evidence
);
- /// @dev Indicate that a party has to pay a fee or would otherwise be considered as losing.
+ /// @notice Indicate that a party has to pay a fee or would otherwise be considered as losing.
/// @param _evidenceID The ID of the evidence being moderated.
/// @param _currentWinner The party who is currently winning.
event ModerationStatusChanged(bytes32 indexed _evidenceID, Party _currentWinner);
@@ -94,9 +91,9 @@ contract ModeratedEvidenceModule is IArbitrableV2 {
// * Constructor * //
// ************************************* //
- /// @dev Constructor.
+ /// @notice Constructor.
/// @param _arbitrator The trusted arbitrator to resolve potential disputes.
- /// @param _governor The trusted governor of the contract.
+ /// @param _owner The trusted owner of the contract.
/// @param _totalCostMultiplier Multiplier of arbitration fees that must be ultimately paid as fee stake. In basis points.
/// @param _initialDepositMultiplier Multiplier of arbitration fees that must be paid as initial stake for submitting evidence. In basis points.
/// @param _bondTimeout The time in seconds during which the last moderation status can be challenged.
@@ -105,7 +102,7 @@ contract ModeratedEvidenceModule is IArbitrableV2 {
/// @param _templateDataMappings The dispute template data mappings.
constructor(
IArbitratorV2 _arbitrator,
- address _governor,
+ address _owner,
IDisputeTemplateRegistry _templateRegistry,
uint256 _totalCostMultiplier,
uint256 _initialDepositMultiplier,
@@ -115,7 +112,7 @@ contract ModeratedEvidenceModule is IArbitrableV2 {
string memory _templateDataMappings
) {
arbitrator = _arbitrator;
- governor = _governor;
+ owner = _owner;
templateRegistry = _templateRegistry;
totalCostMultiplier = _totalCostMultiplier; // For example 15000, which would provide a 100% reward to the dispute winner.
@@ -135,37 +132,37 @@ contract ModeratedEvidenceModule is IArbitrableV2 {
// * Governance * //
// ************************************* //
- /// @dev Change the governor of the contract.
- /// @param _governor The address of the new governor.
- function changeGovernor(address _governor) external onlyGovernor {
- governor = _governor;
+ /// @notice Change the owner of the contract.
+ /// @param _owner The address of the new owner.
+ function changeOwner(address _owner) external onlyOwner {
+ owner = _owner;
}
- /// @dev Change the proportion of arbitration fees that must be paid as fee stake by parties when there is no winner or loser (e.g. when the arbitrator refused to rule).
+ /// @notice Change the proportion of arbitration fees that must be paid as fee stake by parties when there is no winner or loser (e.g. when the arbitrator refused to rule).
/// @param _initialDepositMultiplier Multiplier of arbitration fees that must be paid as fee stake. In basis points.
- function changeInitialDepositMultiplier(uint256 _initialDepositMultiplier) external onlyGovernor {
+ function changeInitialDepositMultiplier(uint256 _initialDepositMultiplier) external onlyOwner {
initialDepositMultiplier = _initialDepositMultiplier;
}
- /// @dev Change the proportion of arbitration fees that must be paid as fee stake by the winner of the previous round.
+ /// @notice Change the proportion of arbitration fees that must be paid as fee stake by the winner of the previous round.
/// @param _totalCostMultiplier Multiplier of arbitration fees that must be paid as fee stake. In basis points.
- function changeTotalCostMultiplier(uint256 _totalCostMultiplier) external onlyGovernor {
+ function changeTotalCostMultiplier(uint256 _totalCostMultiplier) external onlyOwner {
totalCostMultiplier = _totalCostMultiplier;
}
- /// @dev Change the time window within which evidence submissions and removals can be contested.
+ /// @notice Change the time window within which evidence submissions and removals can be contested.
/// Ongoing moderations will start using the latest bondTimeout available after calling moderate() again.
/// @param _bondTimeout Multiplier of arbitration fees that must be paid as fee stake. In basis points.
- function changeBondTimeout(uint256 _bondTimeout) external onlyGovernor {
+ function changeBondTimeout(uint256 _bondTimeout) external onlyOwner {
bondTimeout = _bondTimeout;
}
- /// @dev Update the dispute template data.
+ /// @notice Update the dispute template data.
/// @param _templateData The new dispute template data.
function changeDisputeTemplate(
string calldata _templateData,
string memory _templateDataMappings
- ) external onlyGovernor {
+ ) external onlyOwner {
ArbitratorData storage arbitratorData = arbitratorDataList[arbitratorDataList.length - 1];
uint256 newDisputeTemplateId = templateRegistry.setDisputeTemplate("", _templateData, _templateDataMappings);
arbitratorDataList.push(
@@ -176,9 +173,9 @@ contract ModeratedEvidenceModule is IArbitrableV2 {
);
}
- /// @dev Change the arbitrator to be used for disputes that may be raised in the next requests. The arbitrator is trusted to support appeal period and not reenter.
+ /// @notice Change the arbitrator to be used for disputes that may be raised in the next requests. The arbitrator is trusted to support appeal period and not reenter.
/// @param _arbitratorExtraData The extra data used by the new arbitrator.
- function changeArbitratorExtraData(bytes calldata _arbitratorExtraData) external onlyGovernor {
+ function changeArbitratorExtraData(bytes calldata _arbitratorExtraData) external onlyOwner {
ArbitratorData storage arbitratorData = arbitratorDataList[arbitratorDataList.length - 1];
arbitratorDataList.push(
ArbitratorData({
@@ -192,8 +189,8 @@ contract ModeratedEvidenceModule is IArbitrableV2 {
// * State Modifiers * //
// ************************************* //
- /// @dev Submits evidence.
- /// @param _evidenceGroupID Unique identifier of the evidence group the evidence belongs to. It's the submitter responsability to submit the right evidence group ID.
+ /// @notice Submits evidence.
+ /// @param _evidenceGroupID Unique identifier of the evidence group the evidence belongs to. It's the submitter responsibility to submit the right evidence group ID.
/// @param _evidence Stringified evidence object, example: '{"name" : "Justification", "description" : "Description", "fileURI" : "/ipfs/QmWQV5ZFFhEJiW8Lm7ay2zLxC2XS4wx1b2W7FfdrLMyQQc"}'.
function submitEvidence(uint256 _evidenceGroupID, string calldata _evidence) external payable {
// Optimization opportunity: map evidenceID to an incremental index that can be safely assumed to be less than a small uint.
@@ -205,8 +202,8 @@ contract ModeratedEvidenceModule is IArbitrableV2 {
ArbitratorData storage arbitratorData = arbitratorDataList[arbitratorDataList.length - 1];
uint256 arbitrationCost = arbitrator.arbitrationCost(arbitratorData.arbitratorExtraData);
- uint256 totalCost = arbitrationCost.mulCap(totalCostMultiplier) / MULTIPLIER_DIVISOR;
- uint256 depositRequired = totalCost.mulCap(initialDepositMultiplier) / MULTIPLIER_DIVISOR;
+ uint256 totalCost = (arbitrationCost * totalCostMultiplier) / MULTIPLIER_DIVISOR;
+ uint256 depositRequired = (totalCost * initialDepositMultiplier) / MULTIPLIER_DIVISOR;
Moderation storage moderation = evidenceData.moderations.push();
// Overpaying is allowed.
@@ -217,10 +214,10 @@ contract ModeratedEvidenceModule is IArbitrableV2 {
moderation.arbitratorDataID = arbitratorDataList.length - 1;
// When evidence is submitted for a foreign arbitrable, the arbitrator field of Evidence is ignored.
- emit ModeratedEvidence(arbitrator, _evidenceGroupID, msg.sender, _evidence);
+ emit ModeratedEvidence(arbitrator, evidenceData.disputeID, msg.sender, _evidence);
}
- /// @dev Moderates an evidence submission. Requires the contester to at least double the accumulated stake of the oposing party.
+ /// @notice Moderates an evidence submission. Requires the contester to at least double the accumulated stake of the oposing party.
/// Optimization opportunity: use `bytes calldata args` and compress _evidenceID and _side (only for optimistic rollups).
/// @param _evidenceID Unique identifier of the evidence submission.
/// @param _side The side to contribute to.
@@ -245,12 +242,12 @@ contract ModeratedEvidenceModule is IArbitrableV2 {
ArbitratorData storage arbitratorData = arbitratorDataList[moderation.arbitratorDataID];
uint256 arbitrationCost = arbitrator.arbitrationCost(arbitratorData.arbitratorExtraData);
- uint256 totalCost = arbitrationCost.mulCap(totalCostMultiplier) / MULTIPLIER_DIVISOR;
+ uint256 totalCost = (arbitrationCost * totalCostMultiplier) / MULTIPLIER_DIVISOR;
uint256 opposition = 3 - uint256(_side);
uint256 depositRequired = moderation.paidFees[opposition] * 2;
if (depositRequired == 0) {
- depositRequired = totalCost.mulCap(initialDepositMultiplier) / MULTIPLIER_DIVISOR;
+ depositRequired = (totalCost * initialDepositMultiplier) / MULTIPLIER_DIVISOR;
} else if (depositRequired > totalCost) {
depositRequired = totalCost;
}
@@ -268,13 +265,7 @@ contract ModeratedEvidenceModule is IArbitrableV2 {
);
disputeIDtoEvidenceID[evidenceData.disputeID] = _evidenceID;
- emit DisputeRequest(
- arbitrator,
- evidenceData.disputeID,
- uint256(_evidenceID),
- arbitratorData.disputeTemplateId,
- ""
- );
+ emit DisputeRequest(arbitrator, evidenceData.disputeID, arbitratorData.disputeTemplateId);
evidenceData.disputed = true;
moderation.bondDeadline = 0;
moderation.currentWinner = Party.None;
@@ -285,7 +276,7 @@ contract ModeratedEvidenceModule is IArbitrableV2 {
emit ModerationStatusChanged(_evidenceID, moderation.currentWinner);
}
- /// @dev Resolves a moderation event once the timeout has passed.
+ /// @notice Resolves a moderation event once the timeout has passed.
/// @param _evidenceID Unique identifier of the evidence submission.
function resolveModerationMarket(bytes32 _evidenceID) external {
// Moderation market resolutions are not final.
@@ -301,7 +292,7 @@ contract ModeratedEvidenceModule is IArbitrableV2 {
evidenceData.ruling = moderation.currentWinner;
}
- /// @dev Make a fee contribution.
+ /// @notice Make a fee contribution.
/// @param _moderation The moderation to contribute to.
/// @param _side The side to contribute to.
/// @param _contributor The contributor.
@@ -317,7 +308,9 @@ contract ModeratedEvidenceModule is IArbitrableV2 {
) internal returns (uint256) {
uint256 contribution;
uint256 remainingETH;
- uint256 requiredAmount = _totalRequired.subCap(_moderation.paidFees[uint256(_side)]);
+ uint256 requiredAmount = _moderation.paidFees[uint256(_side)] >= _totalRequired
+ ? 0
+ : _totalRequired - _moderation.paidFees[uint256(_side)];
(contribution, remainingETH) = calculateContribution(_amount, requiredAmount);
_moderation.contributions[_contributor][uint256(_side)] += contribution;
_moderation.paidFees[uint256(_side)] += contribution;
@@ -328,7 +321,7 @@ contract ModeratedEvidenceModule is IArbitrableV2 {
return contribution;
}
- /// @dev Returns the contribution value and remainder from available ETH and required amount.
+ /// @notice Returns the contribution value and remainder from available ETH and required amount.
/// @param _available The amount of ETH available for the contribution.
/// @param _requiredAmount The amount of ETH required for the contribution.
/// @return taken The amount of ETH taken.
@@ -343,9 +336,11 @@ contract ModeratedEvidenceModule is IArbitrableV2 {
return (_requiredAmount, remainder);
}
- /// @dev Withdraws contributions of moderations. Reimburses contributions if the appeal was not fully funded.
- /// If the appeal was fully funded, sends the fee stake rewards and reimbursements proportional to the contributions made to the winner of a dispute.
+ /// @notice Withdraws contributions of moderations. Reimburses contributions if the appeal was not fully funded.
+ ///
+ /// @dev If the appeal was fully funded, sends the fee stake rewards and reimbursements proportional to the contributions made to the winner of a dispute.
/// Optimization opportunity: use `bytes calldata args` and compress _evidenceID and _moderationID (only for optimistic rollups).
+ ///
/// @param _beneficiary The address that made contributions.
/// @param _evidenceID The ID of the associated evidence submission.
/// @param _moderationID The ID of the moderatino occurence.
@@ -380,10 +375,7 @@ contract ModeratedEvidenceModule is IArbitrableV2 {
_beneficiary.send(reward); // It is the user responsibility to accept ETH.
}
- /// @dev Give a ruling for a dispute. Must be called by the arbitrator to enforce the final ruling.
- /// The purpose of this function is to ensure that the address calling it has the right to rule on the contract.
- /// @param _disputeID ID of the dispute in the Arbitrator contract.
- /// @param _ruling Ruling given by the arbitrator. Note that 0 is reserved for "Not able/wanting to make a decision".
+ /// @inheritdoc IArbitrableV2
function rule(uint256 _disputeID, uint256 _ruling) public override {
bytes32 evidenceID = disputeIDtoEvidenceID[_disputeID];
EvidenceData storage evidenceData = evidences[evidenceID];
@@ -406,7 +398,7 @@ contract ModeratedEvidenceModule is IArbitrableV2 {
// * Public Views * //
// ************************************* //
- /// @dev Gets the number of moderation events of the specific evidence submission.
+ /// @notice Gets the number of moderation events of the specific evidence submission.
/// @param _evidenceID The ID of the evidence submission.
/// @return The number of moderations.
function getNumberOfModerations(bytes32 _evidenceID) external view returns (uint256) {
@@ -414,7 +406,7 @@ contract ModeratedEvidenceModule is IArbitrableV2 {
return evidenceData.moderations.length;
}
- /// @dev Gets the contributions made by a party for a given moderation.
+ /// @notice Gets the contributions made by a party for a given moderation.
/// @param _evidenceID The ID of the evidence submission.
/// @param _moderationID The ID of the moderation occurence.
/// @param _contributor The address of the contributor.
@@ -429,7 +421,7 @@ contract ModeratedEvidenceModule is IArbitrableV2 {
contributions = moderation.contributions[_contributor];
}
- /// @dev Gets the information of a moderation event.
+ /// @notice Gets the information of a moderation event.
/// @param _evidenceID The ID of the evidence submission.
/// @param _moderationID The ID of the moderation occurence.
/// @return paidFees currentWinner feeRewards The moderation information.
@@ -442,7 +434,7 @@ contract ModeratedEvidenceModule is IArbitrableV2 {
return (moderation.paidFees, moderation.currentWinner, moderation.feeRewards);
}
- /// @dev Gets the last arbitrator data index, which is used for current new submissions.
+ /// @notice Gets the last arbitrator data index, which is used for current new submissions.
/// @return The last arbitrator data index.
function getCurrentArbitratorIndex() external view returns (uint256) {
return arbitratorDataList.length - 1;
diff --git a/contracts/src/arbitration/interfaces/IArbitrableV2.sol b/contracts/src/arbitration/interfaces/IArbitrableV2.sol
index cba10115e..9235f059c 100644
--- a/contracts/src/arbitration/interfaces/IArbitrableV2.sol
+++ b/contracts/src/arbitration/interfaces/IArbitrableV2.sol
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT
-pragma solidity ^0.8.24;
+pragma solidity >=0.8.0 <0.9.0;
import "./IArbitratorV2.sol";
@@ -8,33 +8,35 @@ import "./IArbitratorV2.sol";
/// @notice Arbitrable interface.
/// @dev When developing arbitrable contracts, we need to:
/// - Define the action taken when a ruling is received by the contract.
-/// - Allow dispute creation. For this a function must call arbitrator.createDispute{value: _fee}(_choices,_extraData);
+/// - Allow dispute creation which calls `arbitrator.createDispute{value: _fee}(_choices,_extraData)`.
interface IArbitrableV2 {
- /// @dev To be emitted when a dispute is created to link the correct meta-evidence to the disputeID.
+ // ************************************* //
+ // * Events * //
+ // ************************************* //
+
+ /// @notice To be emitted when a dispute is created to link the correct template to the disputeID.
/// @param _arbitrator The arbitrator of the contract.
/// @param _arbitratorDisputeID The identifier of the dispute in the Arbitrator contract.
- /// @param _externalDisputeID An identifier created outside Kleros by the protocol requesting arbitration.
- /// @param _templateId The identifier of the dispute template. Should not be used with _templateUri.
- /// @param _templateUri The URI to the dispute template. For example on IPFS: starting with '/ipfs/'. Should not be used with _templateId.
- event DisputeRequest(
- IArbitratorV2 indexed _arbitrator,
- uint256 indexed _arbitratorDisputeID,
- uint256 _externalDisputeID,
- uint256 _templateId,
- string _templateUri
- );
+ /// @param _templateId The identifier of the dispute template.
+ event DisputeRequest(IArbitratorV2 indexed _arbitrator, uint256 indexed _arbitratorDisputeID, uint256 _templateId);
- /// @dev To be raised when a ruling is given.
+ /// @notice To be raised when a ruling is given.
/// @param _arbitrator The arbitrator giving the ruling.
/// @param _disputeID The identifier of the dispute in the Arbitrator contract.
/// @param _ruling The ruling which was given.
event Ruling(IArbitratorV2 indexed _arbitrator, uint256 indexed _disputeID, uint256 _ruling);
- /// @dev Give a ruling for a dispute.
- /// Must be called by the arbitrator.
- /// The purpose of this function is to ensure that the address calling it has the right to rule on the contract.
+ // ************************************* //
+ // * State Modifiers * //
+ // ************************************* //
+
+ /// @notice Give a ruling for a dispute.
+ ///
+ /// @dev This is a callback function for the arbitrator to provide the ruling to this contract.
+ /// Only the arbitrator must be allowed to call this function.
+ /// Ruling 0 is reserved for "Not able/wanting to make a decision".
+ ///
/// @param _disputeID The identifier of the dispute in the Arbitrator contract.
/// @param _ruling Ruling given by the arbitrator.
- /// Note that 0 is reserved for "Not able/wanting to make a decision".
function rule(uint256 _disputeID, uint256 _ruling) external;
}
diff --git a/contracts/src/arbitration/interfaces/IArbitratorV2.sol b/contracts/src/arbitration/interfaces/IArbitratorV2.sol
index e2e76badb..41c7e48c5 100644
--- a/contracts/src/arbitration/interfaces/IArbitratorV2.sol
+++ b/contracts/src/arbitration/interfaces/IArbitratorV2.sol
@@ -1,43 +1,46 @@
// SPDX-License-Identifier: MIT
-pragma solidity ^0.8.24;
+pragma solidity >=0.8.0 <0.9.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "./IArbitrableV2.sol";
/// @title Arbitrator
-/// Arbitrator interface that implements the new arbitration standard.
-/// Unlike the ERC-792 this standard is not concerned with appeals, so each arbitrator can implement an appeal system that suits it the most.
-/// When developing arbitrator contracts we need to:
-/// - Define the functions for dispute creation (createDispute). Don't forget to store the arbitrated contract and the disputeID (which should be unique, may nbDisputes).
-/// - Define the functions for cost display (arbitrationCost).
-/// - Allow giving rulings. For this a function must call arbitrable.rule(disputeID, ruling).
+/// @notice Arbitrator interface for the Kleros V2 protocol.
+/// @dev Unlike the ERC-792 this standard is not concerned with appeals, so each arbitrator can implement an appeal system that suits it the most.
interface IArbitratorV2 {
- /// @dev To be emitted when a dispute is created.
+ // ************************************* //
+ // * Events * //
+ // ************************************* //
+
+ /// @notice To be emitted when a dispute is created.
/// @param _disputeID The identifier of the dispute in the Arbitrator contract.
/// @param _arbitrable The contract which created the dispute.
event DisputeCreation(uint256 indexed _disputeID, IArbitrableV2 indexed _arbitrable);
- /// @dev To be raised when a ruling is given.
+ /// @notice To be raised when a ruling is given.
/// @param _arbitrable The arbitrable receiving the ruling.
/// @param _disputeID The identifier of the dispute in the Arbitrator contract.
/// @param _ruling The ruling which was given.
event Ruling(IArbitrableV2 indexed _arbitrable, uint256 indexed _disputeID, uint256 _ruling);
- /// @dev To be emitted when an ERC20 token is added or removed as a method to pay fees.
+ /// @notice To be emitted when an ERC20 token is added or removed as a method to pay fees.
/// @param _token The ERC20 token.
/// @param _accepted Whether the token is accepted or not.
event AcceptedFeeToken(IERC20 indexed _token, bool indexed _accepted);
- /// @dev To be emitted when the fee for a particular ERC20 token is updated.
+ /// @notice To be emitted when the fee for a particular ERC20 token is updated.
/// @param _feeToken The ERC20 token.
/// @param _rateInEth The new rate of the fee token in ETH.
/// @param _rateDecimals The new decimals of the fee token rate.
event NewCurrencyRate(IERC20 indexed _feeToken, uint64 _rateInEth, uint8 _rateDecimals);
- /// @dev Create a dispute and pay for the fees in the native currency, typically ETH.
- /// Must be called by the arbitrable contract.
- /// Must pay at least arbitrationCost(_extraData).
+ // ************************************* //
+ // * State Modifiers * //
+ // ************************************* //
+
+ /// @notice Create a dispute and pay for the fees in the native currency, typically ETH.
+ /// @dev Must be called by the arbitrable contract and pay at least `arbitrationCost(_extraData)` in ETH.
/// @param _numberOfChoices The number of choices the arbitrator can choose from in this dispute.
/// @param _extraData Additional info about the dispute. We use it to pass the ID of the dispute's court (first 32 bytes), the minimum number of jurors required (next 32 bytes) and the ID of the specific dispute kit (last 32 bytes).
/// @return disputeID The identifier of the dispute created.
@@ -46,9 +49,8 @@ interface IArbitratorV2 {
bytes calldata _extraData
) external payable returns (uint256 disputeID);
- /// @dev Create a dispute and pay for the fees in a supported ERC20 token.
- /// Must be called by the arbitrable contract.
- /// Must pay at least arbitrationCost(_extraData).
+ /// @notice Create a dispute and pay for the fees in a supported ERC20 token.
+ /// @dev Must be called by the arbitrable contract and pay at least `arbitrationCost(_extraData, _feeToken)` in the supported ERC20 token.
/// @param _numberOfChoices The number of choices the arbitrator can choose from in this dispute.
/// @param _extraData Additional info about the dispute. We use it to pass the ID of the dispute's court (first 32 bytes), the minimum number of jurors required (next 32 bytes) and the ID of the specific dispute kit (last 32 bytes).
/// @param _feeToken The ERC20 token used to pay fees.
@@ -61,20 +63,24 @@ interface IArbitratorV2 {
uint256 _feeAmount
) external returns (uint256 disputeID);
- /// @dev Compute the cost of arbitration denominated in the native currency, typically ETH.
- /// It is recommended not to increase it often, as it can be highly time and gas consuming for the arbitrated contracts to cope with fee augmentation.
+ // ************************************* //
+ // * Public Views * //
+ // ************************************* //
+
+ /// @notice Compute the cost of arbitration denominated in the native currency, typically ETH.
+ /// @dev It is recommended not to increase it often, as it can be highly time and gas consuming for the arbitrated contracts to cope with fee augmentation.
/// @param _extraData Additional info about the dispute. We use it to pass the ID of the dispute's court (first 32 bytes), the minimum number of jurors required (next 32 bytes) and the ID of the specific dispute kit (last 32 bytes).
/// @return cost The arbitration cost in ETH.
function arbitrationCost(bytes calldata _extraData) external view returns (uint256 cost);
- /// @dev Compute the cost of arbitration denominated in `_feeToken`.
- /// It is recommended not to increase it often, as it can be highly time and gas consuming for the arbitrated contracts to cope with fee augmentation.
+ /// @notice Compute the cost of arbitration denominated in `_feeToken`.
+ /// @dev It is recommended not to increase it often, as it can be highly time and gas consuming for the arbitrated contracts to cope with fee augmentation.
/// @param _extraData Additional info about the dispute. We use it to pass the ID of the dispute's court (first 32 bytes), the minimum number of jurors required (next 32 bytes) and the ID of the specific dispute kit (last 32 bytes).
/// @param _feeToken The ERC20 token used to pay fees.
/// @return cost The arbitration cost in `_feeToken`.
function arbitrationCost(bytes calldata _extraData, IERC20 _feeToken) external view returns (uint256 cost);
- /// @dev Gets the current ruling of a specified dispute.
+ /// @notice Gets the current ruling of a specified dispute.
/// @param _disputeID The ID of the dispute.
/// @return ruling The current ruling.
/// @return tied Whether it's a tie or not.
diff --git a/contracts/src/arbitration/interfaces/IDisputeKit.sol b/contracts/src/arbitration/interfaces/IDisputeKit.sol
index 4c8f458cc..f5de3d8ec 100644
--- a/contracts/src/arbitration/interfaces/IDisputeKit.sol
+++ b/contracts/src/arbitration/interfaces/IDisputeKit.sol
@@ -1,18 +1,18 @@
// SPDX-License-Identifier: MIT
-pragma solidity ^0.8.24;
+pragma solidity >=0.8.0 <0.9.0;
import "./IArbitratorV2.sol";
/// @title IDisputeKit
-/// An abstraction of the Dispute Kits intended for interfacing with KlerosCore.
-/// It does not intend to abstract the interactions with the user (such as voting or appeal funding) to allow for implementation-specific parameters.
+/// @notice An abstraction of the Dispute Kits intended for interfacing with KlerosCore.
+/// @dev It does not intend to abstract the interactions with the user (such as voting or appeal funding) to allow for implementation-specific parameters.
interface IDisputeKit {
// ************************************ //
// * Events * //
// ************************************ //
- /// @dev Emitted when casting a vote to provide the justification of juror's choice.
+ /// @notice Emitted when casting a vote to provide the justification of juror's choice.
/// @param _coreDisputeID The identifier of the dispute in the Arbitrator contract.
/// @param _juror Address of the juror.
/// @param _voteIDs The identifiers of the votes in the dispute.
@@ -30,80 +30,134 @@ interface IDisputeKit {
// * State Modifiers * //
// ************************************* //
- /// @dev Creates a local dispute and maps it to the dispute ID in the Core contract.
- /// Note: Access restricted to Kleros Core only.
+ /// @notice Creates a local dispute and maps it to the dispute ID in the Core contract.
+ /// @dev Access restricted to Kleros Core only.
+ /// @dev The new `KlerosCore.Round` must be created before calling this function.
/// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.
+ /// @param _coreRoundID The ID of the round in Kleros Core, not in the Dispute Kit.
/// @param _numberOfChoices Number of choices of the dispute
/// @param _extraData Additional info about the dispute, for possible use in future dispute kits.
- /// @param _nbVotes Maximal number of votes this dispute can get. DEPRECATED as we don't need to pass it now. KC handles the count.
+ /// @param _nbVotes Maximal number of votes this dispute can get. Added for future-proofing.
function createDispute(
uint256 _coreDisputeID,
+ uint256 _coreRoundID,
uint256 _numberOfChoices,
bytes calldata _extraData,
uint256 _nbVotes
) external;
- /// @dev Draws the juror from the sortition tree. The drawn address is picked up by Kleros Core.
- /// Note: Access restricted to Kleros Core only.
+ /// @notice Draws the juror from the sortition tree. The drawn address is picked up by Kleros Core.
+ /// @dev Access restricted to Kleros Core only.
/// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.
/// @param _nonce Nonce.
/// @return drawnAddress The drawn address.
- function draw(uint256 _coreDisputeID, uint256 _nonce) external returns (address drawnAddress);
+ function draw(
+ uint256 _coreDisputeID,
+ uint256 _nonce
+ ) external returns (address drawnAddress, uint96 fromSubcourtID);
// ************************************* //
// * Public Views * //
// ************************************* //
- /// @dev Gets the current ruling of a specified dispute.
+ /// @notice Gets the current ruling of a specified dispute.
/// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.
/// @return ruling The current ruling.
/// @return tied Whether it's a tie or not.
/// @return overridden Whether the ruling was overridden by appeal funding or not.
function currentRuling(uint256 _coreDisputeID) external view returns (uint256 ruling, bool tied, bool overridden);
- /// @dev Gets the degree of coherence of a particular voter. This function is called by Kleros Core in order to determine the amount of the reward.
+ /// @notice Gets the degree of coherence of a particular voter.
+ /// @dev This function is called by Kleros Core in order to determine the amount of the reward.
/// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.
/// @param _coreRoundID The ID of the round in Kleros Core, not in the Dispute Kit.
/// @param _voteID The ID of the vote.
/// @param _feePerJuror The fee per juror.
/// @param _pnkAtStakePerJuror The PNK at stake per juror.
- /// @return The degree of coherence in basis points.
- function getDegreeOfCoherence(
+ /// @return pnkCoherence The degree of coherence in basis points for the dispute PNK reward.
+ /// @return feeCoherence The degree of coherence in basis points for the dispute fee reward.
+ function getDegreeOfCoherenceReward(
uint256 _coreDisputeID,
uint256 _coreRoundID,
uint256 _voteID,
uint256 _feePerJuror,
uint256 _pnkAtStakePerJuror
- ) external view returns (uint256);
+ ) external view returns (uint256 pnkCoherence, uint256 feeCoherence);
- /// @dev Gets the number of jurors who are eligible to a reward in this round.
+ /// @notice Gets the degree of coherence of a particular voter.
+ /// @dev This function is called by Kleros Core in order to determine the amount of the penalty.
+ /// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.
+ /// @param _coreRoundID The ID of the round in Kleros Core, not in the Dispute Kit.
+ /// @param _voteID The ID of the vote.
+ /// @param _feePerJuror The fee per juror.
+ /// @param _pnkAtStakePerJuror The PNK at stake per juror.
+ /// @return pnkCoherence The degree of coherence in basis points for the dispute PNK reward.
+ function getDegreeOfCoherencePenalty(
+ uint256 _coreDisputeID,
+ uint256 _coreRoundID,
+ uint256 _voteID,
+ uint256 _feePerJuror,
+ uint256 _pnkAtStakePerJuror
+ ) external view returns (uint256 pnkCoherence);
+
+ /// @notice Gets the number of jurors who are eligible to a reward in this round.
/// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.
/// @param _coreRoundID The ID of the round in Kleros Core, not in the Dispute Kit.
/// @return The number of coherent jurors.
function getCoherentCount(uint256 _coreDisputeID, uint256 _coreRoundID) external view returns (uint256);
- /// @dev Returns true if all of the jurors have cast their commits for the last round.
+ /// @notice Returns true if all of the jurors have cast their commits for the last round.
/// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.
/// @return Whether all of the jurors have cast their commits for the last round.
function areCommitsAllCast(uint256 _coreDisputeID) external view returns (bool);
- /// @dev Returns true if all of the jurors have cast their votes for the last round.
+ /// @notice Returns true if all of the jurors have cast their votes for the last round.
+ /// @dev This function is to be called directly by the core contract and is not for off-chain usage.
/// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.
/// @return Whether all of the jurors have cast their votes for the last round.
function areVotesAllCast(uint256 _coreDisputeID) external view returns (bool);
- /// @dev Returns true if the appeal funding is finished prematurely (e.g. when losing side didn't fund).
+ /// @notice Returns true if the appeal funding is finished prematurely (e.g. when losing side didn't fund).
+ /// @dev This function is to be called directly by the core contract and is not for off-chain usage.
/// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.
/// @return Whether the appeal funding is finished.
function isAppealFunded(uint256 _coreDisputeID) external view returns (bool);
- /// @dev Returns true if the specified voter was active in this round.
+ /// @dev Returns true if the dispute is jumping to a parent court.
+ /// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.
+ /// @return Whether the dispute is jumping to a parent court or not.
+ function earlyCourtJump(uint256 _coreDisputeID) external view returns (bool);
+
+ /// @notice Returns the number of votes after the appeal.
+ /// @param _previousDisputeKit The previous Dispute Kit.
+ /// @param _currentNbVotes The number of votes before the appeal.
+ /// @return The number of votes after the appeal.
+ function getNbVotesAfterAppeal(
+ IDisputeKit _previousDisputeKit,
+ uint256 _currentNbVotes
+ ) external view returns (uint256);
+
+ /// @notice Returns the dispute kit ID to be used after court jump by Kleros Core.
+ /// @return The ID of the dispute kit in Kleros Core disputeKits array.
+ function getJumpDisputeKitID() external view returns (uint256);
+
+ /// @notice Returns true if the specified voter was active in this round.
/// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.
/// @param _coreRoundID The ID of the round in Kleros Core, not in the Dispute Kit.
/// @param _voteID The ID of the voter.
/// @return Whether the voter was active or not.
function isVoteActive(uint256 _coreDisputeID, uint256 _coreRoundID, uint256 _voteID) external view returns (bool);
+ /// @notice Returns the info of the specified round in the core contract.
+ /// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.
+ /// @param _coreRoundID The ID of the round in Kleros Core, not in the Dispute Kit.
+ /// @param _choice The choice to query.
+ /// @return winningChoice The winning choice of this round.
+ /// @return tied Whether it's a tie or not.
+ /// @return totalVoted Number of jurors who cast the vote already.
+ /// @return totalCommited Number of jurors who cast the commit already (only relevant for hidden votes).
+ /// @return nbVoters Total number of voters in this round.
+ /// @return choiceCount Number of votes cast for the queried choice.
function getRoundInfo(
uint256 _coreDisputeID,
uint256 _coreRoundID,
@@ -120,6 +174,14 @@ interface IDisputeKit {
uint256 choiceCount
);
+ /// @notice Returns the vote information for a given vote ID.
+ /// @param _coreDisputeID The ID of the dispute in Kleros Core.
+ /// @param _coreRoundID The ID of the round in Kleros Core.
+ /// @param _voteID The ID of the vote.
+ /// @return account The address of the juror who cast the vote.
+ /// @return commit The commit of the vote.
+ /// @return choice The choice that got the vote.
+ /// @return voted Whether the vote was cast or not.
function getVoteInfo(
uint256 _coreDisputeID,
uint256 _coreRoundID,
diff --git a/contracts/src/arbitration/interfaces/IDisputeTemplateRegistry.sol b/contracts/src/arbitration/interfaces/IDisputeTemplateRegistry.sol
index 3ce9d522d..cfa207448 100644
--- a/contracts/src/arbitration/interfaces/IDisputeTemplateRegistry.sol
+++ b/contracts/src/arbitration/interfaces/IDisputeTemplateRegistry.sol
@@ -1,11 +1,15 @@
// SPDX-License-Identifier: MIT
-pragma solidity ^0.8.24;
+pragma solidity >=0.8.0 <0.9.0;
/// @title IDisputeTemplate
/// @notice Dispute Template interface.
interface IDisputeTemplateRegistry {
- /// @dev To be emitted when a new dispute template is created.
+ // ************************************* //
+ // * Events * //
+ // ************************************* //
+
+ /// @notice To be emitted when a new dispute template is created.
/// @param _templateId The identifier of the dispute template.
/// @param _templateTag An optional tag for the dispute template, such as "registration" or "removal".
/// @param _templateData The template data.
@@ -17,6 +21,15 @@ interface IDisputeTemplateRegistry {
string _templateDataMappings
);
+ // ************************************* //
+ // * State Modifiers * //
+ // ************************************* //
+
+ /// @notice Registers a new dispute template.
+ /// @param _templateTag An optional tag for the dispute template, such as "registration" or "removal".
+ /// @param _templateData The template data.
+ /// @param _templateDataMappings The data mappings for the template.
+ /// @return templateId The identifier of the dispute template.
function setDisputeTemplate(
string memory _templateTag,
string memory _templateData,
diff --git a/contracts/src/arbitration/interfaces/IEvidence.sol b/contracts/src/arbitration/interfaces/IEvidence.sol
index 0be6082b5..5acf10d27 100644
--- a/contracts/src/arbitration/interfaces/IEvidence.sol
+++ b/contracts/src/arbitration/interfaces/IEvidence.sol
@@ -1,12 +1,12 @@
// SPDX-License-Identifier: MIT
-pragma solidity ^0.8.24;
+pragma solidity >=0.8.0 <0.9.0;
/// @title IEvidence
interface IEvidence {
- /// @dev To be raised when evidence is submitted. Should point to the resource (evidences are not to be stored on chain due to gas considerations).
- /// @param _externalDisputeID Unique identifier for this dispute outside Kleros. It's the submitter responsability to submit the right external dispute ID.
- /// @param _party The address of the party submiting the evidence. Note that 0x0 refers to evidence not submitted by any party.
+ /// @notice To be raised when evidence is submitted. Should point to the resource (evidences are not to be stored on chain due to gas considerations).
+ /// @param _arbitratorDisputeID The identifier of the dispute in the Arbitrator contract.
+ /// @param _party The address of the party submitting the evidence.
/// @param _evidence Stringified evidence object, example: '{"name" : "Justification", "description" : "Description", "fileURI" : "/ipfs/QmWQV5ZFFhEJiW8Lm7ay2zLxC2XS4wx1b2W7FfdrLMyQQc"}'.
- event Evidence(uint256 indexed _externalDisputeID, address indexed _party, string _evidence);
+ event Evidence(uint256 indexed _arbitratorDisputeID, address indexed _party, string _evidence);
}
diff --git a/contracts/src/arbitration/interfaces/ISortitionModule.sol b/contracts/src/arbitration/interfaces/ISortitionModule.sol
index 183fc331a..ccc66a2f5 100644
--- a/contracts/src/arbitration/interfaces/ISortitionModule.sol
+++ b/contracts/src/arbitration/interfaces/ISortitionModule.sol
@@ -1,25 +1,75 @@
// SPDX-License-Identifier: MIT
-pragma solidity ^0.8.24;
+
+pragma solidity >=0.8.0 <0.9.0;
import "../../libraries/Constants.sol";
+/// @title ISortitionModule
+/// @notice Interface for the SortitionModule contract.
interface ISortitionModule {
+ // ************************************* //
+ // * Enums * //
+ // ************************************* //
+
enum Phase {
staking, // Stake sum trees can be updated. Pass after `minStakingTime` passes and there is at least one dispute without jurors.
generating, // Waiting for a random number. Pass as soon as it is ready.
drawing // Jurors can be drawn. Pass after all disputes have jurors or `maxDrawingTime` passes.
}
- event NewPhase(Phase _phase);
+ // ************************************* //
+ // * Events * //
+ // ************************************* //
- function createTree(bytes32 _key, bytes memory _extraData) external;
+ /// @notice Emitted when the phase is changed.
+ /// @param _phase The new phase.
+ event NewPhase(Phase _phase);
+ // ************************************* //
+ // * State Modifiers * //
+ // ************************************* //
+
+ /// @notice Passes the phase.
+ function passPhase() external;
+
+ /// @notice Executes the next delayed stakes.
+ /// @param _iterations The number of delayed stakes to execute.
+ function executeDelayedStakes(uint256 _iterations) external;
+
+ /// @notice Create a sortition sum tree at the specified key.
+ /// @param _courtID The ID of the court.
+ /// @param _extraData Extra data that contains the number of children each node in the tree should have.
+ function createTree(uint96 _courtID, bytes memory _extraData) external;
+
+ /// @notice Validate the specified juror's new stake for a court.
+ /// @dev No state changes should be made when returning stakingResult != Successful, otherwise delayed stakes might break invariants.
+ /// @param _account The address of the juror.
+ /// @param _courtID The ID of the court.
+ /// @param _newStake The new stake.
+ /// @param _noDelay True if the stake change should not be delayed.
+ /// @return pnkDeposit The amount of PNK to be deposited.
+ /// @return pnkWithdrawal The amount of PNK to be withdrawn.
+ /// @return stakingResult The result of the staking operation.
function validateStake(
address _account,
uint96 _courtID,
- uint256 _newStake
+ uint256 _newStake,
+ bool _noDelay
) external returns (uint256 pnkDeposit, uint256 pnkWithdrawal, StakingResult stakingResult);
+ /// @notice Update the state of the stakes, called by KC at the end of setStake flow.
+ ///
+ /// @dev `O(n + p * log_k(j))` where
+ /// `n` is the number of courts the juror has staked in,
+ /// `p` is the depth of the court tree,
+ /// `k` is the minimum number of children per node of one of these courts' sortition sum tree,
+ /// and `j` is the maximum number of jurors that ever staked in one of these courts simultaneously.
+ ///
+ /// @param _account The address of the juror.
+ /// @param _courtID The ID of the court.
+ /// @param _pnkDeposit The amount of PNK to be deposited.
+ /// @param _pnkWithdrawal The amount of PNK to be withdrawn.
+ /// @param _newStake The new stake.
function setStake(
address _account,
uint96 _courtID,
@@ -28,35 +78,139 @@ interface ISortitionModule {
uint256 _newStake
) external;
- function setJurorInactive(address _account) external;
-
+ /// @notice Update the state of the stakes with a PNK penalty, called by KC during rewards execution.
+ ///
+ /// @dev `O(n + p * log_k(j))` where
+ /// `n` is the number of courts the juror has staked in,
+ /// `p` is the depth of the court tree,
+ /// `k` is the minimum number of children per node of one of these courts' sortition sum tree,
+ /// and `j` is the maximum number of jurors that ever staked in one of these courts simultaneously.
+ ///
+ /// @param _account The address of the juror.
+ /// @param _courtID The ID of the court.
+ /// @param _penalty The amount of PNK to be deducted.
+ /// @return pnkBalance The updated total PNK balance of the juror, including the penalty.
+ /// @return newCourtStake The updated stake of the juror in the court.
+ /// @return availablePenalty The amount of PNK that was actually deducted.
+ function setStakePenalty(
+ address _account,
+ uint96 _courtID,
+ uint256 _penalty
+ ) external returns (uint256 pnkBalance, uint256 newCourtStake, uint256 availablePenalty);
+
+ /// @notice Update the state of the stakes with a PNK reward deposit, called by KC during rewards execution.
+ ///
+ /// @dev `O(n + p * log_k(j))` where
+ /// `O(n + p * log_k(j))` where
+ /// `n` is the number of courts the juror has staked in,
+ /// `p` is the depth of the court tree,
+ /// `k` is the minimum number of children per node of one of these courts' sortition sum tree,
+ /// and `j` is the maximum number of jurors that ever staked in one of these courts simultaneously.
+ ///
+ /// @param _account The address of the juror.
+ /// @param _courtID The ID of the court.
+ /// @param _reward The amount of PNK to be deposited as a reward.
+ /// @return success True if the reward was added successfully.
+ function setStakeReward(address _account, uint96 _courtID, uint256 _reward) external returns (bool success);
+
+ /// @notice Unstakes the inactive juror from all courts.
+ ///
+ /// @dev `O(n * (p * log_k(j)) )` where
+ /// `O(n * (p * log_k(j)) )` where
+ /// `n` is the number of courts the juror has staked in,
+ /// `p` is the depth of the court tree,
+ /// `k` is the minimum number of children per node of one of these courts' sortition sum tree,
+ /// and `j` is the maximum number of jurors that ever staked in one of these courts simultaneously.
+ ///
+ /// @param _account The juror to unstake.
+ function forcedUnstakeAllCourts(address _account) external;
+
+ /// @notice Unstakes the inactive juror from a specific court.
+ ///
+ /// @dev `O(n * (p * log_k(j)) )` where
+ /// `n` is the number of courts the juror has staked in,
+ /// `p` is the depth of the court tree,
+ /// `k` is the minimum number of children per node of one of these courts' sortition sum tree,
+ /// and `j` is the maximum number of jurors that ever staked in one of these courts simultaneously.
+ ///
+ /// @param _account The juror to unstake.
+ /// @param _courtID The ID of the court.
+ function forcedUnstake(address _account, uint96 _courtID) external;
+
+ /// @notice Locks the tokens of the drawn juror.
+ /// @param _account The address of the juror.
+ /// @param _relativeAmount The amount to lock.
function lockStake(address _account, uint256 _relativeAmount) external;
+ /// @notice Unlocks the tokens of the drawn juror.
+ /// @param _account The address of the juror.
+ /// @param _relativeAmount The amount to unlock.
function unlockStake(address _account, uint256 _relativeAmount) external;
- function penalizeStake(
- address _account,
- uint256 _relativeAmount
- ) external returns (uint256 pnkBalance, uint256 availablePenalty);
+ /// @notice Triggers the state changes after dispute creation.
+ /// @param _disputeID The ID of the dispute.
+ /// @param _roundID The ID of the round.
+ function createDisputeHook(uint256 _disputeID, uint256 _roundID) external;
- function notifyRandomNumber(uint256 _drawnNumber) external;
+ /// @notice Triggers the state changes after drawing.
+ /// @param _disputeID The ID of the dispute.
+ /// @param _roundID The ID of the round.
+ function postDrawHook(uint256 _disputeID, uint256 _roundID) external;
- function draw(bytes32 _court, uint256 _coreDisputeID, uint256 _nonce) external view returns (address);
+ /// @notice Gives back the locked PNKs in case the juror fully unstaked earlier.
+ ///
+ /// @dev that since locked and staked PNK are async it is possible for the juror to have positive staked PNK balance
+ /// while having 0 stake in courts and 0 locked tokens (eg. when the juror fully unstaked during dispute and later got his tokens unlocked).
+ /// In this case the juror can use this function to withdraw the leftover tokens.
+ /// Also note that if the juror has some leftover PNK while not fully unstaked he'll have to manually unstake from all courts to trigger this function.
+ ///
+ /// @param _account The juror whose PNK to withdraw.
+ function withdrawLeftoverPNK(address _account) external;
+ // ************************************* //
+ // * Public Views * //
+ // ************************************* //
+
+ /// @notice Draw an ID from a tree using a number.
+ ///
+ /// @dev that this function reverts if the sum of all values in the tree is 0.
+ /// `O(k * log_k(n))` where
+ /// `k` is the maximum number of children per node in the tree,
+ /// and `n` is the maximum number of nodes ever appended.
+ ///
+ /// @param _courtID The ID of the court.
+ /// @param _coreDisputeID Index of the dispute in Kleros Core.
+ /// @param _nonce Nonce to hash with random number.
+ /// @return drawnAddress The drawn address.
+ function draw(
+ uint96 _courtID,
+ uint256 _coreDisputeID,
+ uint256 _nonce
+ ) external view returns (address drawnAddress, uint96 fromSubcourtID);
+
+ /// @notice Gets the balance of a juror in a court.
+ /// @param _juror The address of the juror.
+ /// @param _courtID The ID of the court.
+ /// @return totalStakedPnk The total amount of tokens staked including locked tokens and penalty deductions. Equivalent to the effective stake in the General court.
+ /// @return totalLocked The total amount of tokens locked in disputes.
+ /// @return stakedInCourt The amount of tokens staked in the specified court including locked tokens and penalty deductions.
+ /// @return nbCourts The number of courts the juror has directly staked in.
function getJurorBalance(
address _juror,
uint96 _courtID
- ) external view returns (uint256 totalStaked, uint256 totalLocked, uint256 stakedInCourt, uint256 nbCourts);
+ ) external view returns (uint256 totalStakedPnk, uint256 totalLocked, uint256 stakedInCourt, uint256 nbCourts);
+ /// @notice Gets the court identifiers where a specific `_juror` has staked.
+ /// @param _juror The address of the juror.
function getJurorCourtIDs(address _juror) external view returns (uint96[] memory);
+ /// @notice Checks if the juror is staked in any court.
+ /// @param _juror The address of the juror.
+ /// @return Whether the juror is staked or not.
function isJurorStaked(address _juror) external view returns (bool);
+ /// @notice Checks if the juror has any leftover PNK in the contract.
+ /// @param _juror The address of the juror.
+ /// @return Whether the juror has leftover PNK.
function getJurorLeftoverPNK(address _juror) external view returns (uint256);
-
- function createDisputeHook(uint256 _disputeID, uint256 _roundID) external;
-
- function postDrawHook(uint256 _disputeID, uint256 _roundID) external;
-
- function withdrawLeftoverPNK(address _account) external;
}
diff --git a/contracts/src/arbitration/university/KlerosCoreUniversity.sol b/contracts/src/arbitration/university/KlerosCoreUniversity.sol
index 35fd5262c..39f4414a4 100644
--- a/contracts/src/arbitration/university/KlerosCoreUniversity.sol
+++ b/contracts/src/arbitration/university/KlerosCoreUniversity.sol
@@ -6,16 +6,16 @@ import {IArbitrableV2, IArbitratorV2} from "../interfaces/IArbitratorV2.sol";
import {IDisputeKit} from "../interfaces/IDisputeKit.sol";
import {ISortitionModuleUniversity} from "./ISortitionModuleUniversity.sol";
import {SafeERC20, IERC20} from "../../libraries/SafeERC20.sol";
-import "../../libraries/Constants.sol";
import {UUPSProxiable} from "../../proxy/UUPSProxiable.sol";
import {Initializable} from "../../proxy/Initializable.sol";
+import "../../libraries/Constants.sol";
/// @title KlerosCoreUniversity
-/// Core arbitrator contract for educational purposes.
+/// @notice Core arbitrator contract for educational purposes.
contract KlerosCoreUniversity is IArbitratorV2, UUPSProxiable, Initializable {
using SafeERC20 for IERC20;
- string public constant override version = "0.8.0";
+ string public constant override version = "2.0.0";
// ************************************* //
// * Enums / Structs * //
@@ -39,7 +39,7 @@ contract KlerosCoreUniversity is IArbitratorV2, UUPSProxiable, Initializable {
uint256 jurorsForCourtJump; // The appeal after the one that reaches this number of jurors will go to the parent court if any.
uint256[4] timesPerPeriod; // The time allotted to each dispute period in the form `timesPerPeriod[period]`.
mapping(uint256 disputeKitId => bool) supportedDisputeKits; // True if DK with this ID is supported by the court. Note that each court must support classic dispute kit.
- bool disabled; // True if the court is disabled. Unused for now, will be implemented later.
+ uint256[10] __gap; // Reserved slots for future upgrades.
}
struct Dispute {
@@ -49,6 +49,7 @@ contract KlerosCoreUniversity is IArbitratorV2, UUPSProxiable, Initializable {
bool ruled; // True if the ruling has been executed, false otherwise.
uint256 lastPeriodChange; // The last time the period was changed.
Round[] rounds;
+ uint256[10] __gap; // Reserved slots for future upgrades.
}
struct Round {
@@ -59,10 +60,12 @@ contract KlerosCoreUniversity is IArbitratorV2, UUPSProxiable, Initializable {
uint256 repartitions; // A counter of reward repartitions made in this round.
uint256 pnkPenalties; // The amount of PNKs collected from penalties in this round.
address[] drawnJurors; // Addresses of the jurors that were drawn in this round.
+ uint96[] drawnJurorFromCourtIDs; // The courtIDs where the juror was drawn from, possibly their stake in a subcourt.
uint256 sumFeeRewardPaid; // Total sum of arbitration fees paid to coherent jurors as a reward in this round.
uint256 sumPnkRewardPaid; // Total sum of PNK paid to coherent jurors as a reward in this round.
IERC20 feeToken; // The token used for paying fees in this round.
uint256 drawIterations; // The number of iterations passed drawing the jurors for this round.
+ uint256[10] __gap; // Reserved slots for future upgrades.
}
// Workaround "stack too deep" errors
@@ -87,10 +90,9 @@ contract KlerosCoreUniversity is IArbitratorV2, UUPSProxiable, Initializable {
// * Storage * //
// ************************************* //
- uint256 private constant ALPHA_DIVISOR = 1e4; // The number to divide `Court.alpha` by.
uint256 private constant NON_PAYABLE_AMOUNT = (2 ** 256 - 2) / 2; // An amount higher than the supply of ETH.
- address public governor; // The governor of the contract.
+ address public owner; // The owner of the contract.
address public instructor; // The instructor who is allowed to choose the jurors.
IERC20 public pinakion; // The Pinakion token contract.
address public jurorProsecutionModule; // The module for juror's prosecution.
@@ -142,20 +144,21 @@ contract KlerosCoreUniversity is IArbitratorV2, UUPSProxiable, Initializable {
uint256 indexed _fromDisputeKitID,
uint256 _toDisputeKitID
);
- event TokenAndETHShift(
+ event JurorRewardPenalty(
address indexed _account,
uint256 indexed _disputeID,
uint256 indexed _roundID,
- uint256 _degreeOfCoherency,
- int256 _pnkAmount,
- int256 _feeAmount,
+ uint256 _degreeOfCoherencyPnk,
+ uint256 _degreeOfCoherencyFee,
+ int256 _amountPnk,
+ int256 _amountFee,
IERC20 _feeToken
);
event LeftoverRewardSent(
uint256 indexed _disputeID,
uint256 indexed _roundID,
- uint256 _pnkAmount,
- uint256 _feeAmount,
+ uint256 _amountPnk,
+ uint256 _amountFee,
IERC20 _feeToken
);
@@ -163,8 +166,8 @@ contract KlerosCoreUniversity is IArbitratorV2, UUPSProxiable, Initializable {
// * Function Modifiers * //
// ************************************* //
- modifier onlyByGovernor() {
- if (governor != msg.sender) revert GovernorOnly();
+ modifier onlyByOwner() {
+ if (owner != msg.sender) revert OwnerOnly();
_;
}
@@ -173,8 +176,8 @@ contract KlerosCoreUniversity is IArbitratorV2, UUPSProxiable, Initializable {
_;
}
- modifier onlyByGovernorOrInstructor() {
- if (msg.sender != governor && msg.sender != instructor) revert GovernorOrInstructorOnly();
+ modifier onlyByOwnerOrInstructor() {
+ if (msg.sender != owner && msg.sender != instructor) revert OwnerOrInstructorOnly();
_;
}
@@ -187,8 +190,8 @@ contract KlerosCoreUniversity is IArbitratorV2, UUPSProxiable, Initializable {
_disableInitializers();
}
- /// @dev Initializer (constructor equivalent for upgradable contracts).
- /// @param _governor The governor's address.
+ /// @notice Initializer (constructor equivalent for upgradable contracts).
+ /// @param _owner The owner's address.
/// @param _instructor The address of the instructor.
/// @param _pinakion The address of the token contract.
/// @param _jurorProsecutionModule The address of the juror prosecution module.
@@ -198,7 +201,7 @@ contract KlerosCoreUniversity is IArbitratorV2, UUPSProxiable, Initializable {
/// @param _timesPerPeriod The `timesPerPeriod` property value of the general court.
/// @param _sortitionModuleAddress The sortition module responsible for sortition of the jurors.
function initialize(
- address _governor,
+ address _owner,
address _instructor,
IERC20 _pinakion,
address _jurorProsecutionModule,
@@ -207,8 +210,8 @@ contract KlerosCoreUniversity is IArbitratorV2, UUPSProxiable, Initializable {
uint256[4] memory _courtParameters,
uint256[4] memory _timesPerPeriod,
ISortitionModuleUniversity _sortitionModuleAddress
- ) external reinitializer(1) {
- governor = _governor;
+ ) external initializer {
+ owner = _owner;
instructor = _instructor;
pinakion = _pinakion;
jurorProsecutionModule = _jurorProsecutionModule;
@@ -256,65 +259,61 @@ contract KlerosCoreUniversity is IArbitratorV2, UUPSProxiable, Initializable {
// ************************************* //
/* @dev Access Control to perform implementation upgrades (UUPS Proxiable)
- * @dev Only the governor can perform upgrades (`onlyByGovernor`)
+ * @dev Only the owner can perform upgrades (`onlyByOwner`)
*/
- function _authorizeUpgrade(address) internal view override onlyByGovernor {
+ function _authorizeUpgrade(address) internal view override onlyByOwner {
// NOP
}
- /// @dev Allows the governor to call anything on behalf of the contract.
+ /// @notice Allows the owner to call anything on behalf of the contract.
/// @param _destination The destination of the call.
/// @param _amount The value sent with the call.
/// @param _data The data sent with the call.
- function executeGovernorProposal(
- address _destination,
- uint256 _amount,
- bytes memory _data
- ) external onlyByGovernor {
+ function executeOwnerProposal(address _destination, uint256 _amount, bytes memory _data) external onlyByOwner {
(bool success, ) = _destination.call{value: _amount}(_data);
if (!success) revert UnsuccessfulCall();
}
- /// @dev Changes the `governor` storage variable.
- /// @param _governor The new value for the `governor` storage variable.
- function changeGovernor(address payable _governor) external onlyByGovernor {
- governor = _governor;
+ /// @notice Changes the `owner` storage variable.
+ /// @param _owner The new value for the `owner` storage variable.
+ function changeOwner(address payable _owner) external onlyByOwner {
+ owner = _owner;
}
- /// @dev Changes the `instructor` storage variable.
+ /// @notice Changes the `instructor` storage variable.
/// @param _instructor The new value for the `instructor` storage variable.
- function changeInstructor(address _instructor) external onlyByGovernorOrInstructor {
+ function changeInstructor(address _instructor) external onlyByOwnerOrInstructor {
instructor = _instructor;
}
- /// @dev Changes the `pinakion` storage variable.
+ /// @notice Changes the `pinakion` storage variable.
/// @param _pinakion The new value for the `pinakion` storage variable.
- function changePinakion(IERC20 _pinakion) external onlyByGovernor {
+ function changePinakion(IERC20 _pinakion) external onlyByOwner {
pinakion = _pinakion;
}
- /// @dev Changes the `jurorProsecutionModule` storage variable.
+ /// @notice Changes the `jurorProsecutionModule` storage variable.
/// @param _jurorProsecutionModule The new value for the `jurorProsecutionModule` storage variable.
- function changeJurorProsecutionModule(address _jurorProsecutionModule) external onlyByGovernor {
+ function changeJurorProsecutionModule(address _jurorProsecutionModule) external onlyByOwner {
jurorProsecutionModule = _jurorProsecutionModule;
}
- /// @dev Changes the `_sortitionModule` storage variable.
+ /// @notice Changes the `_sortitionModule` storage variable.
/// Note that the new module should be initialized for all courts.
/// @param _sortitionModule The new value for the `sortitionModule` storage variable.
- function changeSortitionModule(ISortitionModuleUniversity _sortitionModule) external onlyByGovernor {
+ function changeSortitionModule(ISortitionModuleUniversity _sortitionModule) external onlyByOwner {
sortitionModule = _sortitionModule;
}
- /// @dev Add a new supported dispute kit module to the court.
+ /// @notice Add a new supported dispute kit module to the court.
/// @param _disputeKitAddress The address of the dispute kit contract.
- function addNewDisputeKit(IDisputeKit _disputeKitAddress) external onlyByGovernor {
+ function addNewDisputeKit(IDisputeKit _disputeKitAddress) external onlyByOwner {
uint256 disputeKitID = disputeKits.length;
disputeKits.push(_disputeKitAddress);
emit DisputeKitCreated(disputeKitID, _disputeKitAddress);
}
- /// @dev Creates a court under a specified parent court.
+ /// @notice Creates a court under a specified parent court.
/// @param _parent The `parent` property value of the court.
/// @param _hiddenVotes The `hiddenVotes` property value of the court.
/// @param _minStake The `minStake` property value of the court.
@@ -332,7 +331,7 @@ contract KlerosCoreUniversity is IArbitratorV2, UUPSProxiable, Initializable {
uint256 _jurorsForCourtJump,
uint256[4] memory _timesPerPeriod,
uint256[] memory _supportedDisputeKits
- ) external onlyByGovernor {
+ ) external onlyByOwner {
if (courts[_parent].minStake > _minStake) revert MinStakeLowerThanParentCourt();
if (_supportedDisputeKits.length == 0) revert UnsupportedDisputeKit();
if (_parent == FORKING_COURT) revert InvalidForkingCourtAsParent();
@@ -381,7 +380,7 @@ contract KlerosCoreUniversity is IArbitratorV2, UUPSProxiable, Initializable {
uint256 _feeForJuror,
uint256 _jurorsForCourtJump,
uint256[4] memory _timesPerPeriod
- ) external onlyByGovernor {
+ ) external onlyByOwner {
Court storage court = courts[_courtID];
if (_courtID != GENERAL_COURT && courts[court.parent].minStake > _minStake) {
revert MinStakeLowerThanParentCourt();
@@ -408,11 +407,11 @@ contract KlerosCoreUniversity is IArbitratorV2, UUPSProxiable, Initializable {
);
}
- /// @dev Adds/removes court's support for specified dispute kits.
+ /// @notice Adds/removes court's support for specified dispute kits.
/// @param _courtID The ID of the court.
/// @param _disputeKitIDs The IDs of dispute kits which support should be added/removed.
/// @param _enable Whether add or remove the dispute kits from the court.
- function enableDisputeKits(uint96 _courtID, uint256[] memory _disputeKitIDs, bool _enable) external onlyByGovernor {
+ function enableDisputeKits(uint96 _courtID, uint256[] memory _disputeKitIDs, bool _enable) external onlyByOwner {
for (uint256 i = 0; i < _disputeKitIDs.length; i++) {
if (_enable) {
if (_disputeKitIDs[i] == 0 || _disputeKitIDs[i] >= disputeKits.length) {
@@ -429,19 +428,19 @@ contract KlerosCoreUniversity is IArbitratorV2, UUPSProxiable, Initializable {
}
}
- /// @dev Changes the supported fee tokens.
+ /// @notice Changes the supported fee tokens.
/// @param _feeToken The fee token.
/// @param _accepted Whether the token is supported or not as a method of fee payment.
- function changeAcceptedFeeTokens(IERC20 _feeToken, bool _accepted) external onlyByGovernor {
+ function changeAcceptedFeeTokens(IERC20 _feeToken, bool _accepted) external onlyByOwner {
currencyRates[_feeToken].feePaymentAccepted = _accepted;
emit AcceptedFeeToken(_feeToken, _accepted);
}
- /// @dev Changes the currency rate of a fee token.
+ /// @notice Changes the currency rate of a fee token.
/// @param _feeToken The fee token.
/// @param _rateInEth The new rate of the fee token in ETH.
/// @param _rateDecimals The new decimals of the fee token rate.
- function changeCurrencyRates(IERC20 _feeToken, uint64 _rateInEth, uint8 _rateDecimals) external onlyByGovernor {
+ function changeCurrencyRates(IERC20 _feeToken, uint64 _rateInEth, uint8 _rateDecimals) external onlyByOwner {
currencyRates[_feeToken].rateInEth = _rateInEth;
currencyRates[_feeToken].rateDecimals = _rateDecimals;
emit NewCurrencyRate(_feeToken, _rateInEth, _rateDecimals);
@@ -451,24 +450,25 @@ contract KlerosCoreUniversity is IArbitratorV2, UUPSProxiable, Initializable {
// * State Modifiers * //
// ************************************* //
- /// @dev Sets the caller's stake in a court.
+ /// @notice Sets the caller's stake in a court.
/// @param _courtID The ID of the court.
/// @param _newStake The new stake.
/// Note that the existing delayed stake will be nullified as non-relevant.
function setStake(uint96 _courtID, uint256 _newStake) external {
- _setStake(msg.sender, _courtID, _newStake, OnError.Revert);
+ _setStake(msg.sender, _courtID, _newStake, false, OnError.Revert);
}
- /// @dev Sets the stake of a specified account in a court, typically to apply a delayed stake or unstake inactive jurors.
+ /// @notice Sets the stake of a specified account in a court, typically to apply a delayed stake or unstake inactive jurors.
/// @param _account The account whose stake is being set.
/// @param _courtID The ID of the court.
/// @param _newStake The new stake.
- function setStakeBySortitionModule(address _account, uint96 _courtID, uint256 _newStake) external {
+ /// @return True if the stake was set successfully.
+ function setStakeBySortitionModule(address _account, uint96 _courtID, uint256 _newStake) external returns (bool) {
if (msg.sender != address(sortitionModule)) revert SortitionModuleOnly();
- _setStake(_account, _courtID, _newStake, OnError.Return);
+ return _setStake(_account, _courtID, _newStake, true, OnError.Return);
}
- /// @dev Transfers PNK to the juror by SortitionModule.
+ /// @notice Transfers PNK to the juror by SortitionModule.
/// @param _account The account of the juror whose PNK to transfer.
/// @param _amount The amount to transfer.
function transferBySortitionModule(address _account, uint256 _amount) external {
@@ -526,17 +526,17 @@ contract KlerosCoreUniversity is IArbitratorV2, UUPSProxiable, Initializable {
: convertEthToTokenAmount(_feeToken, court.feeForJuror);
round.nbVotes = _feeAmount / feeForJuror;
round.disputeKitID = disputeKitID;
- round.pnkAtStakePerJuror = (court.minStake * court.alpha) / ALPHA_DIVISOR;
+ round.pnkAtStakePerJuror = (court.minStake * court.alpha) / ONE_BASIS_POINT;
round.totalFeesForJurors = _feeAmount;
round.feeToken = IERC20(_feeToken);
sortitionModule.createDisputeHook(disputeID, 0); // Default round ID.
- disputeKit.createDispute(disputeID, _numberOfChoices, _extraData, round.nbVotes);
+ disputeKit.createDispute(disputeID, 0, _numberOfChoices, _extraData, round.nbVotes);
emit DisputeCreation(disputeID, IArbitrableV2(msg.sender));
}
- /// @dev Passes the period of a specified dispute.
+ /// @notice Passes the period of a specified dispute.
/// @param _disputeID The ID of the dispute.
function passPeriod(uint256 _disputeID) external {
Dispute storage dispute = disputes[_disputeID];
@@ -586,10 +586,10 @@ contract KlerosCoreUniversity is IArbitratorV2, UUPSProxiable, Initializable {
emit NewPeriod(_disputeID, dispute.period);
}
- /// @dev Draws one juror for the dispute until the number votes paid for is reached.
+ /// @notice Draws one juror for the dispute until the number votes paid for is reached.
/// @param _disputeID The ID of the dispute.
/// @param _juror The address of the juror to draw.
- function draw(uint256 _disputeID, address _juror) external onlyByGovernorOrInstructor {
+ function draw(uint256 _disputeID, address _juror) external onlyByOwnerOrInstructor {
Dispute storage dispute = disputes[_disputeID];
uint256 currentRound = dispute.rounds.length - 1;
Round storage round = dispute.rounds[currentRound];
@@ -600,13 +600,14 @@ contract KlerosCoreUniversity is IArbitratorV2, UUPSProxiable, Initializable {
{
IDisputeKit disputeKit = disputeKits[round.disputeKitID];
uint256 iteration = round.drawIterations + 1;
- address drawnAddress = disputeKit.draw(_disputeID, iteration);
+ (address drawnAddress, uint96 fromSubcourtID) = disputeKit.draw(_disputeID, iteration);
if (drawnAddress == address(0)) {
revert NoJurorDrawn();
}
sortitionModule.lockStake(drawnAddress, round.pnkAtStakePerJuror);
emit Draw(drawnAddress, _disputeID, currentRound, round.drawnJurors.length);
round.drawnJurors.push(drawnAddress);
+ round.drawnJurorFromCourtIDs.push(fromSubcourtID != 0 ? fromSubcourtID : dispute.courtID);
if (round.drawnJurors.length == round.nbVotes) {
sortitionModule.postDrawHook(_disputeID, currentRound);
}
@@ -615,8 +616,8 @@ contract KlerosCoreUniversity is IArbitratorV2, UUPSProxiable, Initializable {
sortitionModule.setTransientJuror(address(0));
}
- /// @dev Appeals the ruling of a specified dispute.
- /// Note: Access restricted to the Dispute Kit for this `disputeID`.
+ /// @notice Appeals the ruling of a specified dispute.
+ /// @dev Access restricted to the Dispute Kit for this `disputeID`.
/// @param _disputeID The ID of the dispute.
/// @param _numberOfChoices Number of choices for the dispute. Can be required during court jump.
/// @param _extraData Extradata for the dispute. Can be required during court jump.
@@ -634,6 +635,7 @@ contract KlerosCoreUniversity is IArbitratorV2, UUPSProxiable, Initializable {
// Warning: the extra round must be created before calling disputeKit.createDispute()
Round storage extraRound = dispute.rounds.push();
+ uint256 extraRoundID = dispute.rounds.length - 1;
if (round.nbVotes >= courts[newCourtID].jurorsForCourtJump) {
// Jump to parent court.
@@ -645,7 +647,7 @@ contract KlerosCoreUniversity is IArbitratorV2, UUPSProxiable, Initializable {
}
if (newCourtID != dispute.courtID) {
- emit CourtJump(_disputeID, dispute.rounds.length - 1, dispute.courtID, newCourtID);
+ emit CourtJump(_disputeID, extraRoundID, dispute.courtID, newCourtID);
}
}
@@ -655,17 +657,18 @@ contract KlerosCoreUniversity is IArbitratorV2, UUPSProxiable, Initializable {
Court storage court = courts[newCourtID];
extraRound.nbVotes = msg.value / court.feeForJuror; // As many votes that can be afforded by the provided funds.
- extraRound.pnkAtStakePerJuror = (court.minStake * court.alpha) / ALPHA_DIVISOR;
+ extraRound.pnkAtStakePerJuror = (court.minStake * court.alpha) / ONE_BASIS_POINT;
extraRound.totalFeesForJurors = msg.value;
extraRound.disputeKitID = newDisputeKitID;
- sortitionModule.createDisputeHook(_disputeID, dispute.rounds.length - 1);
+ sortitionModule.createDisputeHook(_disputeID, extraRoundID);
// Dispute kit was changed, so create a dispute in the new DK contract.
if (extraRound.disputeKitID != round.disputeKitID) {
emit DisputeKitJump(_disputeID, dispute.rounds.length - 1, round.disputeKitID, extraRound.disputeKitID);
disputeKits[extraRound.disputeKitID].createDispute(
_disputeID,
+ extraRoundID,
_numberOfChoices,
_extraData,
extraRound.nbVotes
@@ -676,7 +679,7 @@ contract KlerosCoreUniversity is IArbitratorV2, UUPSProxiable, Initializable {
emit NewPeriod(_disputeID, Period.evidence);
}
- /// @dev Distribute the PNKs at stake and the dispute fees for the specific round of the dispute. Can be called in parts.
+ /// @notice Distribute the PNKs at stake and the dispute fees for the specific round of the dispute. Can be called in parts.
/// @param _disputeID The ID of the dispute.
/// @param _round The appeal round.
/// @param _iterations The number of iterations to run.
@@ -745,7 +748,7 @@ contract KlerosCoreUniversity is IArbitratorV2, UUPSProxiable, Initializable {
}
}
- /// @dev Distribute the PNKs at stake and the dispute fees for the specific round of the dispute, penalties only.
+ /// @notice Distribute the PNKs at stake and the dispute fees for the specific round of the dispute, penalties only.
/// @param _params The parameters for the execution, see `ExecuteParams`.
/// @return pnkPenaltiesInRoundCache The updated penalties in round cache.
function _executePenalties(ExecuteParams memory _params) internal returns (uint256) {
@@ -754,51 +757,63 @@ contract KlerosCoreUniversity is IArbitratorV2, UUPSProxiable, Initializable {
IDisputeKit disputeKit = disputeKits[round.disputeKitID];
// [0, 1] value that determines how coherent the juror was in this round, in basis points.
- uint256 degreeOfCoherence = disputeKit.getDegreeOfCoherence(
+ uint256 coherence = disputeKit.getDegreeOfCoherencePenalty(
_params.disputeID,
_params.round,
_params.repartition,
_params.feePerJurorInRound,
_params.pnkAtStakePerJurorInRound
);
- if (degreeOfCoherence > ALPHA_DIVISOR) {
- // Make sure the degree doesn't exceed 1, though it should be ensured by the dispute kit.
- degreeOfCoherence = ALPHA_DIVISOR;
+
+ // Guard against degree exceeding 1, though it should be ensured by the dispute kit.
+ if (coherence > ONE_BASIS_POINT) {
+ coherence = ONE_BASIS_POINT;
}
// Fully coherent jurors won't be penalized.
- uint256 penalty = (round.pnkAtStakePerJuror * (ALPHA_DIVISOR - degreeOfCoherence)) / ALPHA_DIVISOR;
+ uint256 penalty = (round.pnkAtStakePerJuror * (ONE_BASIS_POINT - coherence)) / ONE_BASIS_POINT;
// Unlock the PNKs affected by the penalty
address account = round.drawnJurors[_params.repartition];
sortitionModule.unlockStake(account, penalty);
// Apply the penalty to the staked PNKs.
- (uint256 pnkBalance, uint256 availablePenalty) = sortitionModule.penalizeStake(account, penalty);
+ uint96 penalizedInCourtID = round.drawnJurorFromCourtIDs[_params.repartition];
+ (uint256 pnkBalance, uint256 newCourtStake, uint256 availablePenalty) = sortitionModule.setStakePenalty(
+ account,
+ penalizedInCourtID,
+ penalty
+ );
_params.pnkPenaltiesInRound += availablePenalty;
- emit TokenAndETHShift(
+ emit JurorRewardPenalty(
account,
_params.disputeID,
_params.round,
- degreeOfCoherence,
+ coherence,
+ coherence,
-int256(availablePenalty),
0,
round.feeToken
);
- // Unstake the juror from all courts if he was inactive or his balance can't cover penalties anymore.
+
if (pnkBalance == 0 || !disputeKit.isVoteActive(_params.disputeID, _params.round, _params.repartition)) {
- sortitionModule.setJurorInactive(account);
+ // The juror is inactive or their balance is can't cover penalties anymore, unstake them from all courts.
+ sortitionModule.forcedUnstakeAllCourts(account);
+ } else if (newCourtStake < courts[penalizedInCourtID].minStake) {
+ // The juror's balance fell below the court minStake, unstake them from the court.
+ sortitionModule.forcedUnstake(account, penalizedInCourtID);
}
+
if (_params.repartition == _params.numberOfVotesInRound - 1 && _params.coherentCount == 0) {
- // No one was coherent, send the rewards to the governor.
+ // No one was coherent, send the rewards to the owner.
if (round.feeToken == NATIVE_CURRENCY) {
// The dispute fees were paid in ETH
- payable(governor).send(round.totalFeesForJurors);
+ payable(owner).send(round.totalFeesForJurors);
} else {
// The dispute fees were paid in ERC20
- round.feeToken.safeTransfer(governor, round.totalFeesForJurors);
+ round.feeToken.safeTransfer(owner, round.totalFeesForJurors);
}
- pinakion.safeTransfer(governor, _params.pnkPenaltiesInRound);
+ pinakion.safeTransfer(owner, _params.pnkPenaltiesInRound);
emit LeftoverRewardSent(
_params.disputeID,
_params.round,
@@ -810,7 +825,7 @@ contract KlerosCoreUniversity is IArbitratorV2, UUPSProxiable, Initializable {
return _params.pnkPenaltiesInRound;
}
- /// @dev Distribute the PNKs at stake and the dispute fees for the specific round of the dispute, rewards only.
+ /// @notice Distribute the PNKs at stake and the dispute fees for the specific round of the dispute, rewards only.
/// @param _params The parameters for the execution, see `ExecuteParams`.
function _executeRewards(ExecuteParams memory _params) internal {
Dispute storage dispute = disputes[_params.disputeID];
@@ -818,7 +833,7 @@ contract KlerosCoreUniversity is IArbitratorV2, UUPSProxiable, Initializable {
IDisputeKit disputeKit = disputeKits[round.disputeKitID];
// [0, 1] value that determines how coherent the juror was in this round, in basis points.
- uint256 degreeOfCoherence = disputeKit.getDegreeOfCoherence(
+ (uint256 pnkCoherence, uint256 feeCoherence) = disputeKit.getDegreeOfCoherenceReward(
_params.disputeID,
_params.round,
_params.repartition % _params.numberOfVotesInRound,
@@ -826,23 +841,27 @@ contract KlerosCoreUniversity is IArbitratorV2, UUPSProxiable, Initializable {
_params.pnkAtStakePerJurorInRound
);
- // Make sure the degree doesn't exceed 1, though it should be ensured by the dispute kit.
- if (degreeOfCoherence > ALPHA_DIVISOR) {
- degreeOfCoherence = ALPHA_DIVISOR;
+ // Guard against degree exceeding 1, though it should be ensured by the dispute kit.
+ if (pnkCoherence > ONE_BASIS_POINT) {
+ pnkCoherence = ONE_BASIS_POINT;
+ }
+ if (feeCoherence > ONE_BASIS_POINT) {
+ feeCoherence = ONE_BASIS_POINT;
}
address account = round.drawnJurors[_params.repartition % _params.numberOfVotesInRound];
- uint256 pnkLocked = (round.pnkAtStakePerJuror * degreeOfCoherence) / ALPHA_DIVISOR;
+ uint256 pnkLocked = (round.pnkAtStakePerJuror * pnkCoherence) / ONE_BASIS_POINT;
// Release the rest of the PNKs of the juror for this round.
sortitionModule.unlockStake(account, pnkLocked);
- // Transfer the rewards
- uint256 pnkReward = ((_params.pnkPenaltiesInRound / _params.coherentCount) * degreeOfCoherence) / ALPHA_DIVISOR;
+ // Compute the rewards
+ uint256 pnkReward = ((_params.pnkPenaltiesInRound / _params.coherentCount) * pnkCoherence) / ONE_BASIS_POINT; /// forge-lint: disable-line(divide-before-multiply)
round.sumPnkRewardPaid += pnkReward;
- uint256 feeReward = ((round.totalFeesForJurors / _params.coherentCount) * degreeOfCoherence) / ALPHA_DIVISOR;
+ uint256 feeReward = ((round.totalFeesForJurors / _params.coherentCount) * feeCoherence) / ONE_BASIS_POINT; /// forge-lint: disable-line(divide-before-multiply)
round.sumFeeRewardPaid += feeReward;
- pinakion.safeTransfer(account, pnkReward);
+
+ // Transfer the fee reward
if (round.feeToken == NATIVE_CURRENCY) {
// The dispute fees were paid in ETH
payable(account).send(feeReward);
@@ -850,31 +869,38 @@ contract KlerosCoreUniversity is IArbitratorV2, UUPSProxiable, Initializable {
// The dispute fees were paid in ERC20
round.feeToken.safeTransfer(account, feeReward);
}
- emit TokenAndETHShift(
+
+ // Stake the PNK reward if possible, by-passes delayed stakes and other checks usually done by validateStake()
+ if (!sortitionModule.setStakeReward(account, dispute.courtID, pnkReward)) {
+ pinakion.safeTransfer(account, pnkReward);
+ }
+
+ emit JurorRewardPenalty(
account,
_params.disputeID,
_params.round,
- degreeOfCoherence,
+ pnkCoherence,
+ feeCoherence,
int256(pnkReward),
int256(feeReward),
round.feeToken
);
- // Transfer any residual rewards to the governor. It may happen due to partial coherence of the jurors.
+ // Transfer any residual rewards to the owner. It may happen due to partial coherence of the jurors.
if (_params.repartition == _params.numberOfVotesInRound * 2 - 1) {
uint256 leftoverPnkReward = _params.pnkPenaltiesInRound - round.sumPnkRewardPaid;
uint256 leftoverFeeReward = round.totalFeesForJurors - round.sumFeeRewardPaid;
if (leftoverPnkReward != 0 || leftoverFeeReward != 0) {
if (leftoverPnkReward != 0) {
- pinakion.safeTransfer(governor, leftoverPnkReward);
+ pinakion.safeTransfer(owner, leftoverPnkReward);
}
if (leftoverFeeReward != 0) {
if (round.feeToken == NATIVE_CURRENCY) {
// The dispute fees were paid in ETH
- payable(governor).send(leftoverFeeReward);
+ payable(owner).send(leftoverFeeReward);
} else {
// The dispute fees were paid in ERC20
- round.feeToken.safeTransfer(governor, leftoverFeeReward);
+ round.feeToken.safeTransfer(owner, leftoverFeeReward);
}
}
emit LeftoverRewardSent(
@@ -888,7 +914,7 @@ contract KlerosCoreUniversity is IArbitratorV2, UUPSProxiable, Initializable {
}
}
- /// @dev Executes a specified dispute's ruling.
+ /// @notice Executes a specified dispute's ruling.
/// @param _disputeID The ID of the dispute.
function executeRuling(uint256 _disputeID) external {
Dispute storage dispute = disputes[_disputeID];
@@ -905,25 +931,18 @@ contract KlerosCoreUniversity is IArbitratorV2, UUPSProxiable, Initializable {
// * Public Views * //
// ************************************* //
- /// @dev Compute the cost of arbitration denominated in ETH.
- /// It is recommended not to increase it often, as it can be highly time and gas consuming for the arbitrated contracts to cope with fee augmentation.
- /// @param _extraData Additional info about the dispute. We use it to pass the ID of the dispute's court (first 32 bytes), the minimum number of jurors required (next 32 bytes) and the ID of the specific dispute kit (last 32 bytes).
- /// @return cost The arbitration cost in ETH.
+ /// @inheritdoc IArbitratorV2
function arbitrationCost(bytes memory _extraData) public view override returns (uint256 cost) {
(uint96 courtID, uint256 minJurors, ) = _extraDataToCourtIDMinJurorsDisputeKit(_extraData);
cost = courts[courtID].feeForJuror * minJurors;
}
- /// @dev Compute the cost of arbitration denominated in `_feeToken`.
- /// It is recommended not to increase it often, as it can be highly time and gas consuming for the arbitrated contracts to cope with fee augmentation.
- /// @param _extraData Additional info about the dispute. We use it to pass the ID of the dispute's court (first 32 bytes), the minimum number of jurors required (next 32 bytes) and the ID of the specific dispute kit (last 32 bytes).
- /// @param _feeToken The ERC20 token used to pay fees.
- /// @return cost The arbitration cost in `_feeToken`.
+ /// @inheritdoc IArbitratorV2
function arbitrationCost(bytes calldata _extraData, IERC20 _feeToken) public view override returns (uint256 cost) {
cost = convertEthToTokenAmount(_feeToken, arbitrationCost(_extraData));
}
- /// @dev Gets the cost of appealing a specified dispute.
+ /// @notice Gets the cost of appealing a specified dispute.
/// @param _disputeID The ID of the dispute.
/// @return cost The appeal cost.
function appealCost(uint256 _disputeID) public view returns (uint256 cost) {
@@ -944,7 +963,7 @@ contract KlerosCoreUniversity is IArbitratorV2, UUPSProxiable, Initializable {
}
}
- /// @dev Gets the start and the end of a specified dispute's current appeal period.
+ /// @notice Gets the start and the end of a specified dispute's current appeal period.
/// @param _disputeID The ID of the dispute.
/// @return start The start of the appeal period.
/// @return end The end of the appeal period.
@@ -959,11 +978,7 @@ contract KlerosCoreUniversity is IArbitratorV2, UUPSProxiable, Initializable {
}
}
- /// @dev Gets the current ruling of a specified dispute.
- /// @param _disputeID The ID of the dispute.
- /// @return ruling The current ruling.
- /// @return tied Whether it's a tie or not.
- /// @return overridden Whether the ruling was overridden by appeal funding or not.
+ /// @inheritdoc IArbitratorV2
function currentRuling(uint256 _disputeID) public view returns (uint256 ruling, bool tied, bool overridden) {
Dispute storage dispute = disputes[_disputeID];
Round storage round = dispute.rounds[dispute.rounds.length - 1];
@@ -971,7 +986,7 @@ contract KlerosCoreUniversity is IArbitratorV2, UUPSProxiable, Initializable {
(ruling, tied, overridden) = disputeKit.currentRuling(_disputeID);
}
- /// @dev Gets the round info for a specified dispute and round.
+ /// @notice Gets the round info for a specified dispute and round.
/// @dev This function must not be called from a non-view function because it returns a dynamic array which might be very large, theoretically exceeding the block gas limit.
/// @param _disputeID The ID of the dispute.
/// @param _round The round to get the info for.
@@ -980,7 +995,7 @@ contract KlerosCoreUniversity is IArbitratorV2, UUPSProxiable, Initializable {
return disputes[_disputeID].rounds[_round];
}
- /// @dev Gets the PNK at stake per juror for a specified dispute and round.
+ /// @notice Gets the PNK at stake per juror for a specified dispute and round.
/// @param _disputeID The ID of the dispute.
/// @param _round The round to get the info for.
/// @return pnkAtStakePerJuror The PNK at stake per juror.
@@ -988,14 +1003,14 @@ contract KlerosCoreUniversity is IArbitratorV2, UUPSProxiable, Initializable {
return disputes[_disputeID].rounds[_round].pnkAtStakePerJuror;
}
- /// @dev Gets the number of rounds for a specified dispute.
+ /// @notice Gets the number of rounds for a specified dispute.
/// @param _disputeID The ID of the dispute.
/// @return The number of rounds.
function getNumberOfRounds(uint256 _disputeID) external view returns (uint256) {
return disputes[_disputeID].rounds.length;
}
- /// @dev Checks if a given dispute kit is supported by a given court.
+ /// @notice Checks if a given dispute kit is supported by a given court.
/// @param _courtID The ID of the court to check the support for.
/// @param _disputeKitID The ID of the dispute kit to check the support for.
/// @return Whether the dispute kit is supported or not.
@@ -1003,7 +1018,7 @@ contract KlerosCoreUniversity is IArbitratorV2, UUPSProxiable, Initializable {
return courts[_courtID].supportedDisputeKits[_disputeKitID];
}
- /// @dev Gets the timesPerPeriod array for a given court.
+ /// @notice Gets the timesPerPeriod array for a given court.
/// @param _courtID The ID of the court to get the times from.
/// @return timesPerPeriod The timesPerPeriod array for the given court.
function getTimesPerPeriod(uint96 _courtID) external view returns (uint256[4] memory timesPerPeriod) {
@@ -1014,14 +1029,14 @@ contract KlerosCoreUniversity is IArbitratorV2, UUPSProxiable, Initializable {
// * Public Views for Dispute Kits * //
// ************************************* //
- /// @dev Gets the number of votes permitted for the specified dispute in the latest round.
+ /// @notice Gets the number of votes permitted for the specified dispute in the latest round.
/// @param _disputeID The ID of the dispute.
function getNumberOfVotes(uint256 _disputeID) external view returns (uint256) {
Dispute storage dispute = disputes[_disputeID];
return dispute.rounds[dispute.rounds.length - 1].nbVotes;
}
- /// @dev Returns true if the dispute kit will be switched to a parent DK.
+ /// @notice Returns true if the dispute kit will be switched to a parent DK.
/// @param _disputeID The ID of the dispute.
/// @return Whether DK will be switched or not.
function isDisputeKitJumping(uint256 _disputeID) external view returns (bool) {
@@ -1049,7 +1064,7 @@ contract KlerosCoreUniversity is IArbitratorV2, UUPSProxiable, Initializable {
// * Internal * //
// ************************************* //
- /// @dev Toggles the dispute kit support for a given court.
+ /// @notice Toggles the dispute kit support for a given court.
/// @param _courtID The ID of the court to toggle the support for.
/// @param _disputeKitID The ID of the dispute kit to toggle the support for.
/// @param _enable Whether to enable or disable the support. Note that classic dispute kit should always be enabled.
@@ -1058,13 +1073,20 @@ contract KlerosCoreUniversity is IArbitratorV2, UUPSProxiable, Initializable {
emit DisputeKitEnabled(_courtID, _disputeKitID, _enable);
}
- /// @dev If called only once then set _onError to Revert, otherwise set it to Return
+ /// @notice If called only once then set _onError to Revert, otherwise set it to Return
/// @param _account The account to set the stake for.
/// @param _courtID The ID of the court to set the stake for.
/// @param _newStake The new stake.
+ /// @param _noDelay True if the stake change should not be delayed.
/// @param _onError Whether to revert or return false on error.
/// @return Whether the stake was successfully set or not.
- function _setStake(address _account, uint96 _courtID, uint256 _newStake, OnError _onError) internal returns (bool) {
+ function _setStake(
+ address _account,
+ uint96 _courtID,
+ uint256 _newStake,
+ bool _noDelay,
+ OnError _onError
+ ) internal returns (bool) {
if (_courtID == FORKING_COURT || _courtID >= courts.length) {
_stakingFailed(_onError, StakingResult.CannotStakeInThisCourt); // Staking directly into the forking court is not allowed.
return false;
@@ -1076,7 +1098,8 @@ contract KlerosCoreUniversity is IArbitratorV2, UUPSProxiable, Initializable {
(uint256 pnkDeposit, uint256 pnkWithdrawal, StakingResult stakingResult) = sortitionModule.validateStake(
_account,
_courtID,
- _newStake
+ _newStake,
+ _noDelay
);
if (stakingResult != StakingResult.Successful) {
_stakingFailed(_onError, stakingResult);
@@ -1099,7 +1122,7 @@ contract KlerosCoreUniversity is IArbitratorV2, UUPSProxiable, Initializable {
return true;
}
- /// @dev It may revert depending on the _onError parameter.
+ /// @notice It may revert depending on the _onError parameter.
function _stakingFailed(OnError _onError, StakingResult _result) internal pure virtual {
if (_onError == OnError.Return) return;
if (_result == StakingResult.StakingTransferFailed) revert StakingTransferFailed();
@@ -1110,8 +1133,8 @@ contract KlerosCoreUniversity is IArbitratorV2, UUPSProxiable, Initializable {
if (_result == StakingResult.CannotStakeZeroWhenNoStake) revert StakingZeroWhenNoStake();
}
- /// @dev Gets a court ID, the minimum number of jurors and an ID of a dispute kit from a specified extra data bytes array.
- /// Note that if extradata contains an incorrect value then this value will be switched to default.
+ /// @notice Gets a court ID, the minimum number of jurors and an ID of a dispute kit from a specified extra data bytes array.
+ /// @dev If `_extraData` contains an incorrect value then this value will be switched to default.
/// @param _extraData The extra data bytes array. The first 32 bytes are the court ID, the next are the minimum number of jurors and the last are the dispute kit ID.
/// @return courtID The court ID.
/// @return minJurors The minimum number of jurors required.
@@ -1147,13 +1170,13 @@ contract KlerosCoreUniversity is IArbitratorV2, UUPSProxiable, Initializable {
// * Errors * //
// ************************************* //
- error GovernorOnly();
+ error OwnerOnly();
error InstructorOnly();
- error GovernorOrInstructorOnly();
+ error OwnerOrInstructorOnly();
error DisputeKitOnly();
error SortitionModuleOnly();
error UnsuccessfulCall();
- error InvalidDisputKitParent();
+ error InvalidDisputeKitParent();
error MinStakeLowerThanParentCourt();
error UnsupportedDisputeKit();
error InvalidForkingCourtAsParent();
diff --git a/contracts/src/arbitration/university/SortitionModuleUniversity.sol b/contracts/src/arbitration/university/SortitionModuleUniversity.sol
index 619a0b934..c1c1cd076 100644
--- a/contracts/src/arbitration/university/SortitionModuleUniversity.sol
+++ b/contracts/src/arbitration/university/SortitionModuleUniversity.sol
@@ -10,9 +10,9 @@ import "../../proxy/Initializable.sol";
import "../../libraries/Constants.sol";
/// @title SortitionModuleUniversity
-/// @dev An adapted version of the SortitionModule contract for educational purposes.
+/// @notice An adapted version of the SortitionModule contract for educational purposes.
contract SortitionModuleUniversity is ISortitionModuleUniversity, UUPSProxiable, Initializable {
- string public constant override version = "0.8.0";
+ string public constant override version = "2.0.0";
// ************************************* //
// * Enums / Structs * //
@@ -29,7 +29,7 @@ contract SortitionModuleUniversity is ISortitionModuleUniversity, UUPSProxiable,
// * Storage * //
// ************************************* //
- address public governor; // The governor of the contract.
+ address public owner; // The owner of the contract.
KlerosCoreUniversity public core; // The core arbitrator contract.
uint256 public disputesWithoutJurors; // The number of disputes that have not finished drawing jurors.
mapping(address account => Juror) public jurors; // The jurors.
@@ -52,12 +52,12 @@ contract SortitionModuleUniversity is ISortitionModuleUniversity, UUPSProxiable,
/// @param _unlock Whether the stake is locked or unlocked.
event StakeLocked(address indexed _address, uint256 _relativeAmount, bool _unlock);
- /// @dev Emitted when leftover PNK is available.
+ /// @notice Emitted when leftover PNK is available.
/// @param _account The account of the juror.
/// @param _amount The amount of PNK available.
event LeftoverPNK(address indexed _account, uint256 _amount);
- /// @dev Emitted when leftover PNK is withdrawn.
+ /// @notice Emitted when leftover PNK is withdrawn.
/// @param _account The account of the juror withdrawing PNK.
/// @param _amount The amount of PNK withdrawn.
event LeftoverPNKWithdrawn(address indexed _account, uint256 _amount);
@@ -66,13 +66,13 @@ contract SortitionModuleUniversity is ISortitionModuleUniversity, UUPSProxiable,
// * Function Modifiers * //
// ************************************* //
- modifier onlyByGovernor() {
- require(address(governor) == msg.sender, "Access not allowed: Governor only.");
+ modifier onlyByOwner() {
+ if (owner != msg.sender) revert OwnerOnly();
_;
}
modifier onlyByCore() {
- require(address(core) == msg.sender, "Access not allowed: KlerosCore only.");
+ if (address(core) != msg.sender) revert KlerosCoreOnly();
_;
}
@@ -85,10 +85,10 @@ contract SortitionModuleUniversity is ISortitionModuleUniversity, UUPSProxiable,
_disableInitializers();
}
- /// @dev Initializer (constructor equivalent for upgradable contracts).
+ /// @notice Initializer (constructor equivalent for upgradable contracts).
/// @param _core The KlerosCore.
- function initialize(address _governor, KlerosCoreUniversity _core) external reinitializer(1) {
- governor = _governor;
+ function initialize(address _owner, KlerosCoreUniversity _core) external initializer {
+ owner = _owner;
core = _core;
}
@@ -98,9 +98,9 @@ contract SortitionModuleUniversity is ISortitionModuleUniversity, UUPSProxiable,
/**
* @dev Access Control to perform implementation upgrades (UUPS Proxiable)
- * @dev Only the governor can perform upgrades (`onlyByGovernor`)
+ * @dev Only the owner can perform upgrades (`onlyByOwner`)
*/
- function _authorizeUpgrade(address) internal view override onlyByGovernor {
+ function _authorizeUpgrade(address) internal view override onlyByOwner {
// NOP
}
@@ -108,38 +108,42 @@ contract SortitionModuleUniversity is ISortitionModuleUniversity, UUPSProxiable,
// * State Modifiers * //
// ************************************* //
+ /// @inheritdoc ISortitionModule
+ function passPhase() external override onlyByCore {
+ // NOP
+ }
+
+ /// @inheritdoc ISortitionModule
+ function executeDelayedStakes(uint256 _iterations) external override onlyByCore {
+ // NOP
+ }
+
+ /// @inheritdoc ISortitionModuleUniversity
function setTransientJuror(address _juror) external override onlyByCore {
transientJuror = _juror;
}
- function createTree(bytes32 _key, bytes memory _extraData) external {
+ /// @inheritdoc ISortitionModule
+ function createTree(uint96 _courtID, bytes memory _extraData) external {
// NOP
}
+ /// @inheritdoc ISortitionModule
function createDisputeHook(uint256 /*_disputeID*/, uint256 /*_roundID*/) external override onlyByCore {
disputesWithoutJurors++;
}
+ /// @inheritdoc ISortitionModule
function postDrawHook(uint256 /*_disputeID*/, uint256 /*_roundID*/) external override onlyByCore {
disputesWithoutJurors--;
}
- /// @dev Saves the random number to use it in sortition. Not used by this contract because the storing of the number is inlined in passPhase().
- /// @param _randomNumber Random number returned by RNG contract.
- function notifyRandomNumber(uint256 _randomNumber) public override {}
-
- /// @dev Validate the specified juror's new stake for a court.
- /// Note: no state changes should be made when returning stakingResult != Successful, otherwise delayed stakes might break invariants.
- /// @param _account The address of the juror.
- /// @param _courtID The ID of the court.
- /// @param _newStake The new stake.
- /// @return pnkDeposit The amount of PNK to be deposited.
- /// @return pnkWithdrawal The amount of PNK to be withdrawn.
- /// @return stakingResult The result of the staking operation.
+ /// @inheritdoc ISortitionModule
function validateStake(
address _account,
uint96 _courtID,
- uint256 _newStake
+ uint256 _newStake,
+ bool /*_noDelay*/
)
external
view
@@ -172,17 +176,7 @@ contract SortitionModuleUniversity is ISortitionModuleUniversity, UUPSProxiable,
return (pnkDeposit, pnkWithdrawal, StakingResult.Successful);
}
- /// @dev Update the state of the stakes, called by KC at the end of setStake flow.
- /// `O(n + p * log_k(j))` where
- /// `n` is the number of courts the juror has staked in,
- /// `p` is the depth of the court tree,
- /// `k` is the minimum number of children per node of one of these courts' sortition sum tree,
- /// and `j` is the maximum number of jurors that ever staked in one of these courts simultaneously.
- /// @param _account The address of the juror.
- /// @param _courtID The ID of the court.
- /// @param _pnkDeposit The amount of PNK to be deposited.
- /// @param _pnkWithdrawal The amount of PNK to be withdrawn.
- /// @param _newStake The new stake.
+ /// @inheritdoc ISortitionModule
function setStake(
address _account,
uint96 _courtID,
@@ -190,6 +184,56 @@ contract SortitionModuleUniversity is ISortitionModuleUniversity, UUPSProxiable,
uint256 _pnkWithdrawal,
uint256 _newStake
) external override onlyByCore {
+ _setStake(_account, _courtID, _pnkDeposit, _pnkWithdrawal, _newStake);
+ }
+
+ function setStakePenalty(
+ address _account,
+ uint96 _courtID,
+ uint256 _penalty
+ ) external override onlyByCore returns (uint256 pnkBalance, uint256 newCourtStake, uint256 availablePenalty) {
+ Juror storage juror = jurors[_account];
+ availablePenalty = _penalty;
+ newCourtStake = _stakeOf(_account, _courtID);
+ if (juror.stakedPnk < _penalty) {
+ availablePenalty = juror.stakedPnk;
+ }
+
+ if (availablePenalty == 0) return (juror.stakedPnk, newCourtStake, 0); // No penalty to apply.
+
+ uint256 currentStake = _stakeOf(_account, _courtID);
+ uint256 newStake = 0;
+ if (currentStake >= availablePenalty) {
+ newStake = currentStake - availablePenalty;
+ }
+ _setStake(_account, _courtID, 0, availablePenalty, newStake);
+ pnkBalance = juror.stakedPnk; // updated by _setStake()
+ newCourtStake = _stakeOf(_account, _courtID); // updated by _setStake()
+ }
+
+ /// @inheritdoc ISortitionModule
+ function setStakeReward(
+ address _account,
+ uint96 _courtID,
+ uint256 _reward
+ ) external override onlyByCore returns (bool success) {
+ if (_reward == 0) return true; // No reward to add.
+
+ uint256 currentStake = _stakeOf(_account, _courtID);
+ if (currentStake == 0) return false; // Juror has been unstaked, don't increase their stake.
+
+ uint256 newStake = currentStake + _reward;
+ _setStake(_account, _courtID, _reward, 0, newStake);
+ return true;
+ }
+
+ function _setStake(
+ address _account,
+ uint96 _courtID,
+ uint256 _pnkDeposit,
+ uint256 _pnkWithdrawal,
+ uint256 _newStake
+ ) internal {
Juror storage juror = jurors[_account];
uint256 currentStake = _stakeOf(_account, _courtID);
if (_pnkDeposit > 0) {
@@ -221,7 +265,7 @@ contract SortitionModuleUniversity is ISortitionModuleUniversity, UUPSProxiable,
if (currentCourtID == GENERAL_COURT) {
finished = true;
} else {
- (currentCourtID, , , , , , ) = core.courts(currentCourtID);
+ (currentCourtID, , , , , ) = core.courts(currentCourtID);
}
}
emit StakeSet(_account, _courtID, _newStake, juror.stakedPnk);
@@ -237,50 +281,25 @@ contract SortitionModuleUniversity is ISortitionModuleUniversity, UUPSProxiable,
emit StakeLocked(_account, _relativeAmount, true);
}
- function penalizeStake(
- address _account,
- uint256 _relativeAmount
- ) external override onlyByCore returns (uint256 pnkBalance, uint256 availablePenalty) {
- Juror storage juror = jurors[_account];
- uint256 stakedPnk = juror.stakedPnk;
-
- if (stakedPnk >= _relativeAmount) {
- availablePenalty = _relativeAmount;
- juror.stakedPnk -= _relativeAmount;
- } else {
- availablePenalty = stakedPnk;
- juror.stakedPnk = 0;
- }
-
- pnkBalance = juror.stakedPnk;
- return (pnkBalance, availablePenalty);
- }
-
- /// @dev Unstakes the inactive juror from all courts.
- /// `O(n * (p * log_k(j)) )` where
- /// `n` is the number of courts the juror has staked in,
- /// `p` is the depth of the court tree,
- /// `k` is the minimum number of children per node of one of these courts' sortition sum tree,
- /// and `j` is the maximum number of jurors that ever staked in one of these courts simultaneously.
- /// @param _account The juror to unstake.
- function setJurorInactive(address _account) external override onlyByCore {
+ /// @inheritdoc ISortitionModule
+ function forcedUnstakeAllCourts(address _account) external override onlyByCore {
uint96[] memory courtIDs = getJurorCourtIDs(_account);
for (uint256 j = courtIDs.length; j > 0; j--) {
core.setStakeBySortitionModule(_account, courtIDs[j - 1], 0);
}
}
- /// @dev Gives back the locked PNKs in case the juror fully unstaked earlier.
- /// Note that since locked and staked PNK are async it is possible for the juror to have positive staked PNK balance
- /// while having 0 stake in courts and 0 locked tokens (eg. when the juror fully unstaked during dispute and later got his tokens unlocked).
- /// In this case the juror can use this function to withdraw the leftover tokens.
- /// Also note that if the juror has some leftover PNK while not fully unstaked he'll have to manually unstake from all courts to trigger this function.
- /// @param _account The juror whose PNK to withdraw.
+ /// @inheritdoc ISortitionModule
+ function forcedUnstake(address _account, uint96 _courtID) external override onlyByCore {
+ core.setStakeBySortitionModule(_account, _courtID, 0);
+ }
+
+ /// @inheritdoc ISortitionModule
function withdrawLeftoverPNK(address _account) external override {
// Can withdraw the leftover PNK if fully unstaked, has no tokens locked and has positive balance.
// This withdrawal can't be triggered by calling setStake() in KlerosCore because current stake is technically 0, thus it is done via separate function.
uint256 amount = getJurorLeftoverPNK(_account);
- require(amount > 0, "Not eligible for withdrawal.");
+ if (amount == 0) revert NotEligibleForWithdrawal();
jurors[_account].stakedPnk = 0;
core.transferBySortitionModule(_account, amount);
emit LeftoverPNKWithdrawn(_account, amount);
@@ -290,22 +309,12 @@ contract SortitionModuleUniversity is ISortitionModuleUniversity, UUPSProxiable,
// * Public Views * //
// ************************************* //
- /// @dev Draw an ID from a tree using a number.
- /// Note that this function reverts if the sum of all values in the tree is 0.
- /// @return drawnAddress The drawn address.
- function draw(bytes32, uint256, uint256) public view override returns (address drawnAddress) {
+ /// @inheritdoc ISortitionModule
+ function draw(uint96, uint256, uint256) public view override returns (address drawnAddress, uint96 fromSubcourtID) {
drawnAddress = transientJuror;
}
- /// @dev Gets the stake of a juror in a court.
- /// Warning: `O(n)` complexity where `n` is the number of courts the juror has staked in
- /// but acceptable for this educational implementation.
- /// @param _juror The address of the juror.
- /// @param _courtID The ID of the court.
- /// @return totalStaked The total amount of tokens staked by the juror in the court.
- /// @return totalLocked The total amount of tokens locked by the juror in the court.
- /// @return stakedInCourt The amount of tokens staked by the juror in the court.
- /// @return nbCourts The number of courts the juror has staked in.
+ /// @inheritdoc ISortitionModule
function getJurorBalance(
address _juror,
uint96 _courtID
@@ -327,16 +336,17 @@ contract SortitionModuleUniversity is ISortitionModuleUniversity, UUPSProxiable,
}
}
- /// @dev Gets the court identifiers where a specific `_juror` has staked.
- /// @param _juror The address of the juror.
+ /// @inheritdoc ISortitionModule
function getJurorCourtIDs(address _juror) public view override returns (uint96[] memory) {
return jurors[_juror].courtIDs;
}
+ /// @inheritdoc ISortitionModule
function isJurorStaked(address _juror) external view override returns (bool) {
return jurors[_juror].stakedPnk > 0;
}
+ /// @inheritdoc ISortitionModule
function getJurorLeftoverPNK(address _juror) public view override returns (uint256) {
Juror storage juror = jurors[_juror];
if (juror.courtIDs.length == 0 && juror.lockedPnk == 0) {
@@ -349,9 +359,11 @@ contract SortitionModuleUniversity is ISortitionModuleUniversity, UUPSProxiable,
// * Internal * //
// ************************************* //
- /// @dev Gets the stake of a juror in a court.
- /// Warning: `O(n)` complexity where `n` is the number of courts the juror has staked in
+ /// @notice Gets the stake of a juror in a court.
+ ///
+ /// @dev Warning: `O(n)` complexity where `n` is the number of courts the juror has staked in
/// but acceptable for this educational implementation.
+ ///
/// @param _juror The address of the juror.
/// @param _courtID The ID of the court.
/// @return stakedInCourt The amount of tokens staked by the juror in the court.
@@ -364,4 +376,12 @@ contract SortitionModuleUniversity is ISortitionModuleUniversity, UUPSProxiable,
}
}
}
+
+ // ************************************* //
+ // * Errors * //
+ // ************************************* //
+
+ error OwnerOnly();
+ error KlerosCoreOnly();
+ error NotEligibleForWithdrawal();
}
diff --git a/contracts/src/arbitration/view/KlerosCoreSnapshotProxy.sol b/contracts/src/arbitration/view/KlerosCoreSnapshotProxy.sol
index e94eccbd9..82f5b90ac 100644
--- a/contracts/src/arbitration/view/KlerosCoreSnapshotProxy.sol
+++ b/contracts/src/arbitration/view/KlerosCoreSnapshotProxy.sol
@@ -9,14 +9,14 @@ interface IKlerosCore {
}
/// @title KlerosCoreSnapshotProxy
-/// Proxy contract for V2 that exposes staked PNK with balanceOf() function for Snapshot voting.
+/// @notice Proxy contract for V2 that exposes staked PNK with balanceOf() function for Snapshot voting.
contract KlerosCoreSnapshotProxy {
// ************************************* //
// * State Modifiers * //
// ************************************* //
IKlerosCore public core;
- address public governor;
+ address public owner;
string public constant name = "Staked Pinakion";
string public constant symbol = "stPNK";
uint8 public constant decimals = 18;
@@ -25,8 +25,8 @@ contract KlerosCoreSnapshotProxy {
// * Modifiers * //
// ************************************* //
- modifier onlyByGovernor() {
- require(governor == msg.sender, "Access not allowed: Governor only.");
+ modifier onlyByOwner() {
+ if (owner != msg.sender) revert OwnerOnly();
_;
}
@@ -34,11 +34,11 @@ contract KlerosCoreSnapshotProxy {
// * Constructor * //
// ************************************* //
- /// @dev Constructor
- /// @param _governor The governor of the contract.
+ /// @notice Constructor
+ /// @param _owner The owner of the contract.
/// @param _core KlerosCore to read the balance from.
- constructor(address _governor, IKlerosCore _core) {
- governor = _governor;
+ constructor(address _owner, IKlerosCore _core) {
+ owner = _owner;
core = _core;
}
@@ -46,15 +46,15 @@ contract KlerosCoreSnapshotProxy {
// * Governance * //
// ************************************* //
- /// @dev Changes the `governor` storage variable.
- /// @param _governor The new value for the `governor` storage variable.
- function changeGovernor(address _governor) external onlyByGovernor {
- governor = _governor;
+ /// @notice Changes the `owner` storage variable.
+ /// @param _owner The new value for the `owner` storage variable.
+ function changeOwner(address _owner) external onlyByOwner {
+ owner = _owner;
}
- /// @dev Changes the `core` storage variable.
+ /// @notice Changes the `core` storage variable.
/// @param _core The new value for the `core` storage variable.
- function changeCore(IKlerosCore _core) external onlyByGovernor {
+ function changeCore(IKlerosCore _core) external onlyByOwner {
core = _core;
}
@@ -62,11 +62,17 @@ contract KlerosCoreSnapshotProxy {
// * Public Views * //
// ************************************* //
- /// @dev Returns the amount of PNK staked in KlerosV2 for a particular address.
- /// Note: Proxy doesn't need to differentiate between courts so we pass 0 as courtID.
+ /// @notice Returns the amount of PNK staked in KlerosV2 for a particular address.
+ /// @dev Proxy doesn't need to differentiate between courts so we pass 0 as courtID.
/// @param _account The address to query.
/// @return totalStaked Total amount staked in V2 by the address.
function balanceOf(address _account) external view returns (uint256 totalStaked) {
(totalStaked, , , ) = core.sortitionModule().getJurorBalance(_account, 0);
}
+
+ // ************************************* //
+ // * Errors * //
+ // ************************************* //
+
+ error OwnerOnly();
}
diff --git a/contracts/src/gateway/ForeignGateway.sol b/contracts/src/gateway/ForeignGateway.sol
index 5938da773..76f17bb4e 100644
--- a/contracts/src/gateway/ForeignGateway.sol
+++ b/contracts/src/gateway/ForeignGateway.sol
@@ -7,8 +7,8 @@ import "../proxy/UUPSProxiable.sol";
import "../proxy/Initializable.sol";
import "../libraries/Constants.sol";
-/// Foreign Gateway
-/// Counterpart of `HomeGateway`
+/// @title Foreign Gateway
+/// @notice Counterpart of `HomeGateway`
contract ForeignGateway is IForeignGateway, UUPSProxiable, Initializable {
string public constant override version = "0.8.0";
@@ -36,7 +36,7 @@ contract ForeignGateway is IForeignGateway, UUPSProxiable, Initializable {
uint256 internal localDisputeID; // The disputeID must start from 1 as the KlerosV1 proxy governor depends on this implementation. We now also depend on localDisputeID not ever being zero.
mapping(uint96 courtId => uint256) public feeForJuror; // feeForJuror[v2CourtID], it mirrors the value on KlerosCore.
- address public governor;
+ address public owner;
address public veaOutbox;
uint256 public override homeChainID;
address public override homeGateway;
@@ -49,17 +49,16 @@ contract ForeignGateway is IForeignGateway, UUPSProxiable, Initializable {
// ************************************* //
modifier onlyFromVea(address _messageSender) {
- require(
- veaOutbox == msg.sender ||
- (block.timestamp < deprecatedVeaOutboxExpiration && deprecatedVeaOutbox == msg.sender),
- "Access not allowed: Vea Outbox only."
- );
- require(_messageSender == homeGateway, "Access not allowed: HomeGateway only.");
+ if (
+ veaOutbox != msg.sender &&
+ (block.timestamp >= deprecatedVeaOutboxExpiration || deprecatedVeaOutbox != msg.sender)
+ ) revert VeaOutboxOnly();
+ if (_messageSender != homeGateway) revert HomeGatewayMessageSenderOnly();
_;
}
- modifier onlyByGovernor() {
- require(governor == msg.sender, "Access not allowed: Governor only.");
+ modifier onlyByOwner() {
+ if (owner != msg.sender) revert OwnerOnly();
_;
}
@@ -72,18 +71,18 @@ contract ForeignGateway is IForeignGateway, UUPSProxiable, Initializable {
_disableInitializers();
}
- /// @dev Constructs the `PolicyRegistry` contract.
- /// @param _governor The governor's address.
+ /// @notice Constructs the `PolicyRegistry` contract.
+ /// @param _owner The owner's address.
/// @param _veaOutbox The address of the VeaOutbox.
/// @param _homeChainID The chainID of the home chain.
/// @param _homeGateway The address of the home gateway.
function initialize(
- address _governor,
+ address _owner,
address _veaOutbox,
uint256 _homeChainID,
address _homeGateway
- ) external reinitializer(1) {
- governor = _governor;
+ ) external initializer {
+ owner = _owner;
veaOutbox = _veaOutbox;
homeChainID = _homeChainID;
homeGateway = _homeGateway;
@@ -96,40 +95,40 @@ contract ForeignGateway is IForeignGateway, UUPSProxiable, Initializable {
/**
* @dev Access Control to perform implementation upgrades (UUPS Proxiable)
- * @dev Only the governor can perform upgrades (`onlyByGovernor`)
+ * @dev Only the owner can perform upgrades (`onlyByOwner`)
*/
- function _authorizeUpgrade(address) internal view override onlyByGovernor {
+ function _authorizeUpgrade(address) internal view override onlyByOwner {
// NOP
}
- /// @dev Changes the governor.
- /// @param _governor The address of the new governor.
- function changeGovernor(address _governor) external {
- require(governor == msg.sender, "Access not allowed: Governor only.");
- governor = _governor;
+ /// @notice Changes the owner.
+ /// @param _owner The address of the new owner.
+ function changeOwner(address _owner) external {
+ if (owner != msg.sender) revert OwnerOnly();
+ owner = _owner;
}
- /// @dev Changes the outbox.
+ /// @notice Changes the outbox.
/// @param _veaOutbox The address of the new outbox.
/// @param _gracePeriod The duration to accept messages from the deprecated bridge (if at all).
- function changeVea(address _veaOutbox, uint256 _gracePeriod) external onlyByGovernor {
+ function changeVea(address _veaOutbox, uint256 _gracePeriod) external onlyByOwner {
// grace period to relay the remaining messages which are still going through the deprecated bridge.
deprecatedVeaOutboxExpiration = block.timestamp + _gracePeriod;
deprecatedVeaOutbox = veaOutbox;
veaOutbox = _veaOutbox;
}
- /// @dev Changes the home gateway.
+ /// @notice Changes the home gateway.
/// @param _homeGateway The address of the new home gateway.
function changeHomeGateway(address _homeGateway) external {
- require(governor == msg.sender, "Access not allowed: Governor only.");
+ if (owner != msg.sender) revert OwnerOnly();
homeGateway = _homeGateway;
}
- /// @dev Changes the `feeForJuror` property value of a specified court.
+ /// @notice Changes the `feeForJuror` property value of a specified court.
/// @param _courtID The ID of the court on the v2 arbitrator. Not to be confused with the courtID on KlerosLiquid.
/// @param _feeForJuror The new value for the `feeForJuror` property value.
- function changeCourtJurorFee(uint96 _courtID, uint256 _feeForJuror) external onlyByGovernor {
+ function changeCourtJurorFee(uint96 _courtID, uint256 _feeForJuror) external onlyByOwner {
feeForJuror[_courtID] = _feeForJuror;
emit ArbitrationCostModified(_courtID, _feeForJuror);
}
@@ -143,7 +142,7 @@ contract ForeignGateway is IForeignGateway, UUPSProxiable, Initializable {
uint256 _choices,
bytes calldata _extraData
) external payable override returns (uint256 disputeID) {
- require(msg.value >= arbitrationCost(_extraData), "Not paid enough for arbitration");
+ if (msg.value < arbitrationCost(_extraData)) revert ArbitrationFeesNotEnough();
disputeID = localDisputeID++;
uint256 chainID;
@@ -206,8 +205,8 @@ contract ForeignGateway is IForeignGateway, UUPSProxiable, Initializable {
) external override onlyFromVea(_messageSender) {
DisputeData storage dispute = disputeHashtoDisputeData[_disputeHash];
- require(dispute.id != 0, "Dispute does not exist");
- require(!dispute.ruled, "Cannot rule twice");
+ if (dispute.id == 0) revert DisputeDoesNotExist();
+ if (dispute.ruled) revert CannotRuleTwice();
dispute.ruled = true;
dispute.relayer = _relayer;
@@ -219,8 +218,8 @@ contract ForeignGateway is IForeignGateway, UUPSProxiable, Initializable {
/// @inheritdoc IForeignGateway
function withdrawFees(bytes32 _disputeHash) external override {
DisputeData storage dispute = disputeHashtoDisputeData[_disputeHash];
- require(dispute.id != 0, "Dispute does not exist");
- require(dispute.ruled, "Not ruled yet");
+ if (dispute.id == 0) revert DisputeDoesNotExist();
+ if (!dispute.ruled) revert NotRuledYet();
uint256 amount = dispute.paid;
dispute.paid = 0;
@@ -247,9 +246,9 @@ contract ForeignGateway is IForeignGateway, UUPSProxiable, Initializable {
revert("Not supported");
}
- // ************************ //
- // * Internal * //
- // ************************ //
+ // ************************************* //
+ // * Internal * //
+ // ************************************* //
function extraDataToCourtIDMinJurors(
bytes memory _extraData
@@ -268,4 +267,16 @@ contract ForeignGateway is IForeignGateway, UUPSProxiable, Initializable {
minJurors = DEFAULT_NB_OF_JURORS;
}
}
+
+ // ************************************* //
+ // * Errors * //
+ // ************************************* //
+
+ error OwnerOnly();
+ error HomeGatewayMessageSenderOnly();
+ error VeaOutboxOnly();
+ error ArbitrationFeesNotEnough();
+ error DisputeDoesNotExist();
+ error CannotRuleTwice();
+ error NotRuledYet();
}
diff --git a/contracts/src/gateway/HomeGateway.sol b/contracts/src/gateway/HomeGateway.sol
index 40a767790..56b1c835f 100644
--- a/contracts/src/gateway/HomeGateway.sol
+++ b/contracts/src/gateway/HomeGateway.sol
@@ -9,8 +9,8 @@ import "../libraries/Constants.sol";
import "../proxy/UUPSProxiable.sol";
import "../proxy/Initializable.sol";
-/// Home Gateway
-/// Counterpart of `ForeignGateway`
+/// @title Home Gateway
+/// @notice Counterpart of `ForeignGateway`
contract HomeGateway is IHomeGateway, UUPSProxiable, Initializable {
using SafeERC20 for IERC20;
@@ -29,7 +29,7 @@ contract HomeGateway is IHomeGateway, UUPSProxiable, Initializable {
// * Storage * //
// ************************************* //
- address public governor;
+ address public owner;
IArbitratorV2 public arbitrator;
IVeaInbox public veaInbox;
uint256 public override foreignChainID;
@@ -43,9 +43,9 @@ contract HomeGateway is IHomeGateway, UUPSProxiable, Initializable {
// * Function Modifiers * //
// ************************************* //
- /// @dev Requires that the sender is the governor.
- modifier onlyByGovernor() {
- require(governor == msg.sender, "No allowed: governor only");
+ /// @notice Requires that the sender is the owner.
+ modifier onlyByOwner() {
+ if (owner != msg.sender) revert OwnerOnly();
_;
}
@@ -58,22 +58,22 @@ contract HomeGateway is IHomeGateway, UUPSProxiable, Initializable {
_disableInitializers();
}
- /// @dev Constructs the `PolicyRegistry` contract.
- /// @param _governor The governor's address.
+ /// @notice Constructs the `PolicyRegistry` contract.
+ /// @param _owner The owner's address.
/// @param _arbitrator The address of the arbitrator.
/// @param _veaInbox The address of the vea inbox.
/// @param _foreignChainID The ID of the foreign chain.
/// @param _foreignGateway The address of the foreign gateway.
/// @param _feeToken The address of the fee token.
function initialize(
- address _governor,
+ address _owner,
IArbitratorV2 _arbitrator,
IVeaInbox _veaInbox,
uint256 _foreignChainID,
address _foreignGateway,
IERC20 _feeToken
- ) external reinitializer(1) {
- governor = _governor;
+ ) external initializer {
+ owner = _owner;
arbitrator = _arbitrator;
veaInbox = _veaInbox;
foreignChainID = _foreignChainID;
@@ -87,39 +87,39 @@ contract HomeGateway is IHomeGateway, UUPSProxiable, Initializable {
/**
* @dev Access Control to perform implementation upgrades (UUPS Proxiable)
- * @dev Only the governor can perform upgrades (`onlyByGovernor`)
+ * @dev Only the owner can perform upgrades (`onlyByOwner`)
*/
- function _authorizeUpgrade(address) internal view override onlyByGovernor {
+ function _authorizeUpgrade(address) internal view override onlyByOwner {
// NOP
}
- /// @dev Changes the governor.
- /// @param _governor The address of the new governor.
- function changeGovernor(address _governor) external onlyByGovernor {
- governor = _governor;
+ /// @notice Changes the owner.
+ /// @param _owner The address of the new owner.
+ function changeOwner(address _owner) external onlyByOwner {
+ owner = _owner;
}
- /// @dev Changes the arbitrator.
+ /// @notice Changes the arbitrator.
/// @param _arbitrator The address of the new arbitrator.
- function changeArbitrator(IArbitratorV2 _arbitrator) external onlyByGovernor {
+ function changeArbitrator(IArbitratorV2 _arbitrator) external onlyByOwner {
arbitrator = _arbitrator;
}
- /// @dev Changes the vea inbox, useful to increase the claim deposit.
+ /// @notice Changes the vea inbox, useful to increase the claim deposit.
/// @param _veaInbox The address of the new vea inbox.
- function changeVea(IVeaInbox _veaInbox) external onlyByGovernor {
+ function changeVea(IVeaInbox _veaInbox) external onlyByOwner {
veaInbox = _veaInbox;
}
- /// @dev Changes the foreign gateway.
+ /// @notice Changes the foreign gateway.
/// @param _foreignGateway The address of the new foreign gateway.
- function changeForeignGateway(address _foreignGateway) external onlyByGovernor {
+ function changeForeignGateway(address _foreignGateway) external onlyByOwner {
foreignGateway = _foreignGateway;
}
- /// @dev Changes the fee token.
+ /// @notice Changes the fee token.
/// @param _feeToken The address of the new fee token.
- function changeFeeToken(IERC20 _feeToken) external onlyByGovernor {
+ function changeFeeToken(IERC20 _feeToken) external onlyByOwner {
feeToken = _feeToken;
}
@@ -129,8 +129,8 @@ contract HomeGateway is IHomeGateway, UUPSProxiable, Initializable {
/// @inheritdoc IHomeGateway
function relayCreateDispute(RelayCreateDisputeParams memory _params) external payable override {
- require(feeToken == NATIVE_CURRENCY, "Fees paid in ERC20 only");
- require(_params.foreignChainID == foreignChainID, "Foreign chain ID not supported");
+ if (feeToken != NATIVE_CURRENCY) revert FeesPaidInNativeCurrencyOnly();
+ if (_params.foreignChainID != foreignChainID) revert ForeignChainIDNotSupported();
bytes32 disputeHash = keccak256(
abi.encodePacked(
@@ -144,14 +144,14 @@ contract HomeGateway is IHomeGateway, UUPSProxiable, Initializable {
)
);
RelayedData storage relayedData = disputeHashtoRelayedData[disputeHash];
- require(relayedData.relayer == address(0), "Dispute already relayed");
+ if (relayedData.relayer != address(0)) revert DisputeAlreadyRelayed();
uint256 disputeID = arbitrator.createDispute{value: msg.value}(_params.choices, _params.extraData);
disputeIDtoHash[disputeID] = disputeHash;
disputeHashtoID[disputeHash] = disputeID;
relayedData.relayer = msg.sender;
- emit DisputeRequest(arbitrator, disputeID, _params.externalDisputeID, _params.templateId, _params.templateUri);
+ emit DisputeRequest(arbitrator, disputeID, _params.templateId);
emit CrossChainDisputeIncoming(
arbitrator,
@@ -159,16 +159,14 @@ contract HomeGateway is IHomeGateway, UUPSProxiable, Initializable {
_params.foreignArbitrable,
_params.foreignDisputeID,
disputeID,
- _params.externalDisputeID,
- _params.templateId,
- _params.templateUri
+ _params.templateId
);
}
/// @inheritdoc IHomeGateway
function relayCreateDispute(RelayCreateDisputeParams memory _params, uint256 _feeAmount) external {
- require(feeToken != NATIVE_CURRENCY, "Fees paid in native currency only");
- require(_params.foreignChainID == foreignChainID, "Foreign chain ID not supported");
+ if (feeToken == NATIVE_CURRENCY) revert FeesPaidInERC20Only();
+ if (_params.foreignChainID != foreignChainID) revert ForeignChainIDNotSupported();
bytes32 disputeHash = keccak256(
abi.encodePacked(
@@ -182,10 +180,10 @@ contract HomeGateway is IHomeGateway, UUPSProxiable, Initializable {
)
);
RelayedData storage relayedData = disputeHashtoRelayedData[disputeHash];
- require(relayedData.relayer == address(0), "Dispute already relayed");
+ if (relayedData.relayer != address(0)) revert DisputeAlreadyRelayed();
- require(feeToken.safeTransferFrom(msg.sender, address(this), _feeAmount), "Transfer failed");
- require(feeToken.increaseAllowance(address(arbitrator), _feeAmount), "Allowance increase failed");
+ if (!feeToken.safeTransferFrom(msg.sender, address(this), _feeAmount)) revert TransferFailed();
+ if (!feeToken.increaseAllowance(address(arbitrator), _feeAmount)) revert AllowanceIncreaseFailed();
uint256 disputeID = arbitrator.createDispute(_params.choices, _params.extraData, feeToken, _feeAmount);
disputeIDtoHash[disputeID] = disputeHash;
@@ -193,7 +191,7 @@ contract HomeGateway is IHomeGateway, UUPSProxiable, Initializable {
relayedData.relayer = msg.sender;
// Not strictly necessary for functionality, only to satisfy IArbitrableV2
- emit DisputeRequest(arbitrator, disputeID, _params.externalDisputeID, _params.templateId, _params.templateUri);
+ emit DisputeRequest(arbitrator, disputeID, _params.templateId);
emit CrossChainDisputeIncoming(
arbitrator,
@@ -201,15 +199,13 @@ contract HomeGateway is IHomeGateway, UUPSProxiable, Initializable {
_params.foreignArbitrable,
_params.foreignDisputeID,
disputeID,
- _params.externalDisputeID,
- _params.templateId,
- _params.templateUri
+ _params.templateId
);
}
/// @inheritdoc IArbitrableV2
function rule(uint256 _disputeID, uint256 _ruling) external override {
- require(msg.sender == address(arbitrator), "Only Arbitrator");
+ if (msg.sender != address(arbitrator)) revert ArbitratorOnly();
bytes32 disputeHash = disputeIDtoHash[_disputeID];
RelayedData memory relayedData = disputeHashtoRelayedData[disputeHash];
@@ -234,4 +230,17 @@ contract HomeGateway is IHomeGateway, UUPSProxiable, Initializable {
function receiverGateway() external view override returns (address) {
return foreignGateway;
}
+
+ // ************************************* //
+ // * Errors * //
+ // ************************************* //
+
+ error OwnerOnly();
+ error ArbitratorOnly();
+ error FeesPaidInERC20Only();
+ error FeesPaidInNativeCurrencyOnly();
+ error ForeignChainIDNotSupported();
+ error DisputeAlreadyRelayed();
+ error TransferFailed();
+ error AllowanceIncreaseFailed();
}
diff --git a/contracts/src/gateway/interfaces/IForeignGateway.sol b/contracts/src/gateway/interfaces/IForeignGateway.sol
index 7bdbe0f13..845713440 100644
--- a/contracts/src/gateway/interfaces/IForeignGateway.sol
+++ b/contracts/src/gateway/interfaces/IForeignGateway.sol
@@ -1,12 +1,17 @@
// SPDX-License-Identifier: MIT
-pragma solidity ^0.8.24;
+pragma solidity >=0.8.0 <0.9.0;
import "../../arbitration/interfaces/IArbitratorV2.sol";
import "@kleros/vea-contracts/src/interfaces/gateways/IReceiverGateway.sol";
+/// @title Foreign Gateway Interface
interface IForeignGateway is IArbitratorV2, IReceiverGateway {
- /// @dev To be emitted when a dispute is sent to the IHomeGateway.
+ // ************************************* //
+ // * Events * //
+ // ************************************* //
+
+ /// @notice To be emitted when a dispute is sent to the IHomeGateway.
/// @param _foreignBlockHash foreignBlockHash
/// @param _foreignArbitrable The address of the Arbitrable contract.
/// @param _foreignDisputeID The identifier of the dispute in the Arbitrable contract.
@@ -20,20 +25,35 @@ interface IForeignGateway is IArbitratorV2, IReceiverGateway {
bytes _extraData
);
- /// Relay the rule call from the home gateway to the arbitrable.
+ // ************************************* //
+ // * State Modifiers * //
+ // ************************************* //
+
+ /// @notice Relay the rule call from the home gateway to the arbitrable.
+ /// @param _messageSender The address of the message sender.
+ /// @param _disputeHash The dispute hash.
+ /// @param _ruling The ruling.
+ /// @param _forwarder The address of the forwarder.
function relayRule(address _messageSender, bytes32 _disputeHash, uint256 _ruling, address _forwarder) external;
- /// Reimburses the dispute fees to the relayer who paid for these fees on the home chain.
+ /// @notice Reimburses the dispute fees to the relayer who paid for these fees on the home chain.
/// @param _disputeHash The dispute hash for which to withdraw the fees.
function withdrawFees(bytes32 _disputeHash) external;
- /// @dev Looks up the local foreign disputeID for a disputeHash
- /// @param _disputeHash dispute hash
+ // ************************************* //
+ // * Public Views * //
+ // ************************************* //
+
+ /// @notice Looks up the local foreign disputeID for a disputeHash
+ /// @param _disputeHash The dispute hash.
+ /// @return The local foreign disputeID.
function disputeHashToForeignID(bytes32 _disputeHash) external view returns (uint256);
+ /// @notice Home chain identifier.
/// @return The chain ID where the corresponding home gateway is deployed.
function homeChainID() external view returns (uint256);
+ /// @notice Home gateway address.
/// @return The address of the corresponding home gateway.
function homeGateway() external view returns (address);
}
diff --git a/contracts/src/gateway/interfaces/IHomeGateway.sol b/contracts/src/gateway/interfaces/IHomeGateway.sol
index 2ccc00ac7..c2142e405 100644
--- a/contracts/src/gateway/interfaces/IHomeGateway.sol
+++ b/contracts/src/gateway/interfaces/IHomeGateway.sol
@@ -1,68 +1,85 @@
// SPDX-License-Identifier: MIT
-pragma solidity ^0.8.24;
+pragma solidity >=0.8.0 <0.9.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@kleros/vea-contracts/src/interfaces/gateways/ISenderGateway.sol";
import "../../arbitration/interfaces/IArbitrableV2.sol";
+/// @title Home Gateway Interface
interface IHomeGateway is IArbitrableV2, ISenderGateway {
- /// @dev To be emitted when a dispute is received from the IForeignGateway.
+ // ************************************* //
+ // * Events * //
+ // ************************************* //
+
+ /// @notice To be emitted when a dispute is received from the IForeignGateway.
/// @param _arbitrator The arbitrator of the contract.
/// @param _arbitrableChainId The chain identifier where the Arbitrable contract is deployed.
/// @param _arbitrable The address of the Arbitrable contract.
/// @param _arbitrableDisputeID The identifier of the dispute in the Arbitrable contract.
/// @param _arbitratorDisputeID The identifier of the dispute in the Arbitrator contract.
- /// @param _externalDisputeID An identifier created outside Kleros by the protocol requesting arbitration.
- /// @param _templateId The identifier of the dispute template. Should not be used with _templateUri.
- /// @param _templateUri IPFS path to the dispute template starting with '/ipfs/'. Should not be used with _templateId.
event CrossChainDisputeIncoming(
IArbitratorV2 _arbitrator,
uint256 _arbitrableChainId,
address indexed _arbitrable,
uint256 indexed _arbitrableDisputeID,
uint256 indexed _arbitratorDisputeID,
- uint256 _externalDisputeID,
- uint256 _templateId,
- string _templateUri
+ uint256 _templateId
);
+ // ************************************* //
+ // * Enums / Structs * //
+ // ************************************* //
+
// Workaround stack too deep for relayCreateDispute()
struct RelayCreateDisputeParams {
bytes32 foreignBlockHash;
uint256 foreignChainID;
address foreignArbitrable;
uint256 foreignDisputeID;
- uint256 externalDisputeID;
uint256 templateId;
- string templateUri;
uint256 choices;
bytes extraData;
}
- /// @dev Relays a dispute creation from the ForeignGateway to the home arbitrator using the same parameters as the ones on the foreign chain.
- /// Providing incorrect parameters will create a different hash than on the foreignChain and will not affect the actual dispute/arbitrable's ruling.
- /// This function accepts the fees payment in the native currency of the home chain, typically ETH.
+ // ************************************* //
+ // * State Modifiers * //
+ // ************************************* //
+
+ /// @notice Relays a dispute creation from the ForeignGateway to the home arbitrator using the same parameters as the ones on the foreign chain.
+ ///
+ /// @dev Providing incorrect parameters will create a different hash than on the foreignChain and will not affect the actual dispute/arbitrable's ruling.
+ /// This function accepts the fees payment in the native currency of the home chain, typically ETH.
+ ///
/// @param _params The parameters of the dispute, see `RelayCreateDisputeParams`.
function relayCreateDispute(RelayCreateDisputeParams memory _params) external payable;
- /// @dev Relays a dispute creation from the ForeignGateway to the home arbitrator using the same parameters as the ones on the foreign chain.
- /// Providing incorrect parameters will create a different hash than on the foreignChain and will not affect the actual dispute/arbitrable's ruling.
- /// This function accepts the fees payment in the ERC20 `acceptedFeeToken()`.
+ /// @notice Relays a dispute creation from the ForeignGateway to the home arbitrator using the same parameters as the ones on the foreign chain.
+ ///
+ /// @dev Providing incorrect parameters will create a different hash than on the foreignChain and will not affect the actual dispute/arbitrable's ruling.
+ /// This function accepts the fees payment in the ERC20 `acceptedFeeToken()`.
+ ///
/// @param _params The parameters of the dispute, see `RelayCreateDisputeParams`.
function relayCreateDispute(RelayCreateDisputeParams memory _params, uint256 _feeAmount) external;
- /// @dev Looks up the local home disputeID for a disputeHash
+ // ************************************* //
+ // * Public Views * //
+ // ************************************* //
+
+ /// @notice Looks up the local home disputeID for a disputeHash
/// @param _disputeHash dispute hash
/// @return disputeID dispute identifier on the home chain
function disputeHashToHomeID(bytes32 _disputeHash) external view returns (uint256);
+ /// @notice Foreign chain identifier.
/// @return The chain ID where the corresponding foreign gateway is deployed.
function foreignChainID() external view returns (uint256);
+ /// @notice Foreign gateway address.
/// @return The address of the corresponding foreign gateway.
function foreignGateway() external view returns (address);
- /// return The fee token.
+ /// @notice Fee token.
+ /// @return The fee token.
function feeToken() external view returns (IERC20);
}
diff --git a/contracts/src/kleros-v1/interfaces/IKlerosLiquid.sol b/contracts/src/kleros-v1/interfaces/IKlerosLiquid.sol
index 0422c95b3..56d3c7789 100644
--- a/contracts/src/kleros-v1/interfaces/IKlerosLiquid.sol
+++ b/contracts/src/kleros-v1/interfaces/IKlerosLiquid.sol
@@ -77,7 +77,7 @@ interface IKlerosLiquid is IArbitratorV1 {
function changeSubcourtTimesPerPeriod(uint96 _subcourtID, uint256[4] calldata _timesPerPeriod) external;
- function executeGovernorProposal(address _destination, uint256 _amount, bytes calldata _data) external;
+ function executeOwnerProposal(address _destination, uint256 _amount, bytes calldata _data) external;
// Getters
function getVote(
diff --git a/contracts/src/kleros-v1/kleros-liquid-xdai/xKlerosLiquidV2.sol b/contracts/src/kleros-v1/kleros-liquid-xdai/xKlerosLiquidV2.sol
index 0d7d97adb..59ff80353 100644
--- a/contracts/src/kleros-v1/kleros-liquid-xdai/xKlerosLiquidV2.sol
+++ b/contracts/src/kleros-v1/kleros-liquid-xdai/xKlerosLiquidV2.sol
@@ -9,7 +9,7 @@ import {ITokenController} from "../interfaces/ITokenController.sol";
import {WrappedPinakion} from "./WrappedPinakion.sol";
import {IRandomAuRa} from "./interfaces/IRandomAuRa.sol";
-import {SortitionSumTreeFactory} from "../../libraries/SortitionSumTreeFactory.sol";
+import {SortitionSumTreeFactory} from "../libraries/SortitionSumTreeFactory.sol";
import "../../gateway/interfaces/IForeignGateway.sol";
/// @title xKlerosLiquidV2
@@ -141,9 +141,8 @@ contract xKlerosLiquidV2 is Initializable, ITokenController, IArbitratorV2 {
uint256 public constant MAX_STAKE_PATHS = 4; // The maximum number of stake paths a juror can have.
uint256 public constant DEFAULT_NB_OF_JURORS = 3; // The default number of jurors in a dispute.
uint256 public constant NON_PAYABLE_AMOUNT = (2 ** 256 - 2) / 2; // An amount higher than the supply of ETH.
- uint256 public constant ALPHA_DIVISOR = 1e4; // The number to divide `Court.alpha` by.
// General Contracts
- address public governor; // The governor of the contract.
+ address public owner; // The owner of the contract.
WrappedPinakion public pinakion; // The Pinakion token contract.
IRandomAuRa public RNGenerator; // The random number generator contract.
// General Dynamic
@@ -198,9 +197,9 @@ contract xKlerosLiquidV2 is Initializable, ITokenController, IArbitratorV2 {
_;
}
- /// @dev Requires that the sender is the governor. Note that the governor is expected to not be malicious.
- modifier onlyByGovernor() {
- require(governor == msg.sender);
+ /// @dev Requires that the sender is the owner. Note that the owner is expected to not be malicious.
+ modifier onlyByOwner() {
+ require(owner == msg.sender);
_;
}
@@ -209,7 +208,7 @@ contract xKlerosLiquidV2 is Initializable, ITokenController, IArbitratorV2 {
// ************************************* //
/// @dev Constructs the KlerosLiquid contract.
- /// @param _governor The governor's address.
+ /// @param _owner The owner's address.
/// @param _pinakion The address of the token contract.
/// @param _RNGenerator The address of the random number generator contract.
/// @param _minStakingTime The minimum time that the staking phase should last.
@@ -220,7 +219,7 @@ contract xKlerosLiquidV2 is Initializable, ITokenController, IArbitratorV2 {
/// @param _sortitionSumTreeK The number of children per node of the general court's sortition sum tree.
/// @param _foreignGateway Foreign gateway on xDai.
function initialize(
- address _governor,
+ address _owner,
WrappedPinakion _pinakion,
IRandomAuRa _RNGenerator,
uint256 _minStakingTime,
@@ -232,7 +231,7 @@ contract xKlerosLiquidV2 is Initializable, ITokenController, IArbitratorV2 {
IForeignGateway _foreignGateway
) public initializer {
// Initialize contract.
- governor = _governor;
+ owner = _owner;
pinakion = _pinakion;
RNGenerator = _RNGenerator;
minStakingTime = _minStakingTime;
@@ -265,34 +264,30 @@ contract xKlerosLiquidV2 is Initializable, ITokenController, IArbitratorV2 {
// * Governance * //
// ************************************* //
- /// @dev Lets the governor call anything on behalf of the contract.
+ /// @dev Lets the owner call anything on behalf of the contract.
/// @param _destination The destination of the call.
/// @param _amount The value sent with the call.
/// @param _data The data sent with the call.
- function executeGovernorProposal(
- address _destination,
- uint256 _amount,
- bytes memory _data
- ) external onlyByGovernor {
+ function executeOwnerProposal(address _destination, uint256 _amount, bytes memory _data) external onlyByOwner {
(bool success, ) = _destination.call{value: _amount}(_data);
require(success, "Unsuccessful call");
}
- /// @dev Changes the `governor` storage variable.
- /// @param _governor The new value for the `governor` storage variable.
- function changeGovernor(address _governor) external onlyByGovernor {
- governor = _governor;
+ /// @dev Changes the `owner` storage variable.
+ /// @param _owner The new value for the `owner` storage variable.
+ function changeOwner(address _owner) external onlyByOwner {
+ owner = _owner;
}
/// @dev Changes the `pinakion` storage variable.
/// @param _pinakion The new value for the `pinakion` storage variable.
- function changePinakion(WrappedPinakion _pinakion) external onlyByGovernor {
+ function changePinakion(WrappedPinakion _pinakion) external onlyByOwner {
pinakion = _pinakion;
}
/// @dev Changes the `RNGenerator` storage variable.
/// @param _RNGenerator The new value for the `RNGenerator` storage variable.
- function changeRNGenerator(IRandomAuRa _RNGenerator) external onlyByGovernor {
+ function changeRNGenerator(IRandomAuRa _RNGenerator) external onlyByOwner {
RNGenerator = _RNGenerator;
if (phase == Phase.generating) {
RNBlock = RNGenerator.nextCommitPhaseStartBlock() + RNGenerator.collectRoundLength();
@@ -301,19 +296,19 @@ contract xKlerosLiquidV2 is Initializable, ITokenController, IArbitratorV2 {
/// @dev Changes the `minStakingTime` storage variable.
/// @param _minStakingTime The new value for the `minStakingTime` storage variable.
- function changeMinStakingTime(uint256 _minStakingTime) external onlyByGovernor {
+ function changeMinStakingTime(uint256 _minStakingTime) external onlyByOwner {
minStakingTime = _minStakingTime;
}
/// @dev Changes the `maxDrawingTime` storage variable.
/// @param _maxDrawingTime The new value for the `maxDrawingTime` storage variable.
- function changeMaxDrawingTime(uint256 _maxDrawingTime) external onlyByGovernor {
+ function changeMaxDrawingTime(uint256 _maxDrawingTime) external onlyByOwner {
maxDrawingTime = _maxDrawingTime;
}
/// @dev Changes the `foreignGateway` storage variable.
/// @param _foreignGateway The new value for the `foreignGateway` storage variable.
- function changeForeignGateway(IForeignGateway _foreignGateway) external onlyByGovernor {
+ function changeForeignGateway(IForeignGateway _foreignGateway) external onlyByOwner {
foreignGateway = _foreignGateway;
}
@@ -335,7 +330,7 @@ contract xKlerosLiquidV2 is Initializable, ITokenController, IArbitratorV2 {
uint256 _jurorsForCourtJump,
uint256[4] memory _timesPerPeriod,
uint256 _sortitionSumTreeK
- ) external onlyByGovernor {
+ ) external onlyByOwner {
require(
courts[_parent].minStake <= _minStake,
"A subcourt cannot be a child of a subcourt with a higher minimum stake."
@@ -361,7 +356,7 @@ contract xKlerosLiquidV2 is Initializable, ITokenController, IArbitratorV2 {
/// @dev Changes the `minStake` property value of a specified subcourt. Don't set to a value lower than its parent's `minStake` property value.
/// @param _subcourtID The ID of the subcourt.
/// @param _minStake The new value for the `minStake` property value.
- function changeSubcourtMinStake(uint96 _subcourtID, uint256 _minStake) external onlyByGovernor {
+ function changeSubcourtMinStake(uint96 _subcourtID, uint256 _minStake) external onlyByOwner {
require(_subcourtID == 0 || courts[courts[_subcourtID].parent].minStake <= _minStake);
for (uint256 i = 0; i < courts[_subcourtID].children.length; i++) {
require(
@@ -376,31 +371,28 @@ contract xKlerosLiquidV2 is Initializable, ITokenController, IArbitratorV2 {
/// @dev Changes the `alpha` property value of a specified subcourt.
/// @param _subcourtID The ID of the subcourt.
/// @param _alpha The new value for the `alpha` property value.
- function changeSubcourtAlpha(uint96 _subcourtID, uint256 _alpha) external onlyByGovernor {
+ function changeSubcourtAlpha(uint96 _subcourtID, uint256 _alpha) external onlyByOwner {
courts[_subcourtID].alpha = _alpha;
}
/// @dev Changes the `feeForJuror` property value of a specified subcourt.
/// @param _subcourtID The ID of the subcourt.
/// @param _feeForJuror The new value for the `feeForJuror` property value.
- function changeSubcourtJurorFee(uint96 _subcourtID, uint256 _feeForJuror) external onlyByGovernor {
+ function changeSubcourtJurorFee(uint96 _subcourtID, uint256 _feeForJuror) external onlyByOwner {
courts[_subcourtID].feeForJuror = _feeForJuror;
}
/// @dev Changes the `jurorsForCourtJump` property value of a specified subcourt.
/// @param _subcourtID The ID of the subcourt.
/// @param _jurorsForCourtJump The new value for the `jurorsForCourtJump` property value.
- function changeSubcourtJurorsForJump(uint96 _subcourtID, uint256 _jurorsForCourtJump) external onlyByGovernor {
+ function changeSubcourtJurorsForJump(uint96 _subcourtID, uint256 _jurorsForCourtJump) external onlyByOwner {
courts[_subcourtID].jurorsForCourtJump = _jurorsForCourtJump;
}
/// @dev Changes the `timesPerPeriod` property value of a specified subcourt.
/// @param _subcourtID The ID of the subcourt.
/// @param _timesPerPeriod The new value for the `timesPerPeriod` property value.
- function changeSubcourtTimesPerPeriod(
- uint96 _subcourtID,
- uint256[4] memory _timesPerPeriod
- ) external onlyByGovernor {
+ function changeSubcourtTimesPerPeriod(uint96 _subcourtID, uint256[4] memory _timesPerPeriod) external onlyByOwner {
courts[_subcourtID].timesPerPeriod = _timesPerPeriod;
}
diff --git a/contracts/src/kleros-v1/kleros-liquid/KlerosLiquidToV2Governor.sol b/contracts/src/kleros-v1/kleros-liquid/KlerosLiquidToV2Governor.sol
index 509b85101..def339931 100644
--- a/contracts/src/kleros-v1/kleros-liquid/KlerosLiquidToV2Governor.sol
+++ b/contracts/src/kleros-v1/kleros-liquid/KlerosLiquidToV2Governor.sol
@@ -26,7 +26,7 @@ contract KlerosLiquidToV2Governor is IArbitrableV2, ITokenController {
IArbitratorV2 public immutable foreignGateway;
IKlerosLiquid public immutable klerosLiquid;
- address public governor;
+ address public owner;
mapping(uint256 disputeId => uint256 gatewayDisputeId) public klerosLiquidDisputeIDtoGatewayDisputeID;
mapping(uint256 gatewayDisputeId => DisputeData) public disputes; // disputes[gatewayDisputeID]
mapping(address account => uint256 tokenAmount) public frozenTokens; // frozenTokens[account] locked token which shouldn't have been blocked.
@@ -36,8 +36,8 @@ contract KlerosLiquidToV2Governor is IArbitrableV2, ITokenController {
// * Function Modifiers * //
// ************************************* //
- modifier onlyByGovernor() {
- require(governor == msg.sender);
+ modifier onlyByOwner() {
+ require(owner == msg.sender);
_;
}
@@ -45,13 +45,13 @@ contract KlerosLiquidToV2Governor is IArbitrableV2, ITokenController {
// * Constructor * //
// ************************************* //
- /// @dev Constructor. Before this contract is made the new governor of KlerosLiquid, the evidence period of all subcourts has to be set to uint(-1).
+ /// @dev Constructor. Before this contract is made the new owner of KlerosLiquid, the evidence period of all subcourts has to be set to uint(-1).
/// @param _klerosLiquid The trusted arbitrator to resolve potential disputes.
- /// @param _governor The trusted governor of the contract.
+ /// @param _owner The trusted owner of the contract.
/// @param _foreignGateway The trusted gateway that acts as an arbitrator, relaying disputes to v2.
- constructor(IKlerosLiquid _klerosLiquid, address _governor, IArbitratorV2 _foreignGateway) {
+ constructor(IKlerosLiquid _klerosLiquid, address _owner, IArbitratorV2 _foreignGateway) {
klerosLiquid = _klerosLiquid;
- governor = _governor;
+ owner = _owner;
foreignGateway = _foreignGateway;
}
@@ -59,23 +59,19 @@ contract KlerosLiquidToV2Governor is IArbitrableV2, ITokenController {
// * Governance * //
// ************************************* //
- /// @dev Lets the governor call anything on behalf of the contract.
+ /// @dev Lets the owner call anything on behalf of the contract.
/// @param _destination The destination of the call.
/// @param _amount The value sent with the call.
/// @param _data The data sent with the call.
- function executeGovernorProposal(
- address _destination,
- uint256 _amount,
- bytes calldata _data
- ) external onlyByGovernor {
+ function executeOwnerProposal(address _destination, uint256 _amount, bytes calldata _data) external onlyByOwner {
(bool success, ) = _destination.call{value: _amount}(_data); // solium-disable-line security/no-call-value
require(success, "Call execution failed.");
}
- /// @dev Changes the `governor` storage variable.
- /// @param _governor The new value for the `governor` storage variable.
- function changeGovernor(address _governor) external onlyByGovernor {
- governor = _governor;
+ /// @dev Changes the `owner` storage variable.
+ /// @param _owner The new value for the `owner` storage variable.
+ function changeOwner(address _owner) external onlyByOwner {
+ owner = _owner;
}
// ************************************* //
@@ -94,7 +90,7 @@ contract KlerosLiquidToV2Governor is IArbitrableV2, ITokenController {
require(KlerosLiquidDispute.period == IKlerosLiquid.Period.evidence, "Invalid dispute period.");
require(votesLengths.length == 1, "Cannot relay appeals.");
- klerosLiquid.executeGovernorProposal(address(this), totalFeesForJurors[0], "");
+ klerosLiquid.executeOwnerProposal(address(this), totalFeesForJurors[0], "");
uint256 minJurors = votesLengths[0];
bytes memory extraData = abi.encode(KlerosLiquidDispute.subcourtID, minJurors);
@@ -125,7 +121,7 @@ contract KlerosLiquidToV2Governor is IArbitrableV2, ITokenController {
IKlerosLiquid.Dispute memory klerosLiquidDispute = klerosLiquid.disputes(dispute.klerosLiquidDisputeID);
bytes memory data = abi.encodeCall(IArbitrableV2.rule, (dispute.klerosLiquidDisputeID, _ruling));
- klerosLiquid.executeGovernorProposal(klerosLiquidDispute.arbitrated, 0, data);
+ klerosLiquid.executeOwnerProposal(klerosLiquidDispute.arbitrated, 0, data);
}
/// @dev Registers jurors' tokens which where locked due to relaying a given dispute. These tokens don't count as locked.
diff --git a/contracts/src/libraries/SortitionSumTreeFactory.sol b/contracts/src/kleros-v1/libraries/SortitionSumTreeFactory.sol
similarity index 100%
rename from contracts/src/libraries/SortitionSumTreeFactory.sol
rename to contracts/src/kleros-v1/libraries/SortitionSumTreeFactory.sol
diff --git a/contracts/src/libraries/CappedMath.sol b/contracts/src/libraries/CappedMath.sol
deleted file mode 100644
index ce0cdf55c..000000000
--- a/contracts/src/libraries/CappedMath.sol
+++ /dev/null
@@ -1,36 +0,0 @@
-// SPDX-License-Identifier: MIT
-
-pragma solidity ^0.8.24;
-
-/// @title CappedMath
-/// @dev Math operations with caps for under and overflow.
-library CappedMath {
- uint256 private constant UINT_MAX = type(uint256).max;
-
- /// @dev Adds two unsigned integers, returns 2^256 - 1 on overflow.
- function addCap(uint256 _a, uint256 _b) internal pure returns (uint256) {
- unchecked {
- uint256 c = _a + _b;
- return c >= _a ? c : UINT_MAX;
- }
- }
-
- /// @dev Subtracts two integers, returns 0 on underflow.
- function subCap(uint256 _a, uint256 _b) internal pure returns (uint256) {
- if (_b > _a) return 0;
- else return _a - _b;
- }
-
- /// @dev Multiplies two unsigned integers, returns 2^256 - 1 on overflow.
- function mulCap(uint256 _a, uint256 _b) internal pure returns (uint256) {
- // Gas optimization: this is cheaper than requiring '_a' not being zero, but the
- // benefit is lost if '_b' is also tested.
- // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
- if (_a == 0) return 0;
-
- unchecked {
- uint256 c = _a * _b;
- return c / _a == _b ? c : UINT_MAX;
- }
- }
-}
diff --git a/contracts/src/libraries/Constants.sol b/contracts/src/libraries/Constants.sol
index bed573fa6..1f0132668 100644
--- a/contracts/src/libraries/Constants.sol
+++ b/contracts/src/libraries/Constants.sol
@@ -9,7 +9,7 @@ uint96 constant FORKING_COURT = 0; // Index of the forking court.
uint96 constant GENERAL_COURT = 1; // Index of the default (general) court.
// Dispute Kits
-uint256 constant NULL_DISPUTE_KIT = 0; // Null pattern to indicate a top-level DK which has no parent. DEPRECATED, as its main purpose was to accommodate forest structure which is not used now.
+uint256 constant NULL_DISPUTE_KIT = 0; // Null pattern to indicate a top-level DK which has no parent.
uint256 constant DISPUTE_KIT_CLASSIC = 1; // Index of the default DK. 0 index is skipped.
// Sortition Module
@@ -20,6 +20,9 @@ uint256 constant DEFAULT_K = 6; // Default number of children per node.
uint256 constant DEFAULT_NB_OF_JURORS = 3; // The default number of jurors in a dispute.
IERC20 constant NATIVE_CURRENCY = IERC20(address(0)); // The native currency, such as ETH on Arbitrum, Optimism and Ethereum L1.
+// Units
+uint256 constant ONE_BASIS_POINT = 10000;
+
enum OnError {
Revert,
Return
diff --git a/contracts/src/libraries/SafeERC20.sol b/contracts/src/libraries/SafeERC20.sol
index 35f538350..35d1401f9 100644
--- a/contracts/src/libraries/SafeERC20.sol
+++ b/contracts/src/libraries/SafeERC20.sol
@@ -6,14 +6,16 @@ pragma solidity ^0.8.24;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
/// @title SafeERC20
-/// @dev Wrappers around ERC20 operations that throw on failure (when the token
-/// contract returns false). Tokens that return no value (and instead revert or
-/// throw on failure) are also supported, non-reverting calls are assumed to be
-/// successful.
+///
+/// @notice Wrappers around ERC20 operations
+///
+/// @dev Throws on failure (when the token contract returns false).
+/// Tokens that return no value (and instead revert or throw on failure) are also supported.
+/// Non-reverting calls are assumed to be successful.
/// To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
/// which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
library SafeERC20 {
- /// @dev Increases the allowance granted to `spender` by the caller.
+ /// @notice Increases the allowance granted to `spender` by the caller.
/// @param _token Token to transfer.
/// @param _spender The address which will spend the funds.
/// @param _addedValue The amount of tokens to increase the allowance by.
@@ -22,7 +24,7 @@ library SafeERC20 {
return true;
}
- /// @dev Calls transfer() without reverting.
+ /// @notice Calls transfer() without reverting.
/// @param _token Token to transfer.
/// @param _to Recipient address.
/// @param _value Amount transferred.
@@ -32,7 +34,7 @@ library SafeERC20 {
return (success && (data.length == 0 || abi.decode(data, (bool))));
}
- /// @dev Calls transferFrom() without reverting.
+ /// @notice Calls transferFrom() without reverting.
/// @param _token Token to transfer.
/// @param _from Sender address.
/// @param _to Recipient address.
diff --git a/contracts/src/libraries/SafeSend.sol b/contracts/src/libraries/SafeSend.sol
index fcd02d815..850aaf0df 100644
--- a/contracts/src/libraries/SafeSend.sol
+++ b/contracts/src/libraries/SafeSend.sol
@@ -19,6 +19,6 @@ library SafeSend {
if (_to.send(_value)) return;
WethLike(_wethLike).deposit{value: _value}();
- WethLike(_wethLike).transfer(_to, _value);
+ WethLike(_wethLike).transfer(_to, _value); /// forge-lint: disable-line(erc20-unchecked-transfer)
}
}
diff --git a/contracts/src/libraries/SortitionTrees.sol b/contracts/src/libraries/SortitionTrees.sol
new file mode 100644
index 000000000..b6db48e20
--- /dev/null
+++ b/contracts/src/libraries/SortitionTrees.sol
@@ -0,0 +1,239 @@
+// SPDX-License-Identifier: MIT
+
+pragma solidity ^0.8.24;
+
+type TreeKey is bytes32;
+type CourtID is uint96;
+
+using {SortitionTrees.toTreeKey} for CourtID global;
+
+library SortitionTrees {
+ // ************************************* //
+ // * Enums / Structs * //
+ // ************************************* //
+
+ struct Tree {
+ uint256 K; // The maximum number of children per node.
+ uint256[] stack; // We use this to keep track of vacant positions in the tree after removing a leaf. This is for keeping the tree as balanced as possible without spending gas on moving nodes around.
+ uint256[] nodes; // The tree nodes.
+ // Two-way mapping of IDs to node indexes. Note that node index 0 is reserved for the root node, and means the ID does not have a node.
+ mapping(bytes32 stakePathID => uint256 nodeIndex) IDsToNodeIndexes;
+ mapping(uint256 nodeIndex => bytes32 stakePathID) nodeIndexesToIDs;
+ }
+
+ function toTreeKey(CourtID _courtID) internal pure returns (TreeKey) {
+ return TreeKey.wrap(bytes32(uint256(CourtID.unwrap(_courtID))));
+ }
+
+ // ************************************* //
+ // * State Modifiers * //
+ // ************************************* //
+
+ /// @notice Create a sortition sum tree at the specified key.
+ /// @param _trees The mapping of sortition sum trees.
+ /// @param _key The key of the new tree.
+ /// @param _k The maximum number of children per node.
+ function createTree(mapping(TreeKey key => Tree) storage _trees, TreeKey _key, uint256 _k) internal {
+ Tree storage tree = _trees[_key];
+ if (tree.K != 0) revert TreeAlreadyExists();
+ if (_k <= 1) revert KMustBeGreaterThanOne();
+ tree.K = _k;
+ tree.nodes.push(0);
+ }
+
+ /// @notice Draw an ID from a tree using a number.
+ ///
+ /// @dev This function reverts if the sum of all values in the tree is 0.
+ /// `O(k * log_k(n))` where
+ /// `k` is the maximum number of children per node in the tree,
+ /// and `n` is the maximum number of nodes ever appended.
+ ///
+ /// @param _tree The sortition sum tree.
+ /// @param _coreDisputeID Index of the dispute in Kleros Core.
+ /// @param _nonce Nonce to hash with random number.
+ /// @return drawnAddress The drawn address.
+ function draw(
+ Tree storage _tree,
+ uint256 _coreDisputeID,
+ uint256 _nonce,
+ uint256 _randomNumber
+ ) internal view returns (address drawnAddress, uint96 fromSubcourtID) {
+ if (_tree.nodes[0] == 0) {
+ return (address(0), 0); // No jurors staked.
+ }
+
+ uint256 currentDrawnNumber = uint256(keccak256(abi.encodePacked(_randomNumber, _coreDisputeID, _nonce))) %
+ _tree.nodes[0];
+
+ // While it still has children
+ uint256 treeIndex = 0;
+ while ((_tree.K * treeIndex) + 1 < _tree.nodes.length) {
+ for (uint256 i = 1; i <= _tree.K; i++) {
+ // Loop over children.
+ uint256 nodeIndex = (_tree.K * treeIndex) + i;
+ uint256 nodeValue = _tree.nodes[nodeIndex];
+
+ if (currentDrawnNumber >= nodeValue) {
+ // Go to the next child.
+ currentDrawnNumber -= nodeValue;
+ } else {
+ // Pick this child.
+ treeIndex = nodeIndex;
+ break;
+ }
+ }
+ }
+
+ bytes32 stakePathID = _tree.nodeIndexesToIDs[treeIndex];
+ (drawnAddress, fromSubcourtID) = toAccountAndCourtID(stakePathID);
+ }
+
+ /// @notice Set a value in a tree.
+ ///
+ /// @dev `O(log_k(n))` where
+ /// `k` is the maximum number of children per node in the tree,
+ /// and `n` is the maximum number of nodes ever appended.
+ ///
+ /// @param _tree The sortition sum tree.
+ /// @param _value The new value.
+ /// @param _stakePathID The ID of the value.
+ function set(Tree storage _tree, uint256 _value, bytes32 _stakePathID) internal {
+ uint256 treeIndex = _tree.IDsToNodeIndexes[_stakePathID];
+
+ if (treeIndex == 0) {
+ // No existing node.
+ if (_value != 0) {
+ // Non zero value.
+ // Append.
+ // Add node.
+ if (_tree.stack.length == 0) {
+ // No vacant spots.
+ // Get the index and append the value.
+ treeIndex = _tree.nodes.length;
+ _tree.nodes.push(_value);
+
+ // Potentially append a new node and make the parent a sum node.
+ if (treeIndex != 1 && (treeIndex - 1) % _tree.K == 0) {
+ // Is first child.
+ uint256 parentIndex = treeIndex / _tree.K;
+ bytes32 parentID = _tree.nodeIndexesToIDs[parentIndex];
+ uint256 newIndex = treeIndex + 1;
+ _tree.nodes.push(_tree.nodes[parentIndex]);
+ delete _tree.nodeIndexesToIDs[parentIndex];
+ _tree.IDsToNodeIndexes[parentID] = newIndex;
+ _tree.nodeIndexesToIDs[newIndex] = parentID;
+ }
+ } else {
+ // Some vacant spot.
+ // Pop the stack and append the value.
+ treeIndex = _tree.stack[_tree.stack.length - 1];
+ _tree.stack.pop();
+ _tree.nodes[treeIndex] = _value;
+ }
+
+ // Add label.
+ _tree.IDsToNodeIndexes[_stakePathID] = treeIndex;
+ _tree.nodeIndexesToIDs[treeIndex] = _stakePathID;
+
+ updateParents(_tree, treeIndex, true, _value);
+ }
+ } else {
+ // Existing node.
+ if (_value == 0) {
+ // Zero value.
+ // Remove.
+ // Remember value and set to 0.
+ uint256 value = _tree.nodes[treeIndex];
+ _tree.nodes[treeIndex] = 0;
+
+ // Push to stack.
+ _tree.stack.push(treeIndex);
+
+ // Clear label.
+ delete _tree.IDsToNodeIndexes[_stakePathID];
+ delete _tree.nodeIndexesToIDs[treeIndex];
+
+ updateParents(_tree, treeIndex, false, value);
+ } else if (_value != _tree.nodes[treeIndex]) {
+ // New, non zero value.
+ // Set.
+ bool plusOrMinus = _tree.nodes[treeIndex] <= _value;
+ uint256 plusOrMinusValue = plusOrMinus
+ ? _value - _tree.nodes[treeIndex]
+ : _tree.nodes[treeIndex] - _value;
+ _tree.nodes[treeIndex] = _value;
+
+ updateParents(_tree, treeIndex, plusOrMinus, plusOrMinusValue);
+ }
+ }
+ }
+
+ /// @notice Update all the parents of a node.
+ ///
+ /// @dev `O(log_k(n))` where
+ /// `k` is the maximum number of children per node in the tree,
+ /// and `n` is the maximum number of nodes ever appended.
+ ///
+ /// @param _tree The sortition sum tree.
+ /// @param _treeIndex The index of the node to start from.
+ /// @param _plusOrMinus Whether to add (true) or substract (false).
+ /// @param _value The value to add or substract.
+ function updateParents(Tree storage _tree, uint256 _treeIndex, bool _plusOrMinus, uint256 _value) private {
+ uint256 parentIndex = _treeIndex;
+ while (parentIndex != 0) {
+ parentIndex = (parentIndex - 1) / _tree.K;
+ _tree.nodes[parentIndex] = _plusOrMinus
+ ? _tree.nodes[parentIndex] + _value
+ : _tree.nodes[parentIndex] - _value;
+ }
+ }
+
+ // ************************************* //
+ // * Public Views * //
+ // ************************************* //
+
+ /// @notice Get the stake of a juror in a court.
+ /// @param _tree The sortition sum tree.
+ /// @param _stakePathID The stake path ID, corresponding to a juror.
+ /// @return The stake of the juror in the court.
+ function stakeOf(Tree storage _tree, bytes32 _stakePathID) internal view returns (uint256) {
+ uint256 treeIndex = _tree.IDsToNodeIndexes[_stakePathID];
+ if (treeIndex == 0) {
+ return 0;
+ }
+ return _tree.nodes[treeIndex];
+ }
+
+ /// @notice Packs an account and a court ID into a stake path ID
+ /// @dev [20 bytes of address][12 bytes of courtID] = 32 bytes total.
+ /// @param _account The address of the juror to pack.
+ /// @param _courtID The court ID to pack.
+ /// @return stakePathID The stake path ID.
+ function toStakePathID(address _account, uint96 _courtID) internal pure returns (bytes32 stakePathID) {
+ assembly {
+ // solium-disable-line security/no-inline-assembly
+ // Pack address (20 bytes) and courtID (12 bytes) into a single bytes32
+ stakePathID := or(shl(96, _account), _courtID)
+ }
+ }
+
+ /// @notice Retrieves both juror's address and court ID from the stake path ID.
+ /// @param _stakePathID The stake path ID to unpack.
+ /// @return account The account.
+ /// @return courtID The court ID.
+ function toAccountAndCourtID(bytes32 _stakePathID) internal pure returns (address account, uint96 courtID) {
+ assembly {
+ // solium-disable-line security/no-inline-assembly
+ // Unpack address (first 20 bytes) and courtID (last 12 bytes) from the stake path ID
+ account := shr(96, _stakePathID) // Right shift by 96 bits to get the address
+ courtID := and(_stakePathID, 0xffffffffffffffffffffffff) // Mask the lower 96 bits to get the court ID
+ }
+ }
+
+ // ************************************* //
+ // * Errors * //
+ // ************************************* //
+
+ error TreeAlreadyExists();
+ error KMustBeGreaterThanOne();
+}
diff --git a/contracts/src/proxy/Initializable.sol b/contracts/src/proxy/Initializable.sol
index 47769a9f2..7bdf08eb4 100644
--- a/contracts/src/proxy/Initializable.sol
+++ b/contracts/src/proxy/Initializable.sol
@@ -93,7 +93,7 @@ abstract contract Initializable {
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts.
*
- * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a
+ * Similar to `initializer()`, except that functions marked with `initializer` can be nested in the context of a
* constructor.
*
* Emits an {Initialized} event.
diff --git a/contracts/src/proxy/KlerosProxies.sol b/contracts/src/proxy/KlerosProxies.sol
index 57b521ffd..9eb9f8ffc 100644
--- a/contracts/src/proxy/KlerosProxies.sol
+++ b/contracts/src/proxy/KlerosProxies.sol
@@ -7,10 +7,6 @@ import "./UUPSProxy.sol";
/// Workaround to get meaningful names for the proxy contracts
/// Otherwise all the contracts are called `UUPSProxy` on the chain explorers
-contract DisputeKitClassicNeoProxy is UUPSProxy {
- constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}
-}
-
contract DisputeKitClassicUniversityProxy is UUPSProxy {
constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}
}
@@ -35,6 +31,10 @@ contract DisputeKitSybilResistantProxy is UUPSProxy {
constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}
}
+contract DisputeTemplateRegistryUniversityProxy is UUPSProxy {
+ constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}
+}
+
contract DisputeTemplateRegistryProxy is UUPSProxy {
constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}
}
@@ -51,10 +51,6 @@ contract HomeGatewayToEthereumProxy is UUPSProxy {
constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}
}
-contract KlerosCoreNeoProxy is UUPSProxy {
- constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}
-}
-
contract KlerosCoreRulerProxy is UUPSProxy {
constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}
}
@@ -75,10 +71,6 @@ contract RandomizerRNGProxy is UUPSProxy {
constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}
}
-contract SortitionModuleNeoProxy is UUPSProxy {
- constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}
-}
-
contract SortitionModuleUniversityProxy is UUPSProxy {
constructor(address _implementation, bytes memory _data) UUPSProxy(_implementation, _data) {}
}
diff --git a/contracts/src/proxy/UUPSProxiable.sol b/contracts/src/proxy/UUPSProxiable.sol
index 34504f686..57e28b3a1 100644
--- a/contracts/src/proxy/UUPSProxiable.sol
+++ b/contracts/src/proxy/UUPSProxiable.sol
@@ -4,7 +4,8 @@ pragma solidity ^0.8.24;
/// @title UUPS Proxiable
/// @author Simon Malatrait
-/// @dev This contract implements an upgradeability mechanism designed for UUPS proxies.
+/// @notice This contract implements an upgradeability mechanism designed for UUPS proxies.
+///
/// @dev Adapted from
/// The functions included here can perform an upgrade of an UUPS Proxy, when this contract is set as the implementation behind such a proxy.
///
@@ -21,7 +22,7 @@ abstract contract UUPSProxiable {
// * Event * //
// ************************************* //
- /// @dev Emitted when the `implementation` has been successfully upgraded.
+ /// @notice Emitted when the `implementation` has been successfully upgraded.
/// @param newImplementation Address of the new implementation the proxy is now forwarding calls to.
event Upgraded(address indexed newImplementation);
@@ -29,13 +30,13 @@ abstract contract UUPSProxiable {
// * Error * //
// ************************************* //
- /// @dev The call is from an unauthorized context.
+ /// @notice The call is from an unauthorized context.
error UUPSUnauthorizedCallContext();
- /// @dev The storage `slot` is unsupported as a UUID.
+ /// @notice The storage `slot` is unsupported as a UUID.
error UUPSUnsupportedProxiableUUID(bytes32 slot);
- /// @dev The `implementation` is not UUPS-compliant
+ /// @notice The `implementation` is not UUPS-compliant
error InvalidImplementation(address implementation);
/// Failed Delegated call
@@ -68,7 +69,7 @@ abstract contract UUPSProxiable {
// * State Modifiers * //
// ************************************* //
- /// @dev Upgrade mechanism including access control and UUPS-compliance.
+ /// @notice Upgrade mechanism including access control and UUPS-compliance.
/// @param newImplementation Address of the new implementation contract.
/// @param data Data used in a delegate call to `newImplementation` if non-empty. This will typically be an encoded
/// function call, and allows initializing the storage of the proxy like a Solidity constructor.
@@ -110,10 +111,10 @@ abstract contract UUPSProxiable {
// * Public Views * //
// ************************************* //
- /// @dev Implementation of the ERC1822 `proxiableUUID` function. This returns the storage slot used by the
+ /// @notice Implementation of the ERC1822 `proxiableUUID` function. This returns the storage slot used by the
/// implementation. It is used to validate the implementation's compatibility when performing an upgrade.
///
- /// IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
+ /// @dev IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
/// bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
/// function revert if invoked through a proxy. This is guaranteed by the if statement.
function proxiableUUID() external view virtual returns (bytes32) {
@@ -124,7 +125,7 @@ abstract contract UUPSProxiable {
return IMPLEMENTATION_SLOT;
}
- /// @dev Returns the version of the implementation.
+ /// @notice Returns the version of the implementation.
/// @return Version string.
function version() external view virtual returns (string memory);
diff --git a/contracts/src/proxy/UUPSProxy.sol b/contracts/src/proxy/UUPSProxy.sol
index 4f190158d..328b0381a 100644
--- a/contracts/src/proxy/UUPSProxy.sol
+++ b/contracts/src/proxy/UUPSProxy.sol
@@ -4,10 +4,11 @@ pragma solidity ^0.8.24;
/// @title UUPS Proxy
/// @author Simon Malatrait
-/// @dev This contract implements a UUPS Proxy compliant with ERC-1967 & ERC-1822.
+/// @notice This contract implements a UUPS Proxy compliant with ERC-1967 & ERC-1822.
+///
/// @dev This contract delegates all calls to another contract (UUPS Proxiable) through a fallback function and the use of the `delegatecall` EVM instruction.
-/// @dev We refer to the Proxiable contract (as per ERC-1822) with `implementation`.
-/// @dev Adapted from
+/// We refer to the Proxiable contract (as per ERC-1822) with `implementation`.
+/// Adapted from
contract UUPSProxy {
/// @dev Storage slot with the address of the current implementation.
/// This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
@@ -19,9 +20,9 @@ contract UUPSProxy {
// * Constructor * //
// ************************************* //
- /// @dev Initializes the upgradeable proxy with an initial implementation specified by `_implementation`.
- /// If `_data` is nonempty, it's used as data in a delegate call to `_implementation`. This will typically be an encoded
- /// function call, and allows initializing the storage of the proxy like a Solidity constructor.
+ /// @notice Initializes the upgradeable proxy with an initial implementation specified by `_implementation`.
+ /// @dev If `_data` is nonempty, it's used as data in a delegate call to `_implementation`.
+ /// This will typically be an encoded function call, and allows initializing the storage of the proxy like a Solidity constructor.
constructor(address _implementation, bytes memory _data) {
assembly {
sstore(IMPLEMENTATION_SLOT, _implementation)
diff --git a/contracts/src/proxy/mock/UUPSUpgradeableMocks.sol b/contracts/src/proxy/mock/UUPSUpgradeableMocks.sol
index 0764c8cd1..3b2bc7959 100644
--- a/contracts/src/proxy/mock/UUPSUpgradeableMocks.sol
+++ b/contracts/src/proxy/mock/UUPSUpgradeableMocks.sol
@@ -20,7 +20,7 @@ contract NonUpgradeableMock {
contract UUPSUpgradeableMock is UUPSProxiable, NonUpgradeableMock {
bool public initialized;
- address public governor;
+ address public owner;
uint256[50] __gap;
@@ -28,14 +28,14 @@ contract UUPSUpgradeableMock is UUPSProxiable, NonUpgradeableMock {
initialized = true;
}
- function initialize(address _governor) external {
+ function initialize(address _owner) external {
require(!initialized, "Contract instance has already been initialized");
- governor = _governor;
+ owner = _owner;
initialized = true;
}
function _authorizeUpgrade(address) internal view override {
- require(governor == msg.sender, "No privilege to upgrade");
+ require(owner == msg.sender, "No privilege to upgrade");
}
function version() external pure virtual override returns (string memory) {
diff --git a/contracts/src/proxy/mock/by-inheritance/UpgradedByInheritance.sol b/contracts/src/proxy/mock/by-inheritance/UpgradedByInheritance.sol
index 2cb9adf03..b443051a8 100644
--- a/contracts/src/proxy/mock/by-inheritance/UpgradedByInheritance.sol
+++ b/contracts/src/proxy/mock/by-inheritance/UpgradedByInheritance.sol
@@ -12,7 +12,7 @@ contract UpgradedByInheritanceV1Proxy is UUPSProxy {
}
contract UpgradedByInheritanceV1 is UUPSProxiable, Initializable {
- address public governor;
+ address public owner;
uint256 public counter;
uint256[50] __gap;
@@ -20,13 +20,13 @@ contract UpgradedByInheritanceV1 is UUPSProxiable, Initializable {
_disableInitializers();
}
- function initialize(address _governor) external virtual reinitializer(1) {
- governor = _governor;
+ function initialize(address _owner) external virtual initializer {
+ owner = _owner;
counter = 1;
}
function _authorizeUpgrade(address) internal view override {
- require(governor == msg.sender, "No privilege to upgrade");
+ require(owner == msg.sender, "No privilege to upgrade");
}
function increment() external {
@@ -61,7 +61,7 @@ contract UpgradedByInheritanceV3Bad is UpgradedByInheritanceV2 {
_disableInitializers();
}
- function initializeV3() external reinitializer(1) {
+ function initializeV3() external initializer {
// Wrong reinitializer version.
}
}
diff --git a/contracts/src/proxy/mock/by-rewrite/UpgradedByRewrite.sol b/contracts/src/proxy/mock/by-rewrite/UpgradedByRewrite.sol
index ca0731da8..d8930796d 100644
--- a/contracts/src/proxy/mock/by-rewrite/UpgradedByRewrite.sol
+++ b/contracts/src/proxy/mock/by-rewrite/UpgradedByRewrite.sol
@@ -15,7 +15,7 @@ contract UpgradedByRewrite is UUPSProxiable, Initializable {
//------------------------
// V1 State
//------------------------
- address public governor;
+ address public owner;
uint256 public counter;
uint256[50] __gap;
@@ -23,13 +23,13 @@ contract UpgradedByRewrite is UUPSProxiable, Initializable {
_disableInitializers();
}
- function initialize(address _governor) external virtual reinitializer(1) {
- governor = _governor;
+ function initialize(address _owner) external virtual initializer {
+ owner = _owner;
counter = 1;
}
function _authorizeUpgrade(address) internal view override {
- require(governor == msg.sender, "No privilege to upgrade");
+ require(owner == msg.sender, "No privilege to upgrade");
}
function increment() external {
diff --git a/contracts/src/proxy/mock/by-rewrite/UpgradedByRewriteV2.sol b/contracts/src/proxy/mock/by-rewrite/UpgradedByRewriteV2.sol
index 1b3c85e0a..5158c73fb 100644
--- a/contracts/src/proxy/mock/by-rewrite/UpgradedByRewriteV2.sol
+++ b/contracts/src/proxy/mock/by-rewrite/UpgradedByRewriteV2.sol
@@ -10,7 +10,7 @@ contract UpgradedByRewrite is UUPSProxiable, Initializable {
//------------------------
// V1 State
//------------------------
- address public governor;
+ address public owner;
uint256 public counter;
uint256[50] __gap;
@@ -29,7 +29,7 @@ contract UpgradedByRewrite is UUPSProxiable, Initializable {
}
function _authorizeUpgrade(address) internal view override {
- require(governor == msg.sender, "No privilege to upgrade");
+ require(owner == msg.sender, "No privilege to upgrade");
}
function increment() external {
diff --git a/contracts/src/rng/BlockhashRNG.sol b/contracts/src/rng/BlockhashRNG.sol
index 4421b4301..f6cfc3f90 100644
--- a/contracts/src/rng/BlockhashRNG.sol
+++ b/contracts/src/rng/BlockhashRNG.sol
@@ -2,43 +2,120 @@
pragma solidity ^0.8.24;
-import "./RNG.sol";
+import "./IRNG.sol";
/// @title Random Number Generator using blockhash with fallback.
-/// @author Clément Lesaege -
-/// @dev
-/// Random Number Generator returning the blockhash with a fallback behaviour.
-/// In case no one called it within the 256 blocks, it returns the previous blockhash.
-/// This contract must be used when returning 0 is a worse failure mode than returning another blockhash.
-/// Allows saving the random number for use in the future. It allows the contract to still access the blockhash even after 256 blocks.
-contract BlockHashRNG is RNG {
- mapping(uint256 block => uint256 number) public randomNumbers; // randomNumbers[block] is the random number for this block, 0 otherwise.
-
- /// @dev Request a random number.
- /// @param _block Block the random number is linked to.
- function requestRandomness(uint256 _block) external override {
- // nop
- }
-
- /// @dev Return the random number. If it has not been saved and is still computable compute it.
- /// @param _block Block the random number is linked to.
+/// @notice Random Number Generator returning the blockhash with a fallback behaviour.
+///
+/// @dev On L2 like Arbitrum block production is sporadic so block timestamp is more reliable than block number.
+/// Returns 0 when no random number is available.
+/// Allows saving the random number for use in the future. It allows the contract to retrieve the blockhash even after the time window.
+contract BlockHashRNG is IRNG {
+ // ************************************* //
+ // * Storage * //
+ // ************************************* //
+
+ address public owner; // The address that can withdraw funds.
+ address public consumer; // The address that can request random numbers.
+ uint256 public immutable lookaheadTime; // Minimal time in seconds between requesting and obtaining a random number.
+ uint256 public requestTimestamp; // Timestamp of the current request
+ mapping(uint256 timestamp => uint256 number) public randomNumbers; // randomNumbers[timestamp] is the random number for this timestamp, 0 otherwise.
+
+ // ************************************* //
+ // * Function Modifiers * //
+ // ************************************* //
+
+ modifier onlyByOwner() {
+ if (owner != msg.sender) revert OwnerOnly();
+ _;
+ }
+
+ modifier onlyByConsumer() {
+ if (consumer != msg.sender) revert ConsumerOnly();
+ _;
+ }
+
+ // ************************************* //
+ // * Constructor * //
+ // ************************************* //
+
+ /// @notice Constructor.
+ /// @param _owner The Owner of the contract.
+ /// @param _consumer The address that can request random numbers.
+ /// @param _lookaheadTime The time lookahead in seconds for the random number.
+ constructor(address _owner, address _consumer, uint256 _lookaheadTime) {
+ owner = _owner;
+ consumer = _consumer;
+ lookaheadTime = _lookaheadTime;
+ }
+
+ // ************************************* //
+ // * Governance * //
+ // ************************************* //
+
+ /// @notice Changes the owner of the contract.
+ /// @param _owner The new owner.
+ function changeOwner(address _owner) external onlyByOwner {
+ owner = _owner;
+ }
+
+ /// @notice Changes the consumer of the RNG.
+ /// @param _consumer The new consumer.
+ function changeConsumer(address _consumer) external onlyByOwner {
+ consumer = _consumer;
+ }
+
+ // ************************************* //
+ // * State Modifiers * //
+ // ************************************* //
+
+ /// @notice Request a random number.
+ function requestRandomness() external override onlyByConsumer {
+ requestTimestamp = block.timestamp;
+ }
+
+ /// @notice Return the random number.
+ /// @dev If it has not been saved and is still computable compute it.
/// @return randomNumber The random number or 0 if it is not ready or has not been requested.
- function receiveRandomness(uint256 _block) external override returns (uint256 randomNumber) {
- randomNumber = randomNumbers[_block];
+ function receiveRandomness() external override onlyByConsumer returns (uint256 randomNumber) {
+ if (requestTimestamp == 0) return 0; // No requests were made yet.
+
+ uint256 expectedTimestamp = requestTimestamp + lookaheadTime;
+
+ // Check if enough time has passed
+ if (block.timestamp < expectedTimestamp) {
+ return 0; // Not ready yet
+ }
+
+ // Check if we already have a saved random number for this timestamp window
+ randomNumber = randomNumbers[expectedTimestamp];
if (randomNumber != 0) {
return randomNumber;
}
- if (_block < block.number) {
- // The random number is not already set and can be.
- if (blockhash(_block) != 0x0) {
- // Normal case.
- randomNumber = uint256(blockhash(_block));
- } else {
- // The contract was not called in time. Fallback to returning previous blockhash.
- randomNumber = uint256(blockhash(block.number - 1));
- }
+ // Use last block hash for randomness
+ randomNumber = uint256(blockhash(block.number - 1));
+ if (randomNumber != 0) {
+ randomNumbers[expectedTimestamp] = randomNumber;
}
- randomNumbers[_block] = randomNumber;
+ return randomNumber;
+ }
+
+ // ************************************* //
+ // * View Functions * //
+ // ************************************* //
+
+ /// @notice Check if randomness is ready to be received.
+ /// @return ready True if randomness can be received.
+ function isRandomnessReady() external view returns (bool ready) {
+ if (requestTimestamp == 0) return false; // No requests were made yet.
+ return block.timestamp >= requestTimestamp + lookaheadTime;
+ }
+
+ /// @notice Get the timestamp when randomness will be ready.
+ /// @return readyTimestamp The timestamp when randomness will be available.
+ function getRandomnessReadyTimestamp() external view returns (uint256 readyTimestamp) {
+ if (requestTimestamp == 0) return 0; // No requests were made yet.
+ return requestTimestamp + lookaheadTime;
}
}
diff --git a/contracts/src/rng/ChainlinkConsumerBaseV2Plus.sol b/contracts/src/rng/ChainlinkConsumerBaseV2Plus.sol
new file mode 100644
index 000000000..73df28caf
--- /dev/null
+++ b/contracts/src/rng/ChainlinkConsumerBaseV2Plus.sol
@@ -0,0 +1,169 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.24;
+
+// This contract is adapted from `@chainlink/contracts/src/v0.8/vrf/dev/VRFConsumerBaseV2Plus.sol` to remove the `ConfirmedOwner` dependency.
+
+import {IVRFCoordinatorV2Plus} from "@chainlink/contracts/src/v0.8/vrf/dev/interfaces/IVRFCoordinatorV2Plus.sol";
+import {IVRFMigratableConsumerV2Plus} from "@chainlink/contracts/src/v0.8/vrf/dev/interfaces/IVRFMigratableConsumerV2Plus.sol";
+
+/** ****************************************************************************
+ * @notice Interface for contracts using VRF randomness
+ * *****************************************************************************
+ * @dev PURPOSE
+ *
+ * @dev Reggie the Random Oracle (not his real job) wants to provide randomness
+ * @dev to Vera the verifier in such a way that Vera can be sure he's not
+ * @dev making his output up to suit himself. Reggie provides Vera a public key
+ * @dev to which he knows the secret key. Each time Vera provides a seed to
+ * @dev Reggie, he gives back a value which is computed completely
+ * @dev deterministically from the seed and the secret key.
+ *
+ * @dev Reggie provides a proof by which Vera can verify that the output was
+ * @dev correctly computed once Reggie tells it to her, but without that proof,
+ * @dev the output is indistinguishable to her from a uniform random sample
+ * @dev from the output space.
+ *
+ * @dev The purpose of this contract is to make it easy for unrelated contracts
+ * @dev to talk to Vera the verifier about the work Reggie is doing, to provide
+ * @dev simple access to a verifiable source of randomness. It ensures 2 things:
+ * @dev 1. The fulfillment came from the VRFCoordinatorV2Plus.
+ * @dev 2. The consumer contract implements fulfillRandomWords.
+ * *****************************************************************************
+ * @dev USAGE
+ *
+ * @dev Calling contracts must inherit from VRFConsumerBaseV2Plus, and can
+ * @dev initialize VRFConsumerBaseV2Plus's attributes in their constructor as
+ * @dev shown:
+ *
+ * @dev contract VRFConsumerV2Plus is VRFConsumerBaseV2Plus {
+ * @dev constructor(, address _vrfCoordinator, address _subOwner)
+ * @dev VRFConsumerBaseV2Plus(_vrfCoordinator, _subOwner) public {
+ * @dev
+ * @dev }
+ * @dev }
+ *
+ * @dev The oracle will have given you an ID for the VRF keypair they have
+ * @dev committed to (let's call it keyHash). Create a subscription, fund it
+ * @dev and your consumer contract as a consumer of it (see VRFCoordinatorInterface
+ * @dev subscription management functions).
+ * @dev Call requestRandomWords(keyHash, subId, minimumRequestConfirmations,
+ * @dev callbackGasLimit, numWords, extraArgs),
+ * @dev see (IVRFCoordinatorV2Plus for a description of the arguments).
+ *
+ * @dev Once the VRFCoordinatorV2Plus has received and validated the oracle's response
+ * @dev to your request, it will call your contract's fulfillRandomWords method.
+ *
+ * @dev The randomness argument to fulfillRandomWords is a set of random words
+ * @dev generated from your requestId and the blockHash of the request.
+ *
+ * @dev If your contract could have concurrent requests open, you can use the
+ * @dev requestId returned from requestRandomWords to track which response is associated
+ * @dev with which randomness request.
+ * @dev See "SECURITY CONSIDERATIONS" for principles to keep in mind,
+ * @dev if your contract could have multiple requests in flight simultaneously.
+ *
+ * @dev Colliding `requestId`s are cryptographically impossible as long as seeds
+ * @dev differ.
+ *
+ * *****************************************************************************
+ * @dev SECURITY CONSIDERATIONS
+ *
+ * @dev A method with the ability to call your fulfillRandomness method directly
+ * @dev could spoof a VRF response with any random value, so it's critical that
+ * @dev it cannot be directly called by anything other than this base contract
+ * @dev (specifically, by the VRFConsumerBaseV2Plus.rawFulfillRandomness method).
+ *
+ * @dev For your users to trust that your contract's random behavior is free
+ * @dev from malicious interference, it's best if you can write it so that all
+ * @dev behaviors implied by a VRF response are executed *during* your
+ * @dev fulfillRandomness method. If your contract must store the response (or
+ * @dev anything derived from it) and use it later, you must ensure that any
+ * @dev user-significant behavior which depends on that stored value cannot be
+ * @dev manipulated by a subsequent VRF request.
+ *
+ * @dev Similarly, both miners and the VRF oracle itself have some influence
+ * @dev over the order in which VRF responses appear on the blockchain, so if
+ * @dev your contract could have multiple VRF requests in flight simultaneously,
+ * @dev you must ensure that the order in which the VRF responses arrive cannot
+ * @dev be used to manipulate your contract's user-significant behavior.
+ *
+ * @dev Since the block hash of the block which contains the requestRandomness
+ * @dev call is mixed into the input to the VRF *last*, a sufficiently powerful
+ * @dev miner could, in principle, fork the blockchain to evict the block
+ * @dev containing the request, forcing the request to be included in a
+ * @dev different block with a different hash, and therefore a different input
+ * @dev to the VRF. However, such an attack would incur a substantial economic
+ * @dev cost. This cost scales with the number of blocks the VRF oracle waits
+ * @dev until it calls responds to a request. It is for this reason that
+ * @dev that you can signal to an oracle you'd like them to wait longer before
+ * @dev responding to the request (however this is not enforced in the contract
+ * @dev and so remains effective only in the case of unmodified oracle software).
+ */
+abstract contract VRFConsumerBaseV2Plus is IVRFMigratableConsumerV2Plus {
+ error OnlyCoordinatorCanFulfill(address have, address want);
+ error OnlyOwnerOrCoordinator(address have, address owner, address coordinator);
+ error ZeroAddress();
+
+ address public owner;
+
+ // s_vrfCoordinator should be used by consumers to make requests to vrfCoordinator
+ // so that coordinator reference is updated after migration
+ IVRFCoordinatorV2Plus public s_vrfCoordinator;
+
+ /**
+ * @param _vrfCoordinator address of VRFCoordinator contract
+ */
+ constructor(address _owner, address _vrfCoordinator) {
+ owner = _owner;
+ if (_vrfCoordinator == address(0)) {
+ revert ZeroAddress();
+ }
+ s_vrfCoordinator = IVRFCoordinatorV2Plus(_vrfCoordinator);
+ }
+
+ /**
+ * @notice fulfillRandomness handles the VRF response. Your contract must
+ * @notice implement it. See "SECURITY CONSIDERATIONS" above for important
+ * @notice principles to keep in mind when implementing your fulfillRandomness
+ * @notice method.
+ *
+ * @dev VRFConsumerBaseV2Plus expects its subcontracts to have a method with this
+ * @dev signature, and will call it once it has verified the proof
+ * @dev associated with the randomness. (It is triggered via a call to
+ * @dev rawFulfillRandomness, below.)
+ *
+ * @param requestId The Id initially returned by requestRandomness
+ * @param randomWords the VRF output expanded to the requested number of words
+ */
+ // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore
+ function fulfillRandomWords(uint256 requestId, uint256[] calldata randomWords) internal virtual;
+
+ // rawFulfillRandomness is called by VRFCoordinator when it receives a valid VRF
+ // proof. rawFulfillRandomness then calls fulfillRandomness, after validating
+ // the origin of the call
+ function rawFulfillRandomWords(uint256 requestId, uint256[] calldata randomWords) external {
+ if (msg.sender != address(s_vrfCoordinator)) {
+ revert OnlyCoordinatorCanFulfill(msg.sender, address(s_vrfCoordinator));
+ }
+ fulfillRandomWords(requestId, randomWords);
+ }
+
+ /**
+ * @inheritdoc IVRFMigratableConsumerV2Plus
+ */
+ function setCoordinator(address _vrfCoordinator) external override onlyOwnerOrCoordinator {
+ if (_vrfCoordinator == address(0)) {
+ revert ZeroAddress();
+ }
+ s_vrfCoordinator = IVRFCoordinatorV2Plus(_vrfCoordinator);
+
+ emit CoordinatorSet(_vrfCoordinator);
+ }
+
+ modifier onlyOwnerOrCoordinator() {
+ if (msg.sender != owner && msg.sender != address(s_vrfCoordinator)) {
+ revert OnlyOwnerOrCoordinator(msg.sender, owner, address(s_vrfCoordinator));
+ }
+ _;
+ }
+}
diff --git a/contracts/src/rng/ChainlinkRNG.sol b/contracts/src/rng/ChainlinkRNG.sol
index b829177c3..09e7e4855 100644
--- a/contracts/src/rng/ChainlinkRNG.sol
+++ b/contracts/src/rng/ChainlinkRNG.sol
@@ -2,20 +2,19 @@
pragma solidity ^0.8.24;
-import {VRFConsumerBaseV2Plus, IVRFCoordinatorV2Plus} from "@chainlink/contracts/src/v0.8/vrf/dev/VRFConsumerBaseV2Plus.sol";
+import {VRFConsumerBaseV2Plus, IVRFCoordinatorV2Plus} from "./ChainlinkConsumerBaseV2Plus.sol";
import {VRFV2PlusClient} from "@chainlink/contracts/src/v0.8/vrf/dev/libraries/VRFV2PlusClient.sol";
-import "./RNG.sol";
+import "./IRNG.sol";
/// @title Random Number Generator that uses Chainlink VRF v2.5
-/// https://blog.chain.link/introducing-vrf-v2-5/
-contract ChainlinkRNG is RNG, VRFConsumerBaseV2Plus {
+/// @dev https://blog.chain.link/introducing-vrf-v2-5/
+contract ChainlinkRNG is IRNG, VRFConsumerBaseV2Plus {
// ************************************* //
// * Storage * //
// ************************************* //
- address public governor; // The address that can withdraw funds.
- address public sortitionModule; // The address of the SortitionModule.
+ address public consumer; // The address that can request random numbers.
bytes32 public keyHash; // The gas lane key hash value - Defines the maximum gas price you are willing to pay for a request in wei (ID of the off-chain VRF job).
uint256 public subscriptionId; // The unique identifier of the subscription used for funding requests.
uint16 public requestConfirmations; // How many confirmations the Chainlink node should wait before responding.
@@ -28,26 +27,26 @@ contract ChainlinkRNG is RNG, VRFConsumerBaseV2Plus {
// * Events * //
// ************************************* //
- /// @dev Emitted when a request is sent to the VRF Coordinator
- /// @param requestId The ID of the request
- event RequestSent(uint256 indexed requestId);
+ /// @notice Emitted when a request is sent to the VRF Coordinator
+ /// @param _requestId The ID of the request
+ event RequestSent(uint256 indexed _requestId);
/// Emitted when a request has been fulfilled.
- /// @param requestId The ID of the request
- /// @param randomWord The random value answering the request.
- event RequestFulfilled(uint256 indexed requestId, uint256 randomWord);
+ /// @param _requestId The ID of the request
+ /// @param _randomWord The random value answering the request.
+ event RequestFulfilled(uint256 indexed _requestId, uint256 _randomWord);
// ************************************* //
// * Function Modifiers * //
// ************************************* //
- modifier onlyByGovernor() {
- require(governor == msg.sender, "Governor only");
+ modifier onlyByOwner() {
+ if (owner != msg.sender) revert OwnerOnly();
_;
}
- modifier onlyBySortitionModule() {
- require(sortitionModule == msg.sender, "SortitionModule only");
+ modifier onlyByConsumer() {
+ if (consumer != msg.sender) revert ConsumerOnly();
_;
}
@@ -55,9 +54,9 @@ contract ChainlinkRNG is RNG, VRFConsumerBaseV2Plus {
// * Constructor * //
// ************************************* //
- /// @dev Constructor, initializing the implementation to reduce attack surface.
- /// @param _governor The Governor of the contract.
- /// @param _sortitionModule The address of the SortitionModule contract.
+ /// @notice Constructor, initializing the implementation to reduce attack surface.
+ /// @param _owner The owner of the contract.
+ /// @param _consumer The address that can request random numbers.
/// @param _vrfCoordinator The address of the VRFCoordinator contract.
/// @param _keyHash The gas lane key hash value - Defines the maximum gas price you are willing to pay for a request in wei (ID of the off-chain VRF job).
/// @param _subscriptionId The unique identifier of the subscription used for funding requests.
@@ -65,16 +64,15 @@ contract ChainlinkRNG is RNG, VRFConsumerBaseV2Plus {
/// @param _callbackGasLimit The limit for how much gas to use for the callback request to the contract's fulfillRandomWords() function.
/// @dev https://docs.chain.link/vrf/v2-5/subscription/get-a-random-number
constructor(
- address _governor,
- address _sortitionModule,
+ address _owner,
+ address _consumer,
address _vrfCoordinator,
bytes32 _keyHash,
uint256 _subscriptionId,
uint16 _requestConfirmations,
uint32 _callbackGasLimit
- ) VRFConsumerBaseV2Plus(_vrfCoordinator) {
- governor = _governor;
- sortitionModule = _sortitionModule;
+ ) VRFConsumerBaseV2Plus(_owner, _vrfCoordinator) {
+ consumer = _consumer;
keyHash = _keyHash;
subscriptionId = _subscriptionId;
requestConfirmations = _requestConfirmations;
@@ -85,46 +83,46 @@ contract ChainlinkRNG is RNG, VRFConsumerBaseV2Plus {
// * Governance * //
// ************************************* //
- /// @dev Changes the governor of the contract.
- /// @param _governor The new governor.
- function changeGovernor(address _governor) external onlyByGovernor {
- governor = _governor;
+ /// @notice Changes the owner of the contract.
+ /// @param _owner The new owner.
+ function changeOwner(address _owner) external onlyByOwner {
+ owner = _owner;
}
- /// @dev Changes the sortition module of the contract.
- /// @param _sortitionModule The new sortition module.
- function changeSortitionModule(address _sortitionModule) external onlyByGovernor {
- sortitionModule = _sortitionModule;
+ /// @notice Changes the consumer of the RNG.
+ /// @param _consumer The new consumer.
+ function changeConsumer(address _consumer) external onlyByOwner {
+ consumer = _consumer;
}
- /// @dev Changes the VRF Coordinator of the contract.
+ /// @notice Changes the VRF Coordinator of the contract.
/// @param _vrfCoordinator The new VRF Coordinator.
- function changeVrfCoordinator(address _vrfCoordinator) external onlyByGovernor {
+ function changeVrfCoordinator(address _vrfCoordinator) external onlyByOwner {
s_vrfCoordinator = IVRFCoordinatorV2Plus(_vrfCoordinator);
emit CoordinatorSet(_vrfCoordinator);
}
- /// @dev Changes the key hash of the contract.
+ /// @notice Changes the key hash of the contract.
/// @param _keyHash The new key hash.
- function changeKeyHash(bytes32 _keyHash) external onlyByGovernor {
+ function changeKeyHash(bytes32 _keyHash) external onlyByOwner {
keyHash = _keyHash;
}
- /// @dev Changes the subscription ID of the contract.
+ /// @notice Changes the subscription ID of the contract.
/// @param _subscriptionId The new subscription ID.
- function changeSubscriptionId(uint256 _subscriptionId) external onlyByGovernor {
+ function changeSubscriptionId(uint256 _subscriptionId) external onlyByOwner {
subscriptionId = _subscriptionId;
}
- /// @dev Changes the request confirmations of the contract.
+ /// @notice Changes the request confirmations of the contract.
/// @param _requestConfirmations The new request confirmations.
- function changeRequestConfirmations(uint16 _requestConfirmations) external onlyByGovernor {
+ function changeRequestConfirmations(uint16 _requestConfirmations) external onlyByOwner {
requestConfirmations = _requestConfirmations;
}
- /// @dev Changes the callback gas limit of the contract.
+ /// @notice Changes the callback gas limit of the contract.
/// @param _callbackGasLimit The new callback gas limit.
- function changeCallbackGasLimit(uint32 _callbackGasLimit) external onlyByGovernor {
+ function changeCallbackGasLimit(uint32 _callbackGasLimit) external onlyByOwner {
callbackGasLimit = _callbackGasLimit;
}
@@ -132,9 +130,10 @@ contract ChainlinkRNG is RNG, VRFConsumerBaseV2Plus {
// * State Modifiers * //
// ************************************* //
- /// @dev Request a random number. SortitionModule only.
- function requestRandomness(uint256 /*_block*/) external override onlyBySortitionModule {
- // Will revert if subscription is not set and funded.
+ /// @notice Request a random number.
+ /// @dev Ensure that the subscription is set and funded.
+ /// @dev Consumer only.
+ function requestRandomness() external override onlyByConsumer {
uint256 requestId = s_vrfCoordinator.requestRandomWords(
VRFV2PlusClient.RandomWordsRequest({
keyHash: keyHash,
@@ -152,7 +151,7 @@ contract ChainlinkRNG is RNG, VRFConsumerBaseV2Plus {
emit RequestSent(requestId);
}
- /// @dev Callback function called by the VRF Coordinator when the random value is generated.
+ /// @notice Callback function called by the VRF Coordinator when the random value is generated.
/// @param _requestId The ID of the request.
/// @param _randomWords The random values answering the request.
function fulfillRandomWords(uint256 _requestId, uint256[] calldata _randomWords) internal override {
@@ -165,9 +164,9 @@ contract ChainlinkRNG is RNG, VRFConsumerBaseV2Plus {
// * Public Views * //
// ************************************* //
- /// @dev Return the random number.
+ /// @notice Return the random number.
/// @return randomNumber The random number or 0 if it is not ready or has not been requested.
- function receiveRandomness(uint256 /*_block*/) external view override returns (uint256 randomNumber) {
+ function receiveRandomness() external view override returns (uint256 randomNumber) {
randomNumber = randomNumbers[lastRequestId];
}
}
diff --git a/contracts/src/rng/IRNG.sol b/contracts/src/rng/IRNG.sol
new file mode 100644
index 000000000..4945a80af
--- /dev/null
+++ b/contracts/src/rng/IRNG.sol
@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: MIT
+
+pragma solidity >=0.8.0 <0.9.0;
+
+/// @title Random Number Generator interface
+interface IRNG {
+ // ************************************* //
+ // * State Modifiers * //
+ // ************************************* //
+
+ /// @notice Request a random number.
+ function requestRandomness() external;
+
+ /// @notice Receive the random number.
+ /// @return randomNumber Random number or 0 if not available
+ function receiveRandomness() external returns (uint256 randomNumber);
+
+ // ************************************* //
+ // * Errors * //
+ // ************************************* //
+
+ error OwnerOnly();
+ error ConsumerOnly();
+}
diff --git a/contracts/src/rng/IRandomizer.sol b/contracts/src/rng/IRandomizer.sol
index ea549ffa4..875d5b574 100644
--- a/contracts/src/rng/IRandomizer.sol
+++ b/contracts/src/rng/IRandomizer.sol
@@ -1,8 +1,8 @@
// SPDX-License-Identifier: MIT
-pragma solidity ^0.8.24;
+pragma solidity >=0.8.0 <0.9.0;
-// Randomizer protocol interface
+// @title Randomizer protocol interface
interface IRandomizer {
function request(uint256 callbackGasLimit) external returns (uint256);
diff --git a/contracts/src/rng/IncrementalNG.sol b/contracts/src/rng/IncrementalNG.sol
index aa4b7d840..7f6170244 100644
--- a/contracts/src/rng/IncrementalNG.sol
+++ b/contracts/src/rng/IncrementalNG.sol
@@ -1,29 +1,26 @@
// SPDX-License-Identifier: MIT
-/// @title Incremental Number Generator
-/// @author JayBuidl
-/// @dev A Random Number Generator which returns a number incremented by 1 each time. Useful as a fallback method.
-
pragma solidity ^0.8.24;
-import "./RNG.sol";
+import "./IRNG.sol";
-contract IncrementalNG is RNG {
+/// @title Incremental Number Generator
+/// @dev A Random Number Generator which returns a number incremented by 1 each time.
+/// For testing purposes.
+contract IncrementalNG is IRNG {
uint256 public number;
constructor(uint256 _start) {
number = _start;
}
- /// @dev Request a random number.
- /// @param _block Block the random number is linked to.
- function requestRandomness(uint256 _block) external override {
+ /// @notice Request a random number.
+ function requestRandomness() external override {
// nop
}
- /// @dev Get the "random number" (which is always the same).
- /// @param _block Block the random number is linked to.
+ /// @notice Get the "random number" (which is always the same).
/// @return randomNumber The random number or 0 if it is not ready or has not been requested.
- function receiveRandomness(uint256 _block) external override returns (uint256 randomNumber) {
+ function receiveRandomness() external override returns (uint256 randomNumber) {
unchecked {
return number++;
}
diff --git a/contracts/src/rng/RNG.sol b/contracts/src/rng/RNG.sol
deleted file mode 100644
index 5142aa0e5..000000000
--- a/contracts/src/rng/RNG.sol
+++ /dev/null
@@ -1,14 +0,0 @@
-// SPDX-License-Identifier: MIT
-
-pragma solidity ^0.8.24;
-
-interface RNG {
- /// @dev Request a random number.
- /// @param _block Block linked to the request.
- function requestRandomness(uint256 _block) external;
-
- /// @dev Receive the random number.
- /// @param _block Block the random number is linked to.
- /// @return randomNumber Random Number. If the number is not ready or has not been required 0 instead.
- function receiveRandomness(uint256 _block) external returns (uint256 randomNumber);
-}
diff --git a/contracts/src/rng/RNGWithFallback.sol b/contracts/src/rng/RNGWithFallback.sol
new file mode 100644
index 000000000..30c84ea4c
--- /dev/null
+++ b/contracts/src/rng/RNGWithFallback.sol
@@ -0,0 +1,110 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.24;
+
+import "./IRNG.sol";
+
+/// @title RNG with fallback mechanism
+/// @notice Uses a primary RNG implementation with automatic fallback to a Blockhash RNG if the primary RNG does not respond passed a timeout.
+contract RNGWithFallback is IRNG {
+ // ************************************* //
+ // * Storage * //
+ // ************************************* //
+
+ IRNG public immutable rng; // RNG address.
+ address public owner; // Owner address
+ address public consumer; // Consumer address
+ uint256 public fallbackTimeoutSeconds; // Time in seconds to wait before falling back to next RNG
+ uint256 public requestTimestamp; // Timestamp of the current request
+
+ // ************************************* //
+ // * Events * //
+ // ************************************* //
+
+ event RNGFallback();
+ event FallbackTimeoutChanged(uint256 _newTimeout);
+
+ // ************************************* //
+ // * Constructor * //
+ // ************************************* //
+
+ /// @notice Constructor
+ /// @param _owner Owner address
+ /// @param _consumer Consumer address
+ /// @param _fallbackTimeoutSeconds Time in seconds to wait before falling back to next RNG
+ /// @param _rng The RNG address (e.g. Chainlink)
+ constructor(address _owner, address _consumer, uint256 _fallbackTimeoutSeconds, IRNG _rng) {
+ if (address(_rng) == address(0)) revert InvalidDefaultRNG();
+
+ owner = _owner;
+ consumer = _consumer;
+ fallbackTimeoutSeconds = _fallbackTimeoutSeconds;
+ rng = _rng;
+ }
+
+ // ************************************* //
+ // * Function Modifiers * //
+ // ************************************* //
+
+ modifier onlyByOwner() {
+ if (owner != msg.sender) revert OwnerOnly();
+ _;
+ }
+
+ modifier onlyByConsumer() {
+ if (consumer != msg.sender) revert ConsumerOnly();
+ _;
+ }
+
+ // ************************************* //
+ // * Governance Functions * //
+ // ************************************* //
+
+ /// @notice Change the owner
+ /// @param _newOwner Address of the new owner
+ function changeOwner(address _newOwner) external onlyByOwner {
+ owner = _newOwner;
+ }
+
+ /// @notice Change the consumer
+ /// @param _consumer Address of the new consumer
+ function changeConsumer(address _consumer) external onlyByOwner {
+ consumer = _consumer;
+ }
+
+ /// @notice Change the fallback timeout
+ /// @param _fallbackTimeoutSeconds New timeout in seconds
+ function changeFallbackTimeout(uint256 _fallbackTimeoutSeconds) external onlyByOwner {
+ fallbackTimeoutSeconds = _fallbackTimeoutSeconds;
+ emit FallbackTimeoutChanged(_fallbackTimeoutSeconds);
+ }
+
+ // ************************************* //
+ // * State Modifiers * //
+ // ************************************* //
+
+ /// @notice Request a random number from the primary RNG
+ /// @dev The consumer is trusted not to make concurrent requests.
+ function requestRandomness() external override onlyByConsumer {
+ requestTimestamp = block.timestamp;
+ rng.requestRandomness();
+ }
+
+ /// @notice Receive the random number from the primary RNG with fallback to the blockhash RNG if the primary RNG does not respond passed a timeout.
+ /// @return randomNumber Random number or 0 if not available
+ function receiveRandomness() external override onlyByConsumer returns (uint256 randomNumber) {
+ randomNumber = rng.receiveRandomness();
+
+ // If we didn't get a random number and the timeout is exceeded, try the fallback
+ if (randomNumber == 0 && block.timestamp > requestTimestamp + fallbackTimeoutSeconds) {
+ randomNumber = uint256(blockhash(block.number - 1));
+ emit RNGFallback();
+ }
+ return randomNumber;
+ }
+
+ // ************************************* //
+ // * Errors * //
+ // ************************************* //
+
+ error InvalidDefaultRNG();
+}
diff --git a/contracts/src/rng/RandomizerRNG.sol b/contracts/src/rng/RandomizerRNG.sol
index 940c2cf5d..2107702bd 100644
--- a/contracts/src/rng/RandomizerRNG.sol
+++ b/contracts/src/rng/RandomizerRNG.sol
@@ -2,18 +2,18 @@
pragma solidity ^0.8.24;
-import "./RNG.sol";
+import "./IRNG.sol";
import "./IRandomizer.sol";
/// @title Random Number Generator that uses Randomizer.ai
/// https://randomizer.ai/
-contract RandomizerRNG is RNG {
+contract RandomizerRNG is IRNG {
// ************************************* //
// * Storage * //
// ************************************* //
- address public governor; // The address that can withdraw funds.
- address public sortitionModule; // The address of the SortitionModule.
+ address public owner; // The address that can withdraw funds.
+ address public consumer; // The address that can request random numbers.
IRandomizer public randomizer; // Randomizer address.
uint256 public callbackGasLimit; // Gas limit for the Randomizer.ai callback.
uint256 public lastRequestId; // The last request ID.
@@ -23,7 +23,7 @@ contract RandomizerRNG is RNG {
// * Events * //
// ************************************* //
- /// @dev Emitted when a request is sent to the VRF Coordinator
+ /// @notice Emitted when a request is sent to the VRF Coordinator
/// @param requestId The ID of the request
event RequestSent(uint256 indexed requestId);
@@ -36,13 +36,13 @@ contract RandomizerRNG is RNG {
// * Function Modifiers * //
// ************************************* //
- modifier onlyByGovernor() {
- require(governor == msg.sender, "Governor only");
+ modifier onlyByOwner() {
+ if (owner != msg.sender) revert OwnerOnly();
_;
}
- modifier onlyBySortitionModule() {
- require(sortitionModule == msg.sender, "SortitionModule only");
+ modifier onlyByConsumer() {
+ if (consumer != msg.sender) revert ConsumerOnly();
_;
}
@@ -50,12 +50,13 @@ contract RandomizerRNG is RNG {
// * Constructor * //
// ************************************* //
- /// @dev Constructor
- /// @param _randomizer Randomizer contract.
- /// @param _governor Governor of the contract.
- constructor(address _governor, address _sortitionModule, IRandomizer _randomizer) {
- governor = _governor;
- sortitionModule = _sortitionModule;
+ /// @notice Constructor
+ /// @param _owner The Owner of the contract.
+ /// @param _consumer The address that can request random numbers.
+ /// @param _randomizer The Randomizer.ai oracle contract.
+ constructor(address _owner, address _consumer, IRandomizer _randomizer) {
+ owner = _owner;
+ consumer = _consumer;
randomizer = _randomizer;
callbackGasLimit = 50000;
}
@@ -64,33 +65,33 @@ contract RandomizerRNG is RNG {
// * Governance * //
// ************************ //
- /// @dev Changes the governor of the contract.
- /// @param _governor The new governor.
- function changeGovernor(address _governor) external onlyByGovernor {
- governor = _governor;
+ /// @notice Changes the owner of the contract.
+ /// @param _owner The new owner.
+ function changeOwner(address _owner) external onlyByOwner {
+ owner = _owner;
}
- /// @dev Changes the sortition module of the contract.
- /// @param _sortitionModule The new sortition module.
- function changeSortitionModule(address _sortitionModule) external onlyByGovernor {
- sortitionModule = _sortitionModule;
+ /// @notice Changes the consumer of the RNG.
+ /// @param _consumer The new consumer.
+ function changeConsumer(address _consumer) external onlyByOwner {
+ consumer = _consumer;
}
- /// @dev Change the Randomizer callback gas limit.
+ /// @notice Change the Randomizer callback gas limit.
/// @param _callbackGasLimit the new limit.
- function setCallbackGasLimit(uint256 _callbackGasLimit) external onlyByGovernor {
+ function setCallbackGasLimit(uint256 _callbackGasLimit) external onlyByOwner {
callbackGasLimit = _callbackGasLimit;
}
- /// @dev Change the Randomizer address.
+ /// @notice Change the Randomizer address.
/// @param _randomizer the new Randomizer address.
- function setRandomizer(address _randomizer) external onlyByGovernor {
+ function setRandomizer(address _randomizer) external onlyByOwner {
randomizer = IRandomizer(_randomizer);
}
- /// @dev Allows the governor to withdraw randomizer funds.
+ /// @notice Allows the owner to withdraw randomizer funds.
/// @param _amount Amount to withdraw in wei.
- function randomizerWithdraw(uint256 _amount) external onlyByGovernor {
+ function randomizerWithdraw(uint256 _amount) external onlyByOwner {
randomizer.clientWithdrawTo(msg.sender, _amount);
}
@@ -98,18 +99,19 @@ contract RandomizerRNG is RNG {
// * State Modifiers * //
// ************************************* //
- /// @dev Request a random number. SortitionModule only.
- function requestRandomness(uint256 /*_block*/) external override onlyBySortitionModule {
+ /// @notice Request a random number.
+ /// @dev Consumer only.
+ function requestRandomness() external override onlyByConsumer {
uint256 requestId = randomizer.request(callbackGasLimit);
lastRequestId = requestId;
emit RequestSent(requestId);
}
- /// @dev Callback function called by the randomizer contract when the random value is generated.
+ /// @notice Callback function called by the randomizer contract when the random value is generated.
/// @param _id The ID of the request.
/// @param _value The random value answering the request.
function randomizerCallback(uint256 _id, bytes32 _value) external {
- require(msg.sender == address(randomizer), "Randomizer only");
+ if (msg.sender != address(randomizer)) revert RandomizerOnly();
randomNumbers[_id] = uint256(_value);
emit RequestFulfilled(_id, uint256(_value));
}
@@ -118,9 +120,15 @@ contract RandomizerRNG is RNG {
// * Public Views * //
// ************************************* //
- /// @dev Return the random number.
+ /// @notice Return the random number.
/// @return randomNumber The random number or 0 if it is not ready or has not been requested.
- function receiveRandomness(uint256 /*_block*/) external view override returns (uint256 randomNumber) {
+ function receiveRandomness() external view override returns (uint256 randomNumber) {
randomNumber = randomNumbers[lastRequestId];
}
+
+ // ************************************* //
+ // * Errors * //
+ // ************************************* //
+
+ error RandomizerOnly();
}
diff --git a/contracts/src/test/DisputeKitGatedMock.sol b/contracts/src/test/DisputeKitGatedMock.sol
new file mode 100644
index 000000000..cc778c916
--- /dev/null
+++ b/contracts/src/test/DisputeKitGatedMock.sol
@@ -0,0 +1,15 @@
+// SPDX-License-Identifier: MIT
+
+pragma solidity ^0.8.24;
+
+import "../arbitration/dispute-kits/DisputeKitGated.sol";
+
+/// @title DisputeKitGatedMock
+/// DisputeKitGated with view functions to use in the tests.
+contract DisputeKitGatedMock is DisputeKitGated {
+ function extraDataToTokenInfo(
+ bytes memory _extraData
+ ) public pure returns (address tokenGate, bool isERC1155, uint256 tokenId) {
+ (tokenGate, isERC1155, tokenId) = _extraDataToTokenInfo(_extraData);
+ }
+}
diff --git a/contracts/src/test/DisputeKitGatedShutterMock.sol b/contracts/src/test/DisputeKitGatedShutterMock.sol
new file mode 100644
index 000000000..4ed4c59b2
--- /dev/null
+++ b/contracts/src/test/DisputeKitGatedShutterMock.sol
@@ -0,0 +1,15 @@
+// SPDX-License-Identifier: MIT
+
+pragma solidity ^0.8.24;
+
+import "../arbitration/dispute-kits/DisputeKitGatedShutter.sol";
+
+/// @title DisputeKitGatedShutterMock
+/// DisputeKitGatedShutter with view functions to use in the tests.
+contract DisputeKitGatedShutterMock is DisputeKitGatedShutter {
+ function extraDataToTokenInfo(
+ bytes memory _extraData
+ ) public pure returns (address tokenGate, bool isERC1155, uint256 tokenId) {
+ (tokenGate, isERC1155, tokenId) = _extraDataToTokenInfo(_extraData);
+ }
+}
diff --git a/contracts/src/test/RNGMock.sol b/contracts/src/test/RNGMock.sol
new file mode 100644
index 000000000..df372265d
--- /dev/null
+++ b/contracts/src/test/RNGMock.sol
@@ -0,0 +1,19 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.24;
+
+import "../rng/IRNG.sol";
+
+/// @title Simple mock rng to check fallback
+contract RNGMock is IRNG {
+ uint256 public randomNumber; // The number to return;
+
+ function setRN(uint256 _rn) external {
+ randomNumber = _rn;
+ }
+
+ function requestRandomness() external override {}
+
+ function receiveRandomness() external view override returns (uint256) {
+ return randomNumber;
+ }
+}
diff --git a/contracts/src/test/SortitionModuleMock.sol b/contracts/src/test/SortitionModuleMock.sol
index d55cbc152..73c9e859c 100644
--- a/contracts/src/test/SortitionModuleMock.sol
+++ b/contracts/src/test/SortitionModuleMock.sol
@@ -3,12 +3,13 @@
pragma solidity ^0.8.24;
import "../arbitration/SortitionModule.sol";
+import {SortitionTrees, TreeKey} from "../libraries/SortitionTrees.sol";
/// @title SortitionModuleMock
/// @dev Adds getter functions to sortition module for Foundry tests.
contract SortitionModuleMock is SortitionModule {
function getSortitionProperties(bytes32 _key) external view returns (uint256 K, uint256 nodeLength) {
- SortitionSumTree storage tree = sortitionSumTrees[_key];
+ SortitionTrees.Tree storage tree = sortitionSumTrees[TreeKey.wrap(_key)];
K = tree.K;
nodeLength = tree.nodes.length;
}
diff --git a/contracts/src/test/SortitionTreesMock.sol b/contracts/src/test/SortitionTreesMock.sol
new file mode 100644
index 000000000..3dcfe8741
--- /dev/null
+++ b/contracts/src/test/SortitionTreesMock.sol
@@ -0,0 +1,154 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.24;
+
+import "../libraries/SortitionTrees.sol";
+
+/// @title SortitionTreesMock
+/// @dev Test contract to expose SortitionTrees library functions for testing
+contract SortitionTreesMock {
+ using SortitionTrees for mapping(TreeKey => SortitionTrees.Tree);
+
+ // Storage for multiple test trees
+ mapping(TreeKey => SortitionTrees.Tree) public trees;
+
+ // Court hierarchy helpers (for testing parent-child relationships)
+ mapping(uint96 => uint96[]) public childCourts;
+ mapping(uint96 => uint96) public parentCourt;
+
+ // ************************************* //
+ // * Main Functions * //
+ // ************************************* //
+
+ /// @dev Create a sortition sum tree for a court
+ function createTree(uint96 _courtID, uint256 _k) external {
+ TreeKey key = CourtID.wrap(_courtID).toTreeKey();
+ trees.createTree(key, _k);
+ }
+
+ /// @dev Set stake for a juror in a specific court
+ function set(uint96 _courtID, address _account, uint256 _value) external {
+ TreeKey key = CourtID.wrap(_courtID).toTreeKey();
+ bytes32 stakePathID = SortitionTrees.toStakePathID(_account, _courtID);
+ SortitionTrees.set(trees[key], _value, stakePathID);
+ }
+
+ /// @dev Draw a juror from a court's tree
+ function draw(
+ uint96 _courtID,
+ uint256 _disputeID,
+ uint256 _nonce,
+ uint256 _randomNumber
+ ) external view returns (address drawnAddress, uint96 fromSubcourtID) {
+ TreeKey key = CourtID.wrap(_courtID).toTreeKey();
+ return SortitionTrees.draw(trees[key], _disputeID, _nonce, _randomNumber);
+ }
+
+ /// @dev Get stake of a juror in a specific court
+ function stakeOf(uint96 _courtID, address _account) external view returns (uint256) {
+ TreeKey key = CourtID.wrap(_courtID).toTreeKey();
+ bytes32 stakePathID = SortitionTrees.toStakePathID(_account, _courtID);
+ return SortitionTrees.stakeOf(trees[key], stakePathID);
+ }
+
+ // ************************************* //
+ // * Multi-Court Operations * //
+ // ************************************* //
+
+ /// @dev Set stake for a juror across multiple courts (for testing hierarchy)
+ function setStakeInHierarchy(uint96[] calldata _courtIDs, address _account, uint256 _value) external {
+ for (uint256 i = 0; i < _courtIDs.length; i++) {
+ this.set(_courtIDs[i], _account, _value);
+ }
+ }
+
+ /// @dev Get stakes of a juror across multiple courts
+ function getStakesAcrossCourts(
+ address _account,
+ uint96[] calldata _courtIDs
+ ) external view returns (uint256[] memory stakes) {
+ stakes = new uint256[](_courtIDs.length);
+ for (uint256 i = 0; i < _courtIDs.length; i++) {
+ stakes[i] = this.stakeOf(_courtIDs[i], _account);
+ }
+ }
+
+ // ************************************* //
+ // * Court Hierarchy Setup * //
+ // ************************************* //
+
+ /// @dev Set parent court for testing hierarchy
+ function setParentCourt(uint96 _childCourt, uint96 _parentCourt) external {
+ parentCourt[_childCourt] = _parentCourt;
+ }
+
+ /// @dev Add child court for testing hierarchy
+ function addChildCourt(uint96 _parentCourt, uint96 _childCourt) external {
+ childCourts[_parentCourt].push(_childCourt);
+ }
+
+ /// @dev Get child courts
+ function getChildCourts(uint96 _parentCourt) external view returns (uint96[] memory) {
+ return childCourts[_parentCourt];
+ }
+
+ // ************************************* //
+ // * Tree State Inspection * //
+ // ************************************* //
+
+ /// @dev Get all nodes in a tree
+ function getTreeNodes(uint96 _courtID) external view returns (uint256[] memory) {
+ TreeKey key = CourtID.wrap(_courtID).toTreeKey();
+ return trees[key].nodes;
+ }
+
+ /// @dev Get tree K value
+ function getTreeK(uint96 _courtID) external view returns (uint256) {
+ TreeKey key = CourtID.wrap(_courtID).toTreeKey();
+ return trees[key].K;
+ }
+
+ /// @dev Get tree stack
+ function getTreeStack(uint96 _courtID) external view returns (uint256[] memory) {
+ TreeKey key = CourtID.wrap(_courtID).toTreeKey();
+ return trees[key].stack;
+ }
+
+ /// @dev Get node index for a juror in a court
+ function getNodeIndex(uint96 _courtID, address _account) external view returns (uint256) {
+ TreeKey key = CourtID.wrap(_courtID).toTreeKey();
+ bytes32 stakePathID = SortitionTrees.toStakePathID(_account, _courtID);
+ return trees[key].IDsToNodeIndexes[stakePathID];
+ }
+
+ /// @dev Check if a court tree exists
+ function courtExists(uint96 _courtID) external view returns (bool) {
+ TreeKey key = CourtID.wrap(_courtID).toTreeKey();
+ return trees[key].K != 0;
+ }
+
+ /// @dev Get the root sum (total stakes) of a court
+ function getRootSum(uint96 _courtID) external view returns (uint256) {
+ TreeKey key = CourtID.wrap(_courtID).toTreeKey();
+ if (trees[key].nodes.length == 0) return 0;
+ return trees[key].nodes[0];
+ }
+
+ // ************************************* //
+ // * Utility Functions * //
+ // ************************************* //
+
+ /// @dev Test function to pack address and court ID
+ function testToStakePathID(address _account, uint96 _courtID) external pure returns (bytes32) {
+ return SortitionTrees.toStakePathID(_account, _courtID);
+ }
+
+ /// @dev Test function to unpack stake path ID
+ function testToAccountAndCourtID(bytes32 _stakePathID) external pure returns (address account, uint96 courtID) {
+ return SortitionTrees.toAccountAndCourtID(_stakePathID);
+ }
+
+ /// @dev Test function to convert court ID to tree key
+ function testToTreeKey(uint96 _courtID) external pure returns (TreeKey) {
+ return CourtID.wrap(_courtID).toTreeKey();
+ }
+}
diff --git a/contracts/src/token/Faucet.sol b/contracts/src/token/Faucet.sol
index 092f93891..2790bc20e 100644
--- a/contracts/src/token/Faucet.sol
+++ b/contracts/src/token/Faucet.sol
@@ -4,13 +4,14 @@ pragma solidity ^0.8.24;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
+/// forge-lint: disable-next-item(erc20-unchecked-transfer)
contract Faucet {
// ************************************* //
// * Storage * //
// ************************************* //
IERC20 public token;
- address public governor;
+ address public owner;
mapping(address => bool) public withdrewAlready;
uint256 public amount = 10_000 ether;
@@ -18,8 +19,8 @@ contract Faucet {
// * Function Modifiers * //
// ************************************* //
- modifier onlyByGovernor() {
- require(address(governor) == msg.sender, "Access not allowed: Governor only.");
+ modifier onlyByOwner() {
+ require(address(owner) == msg.sender, "Access not allowed: Owner only.");
_;
}
@@ -29,23 +30,23 @@ contract Faucet {
constructor(IERC20 _token) {
token = _token;
- governor = msg.sender;
+ owner = msg.sender;
}
// ************************************* //
// * Governance * //
// ************************************* //
- function changeGovernor(address _governor) public onlyByGovernor {
- governor = _governor;
+ function changeOwner(address _owner) public onlyByOwner {
+ owner = _owner;
}
- function changeAmount(uint256 _amount) public onlyByGovernor {
+ function changeAmount(uint256 _amount) public onlyByOwner {
amount = _amount;
}
- function withdraw() public onlyByGovernor {
- token.transfer(governor, token.balanceOf(address(this)));
+ function withdraw() public onlyByOwner {
+ token.transfer(owner, token.balanceOf(address(this)));
}
// ************************************* //
diff --git a/contracts/src/utils/TransactionBatcher.sol b/contracts/src/utils/TransactionBatcher.sol
index 1bbff78a2..bb6d25b23 100644
--- a/contracts/src/utils/TransactionBatcher.sol
+++ b/contracts/src/utils/TransactionBatcher.sol
@@ -3,7 +3,12 @@ pragma solidity ^0.8.0;
// Adapted from https://github.com/daostack/web3-transaction-batcher/blob/1b88d2ea062f8f2d9fdfdf9bbe85d2bbef780151/contracts/Batcher.sol
+/// @title Transaction Batcher
contract TransactionBatcher {
+ /// @notice Batch send transactions, all the calls must succeed.
+ /// @param targets The targets of the calls.
+ /// @param values The values of the calls.
+ /// @param datas The datas of the calls.
function batchSend(address[] memory targets, uint256[] memory values, bytes[] memory datas) public payable {
for (uint256 i = 0; i < targets.length; i++) {
(bool success, ) = targets[i].call{value: values[i]}(datas[i]);
@@ -11,12 +16,17 @@ contract TransactionBatcher {
}
}
+ /// @notice Batch send transactions WITHOUT reverting on call failure.
+ /// @param targets The targets of the calls.
+ /// @param values The values of the calls.
+ /// @param datas The datas of the calls.
function batchSendUnchecked(
address[] memory targets,
uint256[] memory values,
bytes[] memory datas
) public payable {
for (uint256 i = 0; i < targets.length; i++) {
+ /// forge-lint: disable-next-line(unchecked-call)
targets[i].call{value: values[i]}(datas[i]); // Intentionally ignoring return value.
}
}
diff --git a/contracts/test/arbitration/dispute-kit-gated-shutter.ts b/contracts/test/arbitration/dispute-kit-gated-shutter.ts
new file mode 100644
index 000000000..2ea2950fd
--- /dev/null
+++ b/contracts/test/arbitration/dispute-kit-gated-shutter.ts
@@ -0,0 +1,72 @@
+import {
+ setupTokenGatedTest,
+ testTokenWhitelistManagement,
+ testAccessControl,
+ testUnsupportedTokenErrors,
+ testERC20Gating,
+ testERC721Gating,
+ testERC1155Gating,
+ testWhitelistIntegration,
+ testNoTokenGateAddress,
+ TokenGatedTestContext,
+} from "./helpers/dispute-kit-gated-common";
+import {
+ setupShutterTest,
+ testCommitPhase,
+ testNormalFlowBotReveals,
+ testRecoveryFlowJurorReveals,
+ testEdgeCasesAndSecurity,
+ ShutterTestContext,
+} from "./helpers/dispute-kit-shutter-common";
+
+/* eslint-disable no-unused-vars */
+/* eslint-disable no-unused-expressions */
+
+/**
+ * Test suite for DisputeKitGatedShutter - a dispute kit that requires jurors to hold
+ * specific tokens (ERC20, ERC721, or ERC1155) to participate in disputes, with additional
+ * Shutter functionality for commit-reveal voting.
+ *
+ * Tests cover:
+ * - All DisputeKitGated functionality (via shared tests)
+ * - Shutter-specific commit/reveal mechanism
+ * - Recovery commits for juror vote recovery
+ * - Integration between token gating and Shutter features
+ */
+describe("DisputeKitGatedShutter", async () => {
+ describe("Token Gating Features", async () => {
+ let tokenContext: TokenGatedTestContext;
+
+ beforeEach("Setup", async () => {
+ tokenContext = await setupTokenGatedTest({ contractName: "DisputeKitGatedShutterMock" });
+ });
+
+ // Run all shared token gating tests
+ testTokenWhitelistManagement(() => tokenContext);
+ testAccessControl(() => tokenContext);
+ testUnsupportedTokenErrors(() => tokenContext);
+ testERC20Gating(() => tokenContext);
+ testERC721Gating(() => tokenContext);
+ testERC1155Gating(() => tokenContext);
+ testWhitelistIntegration(() => tokenContext);
+ testNoTokenGateAddress(() => tokenContext);
+ });
+
+ describe("Shutter Features", async () => {
+ let shutterContext: ShutterTestContext;
+
+ beforeEach("Setup", async () => {
+ // Setup DisputeKitGatedShutter with token gating enabled
+ shutterContext = await setupShutterTest({
+ contractName: "DisputeKitGatedShutter",
+ isGated: true, // Enable token gating for DAI
+ });
+ });
+
+ // Run all shared Shutter tests
+ testCommitPhase(() => shutterContext);
+ testNormalFlowBotReveals(() => shutterContext);
+ testRecoveryFlowJurorReveals(() => shutterContext);
+ testEdgeCasesAndSecurity(() => shutterContext);
+ });
+});
diff --git a/contracts/test/arbitration/dispute-kit-gated.ts b/contracts/test/arbitration/dispute-kit-gated.ts
index daa78ce0c..83637f988 100644
--- a/contracts/test/arbitration/dispute-kit-gated.ts
+++ b/contracts/test/arbitration/dispute-kit-gated.ts
@@ -1,293 +1,43 @@
-import { deployments, ethers, getNamedAccounts, network } from "hardhat";
-import { toBigInt, BigNumberish, Addressable } from "ethers";
import {
- PNK,
- KlerosCore,
- SortitionModule,
- IncrementalNG,
- DisputeKitGated,
- TestERC20,
- TestERC721,
- TestERC1155,
-} from "../../typechain-types";
-import { expect } from "chai";
-import { Courts } from "../../deploy/utils";
-import { HardhatEthersSigner } from "@nomicfoundation/hardhat-ethers/signers";
-import { deployERC1155, deployERC721 } from "../../deploy/utils/deployTokens";
+ setupTokenGatedTest,
+ testTokenWhitelistManagement,
+ testAccessControl,
+ testUnsupportedTokenErrors,
+ testERC20Gating,
+ testERC721Gating,
+ testERC1155Gating,
+ testWhitelistIntegration,
+ testNoTokenGateAddress,
+ TokenGatedTestContext,
+} from "./helpers/dispute-kit-gated-common";
/* eslint-disable no-unused-vars */
-/* eslint-disable no-unused-expressions */ // https://github.com/standard/standard/issues/690#issuecomment-278533482
-
+/* eslint-disable no-unused-expressions */
+
+/**
+ * Test suite for DisputeKitGated - a dispute kit that requires jurors to hold
+ * specific tokens (ERC20, ERC721, or ERC1155) to participate in disputes.
+ *
+ * Tests cover:
+ * - Token whitelist management and access control
+ * - Error handling for unsupported tokens
+ * - Token gating functionality for different token types
+ * - Integration between whitelist and dispute creation
+ */
describe("DisputeKitGated", async () => {
- const ONE_THOUSAND_PNK = 10n ** 21n;
- const thousandPNK = (amount: BigNumberish) => toBigInt(amount) * ONE_THOUSAND_PNK;
- const PNK = (amount: BigNumberish) => toBigInt(amount) * 10n ** 18n;
-
- let deployer: string;
- let juror1: HardhatEthersSigner;
- let juror2: HardhatEthersSigner;
- let disputeKitGated: DisputeKitGated;
- let pnk: PNK;
- let dai: TestERC20;
- let core: KlerosCore;
- let sortitionModule: SortitionModule;
- let rng: IncrementalNG;
- let nft721: TestERC721;
- let nft1155: TestERC1155;
- const RANDOM = 424242n;
- const GATED_DK_ID = 3;
- const TOKEN_ID = 888;
- const minStake = PNK(200);
+ let context: TokenGatedTestContext;
beforeEach("Setup", async () => {
- ({ deployer } = await getNamedAccounts());
- [, juror1, juror2] = await ethers.getSigners();
-
- await deployments.fixture(["Arbitration", "VeaMock"], {
- fallbackToGlobal: true,
- keepExistingDeployments: false,
- });
- disputeKitGated = (await ethers.getContract("DisputeKitGated")) as DisputeKitGated;
- pnk = (await ethers.getContract("PNK")) as PNK;
- dai = (await ethers.getContract("DAI")) as TestERC20;
- core = (await ethers.getContract("KlerosCore")) as KlerosCore;
- sortitionModule = (await ethers.getContract("SortitionModule")) as SortitionModule;
-
- // Make the tests more deterministic with this dummy RNG
- await deployments.deploy("IncrementalNG", {
- from: deployer,
- args: [RANDOM],
- log: true,
- });
- rng = (await ethers.getContract("IncrementalNG")) as IncrementalNG;
-
- await sortitionModule.changeRandomNumberGenerator(rng.target, 20).then((tx) => tx.wait());
-
- const hre = require("hardhat");
- await deployERC721(hre, deployer, "TestERC721", "Nft721");
- nft721 = (await ethers.getContract("Nft721")) as TestERC721;
-
- await deployERC1155(hre, deployer, "TestERC1155", "Nft1155");
- nft1155 = (await ethers.getContract("Nft1155")) as TestERC1155;
- await nft1155.mint(deployer, TOKEN_ID, 1, "0x00");
- });
-
- const encodeExtraData = (
- courtId: number,
- minJurors: BigNumberish,
- disputeKitId: number,
- tokenGate: string | Addressable,
- isERC1155: boolean,
- tokenId: BigNumberish
- ) => {
- // Packing of tokenGate and isERC1155
- // uint88 (padding 11 bytes) + bool (1 byte) + address (20 bytes) = 32 bytes
- const packed = ethers.solidityPacked(["uint88", "bool", "address"], [0, isERC1155, tokenGate]);
- return ethers.AbiCoder.defaultAbiCoder().encode(
- ["uint256", "uint256", "uint256", "bytes32", "uint256"],
- [courtId, minJurors, disputeKitId, packed, tokenId]
- );
- };
-
- const stakeAndDraw = async (
- courtId: number,
- minJurors: BigNumberish,
- disputeKitId: number,
- tokenGate: string | Addressable,
- isERC1155: boolean,
- tokenId: BigNumberish
- ) => {
- // Stake jurors
- for (const juror of [juror1, juror2]) {
- await pnk.transfer(juror.address, thousandPNK(10)).then((tx) => tx.wait());
- expect(await pnk.balanceOf(juror.address)).to.equal(thousandPNK(10));
-
- await pnk
- .connect(juror)
- .approve(core.target, thousandPNK(10), { gasLimit: 300000 })
- .then((tx) => tx.wait());
-
- await core
- .connect(juror)
- .setStake(Courts.GENERAL, thousandPNK(10), { gasLimit: 300000 })
- .then((tx) => tx.wait());
-
- expect(await sortitionModule.getJurorBalance(juror.address, 1)).to.deep.equal([
- thousandPNK(10), // totalStaked
- 0, // totalLocked
- thousandPNK(10), // stakedInCourt
- 1, // nbOfCourts
- ]);
- }
-
- const extraData = encodeExtraData(courtId, minJurors, disputeKitId, tokenGate, isERC1155, tokenId);
- // console.log("extraData", extraData);
-
- const tokenInfo = await disputeKitGated.extraDataToTokenInfo(extraData);
- expect(tokenInfo[0]).to.equal(tokenGate);
- expect(tokenInfo[1]).to.equal(isERC1155);
- expect(tokenInfo[2]).to.equal(tokenId);
-
- const arbitrationCost = await core["arbitrationCost(bytes)"](extraData);
-
- // Warning: this dispute cannot be executed, in reality it should be created by an arbitrable contract, not an EOA.
- const tx = await core["createDispute(uint256,bytes)"](2, extraData, { value: arbitrationCost }).then((tx) =>
- tx.wait()
- );
- const disputeId = 0;
- // console.log(tx?.logs);
-
- await network.provider.send("evm_increaseTime", [2000]); // Wait for minStakingTime
- await network.provider.send("evm_mine");
- await sortitionModule.passPhase().then((tx) => tx.wait()); // Staking -> Generating
-
- const lookahead = await sortitionModule.rngLookahead();
- for (let index = 0; index < lookahead; index++) {
- await network.provider.send("evm_mine");
- }
-
- await sortitionModule.passPhase().then((tx) => tx.wait()); // Generating -> Drawing
- return core.draw(disputeId, 70, { gasLimit: 10000000 });
- };
-
- describe("When gating with DAI token", async () => {
- it("Should draw no juror if they don't have any DAI balance", async () => {
- const nbOfJurors = 15n;
- const tx = await stakeAndDraw(Courts.GENERAL, nbOfJurors, GATED_DK_ID, dai.target, false, 0).then((tx) =>
- tx.wait()
- );
-
- // Ensure that no juror is drawn
- const drawLogs =
- tx?.logs.filter((log: any) => log.fragment?.name === "Draw" && log.address === core.target) || [];
- expect(drawLogs).to.have.length(0);
- });
-
- it("Should draw only the jurors who have some DAI balance", async () => {
- dai.transfer(juror1.address, 1);
-
- const nbOfJurors = 15n;
- const tx = await stakeAndDraw(Courts.GENERAL, nbOfJurors, GATED_DK_ID, dai.target, false, 0).then((tx) =>
- tx.wait()
- );
-
- // Ensure that only juror1 is drawn
- const drawLogs =
- tx?.logs.filter((log: any) => log.fragment?.name === "Draw" && log.address === core.target) || [];
- expect(drawLogs).to.have.length(nbOfJurors);
- drawLogs.forEach((log: any) => {
- expect(log.args[0]).to.equal(juror1.address);
- });
-
- // Ensure that juror1 has PNK locked
- expect(await sortitionModule.getJurorBalance(juror1.address, Courts.GENERAL)).to.deep.equal([
- thousandPNK(10), // totalStaked
- minStake * nbOfJurors, // totalLocked
- thousandPNK(10), // stakedInCourt
- 1, // nbOfCourts
- ]);
-
- // Ensure that juror2 has no PNK locked
- expect(await sortitionModule.getJurorBalance(juror2.address, Courts.GENERAL)).to.deep.equal([
- thousandPNK(10), // totalStaked
- 0, // totalLocked
- thousandPNK(10), // stakedInCourt
- 1, // nbOfCourts
- ]);
- });
+ context = await setupTokenGatedTest({ contractName: "DisputeKitGatedMock" });
});
- describe("When gating with ERC721 token", async () => {
- it("Should draw no juror if they don't own the ERC721 token", async () => {
- const nbOfJurors = 15n;
- const tx = await stakeAndDraw(Courts.GENERAL, nbOfJurors, GATED_DK_ID, nft721.target, false, 0).then((tx) =>
- tx.wait()
- );
-
- // Ensure that no juror is drawn
- const drawLogs =
- tx?.logs.filter((log: any) => log.fragment?.name === "Draw" && log.address === core.target) || [];
- expect(drawLogs).to.have.length(0);
- });
-
- it("Should draw only the jurors owning the ERC721 token", async () => {
- await nft721.safeMint(juror2.address);
-
- const nbOfJurors = 15n;
- const tx = await stakeAndDraw(Courts.GENERAL, nbOfJurors, GATED_DK_ID, nft721.target, false, 0).then((tx) =>
- tx.wait()
- );
-
- // Ensure that only juror2 is drawn
- const drawLogs =
- tx?.logs.filter((log: any) => log.fragment?.name === "Draw" && log.address === core.target) || [];
- expect(drawLogs).to.have.length(nbOfJurors);
- drawLogs.forEach((log: any) => {
- expect(log.args[0]).to.equal(juror2.address);
- });
-
- // Ensure that juror1 is has no PNK locked
- expect(await sortitionModule.getJurorBalance(juror1.address, Courts.GENERAL)).to.deep.equal([
- thousandPNK(10), // totalStaked
- 0, // totalLocked
- thousandPNK(10), // stakedInCourt
- 1, // nbOfCourts
- ]);
-
- // Ensure that juror2 has PNK locked
- expect(await sortitionModule.getJurorBalance(juror2.address, Courts.GENERAL)).to.deep.equal([
- thousandPNK(10), // totalStaked
- minStake * nbOfJurors, // totalLocked
- thousandPNK(10), // stakedInCourt
- 1, // nbOfCourts
- ]);
- });
- });
-
- describe("When gating with ERC1155 token", async () => {
- it("Should draw no juror if they don't own the ERC1155 token", async () => {
- const nbOfJurors = 15n;
- const tx = await stakeAndDraw(Courts.GENERAL, nbOfJurors, GATED_DK_ID, nft1155.target, true, TOKEN_ID).then(
- (tx) => tx.wait()
- );
-
- // Ensure that no juror is drawn
- const drawLogs =
- tx?.logs.filter((log: any) => log.fragment?.name === "Draw" && log.address === core.target) || [];
- expect(drawLogs).to.have.length(0);
- });
-
- it("Should draw only the jurors owning the ERC1155 token", async () => {
- await nft1155.mint(juror2.address, TOKEN_ID, 1, "0x00");
-
- const nbOfJurors = 15n;
- const tx = await stakeAndDraw(Courts.GENERAL, nbOfJurors, GATED_DK_ID, nft1155.target, true, TOKEN_ID).then(
- (tx) => tx.wait()
- );
-
- // Ensure that only juror2 is drawn
- const drawLogs =
- tx?.logs.filter((log: any) => log.fragment?.name === "Draw" && log.address === core.target) || [];
- expect(drawLogs).to.have.length(nbOfJurors);
- drawLogs.forEach((log: any) => {
- expect(log.args[0]).to.equal(juror2.address);
- });
-
- // Ensure that juror1 is has no PNK locked
- expect(await sortitionModule.getJurorBalance(juror1.address, Courts.GENERAL)).to.deep.equal([
- thousandPNK(10), // totalStaked
- 0, // totalLocked
- thousandPNK(10), // stakedInCourt
- 1, // nbOfCourts
- ]);
-
- // Ensure that juror2 has PNK locked
- expect(await sortitionModule.getJurorBalance(juror2.address, Courts.GENERAL)).to.deep.equal([
- thousandPNK(10), // totalStaked
- minStake * nbOfJurors, // totalLocked
- thousandPNK(10), // stakedInCourt
- 1, // nbOfCourts
- ]);
- });
- });
+ // Run all shared tests with the context
+ testTokenWhitelistManagement(() => context);
+ testAccessControl(() => context);
+ testUnsupportedTokenErrors(() => context);
+ testERC20Gating(() => context);
+ testERC721Gating(() => context);
+ testERC1155Gating(() => context);
+ testWhitelistIntegration(() => context);
+ testNoTokenGateAddress(() => context);
});
diff --git a/contracts/test/arbitration/dispute-kit-shutter.ts b/contracts/test/arbitration/dispute-kit-shutter.ts
new file mode 100644
index 000000000..5bfee9ef7
--- /dev/null
+++ b/contracts/test/arbitration/dispute-kit-shutter.ts
@@ -0,0 +1,36 @@
+import {
+ setupShutterTest,
+ testCommitPhase,
+ testNormalFlowBotReveals,
+ testRecoveryFlowJurorReveals,
+ testEdgeCasesAndSecurity,
+ ShutterTestContext,
+} from "./helpers/dispute-kit-shutter-common";
+
+/* eslint-disable no-unused-vars */
+/* eslint-disable no-unused-expressions */
+
+/**
+ * Test suite for DisputeKitShutter - implements shielded voting with commit-reveal mechanism
+ * using the Shutter protocol for encrypted vote storage and decryption.
+ *
+ * Tests cover:
+ * - Commit phase with recovery commitments
+ * - Normal flow where bot reveals votes
+ * - Recovery flow where jurors reveal their own votes
+ * - Hash function behavior for different callers
+ * - Edge cases and security considerations
+ */
+describe("DisputeKitShutter", async () => {
+ let context: ShutterTestContext;
+
+ beforeEach("Setup", async () => {
+ context = await setupShutterTest({ contractName: "DisputeKitShutter" });
+ });
+
+ // Run all shared Shutter tests with the context
+ testCommitPhase(() => context);
+ testNormalFlowBotReveals(() => context);
+ testRecoveryFlowJurorReveals(() => context);
+ testEdgeCasesAndSecurity(() => context);
+});
diff --git a/contracts/test/arbitration/draw.ts b/contracts/test/arbitration/draw.ts
index 12790fdb5..ad216bdc7 100644
--- a/contracts/test/arbitration/draw.ts
+++ b/contracts/test/arbitration/draw.ts
@@ -62,12 +62,12 @@ describe("Draw Benchmark", async () => {
fallbackToGlobal: true,
keepExistingDeployments: false,
});
- disputeKit = (await ethers.getContract("DisputeKitClassic")) as DisputeKitClassic;
- pnk = (await ethers.getContract("PNK")) as PNK;
- core = (await ethers.getContract("KlerosCore")) as KlerosCore;
- homeGateway = (await ethers.getContract("HomeGatewayToEthereum")) as HomeGateway;
- arbitrable = (await ethers.getContract("ArbitrableExample")) as ArbitrableExample;
- sortitionModule = (await ethers.getContract("SortitionModule")) as SortitionModule;
+ disputeKit = await ethers.getContract("DisputeKitClassic");
+ pnk = await ethers.getContract("PNK");
+ core = await ethers.getContract("KlerosCore");
+ homeGateway = await ethers.getContract("HomeGatewayToEthereum");
+ arbitrable = await ethers.getContract("ArbitrableExample");
+ sortitionModule = await ethers.getContract("SortitionModule");
parentCourtMinStake = await core.courts(Courts.GENERAL).then((court) => court.minStake);
@@ -79,9 +79,9 @@ describe("Draw Benchmark", async () => {
args: [RANDOM],
log: true,
});
- rng = (await ethers.getContract("IncrementalNG")) as IncrementalNG;
+ rng = await ethers.getContract("IncrementalNG");
- await sortitionModule.changeRandomNumberGenerator(rng.target, 20).then((tx) => tx.wait());
+ await sortitionModule.changeRandomNumberGenerator(rng.target).then((tx) => tx.wait());
// CourtId 2 = CHILD_COURT
const minStake = 3n * 10n ** 20n; // 300 PNK
@@ -154,15 +154,13 @@ describe("Draw Benchmark", async () => {
// Relayer tx
await homeGateway
.connect(await ethers.getSigner(relayer))
- ["relayCreateDispute((bytes32,uint256,address,uint256,uint256,uint256,string,uint256,bytes))"](
+ ["relayCreateDispute((bytes32,uint256,address,uint256,uint256,uint256,bytes))"](
{
foreignBlockHash: lastBlock?.hash,
foreignChainID: 31337,
foreignArbitrable: arbitrable.target,
foreignDisputeID: disputeId,
- externalDisputeID: ethers.keccak256(ethers.toUtf8Bytes("future of france")),
templateId: 0,
- templateUri: "",
choices: 2,
extraData: `0x000000000000000000000000000000000000000000000000000000000000000${createDisputeCourtId}0000000000000000000000000000000000000000000000000000000000000003`,
},
@@ -174,11 +172,6 @@ describe("Draw Benchmark", async () => {
await network.provider.send("evm_mine");
await sortitionModule.passPhase().then((tx) => tx.wait()); // Staking -> Generating
- const lookahead = await sortitionModule.rngLookahead();
- for (let index = 0; index < lookahead; index++) {
- await network.provider.send("evm_mine");
- }
-
await sortitionModule.passPhase().then((tx) => tx.wait()); // Generating -> Drawing
await expectFromDraw(core.draw(0, 20, { gasLimit: 1000000 }));
diff --git a/contracts/test/arbitration/helpers/dispute-kit-gated-common.ts b/contracts/test/arbitration/helpers/dispute-kit-gated-common.ts
new file mode 100644
index 000000000..4876093b3
--- /dev/null
+++ b/contracts/test/arbitration/helpers/dispute-kit-gated-common.ts
@@ -0,0 +1,704 @@
+import { deployments, ethers, getNamedAccounts, network } from "hardhat";
+import { toBigInt, BigNumberish, Addressable } from "ethers";
+import {
+ PNK,
+ KlerosCore,
+ SortitionModule,
+ IncrementalNG,
+ DisputeKitGatedMock,
+ DisputeKitGatedShutterMock,
+ TestERC20,
+ TestERC721,
+ TestERC1155,
+} from "../../../typechain-types";
+import { expect } from "chai";
+import { Courts } from "../../../deploy/utils";
+import { HardhatEthersSigner } from "@nomicfoundation/hardhat-ethers/signers";
+import { deployERC1155, deployERC721 } from "../../../deploy/utils/deployTokens";
+import { deployUpgradable } from "../../../deploy/utils/deployUpgradable";
+
+/* eslint-disable no-unused-vars */
+/* eslint-disable no-unused-expressions */ // https://github.com/standard/standard/issues/690#issuecomment-278533482
+
+// Type for the dispute kit (either DisputeKitGated or DisputeKitGatedShutter)
+export type DisputeKitGatedType = DisputeKitGatedMock | DisputeKitGatedShutterMock;
+
+// Test context interface that holds all the test state
+export interface TokenGatedTestContext {
+ deployer: string;
+ juror1: HardhatEthersSigner;
+ juror2: HardhatEthersSigner;
+ disputeKit: DisputeKitGatedType;
+ pnk: PNK;
+ dai: TestERC20;
+ core: KlerosCore;
+ sortitionModule: SortitionModule;
+ rng: IncrementalNG;
+ nft721: TestERC721;
+ nft1155: TestERC1155;
+ gatedDisputeKitID: number;
+ minStake: bigint;
+ RANDOM: bigint;
+ TOKEN_ID: number;
+ ONE_THOUSAND_PNK: bigint;
+ thousandPNK: (amount: BigNumberish) => bigint;
+ PNK: (amount: BigNumberish) => bigint;
+}
+
+// Configuration for setting up a token gated test
+export interface TokenGatedTestConfig {
+ contractName: string; // "DisputeKitGatedMock" or "DisputeKitGatedShutterMock"
+}
+
+// Constants for token amounts
+const ONE_THOUSAND_PNK = 10n ** 21n;
+const thousandPNK = (amount: BigNumberish) => toBigInt(amount) * ONE_THOUSAND_PNK;
+const PNK_AMOUNT = (amount: BigNumberish) => toBigInt(amount) * 10n ** 18n;
+
+// Helper function to encode extra data for dispute creation with token gating parameters
+export const encodeExtraData = (
+ courtId: BigNumberish,
+ minJurors: BigNumberish,
+ disputeKitId: number,
+ tokenGate: string | Addressable,
+ isERC1155: boolean,
+ tokenId: BigNumberish
+) => {
+ // Packing of tokenGate and isERC1155
+ // uint88 (padding 11 bytes) + bool (1 byte) + address (20 bytes) = 32 bytes
+ const packed = ethers.solidityPacked(["uint88", "bool", "address"], [0, isERC1155, tokenGate]);
+ return ethers.AbiCoder.defaultAbiCoder().encode(
+ ["uint256", "uint256", "uint256", "bytes32", "uint256"],
+ [courtId, minJurors, disputeKitId, packed, tokenId]
+ );
+};
+
+// Helper function to add or remove tokens from the whitelist
+export const whitelistTokens = async (
+ context: TokenGatedTestContext,
+ tokens: (string | Addressable)[],
+ supported: boolean = true
+) => {
+ const tokenAddresses = tokens.map((token) => (typeof token === "string" ? token : token.toString()));
+ return context.disputeKit.changeSupportedTokens(tokenAddresses, supported);
+};
+
+// Helper function to create a dispute with the specified token gate
+export const createDisputeWithToken = async (
+ context: TokenGatedTestContext,
+ token: string | Addressable,
+ isERC1155: boolean = false,
+ tokenId: BigNumberish = 0
+) => {
+ const extraData = encodeExtraData(Courts.GENERAL, 3, context.gatedDisputeKitID, token, isERC1155, tokenId);
+ const arbitrationCost = await context.core["arbitrationCost(bytes)"](extraData);
+ return context.core["createDispute(uint256,bytes)"](2, extraData, { value: arbitrationCost });
+};
+
+// Helper function to assert whether a token is supported or not
+export const expectTokenSupported = async (
+ context: TokenGatedTestContext,
+ token: string | Addressable,
+ supported: boolean
+) => {
+ const tokenAddress = typeof token === "string" ? token : token.toString();
+ expect(await context.disputeKit.supportedTokens(tokenAddress)).to.equal(supported);
+};
+
+// Helper function to stake and draw jurors
+export const stakeAndDraw = async (
+ context: TokenGatedTestContext,
+ courtId: number,
+ minJurors: BigNumberish,
+ disputeKitId: number,
+ tokenGate: string | Addressable,
+ isERC1155: boolean,
+ tokenId: BigNumberish
+) => {
+ // Stake jurors
+ for (const juror of [context.juror1, context.juror2]) {
+ await context.pnk.transfer(juror.address, context.thousandPNK(10)).then((tx) => tx.wait());
+ expect(await context.pnk.balanceOf(juror.address)).to.equal(context.thousandPNK(10));
+
+ await context.pnk
+ .connect(juror)
+ .approve(context.core.target, context.thousandPNK(10), { gasLimit: 300000 })
+ .then((tx) => tx.wait());
+
+ await context.core
+ .connect(juror)
+ .setStake(Courts.GENERAL, context.thousandPNK(10), { gasLimit: 500000 })
+ .then((tx) => tx.wait());
+
+ expect(await context.sortitionModule.getJurorBalance(juror.address, 1)).to.deep.equal([
+ context.thousandPNK(10), // totalStaked
+ 0, // totalLocked
+ context.thousandPNK(10), // stakedInCourt
+ 1, // nbOfCourts
+ ]);
+ }
+
+ const extraData = encodeExtraData(courtId, minJurors, disputeKitId, tokenGate, isERC1155, tokenId);
+
+ const tokenInfo = await context.disputeKit.extraDataToTokenInfo(extraData);
+ expect(tokenInfo[0]).to.equal(tokenGate);
+ expect(tokenInfo[1]).to.equal(isERC1155);
+ expect(tokenInfo[2]).to.equal(tokenId);
+
+ const arbitrationCost = await context.core["arbitrationCost(bytes)"](extraData);
+
+ // Warning: this dispute cannot be executed, in reality it should be created by an arbitrable contract, not an EOA.
+ const tx = await context.core["createDispute(uint256,bytes)"](2, extraData, { value: arbitrationCost }).then((tx) =>
+ tx.wait()
+ );
+ const disputeId = 0;
+
+ await network.provider.send("evm_increaseTime", [2000]); // Wait for minStakingTime
+ await network.provider.send("evm_mine");
+ await context.sortitionModule.passPhase().then((tx) => tx.wait()); // Staking -> Generating
+
+ await context.sortitionModule.passPhase().then((tx) => tx.wait()); // Generating -> Drawing
+ return context.core.draw(disputeId, 70, { gasLimit: 10000000 });
+};
+
+// Setup function that creates the test context
+export async function setupTokenGatedTest(config: TokenGatedTestConfig): Promise {
+ const { deployer } = await getNamedAccounts();
+ const [, juror1, juror2] = await ethers.getSigners();
+
+ await deployments.fixture(["Arbitration", "VeaMock"], {
+ fallbackToGlobal: true,
+ keepExistingDeployments: false,
+ });
+
+ const pnk = await ethers.getContract("PNK");
+ const dai = await ethers.getContract("DAI");
+ const weth = await ethers.getContract("WETH");
+ const core = await ethers.getContract("KlerosCore");
+ const sortitionModule = await ethers.getContract("SortitionModule");
+
+ const deploymentResult = await deployUpgradable(deployments, config.contractName, {
+ from: deployer,
+ proxyAlias: "UUPSProxy",
+ args: [deployer, core.target, weth.target, 1],
+ log: true,
+ });
+ await core.addNewDisputeKit(deploymentResult.address);
+ const gatedDisputeKitID = Number((await core.getDisputeKitsLength()) - 1n);
+ await core.enableDisputeKits(Courts.GENERAL, [gatedDisputeKitID], true);
+
+ const disputeKit = await ethers.getContract(config.contractName);
+
+ // Make the tests more deterministic with this dummy RNG
+ await deployments.deploy("IncrementalNG", {
+ from: deployer,
+ args: [424242n],
+ log: true,
+ });
+ const rng = await ethers.getContract("IncrementalNG");
+
+ await sortitionModule.changeRandomNumberGenerator(rng.target).then((tx) => tx.wait());
+
+ const hre = require("hardhat");
+ await deployERC721(hre, deployer, "TestERC721", "Nft721");
+ const nft721 = await ethers.getContract("Nft721");
+
+ await deployERC1155(hre, deployer, "TestERC1155", "Nft1155");
+ const nft1155 = await ethers.getContract("Nft1155");
+ const TOKEN_ID = 888;
+ await nft1155.mint(deployer, TOKEN_ID, 1, "0x00");
+
+ const context: TokenGatedTestContext = {
+ deployer,
+ juror1,
+ juror2,
+ disputeKit,
+ pnk,
+ dai,
+ core,
+ sortitionModule,
+ rng,
+ nft721,
+ nft1155,
+ gatedDisputeKitID,
+ minStake: PNK_AMOUNT(200),
+ RANDOM: 424242n,
+ TOKEN_ID,
+ ONE_THOUSAND_PNK,
+ thousandPNK,
+ PNK: PNK_AMOUNT,
+ };
+
+ // Whitelist all tokens by default
+ await whitelistTokens(context, [dai.target, nft721.target, nft1155.target], true);
+
+ return context;
+}
+
+// Test suites as functions that accept context
+
+export function testTokenWhitelistManagement(context: () => TokenGatedTestContext) {
+ describe("Token Whitelist Management", async () => {
+ describe("changeSupportedTokens function", async () => {
+ it("Should allow owner to whitelist single token", async () => {
+ const ctx = context();
+ await whitelistTokens(ctx, [ctx.dai.target], true);
+ await expectTokenSupported(ctx, ctx.dai.target, true);
+ });
+
+ it("Should allow owner to whitelist multiple tokens", async () => {
+ const ctx = context();
+ await whitelistTokens(ctx, [ctx.dai.target, ctx.nft721.target, ctx.nft1155.target], true);
+ await expectTokenSupported(ctx, ctx.dai.target, true);
+ await expectTokenSupported(ctx, ctx.nft721.target, true);
+ await expectTokenSupported(ctx, ctx.nft1155.target, true);
+ });
+
+ it("Should allow owner to remove single token from whitelist", async () => {
+ const ctx = context();
+ await whitelistTokens(ctx, [ctx.dai.target], true);
+ await expectTokenSupported(ctx, ctx.dai.target, true);
+
+ await whitelistTokens(ctx, [ctx.dai.target], false);
+ await expectTokenSupported(ctx, ctx.dai.target, false);
+ });
+
+ it("Should allow owner to remove multiple tokens from whitelist", async () => {
+ const ctx = context();
+ await whitelistTokens(ctx, [ctx.dai.target, ctx.nft721.target], true);
+ await expectTokenSupported(ctx, ctx.dai.target, true);
+ await expectTokenSupported(ctx, ctx.nft721.target, true);
+
+ await whitelistTokens(ctx, [ctx.dai.target, ctx.nft721.target], false);
+ await expectTokenSupported(ctx, ctx.dai.target, false);
+ await expectTokenSupported(ctx, ctx.nft721.target, false);
+ });
+
+ it("Should handle mixed operations (add some, remove some)", async () => {
+ const ctx = context();
+ await whitelistTokens(ctx, [ctx.dai.target, ctx.nft721.target], true);
+ await expectTokenSupported(ctx, ctx.dai.target, true);
+ await expectTokenSupported(ctx, ctx.nft721.target, true);
+
+ await whitelistTokens(ctx, [ctx.dai.target], false);
+ await whitelistTokens(ctx, [ctx.nft1155.target], true);
+
+ await expectTokenSupported(ctx, ctx.dai.target, false);
+ await expectTokenSupported(ctx, ctx.nft721.target, true);
+ await expectTokenSupported(ctx, ctx.nft1155.target, true);
+ });
+
+ it("Should handle duplicate operations correctly", async () => {
+ const ctx = context();
+ // Whitelist token twice - should not revert
+ await whitelistTokens(ctx, [ctx.dai.target], true);
+ await whitelistTokens(ctx, [ctx.dai.target], true);
+ await expectTokenSupported(ctx, ctx.dai.target, true);
+
+ // Remove token twice - should not revert
+ await whitelistTokens(ctx, [ctx.dai.target], false);
+ await whitelistTokens(ctx, [ctx.dai.target], false);
+ await expectTokenSupported(ctx, ctx.dai.target, false);
+ });
+ });
+ });
+}
+
+export function testAccessControl(context: () => TokenGatedTestContext) {
+ describe("Access Control", async () => {
+ it("Should revert when non-owner tries to change supported tokens", async () => {
+ const ctx = context();
+ await expect(ctx.disputeKit.connect(ctx.juror1).changeSupportedTokens([ctx.dai.target], true)).to.be.reverted;
+ });
+
+ it("Should revert when non-owner tries to remove supported tokens", async () => {
+ const ctx = context();
+ // First whitelist as owner
+ await whitelistTokens(ctx, [ctx.dai.target], true);
+
+ // Then try to remove as non-owner
+ await expect(ctx.disputeKit.connect(ctx.juror1).changeSupportedTokens([ctx.dai.target], false)).to.be.reverted;
+ });
+ });
+}
+
+export function testUnsupportedTokenErrors(context: () => TokenGatedTestContext) {
+ describe("Error Handling - Unsupported Tokens", async () => {
+ it("Should revert with TokenNotSupported when creating dispute with unsupported ERC20", async () => {
+ const ctx = context();
+ await whitelistTokens(ctx, [ctx.dai.target], false);
+
+ await expect(createDisputeWithToken(ctx, ctx.dai.target))
+ .to.be.revertedWithCustomError(ctx.disputeKit, "TokenNotSupported")
+ .withArgs(ctx.dai.target);
+ });
+
+ it("Should revert with TokenNotSupported when creating dispute with unsupported ERC721", async () => {
+ const ctx = context();
+ await whitelistTokens(ctx, [ctx.nft721.target], false);
+
+ await expect(createDisputeWithToken(ctx, ctx.nft721.target))
+ .to.be.revertedWithCustomError(ctx.disputeKit, "TokenNotSupported")
+ .withArgs(ctx.nft721.target);
+ });
+
+ it("Should revert with TokenNotSupported when creating dispute with unsupported ERC1155", async () => {
+ const ctx = context();
+ await whitelistTokens(ctx, [ctx.nft1155.target], false);
+
+ await expect(createDisputeWithToken(ctx, ctx.nft1155.target, true, ctx.TOKEN_ID))
+ .to.be.revertedWithCustomError(ctx.disputeKit, "TokenNotSupported")
+ .withArgs(ctx.nft1155.target);
+ });
+
+ it("Should allow dispute creation after token is whitelisted", async () => {
+ const ctx = context();
+ await whitelistTokens(ctx, [ctx.dai.target], false);
+
+ await expect(createDisputeWithToken(ctx, ctx.dai.target)).to.be.revertedWithCustomError(
+ ctx.disputeKit,
+ "TokenNotSupported"
+ );
+
+ await whitelistTokens(ctx, [ctx.dai.target], true);
+
+ await expect(createDisputeWithToken(ctx, ctx.dai.target)).to.not.be.reverted;
+ });
+ });
+}
+
+export function testERC20Gating(context: () => TokenGatedTestContext) {
+ describe("When gating with DAI token", async () => {
+ it("Should draw no juror if they don't have any DAI balance", async () => {
+ const ctx = context();
+ const nbOfJurors = 15n;
+ const tx = await stakeAndDraw(
+ ctx,
+ Courts.GENERAL,
+ nbOfJurors,
+ ctx.gatedDisputeKitID,
+ ctx.dai.target,
+ false,
+ 0
+ ).then((tx) => tx.wait());
+
+ // Ensure that no juror is drawn
+ const drawLogs =
+ tx?.logs.filter((log: any) => log.fragment?.name === "Draw" && log.address === ctx.core.target) || [];
+ expect(drawLogs).to.have.length(0);
+ });
+
+ it("Should draw only the jurors who have some DAI balance", async () => {
+ const ctx = context();
+ await ctx.dai.transfer(ctx.juror1.address, 1);
+
+ const nbOfJurors = 15n;
+ const tx = await stakeAndDraw(
+ ctx,
+ Courts.GENERAL,
+ nbOfJurors,
+ ctx.gatedDisputeKitID,
+ ctx.dai.target,
+ false,
+ 0
+ ).then((tx) => tx.wait());
+
+ // Ensure that only juror1 is drawn
+ const drawLogs =
+ tx?.logs.filter((log: any) => log.fragment?.name === "Draw" && log.address === ctx.core.target) || [];
+ expect(drawLogs).to.have.length(nbOfJurors);
+ drawLogs.forEach((log: any) => {
+ expect(log.args[0]).to.equal(ctx.juror1.address);
+ });
+
+ // Ensure that juror1 has PNK locked
+ expect(await ctx.sortitionModule.getJurorBalance(ctx.juror1.address, Courts.GENERAL)).to.deep.equal([
+ ctx.thousandPNK(10), // totalStaked
+ ctx.minStake * nbOfJurors, // totalLocked
+ ctx.thousandPNK(10), // stakedInCourt
+ 1, // nbOfCourts
+ ]);
+
+ // Ensure that juror2 has no PNK locked
+ expect(await ctx.sortitionModule.getJurorBalance(ctx.juror2.address, Courts.GENERAL)).to.deep.equal([
+ ctx.thousandPNK(10), // totalStaked
+ 0, // totalLocked
+ ctx.thousandPNK(10), // stakedInCourt
+ 1, // nbOfCourts
+ ]);
+ });
+ });
+}
+
+export function testERC721Gating(context: () => TokenGatedTestContext) {
+ describe("When gating with ERC721 token", async () => {
+ it("Should draw no juror if they don't own the ERC721 token", async () => {
+ const ctx = context();
+ const nbOfJurors = 15n;
+ const tx = await stakeAndDraw(
+ ctx,
+ Courts.GENERAL,
+ nbOfJurors,
+ ctx.gatedDisputeKitID,
+ ctx.nft721.target,
+ false,
+ 0
+ ).then((tx) => tx.wait());
+
+ // Ensure that no juror is drawn
+ const drawLogs =
+ tx?.logs.filter((log: any) => log.fragment?.name === "Draw" && log.address === ctx.core.target) || [];
+ expect(drawLogs).to.have.length(0);
+ });
+
+ it("Should draw only the jurors owning the ERC721 token", async () => {
+ const ctx = context();
+ await ctx.nft721.safeMint(ctx.juror2.address);
+
+ const nbOfJurors = 15n;
+ const tx = await stakeAndDraw(
+ ctx,
+ Courts.GENERAL,
+ nbOfJurors,
+ ctx.gatedDisputeKitID,
+ ctx.nft721.target,
+ false,
+ 0
+ ).then((tx) => tx.wait());
+
+ // Ensure that only juror2 is drawn
+ const drawLogs =
+ tx?.logs.filter((log: any) => log.fragment?.name === "Draw" && log.address === ctx.core.target) || [];
+ expect(drawLogs).to.have.length(nbOfJurors);
+ drawLogs.forEach((log: any) => {
+ expect(log.args[0]).to.equal(ctx.juror2.address);
+ });
+
+ // Ensure that juror1 has no PNK locked
+ expect(await ctx.sortitionModule.getJurorBalance(ctx.juror1.address, Courts.GENERAL)).to.deep.equal([
+ ctx.thousandPNK(10), // totalStaked
+ 0, // totalLocked
+ ctx.thousandPNK(10), // stakedInCourt
+ 1, // nbOfCourts
+ ]);
+
+ // Ensure that juror2 has PNK locked
+ expect(await ctx.sortitionModule.getJurorBalance(ctx.juror2.address, Courts.GENERAL)).to.deep.equal([
+ ctx.thousandPNK(10), // totalStaked
+ ctx.minStake * nbOfJurors, // totalLocked
+ ctx.thousandPNK(10), // stakedInCourt
+ 1, // nbOfCourts
+ ]);
+ });
+ });
+}
+
+export function testERC1155Gating(context: () => TokenGatedTestContext) {
+ describe("When gating with ERC1155 token", async () => {
+ it("Should draw no juror if they don't own the ERC1155 token", async () => {
+ const ctx = context();
+ const nbOfJurors = 15n;
+ const tx = await stakeAndDraw(
+ ctx,
+ Courts.GENERAL,
+ nbOfJurors,
+ ctx.gatedDisputeKitID,
+ ctx.nft1155.target,
+ true,
+ ctx.TOKEN_ID
+ ).then((tx) => tx.wait());
+
+ // Ensure that no juror is drawn
+ const drawLogs =
+ tx?.logs.filter((log: any) => log.fragment?.name === "Draw" && log.address === ctx.core.target) || [];
+ expect(drawLogs).to.have.length(0);
+ });
+
+ it("Should draw only the jurors owning the ERC1155 token", async () => {
+ const ctx = context();
+ await ctx.nft1155.mint(ctx.juror2.address, ctx.TOKEN_ID, 1, "0x00");
+
+ const nbOfJurors = 15n;
+ const tx = await stakeAndDraw(
+ ctx,
+ Courts.GENERAL,
+ nbOfJurors,
+ ctx.gatedDisputeKitID,
+ ctx.nft1155.target,
+ true,
+ ctx.TOKEN_ID
+ ).then((tx) => tx.wait());
+
+ // Ensure that only juror2 is drawn
+ const drawLogs =
+ tx?.logs.filter((log: any) => log.fragment?.name === "Draw" && log.address === ctx.core.target) || [];
+ expect(drawLogs).to.have.length(nbOfJurors);
+ drawLogs.forEach((log: any) => {
+ expect(log.args[0]).to.equal(ctx.juror2.address);
+ });
+
+ // Ensure that juror1 has no PNK locked
+ expect(await ctx.sortitionModule.getJurorBalance(ctx.juror1.address, Courts.GENERAL)).to.deep.equal([
+ ctx.thousandPNK(10), // totalStaked
+ 0, // totalLocked
+ ctx.thousandPNK(10), // stakedInCourt
+ 1, // nbOfCourts
+ ]);
+
+ // Ensure that juror2 has PNK locked
+ expect(await ctx.sortitionModule.getJurorBalance(ctx.juror2.address, Courts.GENERAL)).to.deep.equal([
+ ctx.thousandPNK(10), // totalStaked
+ ctx.minStake * nbOfJurors, // totalLocked
+ ctx.thousandPNK(10), // stakedInCourt
+ 1, // nbOfCourts
+ ]);
+ });
+ });
+}
+
+export function testWhitelistIntegration(context: () => TokenGatedTestContext) {
+ describe("Whitelist Integration Tests", async () => {
+ it("Should allow new disputes after whitelisting a token", async () => {
+ const ctx = context();
+ // Whitelist DAI token
+ await whitelistTokens(ctx, [ctx.dai.target], true);
+
+ // Transfer DAI to juror1 for token gating
+ await ctx.dai.transfer(ctx.juror1.address, 1);
+
+ const nbOfJurors = 3n;
+ const tx = await stakeAndDraw(
+ ctx,
+ Courts.GENERAL,
+ nbOfJurors,
+ ctx.gatedDisputeKitID,
+ ctx.dai.target,
+ false,
+ 0
+ ).then((tx) => tx.wait());
+
+ // Verify dispute was created and juror drawn
+ const drawLogs =
+ tx?.logs.filter((log: any) => log.fragment?.name === "Draw" && log.address === ctx.core.target) || [];
+ expect(drawLogs).to.have.length(nbOfJurors);
+ });
+
+ it("Should prevent new disputes after removing token from whitelist", async () => {
+ const ctx = context();
+ await whitelistTokens(ctx, [ctx.dai.target], true);
+ await ctx.dai.transfer(ctx.juror1.address, 1);
+
+ // Create first dispute (should work)
+ await expect(createDisputeWithToken(ctx, ctx.dai.target)).to.not.be.reverted;
+
+ // Remove token from whitelist
+ await whitelistTokens(ctx, [ctx.dai.target], false);
+
+ // Try to create another dispute (should fail)
+ await expect(createDisputeWithToken(ctx, ctx.dai.target))
+ .to.be.revertedWithCustomError(ctx.disputeKit, "TokenNotSupported")
+ .withArgs(ctx.dai.target);
+ });
+
+ it("Should maintain whitelist state correctly across multiple operations", async () => {
+ const ctx = context();
+ const tokens = [ctx.dai.target, ctx.nft721.target, ctx.nft1155.target];
+
+ // All tokens should already be supported from the main setup
+ for (const token of tokens) {
+ await expectTokenSupported(ctx, token, true);
+ }
+
+ // Remove middle token
+ await whitelistTokens(ctx, [ctx.nft721.target], false);
+ await expectTokenSupported(ctx, ctx.dai.target, true);
+ await expectTokenSupported(ctx, ctx.nft721.target, false);
+ await expectTokenSupported(ctx, ctx.nft1155.target, true);
+
+ // Re-add middle token
+ await whitelistTokens(ctx, [ctx.nft721.target], true);
+ for (const token of tokens) {
+ await expectTokenSupported(ctx, token, true);
+ }
+ });
+ });
+}
+
+export function testNoTokenGateAddress(context: () => TokenGatedTestContext) {
+ describe("No Token Gate Edge Case (address(0))", async () => {
+ it("Should verify that address(0) is supported by default", async () => {
+ const ctx = context();
+ await expectTokenSupported(ctx, ethers.ZeroAddress, true);
+ });
+
+ it("Should allow dispute creation with address(0) as tokenGate", async () => {
+ const ctx = context();
+ // Create dispute with address(0) as tokenGate - should not revert
+ await expect(createDisputeWithToken(ctx, ethers.ZeroAddress, false, 0)).to.not.be.reverted;
+ });
+
+ it("Should draw all staked jurors when tokenGate is address(0)", async () => {
+ const ctx = context();
+ // Neither juror has any special tokens, but both are staked
+ const nbOfJurors = 15n;
+ const tx = await stakeAndDraw(
+ ctx,
+ Courts.GENERAL,
+ nbOfJurors,
+ ctx.gatedDisputeKitID,
+ ethers.ZeroAddress,
+ false,
+ 0
+ ).then((tx) => tx.wait());
+
+ // Both jurors should be eligible for drawing since there's no token gate
+ const drawLogs =
+ tx?.logs.filter((log: any) => log.fragment?.name === "Draw" && log.address === ctx.core.target) || [];
+ expect(drawLogs.length).to.equal(nbOfJurors);
+
+ // Verify that draws include both jurors (not just one)
+ const drawnJurors = new Set(drawLogs.map((log: any) => log.args[0]));
+ expect(drawnJurors.size).to.be.greaterThan(1, "Should draw from multiple jurors");
+ });
+
+ it("Should behave like non-gated dispute kit when tokenGate is address(0)", async () => {
+ const ctx = context();
+ // Verify that with address(0), jurors don't need any token balance
+ const nbOfJurors = 3n;
+
+ // Ensure jurors have no DAI tokens
+ expect(await ctx.dai.balanceOf(ctx.juror1.address)).to.equal(0);
+ expect(await ctx.dai.balanceOf(ctx.juror2.address)).to.equal(0);
+
+ const tx = await stakeAndDraw(
+ ctx,
+ Courts.GENERAL,
+ nbOfJurors,
+ ctx.gatedDisputeKitID,
+ ethers.ZeroAddress,
+ false,
+ 0
+ ).then((tx) => tx.wait());
+
+ // Jurors should still be drawn despite having no tokens
+ const drawLogs =
+ tx?.logs.filter((log: any) => log.fragment?.name === "Draw" && log.address === ctx.core.target) || [];
+ expect(drawLogs).to.have.length(nbOfJurors);
+ });
+
+ it("Should parse address(0) correctly from insufficient extraData", async () => {
+ const ctx = context();
+ // Create extraData that's too short (less than 160 bytes)
+ // This should return address(0) from _extraDataToTokenInfo
+ const shortExtraData = ethers.AbiCoder.defaultAbiCoder().encode(
+ ["uint256", "uint256", "uint256"],
+ [Courts.GENERAL, 3, ctx.gatedDisputeKitID]
+ );
+
+ const tokenInfo = await ctx.disputeKit.extraDataToTokenInfo(shortExtraData);
+ expect(tokenInfo[0]).to.equal(ethers.ZeroAddress);
+ expect(tokenInfo[1]).to.equal(false);
+ expect(tokenInfo[2]).to.equal(0);
+ });
+ });
+}
diff --git a/contracts/test/arbitration/helpers/dispute-kit-shutter-common.ts b/contracts/test/arbitration/helpers/dispute-kit-shutter-common.ts
new file mode 100644
index 000000000..699968f9c
--- /dev/null
+++ b/contracts/test/arbitration/helpers/dispute-kit-shutter-common.ts
@@ -0,0 +1,852 @@
+import { deployments, ethers, getNamedAccounts, network } from "hardhat";
+import { toBigInt, BigNumberish } from "ethers";
+import {
+ PNK,
+ KlerosCore,
+ SortitionModule,
+ IncrementalNG,
+ DisputeKitShutter,
+ DisputeKitGatedShutterMock,
+ TestERC20,
+} from "../../../typechain-types";
+import { expect } from "chai";
+import { Courts } from "../../../deploy/utils";
+import { HardhatEthersSigner } from "@nomicfoundation/hardhat-ethers/signers";
+import { deployUpgradable } from "../../../deploy/utils/deployUpgradable";
+import { encodeExtraData as encodeGatedExtraData } from "./dispute-kit-gated-common";
+
+/* eslint-disable no-unused-vars */
+/* eslint-disable no-unused-expressions */
+
+// Type for the dispute kit (either DisputeKitShutter or DisputeKitGatedShutter)
+export type DisputeKitShutterType = DisputeKitShutter | DisputeKitGatedShutterMock;
+
+// Test context interface that holds all the test state
+export interface ShutterTestContext {
+ deployer: string;
+ juror1: HardhatEthersSigner;
+ juror2: HardhatEthersSigner;
+ bot: HardhatEthersSigner;
+ attacker: HardhatEthersSigner;
+ disputeKit: DisputeKitShutterType;
+ pnk: PNK;
+ core: KlerosCore;
+ sortitionModule: SortitionModule;
+ rng: IncrementalNG;
+ shutterDKID: number;
+ shutterCourtID: number;
+ RANDOM: bigint;
+ ONE_THOUSAND_PNK: bigint;
+ thousandPNK: (amount: BigNumberish) => bigint;
+ // Shutter test data
+ choice: bigint;
+ salt: bigint;
+ justification: string;
+ identity: string;
+ encryptedVote: Uint8Array;
+ // Token gating support (optional)
+ dai?: TestERC20;
+ isGated?: boolean;
+}
+
+// Configuration for setting up a Shutter test
+export interface ShutterTestConfig {
+ contractName: string; // "DisputeKitShutter" or "DisputeKitGatedShutter"
+ isGated?: boolean; // Whether to setup token gating
+}
+
+// Constants
+export const enum Period {
+ evidence = 0,
+ commit = 1,
+ vote = 2,
+ appeal = 3,
+ execution = 4,
+}
+
+const ONE_THOUSAND_PNK = 10n ** 21n;
+const thousandPNK = (amount: BigNumberish) => toBigInt(amount) * ONE_THOUSAND_PNK;
+
+// Helper function to encode extra data for dispute creation
+export const encodeExtraData = (courtId: BigNumberish, minJurors: BigNumberish, disputeKitId: number) =>
+ ethers.AbiCoder.defaultAbiCoder().encode(["uint256", "uint256", "uint256"], [courtId, minJurors, disputeKitId]);
+
+// Helper function to generate choice and justification commitments
+export const generateCommitments = (choice: bigint, salt: bigint, justification: string) => {
+ // Choice commitment: hash(choice, salt)
+ const justificationHash = ethers.keccak256(ethers.toUtf8Bytes(justification));
+ // Justification commitment: hash(salt, justificationHash)
+ const justificationCommit = ethers.keccak256(
+ ethers.AbiCoder.defaultAbiCoder().encode(["uint256", "bytes32"], [salt, justificationHash])
+ );
+
+ const choiceCommit = ethers.keccak256(
+ ethers.AbiCoder.defaultAbiCoder().encode(["uint256", "uint256"], [choice, salt])
+ );
+
+ return { choiceCommit, justificationCommit };
+};
+
+// Helper to create dispute and draw jurors
+export const createDisputeAndDraw = async (
+ context: ShutterTestContext,
+ courtId: BigNumberish,
+ minJurors: BigNumberish,
+ disputeKitId: number
+) => {
+ // Stake jurors
+ for (const juror of [context.juror1, context.juror2]) {
+ await context.pnk.transfer(juror.address, context.thousandPNK(10)).then((tx) => tx.wait());
+ expect(await context.pnk.balanceOf(juror.address)).to.equal(context.thousandPNK(10));
+
+ await context.pnk
+ .connect(juror)
+ .approve(context.core.target, context.thousandPNK(10), { gasLimit: 300000 })
+ .then((tx) => tx.wait());
+
+ await context.core
+ .connect(juror)
+ .setStake(context.shutterCourtID, context.thousandPNK(10), { gasLimit: 500000 })
+ .then((tx) => tx.wait());
+
+ expect(await context.sortitionModule.getJurorBalance(juror.address, context.shutterCourtID)).to.deep.equal([
+ context.thousandPNK(10), // totalStaked
+ 0, // totalLocked
+ context.thousandPNK(10), // stakedInCourt
+ 1, // nbOfCourts
+ ]);
+
+ // If gated, give tokens to jurors
+ if (context.isGated && context.dai) {
+ await context.dai.transfer(juror.address, 1);
+ }
+ }
+
+ // Use gated extra data if this is a gated dispute kit with DAI token
+ let extraData: string;
+ if (context.isGated && context.dai) {
+ extraData = encodeGatedExtraData(courtId, minJurors, disputeKitId, context.dai.target, false, 0);
+ } else {
+ extraData = encodeExtraData(courtId, minJurors, disputeKitId);
+ }
+
+ const arbitrationCost = await context.core["arbitrationCost(bytes)"](extraData);
+
+ // Create dispute via core contract
+ await context.core["createDispute(uint256,bytes)"](2, extraData, { value: arbitrationCost }).then((tx) => tx.wait());
+ const disputeId = 0;
+
+ await network.provider.send("evm_increaseTime", [2000]); // Wait for minStakingTime
+ await network.provider.send("evm_mine");
+ await context.sortitionModule.passPhase().then((tx) => tx.wait()); // Staking -> Generating
+
+ await context.sortitionModule.passPhase().then((tx) => tx.wait()); // Generating -> Drawing
+ await context.core.draw(disputeId, 70, { gasLimit: 10000000 });
+
+ return disputeId;
+};
+
+// Helper to advance to commit period
+export const advanceToCommitPeriod = async (context: ShutterTestContext, disputeId: number) => {
+ // Advance from evidence to commit period
+ await context.core.passPeriod(disputeId).then((tx) => tx.wait());
+
+ // Verify we're in commit period
+ const dispute = await context.core.disputes(disputeId);
+ expect(dispute[2]).to.equal(Period.commit); // period is at index 2
+};
+
+// Helper to advance to vote period
+export const advanceToVotePeriod = async (context: ShutterTestContext, disputeId: number) => {
+ // Advance from commit to vote period
+ const timesPerPeriod = [300, 300, 300, 300]; // Default times from deployment
+ const commitPeriod = timesPerPeriod[Period.commit];
+
+ await network.provider.send("evm_increaseTime", [Number(commitPeriod)]);
+ await network.provider.send("evm_mine");
+
+ await context.core.passPeriod(disputeId).then((tx) => tx.wait());
+
+ // Verify we're in vote period
+ const updatedDispute = await context.core.disputes(disputeId);
+ expect(updatedDispute[2]).to.equal(Period.vote); // period is at index 2
+};
+
+// Helper to get vote IDs for a juror
+export const getVoteIDsForJuror = async (
+ context: ShutterTestContext,
+ disputeId: number,
+ juror: HardhatEthersSigner
+) => {
+ const localDisputeId = await context.disputeKit.coreDisputeIDToLocal(disputeId);
+ const nbRounds = await context.disputeKit.getNumberOfRounds(localDisputeId);
+ const roundIndex = Number(nbRounds) - 1;
+
+ // Get all votes for this round and filter by juror
+ const voteIDs: bigint[] = [];
+ const maxVotes = 10; // Reasonable limit for testing
+
+ for (let i = 0; i < maxVotes; i++) {
+ try {
+ const voteInfo = await context.disputeKit.getVoteInfo(disputeId, roundIndex, i);
+ if (voteInfo[0] === juror.address) {
+ // account is at index 0
+ voteIDs.push(BigInt(i));
+ }
+ } catch {
+ // No more votes
+ break;
+ }
+ }
+
+ return voteIDs;
+};
+
+// Setup function that creates the test context
+export async function setupShutterTest(config: ShutterTestConfig): Promise {
+ const { deployer } = await getNamedAccounts();
+ const [, juror1, juror2, bot, attacker] = await ethers.getSigners();
+
+ await deployments.fixture(["Arbitration", "VeaMock"], {
+ fallbackToGlobal: true,
+ keepExistingDeployments: false,
+ });
+
+ const pnk = await ethers.getContract("PNK");
+ const core = await ethers.getContract("KlerosCore");
+ const sortitionModule = await ethers.getContract("SortitionModule");
+
+ let disputeKit: DisputeKitShutterType;
+ let shutterDKID: number;
+ let shutterCourtID: number;
+ let dai: TestERC20 | undefined;
+
+ if (config.contractName === "DisputeKitShutter") {
+ disputeKit = await ethers.getContract("DisputeKitShutter");
+ shutterDKID = 2;
+ shutterCourtID = 2; // Court with hidden votes
+
+ // Create a court with hidden votes enabled for testing DisputeKitShutter
+ await core.createCourt(
+ Courts.GENERAL, // parent
+ true, // hiddenVotes - MUST be true for DisputeKitShutter
+ ethers.parseEther("200"), // minStake
+ 10000, // alpha
+ ethers.parseEther("0.1"), // feeForJuror
+ 16, // jurorsForCourtJump
+ [300, 300, 300, 300], // timesPerPeriod for evidence, commit, vote, appeal
+ ethers.toBeHex(5), // sortitionExtraData
+ [1, shutterDKID] // supportedDisputeKits - must include Classic (1) and Shutter (2)
+ );
+ } else if (config.contractName === "DisputeKitGatedShutter") {
+ // For gated shutter, we need to deploy it if not already deployed
+ const weth = await ethers.getContract("WETH");
+ dai = await ethers.getContract("DAI");
+
+ const deploymentResult = await deployUpgradable(deployments, "DisputeKitGatedShutterMock", {
+ from: deployer,
+ proxyAlias: "UUPSProxy",
+ args: [deployer, core.target, weth.target, 1],
+ log: true,
+ });
+ await core.addNewDisputeKit(deploymentResult.address);
+ shutterDKID = Number((await core.getDisputeKitsLength()) - 1n);
+
+ // For gated shutter, we use the General Court but with hidden votes enabled
+ shutterCourtID = Courts.GENERAL;
+
+ // Enable hidden votes on the General Court
+ await core.changeCourtParameters(
+ Courts.GENERAL,
+ true, // hiddenVotes
+ ethers.parseEther("200"), // minStake
+ 10000, // alpha
+ ethers.parseEther("0.1"), // feeForJuror
+ 16, // jurorsForCourtJump
+ [300, 300, 300, 300] // timesPerPeriod
+ );
+
+ await core.enableDisputeKits(Courts.GENERAL, [shutterDKID], true);
+
+ disputeKit = await ethers.getContract("DisputeKitGatedShutterMock");
+
+ // If gated, whitelist DAI token
+ if (config.isGated) {
+ const gatedKit = disputeKit as DisputeKitGatedShutterMock;
+ await gatedKit.changeSupportedTokens([dai.target], true);
+ }
+ } else {
+ throw new Error(`Unknown contract name: ${config.contractName}`);
+ }
+
+ // Make the tests more deterministic with this dummy RNG
+ const RANDOM = 424242n;
+ await deployments.deploy("IncrementalNG", {
+ from: deployer,
+ args: [RANDOM],
+ log: true,
+ });
+ const rng = await ethers.getContract("IncrementalNG");
+ await sortitionModule.changeRandomNumberGenerator(rng.target).then((tx) => tx.wait());
+
+ // Test data
+ const choice = 1n;
+ const salt = 12345n;
+ const justification = "This is my justification for the vote";
+ const identity = ethers.keccak256(ethers.toUtf8Bytes("shutter-identity"));
+ const encryptedVote = ethers.toUtf8Bytes("encrypted-vote-data");
+
+ const context: ShutterTestContext = {
+ deployer,
+ juror1,
+ juror2,
+ bot,
+ attacker,
+ disputeKit,
+ pnk,
+ core,
+ sortitionModule,
+ rng,
+ shutterDKID,
+ shutterCourtID,
+ RANDOM,
+ ONE_THOUSAND_PNK,
+ thousandPNK,
+ choice,
+ salt,
+ justification,
+ identity,
+ encryptedVote,
+ dai,
+ isGated: config.isGated,
+ };
+
+ return context;
+}
+
+// Test suites as functions that accept context
+
+export function testCommitPhase(context: () => ShutterTestContext) {
+ describe("Commit Phase - castCommitShutter()", () => {
+ describe("Successful commits", () => {
+ it("Should allow juror to commit vote with justification commitment", async () => {
+ const ctx = context();
+ const disputeId = await createDisputeAndDraw(ctx, ctx.shutterCourtID, 3, ctx.shutterDKID);
+ await advanceToCommitPeriod(ctx, disputeId);
+
+ const voteIDs = await getVoteIDsForJuror(ctx, disputeId, ctx.juror1);
+ expect(voteIDs.length).to.be.greaterThan(0);
+
+ const { choiceCommit, justificationCommit } = generateCommitments(ctx.choice, ctx.salt, ctx.justification);
+
+ await expect(
+ ctx.disputeKit
+ .connect(ctx.juror1)
+ .castCommitShutter(disputeId, voteIDs, choiceCommit, justificationCommit, ctx.identity, ctx.encryptedVote)
+ )
+ .to.emit(ctx.disputeKit, "CommitCastShutter")
+ .withArgs(disputeId, ctx.juror1.address, choiceCommit, justificationCommit, ctx.identity, ctx.encryptedVote);
+
+ // Verify recovery commitment was stored
+ const localDisputeId = await ctx.disputeKit.coreDisputeIDToLocal(disputeId);
+ const storedRecoveryCommit = await ctx.disputeKit.justificationCommitments(localDisputeId, 0, voteIDs[0]);
+ expect(storedRecoveryCommit).to.equal(justificationCommit);
+ });
+
+ it("Should allow juror to update commitment multiple times", async () => {
+ const ctx = context();
+ const disputeId = await createDisputeAndDraw(ctx, ctx.shutterCourtID, 3, ctx.shutterDKID);
+ await advanceToCommitPeriod(ctx, disputeId);
+
+ const voteIDs = await getVoteIDsForJuror(ctx, disputeId, ctx.juror1);
+
+ // First commitment
+ const { choiceCommit: commit1, justificationCommit: justification1 } = generateCommitments(
+ 1n,
+ 111n,
+ "First justification"
+ );
+ await ctx.disputeKit
+ .connect(ctx.juror1)
+ .castCommitShutter(disputeId, voteIDs, commit1, justification1, ctx.identity, ctx.encryptedVote);
+
+ // Second commitment (overwrites first)
+ const { choiceCommit: commit2, justificationCommit: justification2 } = generateCommitments(
+ 2n,
+ 222n,
+ "Second justification"
+ );
+ await ctx.disputeKit
+ .connect(ctx.juror1)
+ .castCommitShutter(disputeId, voteIDs, commit2, justification2, ctx.identity, ctx.encryptedVote);
+
+ // Verify only the second commitment is stored
+ const localDisputeId = await ctx.disputeKit.coreDisputeIDToLocal(disputeId);
+ const storedRecoveryCommit = await ctx.disputeKit.justificationCommitments(localDisputeId, 0, voteIDs[0]);
+ expect(storedRecoveryCommit).to.equal(justification2);
+ });
+ });
+
+ describe("Failed commits", () => {
+ it("Should revert if justification commitment is empty", async () => {
+ const ctx = context();
+ const disputeId = await createDisputeAndDraw(ctx, ctx.shutterCourtID, 3, ctx.shutterDKID);
+ await advanceToCommitPeriod(ctx, disputeId);
+
+ const voteIDs = await getVoteIDsForJuror(ctx, disputeId, ctx.juror1);
+ const { choiceCommit } = generateCommitments(ctx.choice, ctx.salt, ctx.justification);
+
+ await expect(
+ ctx.disputeKit.connect(ctx.juror1).castCommitShutter(
+ disputeId,
+ voteIDs,
+ choiceCommit,
+ ethers.ZeroHash, // Empty justification commit
+ ctx.identity,
+ ctx.encryptedVote
+ )
+ ).to.be.revertedWithCustomError(ctx.disputeKit, "EmptyJustificationCommit");
+ });
+
+ it("Should revert if not in commit period", async () => {
+ const ctx = context();
+ const disputeId = await createDisputeAndDraw(ctx, ctx.shutterCourtID, 3, ctx.shutterDKID);
+ // Still in evidence period
+
+ const voteIDs = await getVoteIDsForJuror(ctx, disputeId, ctx.juror1);
+ const { choiceCommit, justificationCommit } = generateCommitments(ctx.choice, ctx.salt, ctx.justification);
+
+ await expect(
+ ctx.disputeKit
+ .connect(ctx.juror1)
+ .castCommitShutter(disputeId, voteIDs, choiceCommit, justificationCommit, ctx.identity, ctx.encryptedVote)
+ ).to.be.revertedWithCustomError(ctx.disputeKit, "NotCommitPeriod");
+ });
+
+ it("Should revert if juror doesn't own the vote", async () => {
+ const ctx = context();
+ const disputeId = await createDisputeAndDraw(ctx, ctx.shutterCourtID, 3, ctx.shutterDKID);
+ await advanceToCommitPeriod(ctx, disputeId);
+
+ const voteIDs = await getVoteIDsForJuror(ctx, disputeId, ctx.juror1);
+ const { choiceCommit, justificationCommit } = generateCommitments(ctx.choice, ctx.salt, ctx.justification);
+
+ await expect(
+ ctx.disputeKit.connect(ctx.juror2).castCommitShutter(
+ disputeId,
+ voteIDs, // Using juror1's vote IDs
+ choiceCommit,
+ justificationCommit,
+ ctx.identity,
+ ctx.encryptedVote
+ )
+ ).to.be.revertedWithCustomError(ctx.disputeKit, "JurorHasToOwnTheVote");
+ });
+ });
+ });
+}
+
+export function testNormalFlowBotReveals(context: () => ShutterTestContext) {
+ describe("Normal Flow - Bot Reveals", () => {
+ describe("Successful reveals", () => {
+ it("Should allow bot to reveal vote with full justification", async () => {
+ const ctx = context();
+ const disputeId = await createDisputeAndDraw(ctx, ctx.shutterCourtID, 3, ctx.shutterDKID);
+ await advanceToCommitPeriod(ctx, disputeId);
+
+ const voteIDs = await getVoteIDsForJuror(ctx, disputeId, ctx.juror1);
+ const { choiceCommit, justificationCommit } = generateCommitments(ctx.choice, ctx.salt, ctx.justification);
+
+ // Juror commits
+ await ctx.disputeKit
+ .connect(ctx.juror1)
+ .castCommitShutter(disputeId, voteIDs, choiceCommit, justificationCommit, ctx.identity, ctx.encryptedVote);
+
+ await advanceToVotePeriod(ctx, disputeId);
+
+ // Bot reveals vote
+ await expect(
+ ctx.disputeKit.connect(ctx.bot).castVoteShutter(disputeId, voteIDs, ctx.choice, ctx.salt, ctx.justification)
+ )
+ .to.emit(ctx.disputeKit, "VoteCast")
+ .withArgs(disputeId, ctx.juror1.address, voteIDs, ctx.choice, ctx.justification);
+
+ // Verify vote was counted
+ const voteInfo = await ctx.disputeKit.getVoteInfo(disputeId, 0, Number(voteIDs[0]));
+ expect(voteInfo[3]).to.be.true; // voted is at index 3
+ expect(voteInfo[2]).to.equal(ctx.choice); // choice is at index 2
+ });
+ });
+
+ describe("Failed reveals", () => {
+ it("Should revert if wrong choice provided", async () => {
+ const ctx = context();
+ const disputeId = await createDisputeAndDraw(ctx, ctx.shutterCourtID, 3, ctx.shutterDKID);
+ await advanceToCommitPeriod(ctx, disputeId);
+
+ const voteIDs = await getVoteIDsForJuror(ctx, disputeId, ctx.juror1);
+ const { choiceCommit, justificationCommit } = generateCommitments(ctx.choice, ctx.salt, ctx.justification);
+
+ await ctx.disputeKit
+ .connect(ctx.juror1)
+ .castCommitShutter(disputeId, voteIDs, choiceCommit, justificationCommit, ctx.identity, ctx.encryptedVote);
+
+ await advanceToVotePeriod(ctx, disputeId);
+
+ const wrongChoice = 2n;
+ await expect(
+ ctx.disputeKit.connect(ctx.bot).castVoteShutter(
+ disputeId,
+ voteIDs,
+ wrongChoice, // Wrong choice
+ ctx.salt,
+ ctx.justification
+ )
+ ).to.be.revertedWithCustomError(ctx.disputeKit, "ChoiceCommitmentMismatch");
+ });
+
+ it("Should revert if wrong salt provided", async () => {
+ const ctx = context();
+ const disputeId = await createDisputeAndDraw(ctx, ctx.shutterCourtID, 3, ctx.shutterDKID);
+ await advanceToCommitPeriod(ctx, disputeId);
+
+ const voteIDs = await getVoteIDsForJuror(ctx, disputeId, ctx.juror1);
+ const { choiceCommit, justificationCommit } = generateCommitments(ctx.choice, ctx.salt, ctx.justification);
+
+ await ctx.disputeKit
+ .connect(ctx.juror1)
+ .castCommitShutter(disputeId, voteIDs, choiceCommit, justificationCommit, ctx.identity, ctx.encryptedVote);
+
+ await advanceToVotePeriod(ctx, disputeId);
+
+ const wrongSalt = 99999n;
+ await expect(
+ ctx.disputeKit.connect(ctx.bot).castVoteShutter(
+ disputeId,
+ voteIDs,
+ ctx.choice,
+ wrongSalt, // Wrong salt
+ ctx.justification
+ )
+ ).to.be.revertedWithCustomError(ctx.disputeKit, "ChoiceCommitmentMismatch");
+ });
+
+ it("Should revert if wrong justification provided", async () => {
+ const ctx = context();
+ const disputeId = await createDisputeAndDraw(ctx, ctx.shutterCourtID, 3, ctx.shutterDKID);
+ await advanceToCommitPeriod(ctx, disputeId);
+
+ const voteIDs = await getVoteIDsForJuror(ctx, disputeId, ctx.juror1);
+ const { choiceCommit, justificationCommit } = generateCommitments(ctx.choice, ctx.salt, ctx.justification);
+
+ await ctx.disputeKit
+ .connect(ctx.juror1)
+ .castCommitShutter(disputeId, voteIDs, choiceCommit, justificationCommit, ctx.identity, ctx.encryptedVote);
+
+ await advanceToVotePeriod(ctx, disputeId);
+
+ const wrongJustification = "Wrong justification";
+ await expect(
+ ctx.disputeKit.connect(ctx.bot).castVoteShutter(
+ disputeId,
+ voteIDs,
+ ctx.choice,
+ ctx.salt,
+ wrongJustification // Wrong justification
+ )
+ ).to.be.revertedWithCustomError(ctx.disputeKit, "JustificationCommitmentMismatch");
+ });
+
+ it("Should revert if vote already cast", async () => {
+ const ctx = context();
+ const disputeId = await createDisputeAndDraw(ctx, ctx.shutterCourtID, 3, ctx.shutterDKID);
+ await advanceToCommitPeriod(ctx, disputeId);
+
+ const voteIDs = await getVoteIDsForJuror(ctx, disputeId, ctx.juror1);
+ const { choiceCommit, justificationCommit } = generateCommitments(ctx.choice, ctx.salt, ctx.justification);
+
+ await ctx.disputeKit
+ .connect(ctx.juror1)
+ .castCommitShutter(disputeId, voteIDs, choiceCommit, justificationCommit, ctx.identity, ctx.encryptedVote);
+
+ await advanceToVotePeriod(ctx, disputeId);
+
+ // First vote succeeds
+ await ctx.disputeKit
+ .connect(ctx.bot)
+ .castVoteShutter(disputeId, voteIDs, ctx.choice, ctx.salt, ctx.justification);
+
+ // Second vote fails
+ await expect(
+ ctx.disputeKit.connect(ctx.bot).castVoteShutter(disputeId, voteIDs, ctx.choice, ctx.salt, ctx.justification)
+ ).to.be.revertedWithCustomError(ctx.disputeKit, "VoteAlreadyCast");
+ });
+ });
+ });
+}
+
+export function testRecoveryFlowJurorReveals(context: () => ShutterTestContext) {
+ describe("Recovery Flow - Juror Reveals", () => {
+ describe("Successful justification reveals", () => {
+ it("Should allow juror to recover vote without justification", async () => {
+ const ctx = context();
+ const disputeId = await createDisputeAndDraw(ctx, ctx.shutterCourtID, 3, ctx.shutterDKID);
+ await advanceToCommitPeriod(ctx, disputeId);
+
+ const voteIDs = await getVoteIDsForJuror(ctx, disputeId, ctx.juror1);
+ const { choiceCommit, justificationCommit } = generateCommitments(ctx.choice, ctx.salt, ctx.justification);
+
+ // Juror commits
+ await ctx.disputeKit
+ .connect(ctx.juror1)
+ .castCommitShutter(disputeId, voteIDs, choiceCommit, justificationCommit, ctx.identity, ctx.encryptedVote);
+
+ await advanceToVotePeriod(ctx, disputeId);
+
+ // Juror reveals vote (Shutter failed, so juror must reveal)
+ // Note: justification can be anything as it won't be validated
+ await expect(
+ ctx.disputeKit.connect(ctx.juror1).castVoteShutter(
+ disputeId,
+ voteIDs,
+ ctx.choice,
+ ctx.salt,
+ "" // Empty justification is fine for recovery
+ )
+ )
+ .to.emit(ctx.disputeKit, "VoteCast")
+ .withArgs(disputeId, ctx.juror1.address, voteIDs, ctx.choice, "");
+
+ // Verify vote was counted
+ const voteInfo = await ctx.disputeKit.getVoteInfo(disputeId, 0, Number(voteIDs[0]));
+ expect(voteInfo[3]).to.be.true; // voted is at index 3
+ expect(voteInfo[2]).to.equal(ctx.choice); // choice is at index 2
+ });
+
+ it("Should validate against justification commitment when juror reveals", async () => {
+ const ctx = context();
+ const disputeId = await createDisputeAndDraw(ctx, ctx.shutterCourtID, 3, ctx.shutterDKID);
+ await advanceToCommitPeriod(ctx, disputeId);
+
+ const voteIDs = await getVoteIDsForJuror(ctx, disputeId, ctx.juror1);
+ const { choiceCommit, justificationCommit } = generateCommitments(ctx.choice, ctx.salt, ctx.justification);
+
+ await ctx.disputeKit
+ .connect(ctx.juror1)
+ .castCommitShutter(disputeId, voteIDs, choiceCommit, justificationCommit, ctx.identity, ctx.encryptedVote);
+
+ await advanceToVotePeriod(ctx, disputeId);
+
+ // Juror can provide any justification - it won't be validated
+ const differentJustification = "This is a different justification that won't be checked";
+ await expect(
+ ctx.disputeKit.connect(ctx.juror1).castVoteShutter(
+ disputeId,
+ voteIDs,
+ ctx.choice,
+ ctx.salt,
+ differentJustification // Different justification is OK for recovery
+ )
+ ).to.not.be.reverted;
+ });
+ });
+
+ describe("Failed recovery reveals", () => {
+ it("Should revert if wrong choice in recovery", async () => {
+ const ctx = context();
+ const disputeId = await createDisputeAndDraw(ctx, ctx.shutterCourtID, 3, ctx.shutterDKID);
+ await advanceToCommitPeriod(ctx, disputeId);
+
+ const voteIDs = await getVoteIDsForJuror(ctx, disputeId, ctx.juror1);
+ const { choiceCommit, justificationCommit } = generateCommitments(ctx.choice, ctx.salt, ctx.justification);
+
+ await ctx.disputeKit
+ .connect(ctx.juror1)
+ .castCommitShutter(disputeId, voteIDs, choiceCommit, justificationCommit, ctx.identity, ctx.encryptedVote);
+
+ await advanceToVotePeriod(ctx, disputeId);
+
+ const wrongChoice = 2n;
+ await expect(
+ ctx.disputeKit.connect(ctx.juror1).castVoteShutter(
+ disputeId,
+ voteIDs,
+ wrongChoice, // Wrong choice
+ ctx.salt,
+ ""
+ )
+ ).to.be.revertedWithCustomError(ctx.disputeKit, "ChoiceCommitmentMismatch");
+ });
+
+ it("Should revert if wrong salt in recovery", async () => {
+ const ctx = context();
+ const disputeId = await createDisputeAndDraw(ctx, ctx.shutterCourtID, 3, ctx.shutterDKID);
+ await advanceToCommitPeriod(ctx, disputeId);
+
+ const voteIDs = await getVoteIDsForJuror(ctx, disputeId, ctx.juror1);
+ const { choiceCommit, justificationCommit } = generateCommitments(ctx.choice, ctx.salt, ctx.justification);
+
+ await ctx.disputeKit
+ .connect(ctx.juror1)
+ .castCommitShutter(disputeId, voteIDs, choiceCommit, justificationCommit, ctx.identity, ctx.encryptedVote);
+
+ await advanceToVotePeriod(ctx, disputeId);
+
+ const wrongSalt = 99999n;
+ await expect(
+ ctx.disputeKit.connect(ctx.juror1).castVoteShutter(
+ disputeId,
+ voteIDs,
+ ctx.choice,
+ wrongSalt, // Wrong salt
+ ""
+ )
+ ).to.be.revertedWithCustomError(ctx.disputeKit, "ChoiceCommitmentMismatch");
+ });
+
+ it("Should revert if non-juror tries to reveal without correct full commitment", async () => {
+ const ctx = context();
+ const disputeId = await createDisputeAndDraw(ctx, ctx.shutterCourtID, 3, ctx.shutterDKID);
+ await advanceToCommitPeriod(ctx, disputeId);
+
+ const voteIDs = await getVoteIDsForJuror(ctx, disputeId, ctx.juror1);
+ const { choiceCommit, justificationCommit } = generateCommitments(ctx.choice, ctx.salt, ctx.justification);
+
+ await ctx.disputeKit
+ .connect(ctx.juror1)
+ .castCommitShutter(disputeId, voteIDs, choiceCommit, justificationCommit, ctx.identity, ctx.encryptedVote);
+
+ await advanceToVotePeriod(ctx, disputeId);
+
+ // Attacker tries to reveal with only choice and salt (no justification)
+ await expect(
+ ctx.disputeKit.connect(ctx.attacker).castVoteShutter(
+ disputeId,
+ voteIDs,
+ ctx.choice,
+ ctx.salt,
+ "" // No justification - would work for juror but not for others
+ )
+ ).to.be.revertedWithCustomError(ctx.disputeKit, "JustificationCommitmentMismatch");
+ });
+ });
+ });
+}
+
+export function testEdgeCasesAndSecurity(context: () => ShutterTestContext) {
+ describe("Edge Cases and Security", () => {
+ it("Should handle mixed normal and recovery reveals in same dispute", async () => {
+ const ctx = context();
+ const disputeId = await createDisputeAndDraw(ctx, ctx.shutterCourtID, 3, ctx.shutterDKID);
+ await advanceToCommitPeriod(ctx, disputeId);
+
+ const voteIDsJuror1 = await getVoteIDsForJuror(ctx, disputeId, ctx.juror1);
+ const voteIDsJuror2 = await getVoteIDsForJuror(ctx, disputeId, ctx.juror2);
+
+ const { choiceCommit: commit1, justificationCommit: justification1 } = generateCommitments(
+ 1n,
+ 111n,
+ "Juror 1 justification"
+ );
+ const { choiceCommit: commit2, justificationCommit: justification2 } = generateCommitments(
+ 2n,
+ 222n,
+ "Juror 2 justification"
+ );
+
+ // Both jurors commit
+ await ctx.disputeKit
+ .connect(ctx.juror1)
+ .castCommitShutter(disputeId, voteIDsJuror1, commit1, justification1, ctx.identity, ctx.encryptedVote);
+
+ await ctx.disputeKit
+ .connect(ctx.juror2)
+ .castCommitShutter(disputeId, voteIDsJuror2, commit2, justification2, ctx.identity, ctx.encryptedVote);
+
+ await advanceToVotePeriod(ctx, disputeId);
+
+ // Juror1 uses recovery flow (Shutter failed for them)
+ await ctx.disputeKit.connect(ctx.juror1).castVoteShutter(
+ disputeId,
+ voteIDsJuror1,
+ 1n,
+ 111n,
+ "Different justification" // Recovery doesn't check this
+ );
+
+ // Bot reveals juror2's vote normally
+ await ctx.disputeKit.connect(ctx.bot).castVoteShutter(
+ disputeId,
+ voteIDsJuror2,
+ 2n,
+ 222n,
+ "Juror 2 justification" // Must match exactly
+ );
+
+ // Verify both votes were counted
+ const vote1Info = await ctx.disputeKit.getVoteInfo(disputeId, 0, Number(voteIDsJuror1[0]));
+ const vote2Info = await ctx.disputeKit.getVoteInfo(disputeId, 0, Number(voteIDsJuror2[0]));
+
+ expect(vote1Info[3]).to.be.true; // voted is at index 3
+ expect(vote1Info[2]).to.equal(1n); // choice is at index 2
+ expect(vote2Info[3]).to.be.true;
+ expect(vote2Info[2]).to.equal(2n);
+ });
+
+ it("Should allow anyone to reveal vote with correct data only", async () => {
+ const ctx = context();
+ const disputeId = await createDisputeAndDraw(ctx, ctx.shutterCourtID, 3, ctx.shutterDKID);
+ await advanceToCommitPeriod(ctx, disputeId);
+
+ const voteIDsJuror1 = await getVoteIDsForJuror(ctx, disputeId, ctx.juror1);
+ const { choiceCommit, justificationCommit } = generateCommitments(ctx.choice, ctx.salt, ctx.justification);
+
+ await ctx.disputeKit
+ .connect(ctx.juror1)
+ .castCommitShutter(
+ disputeId,
+ voteIDsJuror1,
+ choiceCommit,
+ justificationCommit,
+ ctx.identity,
+ ctx.encryptedVote
+ );
+
+ // Juror2 commits with a different choice
+ const differentChoice = 2n;
+ const voteIDsJuror2 = await getVoteIDsForJuror(ctx, disputeId, ctx.juror2);
+ const { choiceCommit: commit2, justificationCommit: justification2 } = generateCommitments(
+ differentChoice,
+ ctx.salt,
+ ctx.justification
+ );
+
+ await ctx.disputeKit
+ .connect(ctx.juror2)
+ .castCommitShutter(disputeId, voteIDsJuror2, commit2, justification2, ctx.identity, ctx.encryptedVote);
+
+ await advanceToVotePeriod(ctx, disputeId);
+
+ // In normal Shutter operation, anyone (bot/attacker) can reveal the vote if they have the correct data
+ // This is by design - the security comes from the fact that only Shutter knows the decryption key
+ await expect(
+ ctx.disputeKit
+ .connect(ctx.attacker)
+ .castVoteShutter(disputeId, voteIDsJuror1, ctx.choice, ctx.salt, ctx.justification)
+ )
+ .to.emit(ctx.disputeKit, "VoteCast")
+ .withArgs(disputeId, ctx.juror1.address, voteIDsJuror1, ctx.choice, ctx.justification);
+
+ // Attacker cannot change juror2's vote to a different choice
+ await expect(
+ ctx.disputeKit.connect(ctx.attacker).castVoteShutter(
+ disputeId,
+ voteIDsJuror2,
+ 1n, // Wrong choice
+ ctx.salt,
+ ctx.justification
+ )
+ ).to.be.revertedWithCustomError(ctx.disputeKit, "ChoiceCommitmentMismatch");
+ });
+ });
+}
diff --git a/contracts/test/arbitration/index.ts b/contracts/test/arbitration/index.ts
index d8e7ef089..be13e1e0c 100644
--- a/contracts/test/arbitration/index.ts
+++ b/contracts/test/arbitration/index.ts
@@ -73,9 +73,9 @@ describe("DisputeKitClassic", async () => {
});
it("Should create a dispute", async () => {
- await expect(disputeKit.connect(deployer).createDispute(0, 0, ethers.toBeHex(3), "0x00")).to.be.revertedWith(
- "Access not allowed: KlerosCore only."
- );
+ await expect(
+ disputeKit.connect(deployer).createDispute(0, 0, 0, ethers.toBeHex(3), "0x00")
+ ).to.be.revertedWithCustomError(disputeKit, "KlerosCoreOnly");
const tx = await core
.connect(deployer)
@@ -100,10 +100,10 @@ async function deployContracts(): Promise<
fallbackToGlobal: true,
keepExistingDeployments: false,
});
- const disputeKit = (await ethers.getContract("DisputeKitClassic")) as DisputeKitClassic;
- const disputeKitShutter = (await ethers.getContract("DisputeKitShutter")) as DisputeKitShutter;
- const disputeKitGated = (await ethers.getContract("DisputeKitGated")) as DisputeKitGated;
- const disputeKitGatedShutter = (await ethers.getContract("DisputeKitGatedShutter")) as DisputeKitGatedShutter;
- const core = (await ethers.getContract("KlerosCore")) as KlerosCore;
+ const disputeKit = await ethers.getContract("DisputeKitClassic");
+ const disputeKitShutter = await ethers.getContract("DisputeKitShutter");
+ const disputeKitGated = await ethers.getContract("DisputeKitGated");
+ const disputeKitGatedShutter = await ethers.getContract("DisputeKitGatedShutter");
+ const core = await ethers.getContract("KlerosCore");
return [core, disputeKit, disputeKitShutter, disputeKitGated, disputeKitGatedShutter];
}
diff --git a/contracts/test/arbitration/ruler.ts b/contracts/test/arbitration/ruler.ts
index bf5754295..1c7fb379b 100644
--- a/contracts/test/arbitration/ruler.ts
+++ b/contracts/test/arbitration/ruler.ts
@@ -94,10 +94,10 @@ describe("KlerosCoreRuler", async () => {
.withArgs(resolver.target, RulingMode.automaticRandom, disputeID, anyValue, anyValue, anyValue)
.and.to.emit(core, "Ruling")
.withArgs(resolver.target, disputeID, anyValue)
- .and.to.emit(core, "TokenAndETHShift")
- .withArgs(dev.address, disputeID, 0, 1, 0, anyValue, ZeroAddress)
+ .and.to.emit(core, "JurorRewardPenalty")
+ .withArgs(dev.address, disputeID, 0, 10000, 10000, 0, anyValue, ZeroAddress)
.and.to.emit(resolver, "DisputeRequest")
- .withArgs(core.target, disputeID, localDisputeID, templateId, "")
+ .withArgs(core.target, disputeID, templateId)
.and.to.emit(resolver, "Ruling")
.withArgs(core.target, disputeID, anyValue);
});
@@ -118,10 +118,10 @@ describe("KlerosCoreRuler", async () => {
.withArgs(resolver.target, RulingMode.automaticPreset, disputeID, 2, true, false)
.and.to.emit(core, "Ruling")
.withArgs(resolver.target, disputeID, 2)
- .and.to.emit(core, "TokenAndETHShift")
- .withArgs(dev.address, disputeID, 0, 1, 0, anyValue, ZeroAddress)
+ .and.to.emit(core, "JurorRewardPenalty")
+ .withArgs(dev.address, disputeID, 0, 10000, 10000, 0, anyValue, ZeroAddress)
.and.to.emit(resolver, "DisputeRequest")
- .withArgs(core.target, disputeID, localDisputeID, templateId, "")
+ .withArgs(core.target, disputeID, templateId)
.and.to.emit(resolver, "Ruling")
.withArgs(core.target, disputeID, 2);
});
@@ -139,7 +139,7 @@ describe("KlerosCoreRuler", async () => {
.to.emit(core, "DisputeCreation")
.withArgs(disputeID, resolver.target)
.and.to.emit(resolver, "DisputeRequest")
- .withArgs(core.target, disputeID, localDisputeID, templateId, "");
+ .withArgs(core.target, disputeID, templateId);
await expect(core.connect(deployer).executeRuling(disputeID, 3, true, true)).revertedWithCustomError(
core,
@@ -153,8 +153,8 @@ describe("KlerosCoreRuler", async () => {
.withArgs(core.target, disputeID, 3);
await expect(core.execute(disputeID, 0))
- .and.to.emit(core, "TokenAndETHShift")
- .withArgs(dev.address, disputeID, 0, 1, 0, anyValue, ZeroAddress);
+ .and.to.emit(core, "JurorRewardPenalty")
+ .withArgs(dev.address, disputeID, 0, 10000, 10000, 0, anyValue, ZeroAddress);
});
});
@@ -163,7 +163,7 @@ async function deployContracts(): Promise<[KlerosCoreRuler, DisputeResolver]> {
fallbackToGlobal: true,
keepExistingDeployments: false,
});
- const resolver = (await ethers.getContract("DisputeResolverRuler")) as DisputeResolver;
- const core = (await ethers.getContract("KlerosCoreRuler")) as KlerosCoreRuler;
+ const resolver = await ethers.getContract("DisputeResolverRuler");
+ const core = await ethers.getContract("KlerosCoreRuler");
return [core, resolver];
}
diff --git a/contracts/test/arbitration/staking-neo.ts b/contracts/test/arbitration/staking-neo.ts
index 85b0dc884..3e34fb8cb 100644
--- a/contracts/test/arbitration/staking-neo.ts
+++ b/contracts/test/arbitration/staking-neo.ts
@@ -3,8 +3,8 @@ import {
PNK,
RandomizerRNG,
RandomizerMock,
- SortitionModuleNeo,
- KlerosCoreNeo,
+ SortitionModule,
+ KlerosCore,
TestERC721,
DisputeResolver,
ChainlinkRNG,
@@ -41,8 +41,8 @@ describe("Staking", async () => {
let juror: HardhatEthersSigner;
let guardian: HardhatEthersSigner;
let pnk: PNK;
- let core: KlerosCoreNeo;
- let sortition: SortitionModuleNeo;
+ let core: KlerosCore;
+ let sortition: SortitionModule;
let rng: ChainlinkRNG;
let vrfCoordinator: ChainlinkVRFCoordinatorV2Mock;
let nft: TestERC721;
@@ -52,17 +52,17 @@ describe("Staking", async () => {
const deployUnhappy = async () => {
({ deployer } = await getNamedAccounts());
- await deployments.fixture(["ArbitrationNeo"], {
+ await deployments.fixture(["ArbitrationMainnet"], {
fallbackToGlobal: true,
keepExistingDeployments: false,
});
- pnk = (await ethers.getContract("PNK")) as PNK;
- core = (await ethers.getContract("KlerosCoreNeo")) as KlerosCoreNeo;
- sortition = (await ethers.getContract("SortitionModuleNeo")) as SortitionModuleNeo;
- rng = (await ethers.getContract("ChainlinkRNG")) as ChainlinkRNG;
- vrfCoordinator = (await ethers.getContract("ChainlinkVRFCoordinator")) as ChainlinkVRFCoordinatorV2Mock;
- resolver = (await ethers.getContract("DisputeResolverNeo")) as DisputeResolver;
- nft = (await ethers.getContract("KlerosV2NeoEarlyUser")) as TestERC721;
+ pnk = await ethers.getContract("PNK");
+ core = await ethers.getContract("KlerosCore");
+ sortition = await ethers.getContract("SortitionModule");
+ rng = await ethers.getContract("ChainlinkRNG");
+ vrfCoordinator = await ethers.getContract("ChainlinkVRFCoordinator");
+ resolver = await ethers.getContract("DisputeResolver");
+ nft = await ethers.getContract("KlerosV2NeoEarlyUser");
// Juror signer setup and funding
const { firstWallet } = await getNamedAccounts();
@@ -105,10 +105,7 @@ describe("Staking", async () => {
const drawFromGeneratingPhase = async () => {
expect(await sortition.phase()).to.be.equal(1); // Generating
- const lookahead = await sortition.rngLookahead();
- for (let index = 0; index < lookahead; index++) {
- await network.provider.send("evm_mine");
- }
+ await network.provider.send("evm_mine");
await vrfCoordinator.fulfillRandomWords(1, rng.target, []);
await sortition.passPhase(); // Generating -> Drawing
@@ -131,60 +128,98 @@ describe("Staking", async () => {
SHOULD BEHAVE LIKE A NEO ARBITRATOR
************************************************************************************************/
- describe("When arbitrable is not whitelisted", () => {
+ describe("When arbitrable whitelist is disabled", () => {
before("Setup", async () => {
await deployUnhappy();
- await core.changeArbitrableWhitelist(resolver.target, false);
+ await core.changeArbitrableWhitelistEnabled(false);
});
- it("Should fail to create a dispute", async () => {
+ it("Should create a dispute", async () => {
const arbitrationCost = ETH(0.5);
- await expect(
- resolver.createDisputeForTemplate(extraData, "", "", 2, { value: arbitrationCost })
- ).to.be.revertedWithCustomError(core, "ArbitrableNotWhitelisted");
+ expect(await resolver.createDisputeForTemplate(extraData, "", "", 2, { value: arbitrationCost }))
+ .to.emit(core, "DisputeCreation")
+ .withArgs(0, resolver.target);
});
});
- describe("When arbitrable is whitelisted", () => {
+ describe("When arbitrable whitelist is enabled", () => {
before("Setup", async () => {
await deployUnhappy();
- await core.changeArbitrableWhitelist(resolver.target, true);
+ await core.changeArbitrableWhitelistEnabled(true);
});
- it("Should create a dispute", async () => {
- const arbitrationCost = ETH(0.5);
- expect(await resolver.createDisputeForTemplate(extraData, "", "", 2, { value: arbitrationCost }))
- .to.emit(core, "DisputeCreation")
- .withArgs(0, resolver.target);
+ describe("When arbitrable is not whitelisted", () => {
+ before("Setup", async () => {
+ await core.changeArbitrableWhitelist(resolver.target, false);
+ });
+
+ it("Should fail to create a dispute", async () => {
+ const arbitrationCost = ETH(0.5);
+ await expect(
+ resolver.createDisputeForTemplate(extraData, "", "", 2, { value: arbitrationCost })
+ ).to.be.revertedWithCustomError(core, "ArbitrableNotWhitelisted");
+ });
+ });
+
+ describe("When arbitrable is whitelisted", () => {
+ before("Setup", async () => {
+ await core.changeArbitrableWhitelist(resolver.target, true);
+ });
+
+ it("Should create a dispute", async () => {
+ const arbitrationCost = ETH(0.5);
+ expect(await resolver.createDisputeForTemplate(extraData, "", "", 2, { value: arbitrationCost }))
+ .to.emit(core, "DisputeCreation")
+ .withArgs(0, resolver.target);
+ });
});
});
- describe("When juror has no NFT", async () => {
+ describe("When juror NFT is not set", async () => {
before("Setup", async () => {
await deployUnhappy();
+ await core.changeJurorNft(ethers.ZeroAddress);
});
- it("Should not be able to stake", async () => {
- await pnk.connect(juror).approve(core.target, PNK(1000));
- await expect(core.connect(juror).setStake(1, PNK(1000))).to.be.revertedWithCustomError(
- core,
- "NotEligibleForStaking"
- );
+ describe("When juror has no NFT", async () => {
+ it("Should be able to stake", async () => {
+ await pnk.connect(juror).approve(core.target, PNK(1000));
+ await expect(await core.connect(juror).setStake(1, PNK(1000)))
+ .to.emit(sortition, "StakeSet")
+ .withArgs(juror.address, 1, PNK(1000), PNK(1000));
+ expect(await sortition.totalStaked()).to.be.equal(PNK(1000));
+ });
});
});
- describe("When juror does have a NFT", async () => {
- before("Setup", async () => {
- await deployUnhappy();
- await nft.safeMint(juror.address);
+ describe("When juror NFT is set", async () => {
+ describe("When juror has no NFT", async () => {
+ before("Setup", async () => {
+ await deployUnhappy();
+ });
+
+ it("Should not be able to stake", async () => {
+ await pnk.connect(juror).approve(core.target, PNK(1000));
+ await expect(core.connect(juror).setStake(1, PNK(1000))).to.be.revertedWithCustomError(
+ core,
+ "NotEligibleForStaking"
+ );
+ });
});
- it("Should be able to stake", async () => {
- await pnk.connect(juror).approve(core.target, PNK(1000));
- await expect(await core.connect(juror).setStake(1, PNK(1000)))
- .to.emit(sortition, "StakeSet")
- .withArgs(juror.address, 1, PNK(1000), PNK(1000));
- expect(await sortition.totalStaked()).to.be.equal(PNK(1000));
+ describe("When juror does have a NFT", async () => {
+ before("Setup", async () => {
+ await deployUnhappy();
+ await nft.safeMint(juror.address);
+ });
+
+ it("Should be able to stake", async () => {
+ await pnk.connect(juror).approve(core.target, PNK(1000));
+ await expect(await core.connect(juror).setStake(1, PNK(1000)))
+ .to.emit(sortition, "StakeSet")
+ .withArgs(juror.address, 1, PNK(1000), PNK(1000));
+ expect(await sortition.totalStaked()).to.be.equal(PNK(1000));
+ });
});
});
@@ -263,7 +298,10 @@ describe("Staking", async () => {
);
expect(await sortition.totalStaked()).to.be.equal(PNK(0));
await drawAndReachStakingPhaseFromGenerating();
- await expect(sortition.executeDelayedStakes(10)).to.revertedWith("No delayed stake to execute.");
+ await expect(sortition.executeDelayedStakes(10)).to.revertedWithCustomError(
+ sortition,
+ "NoDelayedStakeToExecute"
+ );
expect(await sortition.totalStaked()).to.be.equal(PNK(0));
});
@@ -327,7 +365,10 @@ describe("Staking", async () => {
);
expect(await sortition.totalStaked()).to.be.equal(PNK(2000));
await drawAndReachStakingPhaseFromGenerating();
- await expect(sortition.executeDelayedStakes(10)).to.revertedWith("No delayed stake to execute.");
+ await expect(sortition.executeDelayedStakes(10)).to.revertedWithCustomError(
+ sortition,
+ "NoDelayedStakeToExecute"
+ );
expect(await sortition.totalStaked()).to.be.equal(PNK(2000));
});
@@ -356,8 +397,8 @@ describe("Staking", async () => {
await deploy();
});
- it("Should not allow anyone except the guardian or the governor to pause", async () => {
- await expect(core.connect(juror).pause()).to.be.revertedWithCustomError(core, "GuardianOrGovernorOnly");
+ it("Should not allow anyone except the guardian or the owner to pause", async () => {
+ await expect(core.connect(juror).pause()).to.be.revertedWithCustomError(core, "GuardianOrOwnerOnly");
});
it("Should allow the guardian to pause", async () => {
@@ -365,7 +406,7 @@ describe("Staking", async () => {
expect(await core.paused()).to.equal(true);
});
- it("Should allow the governor to pause", async () => {
+ it("Should allow the owner to pause", async () => {
expect(await core.pause()).to.emit(core, "Paused");
expect(await core.paused()).to.equal(true);
});
@@ -381,8 +422,8 @@ describe("Staking", async () => {
await core.connect(guardian).pause();
});
- it("Should allow only the governor to unpause", async () => {
- await expect(core.connect(guardian).unpause()).to.be.revertedWithCustomError(core, "GovernorOnly");
+ it("Should allow only the owner to unpause", async () => {
+ await expect(core.connect(guardian).unpause()).to.be.revertedWithCustomError(core, "OwnerOnly");
expect(await core.unpause()).to.emit(core, "Unpaused");
expect(await core.paused()).to.equal(false);
});
@@ -428,7 +469,6 @@ describe("Staking", async () => {
expect(await sortition.delayedStakeWriteIndex()).to.be.equal(0);
expect(await sortition.delayedStakeReadIndex()).to.be.equal(1);
await pnk.approve(core.target, PNK(1000));
- expect(await sortition.latestDelayedStakeIndex(deployer, 2)).to.be.equal(0); // Deprecated. Always 0
await expect(core.setStake(2, PNK(3000)))
.to.emit(sortition, "StakeDelayed")
.withArgs(deployer, 2, PNK(3000));
@@ -440,10 +480,9 @@ describe("Staking", async () => {
});
it("Should store the delayed stake for later", async () => {
- expect(await sortition.latestDelayedStakeIndex(deployer, 2)).to.be.equal(0); // Deprecated. Always 0
expect(await sortition.delayedStakeWriteIndex()).to.be.equal(1);
expect(await sortition.delayedStakeReadIndex()).to.be.equal(1);
- expect(await sortition.delayedStakes(1)).to.be.deep.equal([deployer, 2, PNK(3000), false]);
+ expect(await sortition.delayedStakes(1)).to.be.deep.equal([deployer, 2, PNK(3000)]);
});
});
@@ -466,9 +505,8 @@ describe("Staking", async () => {
]); // stake unchanged, delayed
expect(await sortition.delayedStakeWriteIndex()).to.be.equal(1);
expect(await sortition.delayedStakeReadIndex()).to.be.equal(2);
- expect(await sortition.delayedStakes(1)).to.be.deep.equal([ethers.ZeroAddress, 0, 0, false]); // the 1st delayed stake got deleted
- expect(await sortition.delayedStakes(2)).to.be.deep.equal([ethers.ZeroAddress, 0, 0, false]); // the 2nd delayed stake got deleted
- expect(await sortition.latestDelayedStakeIndex(deployer, 1)).to.be.equal(0); // Deprecated. Always 0
+ expect(await sortition.delayedStakes(1)).to.be.deep.equal([ethers.ZeroAddress, 0, 0]); // the 1st delayed stake got deleted
+ expect(await sortition.delayedStakes(2)).to.be.deep.equal([ethers.ZeroAddress, 0, 0]); // the 2nd delayed stake got deleted
});
it("Should transfer PNK after delayed stake execution", async () => {
@@ -494,7 +532,6 @@ describe("Staking", async () => {
it("Should delay the stake decrease", async () => {
expect(await sortition.delayedStakeWriteIndex()).to.be.equal(0);
expect(await sortition.delayedStakeReadIndex()).to.be.equal(1);
- expect(await sortition.latestDelayedStakeIndex(deployer, 2)).to.be.equal(0); // Deprecated. Always 0
await expect(core.setStake(2, PNK(1000)))
.to.emit(sortition, "StakeDelayed")
.withArgs(deployer, 2, PNK(1000));
@@ -506,10 +543,9 @@ describe("Staking", async () => {
});
it("Should store the delayed stake for later", async () => {
- expect(await sortition.latestDelayedStakeIndex(deployer, 2)).to.be.equal(0); // Deprecated. Always 0
expect(await sortition.delayedStakeWriteIndex()).to.be.equal(1);
expect(await sortition.delayedStakeReadIndex()).to.be.equal(1);
- expect(await sortition.delayedStakes(1)).to.be.deep.equal([deployer, 2, PNK(1000), false]);
+ expect(await sortition.delayedStakes(1)).to.be.deep.equal([deployer, 2, PNK(1000)]);
});
});
@@ -531,9 +567,8 @@ describe("Staking", async () => {
]); // stake unchanged, delayed
expect(await sortition.delayedStakeWriteIndex()).to.be.equal(1);
expect(await sortition.delayedStakeReadIndex()).to.be.equal(2);
- expect(await sortition.delayedStakes(1)).to.be.deep.equal([ethers.ZeroAddress, 0, 0, false]); // the 1st delayed stake got deleted
- expect(await sortition.delayedStakes(2)).to.be.deep.equal([ethers.ZeroAddress, 0, 0, false]); // the 2nd delayed stake got deleted
- expect(await sortition.latestDelayedStakeIndex(deployer, 1)).to.be.equal(0); // Deprecated. Always 0
+ expect(await sortition.delayedStakes(1)).to.be.deep.equal([ethers.ZeroAddress, 0, 0]); // the 1st delayed stake got deleted
+ expect(await sortition.delayedStakes(2)).to.be.deep.equal([ethers.ZeroAddress, 0, 0]); // the 2nd delayed stake got deleted
});
it("Should withdraw some PNK", async () => {
@@ -559,7 +594,6 @@ describe("Staking", async () => {
it("Should delay the stake decrease", async () => {
expect(await sortition.delayedStakeWriteIndex()).to.be.equal(0);
expect(await sortition.delayedStakeReadIndex()).to.be.equal(1);
- expect(await sortition.latestDelayedStakeIndex(deployer, 2)).to.be.equal(0); // Deprecated. Always 0
await expect(core.setStake(2, PNK(1000)))
.to.emit(sortition, "StakeDelayed")
.withArgs(deployer, 2, PNK(1000));
@@ -571,17 +605,15 @@ describe("Staking", async () => {
});
it("Should store the delayed stake for later", async () => {
- expect(await sortition.latestDelayedStakeIndex(deployer, 2)).to.be.equal(0); // Deprecated. Always 0
expect(await sortition.delayedStakeWriteIndex()).to.be.equal(1);
expect(await sortition.delayedStakeReadIndex()).to.be.equal(1);
- expect(await sortition.delayedStakes(1)).to.be.deep.equal([deployer, 2, PNK(1000), false]);
+ expect(await sortition.delayedStakes(1)).to.be.deep.equal([deployer, 2, PNK(1000)]);
});
});
describe("When stake is increased back to the previous amount", () => {
it("Should delay the stake increase", async () => {
balanceBefore = await pnk.balanceOf(deployer);
- expect(await sortition.latestDelayedStakeIndex(deployer, 2)).to.be.equal(0); // Deprecated. Always 0
await expect(core.setStake(2, PNK(2000)))
.to.emit(sortition, "StakeDelayed")
.withArgs(deployer, 2, PNK(2000));
@@ -593,11 +625,10 @@ describe("Staking", async () => {
});
it("Should store the delayed stake for later", async () => {
- expect(await sortition.latestDelayedStakeIndex(deployer, 2)).to.be.equal(0); // Deprecated. Always 0
expect(await sortition.delayedStakeWriteIndex()).to.be.equal(2);
expect(await sortition.delayedStakeReadIndex()).to.be.equal(1);
- expect(await sortition.delayedStakes(1)).to.be.deep.equal([deployer, 2, PNK(1000), false]);
- expect(await sortition.delayedStakes(2)).to.be.deep.equal([deployer, 2, PNK(2000), false]);
+ expect(await sortition.delayedStakes(1)).to.be.deep.equal([deployer, 2, PNK(1000)]);
+ expect(await sortition.delayedStakes(2)).to.be.deep.equal([deployer, 2, PNK(2000)]);
});
});
@@ -622,9 +653,8 @@ describe("Staking", async () => {
]); // stake unchanged, delayed
expect(await sortition.delayedStakeWriteIndex()).to.be.equal(2);
expect(await sortition.delayedStakeReadIndex()).to.be.equal(3);
- expect(await sortition.delayedStakes(1)).to.be.deep.equal([ethers.ZeroAddress, 0, 0, false]); // the 1st delayed stake got deleted
- expect(await sortition.delayedStakes(2)).to.be.deep.equal([ethers.ZeroAddress, 0, 0, false]); // the 2nd delayed stake got deleted
- expect(await sortition.latestDelayedStakeIndex(deployer, 2)).to.be.equal(0); // Deprecated. Always 0
+ expect(await sortition.delayedStakes(1)).to.be.deep.equal([ethers.ZeroAddress, 0, 0]); // the 1st delayed stake got deleted
+ expect(await sortition.delayedStakes(2)).to.be.deep.equal([ethers.ZeroAddress, 0, 0]); // the 2nd delayed stake got deleted
});
it("Should not transfer any PNK", async () => {
@@ -651,7 +681,6 @@ describe("Staking", async () => {
expect(await sortition.delayedStakeWriteIndex()).to.be.equal(0);
expect(await sortition.delayedStakeReadIndex()).to.be.equal(1);
await pnk.approve(core.target, PNK(1000));
- expect(await sortition.latestDelayedStakeIndex(deployer, 2)).to.be.equal(0); // Deprecated. Always 0
await expect(core.setStake(2, PNK(3000)))
.to.emit(sortition, "StakeDelayed")
.withArgs(deployer, 2, PNK(3000));
@@ -663,17 +692,15 @@ describe("Staking", async () => {
});
it("Should store the delayed stake for later", async () => {
- expect(await sortition.latestDelayedStakeIndex(deployer, 2)).to.be.equal(0); // Deprecated. Always 0
expect(await sortition.delayedStakeWriteIndex()).to.be.equal(1);
expect(await sortition.delayedStakeReadIndex()).to.be.equal(1);
- expect(await sortition.delayedStakes(1)).to.be.deep.equal([deployer, 2, PNK(3000), false]);
+ expect(await sortition.delayedStakes(1)).to.be.deep.equal([deployer, 2, PNK(3000)]);
});
});
describe("When stake is decreased back to the previous amount", () => {
it("Should cancel out the stake decrease back", async () => {
balanceBefore = await pnk.balanceOf(deployer);
- expect(await sortition.latestDelayedStakeIndex(deployer, 2)).to.be.equal(0); // Deprecated. Always 0
await expect(core.setStake(2, PNK(2000)))
.to.emit(sortition, "StakeDelayed")
.withArgs(deployer, 2, PNK(2000));
@@ -685,11 +712,10 @@ describe("Staking", async () => {
});
it("Should store the delayed stake for later", async () => {
- expect(await sortition.latestDelayedStakeIndex(deployer, 2)).to.be.equal(0); // Deprecated. Always 0
expect(await sortition.delayedStakeWriteIndex()).to.be.equal(2);
expect(await sortition.delayedStakeReadIndex()).to.be.equal(1);
- expect(await sortition.delayedStakes(1)).to.be.deep.equal([deployer, 2, PNK(3000), false]);
- expect(await sortition.delayedStakes(2)).to.be.deep.equal([deployer, 2, PNK(2000), false]);
+ expect(await sortition.delayedStakes(1)).to.be.deep.equal([deployer, 2, PNK(3000)]);
+ expect(await sortition.delayedStakes(2)).to.be.deep.equal([deployer, 2, PNK(2000)]);
});
});
@@ -712,9 +738,8 @@ describe("Staking", async () => {
]); // stake unchanged, delayed
expect(await sortition.delayedStakeWriteIndex()).to.be.equal(2);
expect(await sortition.delayedStakeReadIndex()).to.be.equal(3);
- expect(await sortition.delayedStakes(1)).to.be.deep.equal([ethers.ZeroAddress, 0, 0, false]); // the 1st delayed stake got deleted
- expect(await sortition.delayedStakes(2)).to.be.deep.equal([ethers.ZeroAddress, 0, 0, false]); // the 2nd delayed stake got deleted
- expect(await sortition.latestDelayedStakeIndex(deployer, 2)).to.be.equal(0); // Deprecated. Always 0
+ expect(await sortition.delayedStakes(1)).to.be.deep.equal([ethers.ZeroAddress, 0, 0]); // the 1st delayed stake got deleted
+ expect(await sortition.delayedStakes(2)).to.be.deep.equal([ethers.ZeroAddress, 0, 0]); // the 2nd delayed stake got deleted
});
it("Should not transfer any PNK", async () => {
diff --git a/contracts/test/arbitration/staking.ts b/contracts/test/arbitration/staking.ts
index 4d0262c22..7e5344c39 100644
--- a/contracts/test/arbitration/staking.ts
+++ b/contracts/test/arbitration/staking.ts
@@ -27,11 +27,11 @@ describe("Staking", async () => {
fallbackToGlobal: true,
keepExistingDeployments: false,
});
- pnk = (await ethers.getContract("PNK")) as PNK;
- core = (await ethers.getContract("KlerosCore")) as KlerosCore;
- sortition = (await ethers.getContract("SortitionModule")) as SortitionModule;
- rng = (await ethers.getContract("ChainlinkRNG")) as ChainlinkRNG;
- vrfCoordinator = (await ethers.getContract("ChainlinkVRFCoordinator")) as ChainlinkVRFCoordinatorV2Mock;
+ pnk = await ethers.getContract("PNK");
+ core = await ethers.getContract("KlerosCore");
+ sortition = await ethers.getContract("SortitionModule");
+ rng = await ethers.getContract("ChainlinkRNG");
+ vrfCoordinator = await ethers.getContract("ChainlinkVRFCoordinator");
};
describe("When outside the Staking phase", async () => {
@@ -53,11 +53,8 @@ describe("Staking", async () => {
await network.provider.send("evm_increaseTime", [2000]); // Wait for minStakingTime
await network.provider.send("evm_mine");
- const lookahead = await sortition.rngLookahead();
await sortition.passPhase(); // Staking -> Generating
- for (let index = 0; index < lookahead; index++) {
- await network.provider.send("evm_mine");
- }
+ await network.provider.send("evm_mine");
balanceBefore = await pnk.balanceOf(deployer);
};
@@ -85,7 +82,6 @@ describe("Staking", async () => {
expect(await sortition.delayedStakeWriteIndex()).to.be.equal(0);
expect(await sortition.delayedStakeReadIndex()).to.be.equal(1);
await pnk.approve(core.target, PNK(1000));
- expect(await sortition.latestDelayedStakeIndex(deployer, 2)).to.be.equal(0); // Deprecated. Always 0
await expect(core.setStake(2, PNK(3000)))
.to.emit(sortition, "StakeDelayed")
.withArgs(deployer, 2, PNK(3000));
@@ -97,10 +93,9 @@ describe("Staking", async () => {
});
it("Should store the delayed stake for later", async () => {
- expect(await sortition.latestDelayedStakeIndex(deployer, 2)).to.be.equal(0); // Deprecated. Always 0
expect(await sortition.delayedStakeWriteIndex()).to.be.equal(1);
expect(await sortition.delayedStakeReadIndex()).to.be.equal(1);
- expect(await sortition.delayedStakes(1)).to.be.deep.equal([deployer, 2, PNK(3000), false]);
+ expect(await sortition.delayedStakes(1)).to.be.deep.equal([deployer, 2, PNK(3000)]);
});
});
@@ -123,9 +118,8 @@ describe("Staking", async () => {
]); // stake unchanged, delayed
expect(await sortition.delayedStakeWriteIndex()).to.be.equal(1);
expect(await sortition.delayedStakeReadIndex()).to.be.equal(2);
- expect(await sortition.delayedStakes(1)).to.be.deep.equal([ethers.ZeroAddress, 0, 0, false]); // the 1st delayed stake got deleted
- expect(await sortition.delayedStakes(2)).to.be.deep.equal([ethers.ZeroAddress, 0, 0, false]); // the 2nd delayed stake got deleted
- expect(await sortition.latestDelayedStakeIndex(deployer, 1)).to.be.equal(0); // Deprecated. Always 0
+ expect(await sortition.delayedStakes(1)).to.be.deep.equal([ethers.ZeroAddress, 0, 0]); // the 1st delayed stake got deleted
+ expect(await sortition.delayedStakes(2)).to.be.deep.equal([ethers.ZeroAddress, 0, 0]); // the 2nd delayed stake got deleted
});
it("Should transfer PNK after delayed stake execution", async () => {
@@ -149,7 +143,6 @@ describe("Staking", async () => {
it("Should delay the stake decrease", async () => {
expect(await sortition.delayedStakeWriteIndex()).to.be.equal(0);
expect(await sortition.delayedStakeReadIndex()).to.be.equal(1);
- expect(await sortition.latestDelayedStakeIndex(deployer, 2)).to.be.equal(0); // Deprecated. Always 0
await expect(core.setStake(2, PNK(1000)))
.to.emit(sortition, "StakeDelayed")
.withArgs(deployer, 2, PNK(1000));
@@ -161,10 +154,9 @@ describe("Staking", async () => {
});
it("Should store the delayed stake for later", async () => {
- expect(await sortition.latestDelayedStakeIndex(deployer, 2)).to.be.equal(0); // Deprecated. Always 0
expect(await sortition.delayedStakeWriteIndex()).to.be.equal(1);
expect(await sortition.delayedStakeReadIndex()).to.be.equal(1);
- expect(await sortition.delayedStakes(1)).to.be.deep.equal([deployer, 2, PNK(1000), false]);
+ expect(await sortition.delayedStakes(1)).to.be.deep.equal([deployer, 2, PNK(1000)]);
});
});
@@ -186,9 +178,8 @@ describe("Staking", async () => {
]); // stake unchanged, delayed
expect(await sortition.delayedStakeWriteIndex()).to.be.equal(1);
expect(await sortition.delayedStakeReadIndex()).to.be.equal(2);
- expect(await sortition.delayedStakes(1)).to.be.deep.equal([ethers.ZeroAddress, 0, 0, false]); // the 1st delayed stake got deleted
- expect(await sortition.delayedStakes(2)).to.be.deep.equal([ethers.ZeroAddress, 0, 0, false]); // the 2nd delayed stake got deleted
- expect(await sortition.latestDelayedStakeIndex(deployer, 1)).to.be.equal(0); // Deprecated. Always 0
+ expect(await sortition.delayedStakes(1)).to.be.deep.equal([ethers.ZeroAddress, 0, 0]); // the 1st delayed stake got deleted
+ expect(await sortition.delayedStakes(2)).to.be.deep.equal([ethers.ZeroAddress, 0, 0]); // the 2nd delayed stake got deleted
});
it("Should withdraw some PNK", async () => {
@@ -212,7 +203,6 @@ describe("Staking", async () => {
it("Should delay the stake decrease", async () => {
expect(await sortition.delayedStakeWriteIndex()).to.be.equal(0);
expect(await sortition.delayedStakeReadIndex()).to.be.equal(1);
- expect(await sortition.latestDelayedStakeIndex(deployer, 2)).to.be.equal(0); // Deprecated. Always 0
await expect(core.setStake(2, PNK(1000)))
.to.emit(sortition, "StakeDelayed")
.withArgs(deployer, 2, PNK(1000));
@@ -224,17 +214,15 @@ describe("Staking", async () => {
});
it("Should store the delayed stake for later", async () => {
- expect(await sortition.latestDelayedStakeIndex(deployer, 2)).to.be.equal(0); // Deprecated. Always 0
expect(await sortition.delayedStakeWriteIndex()).to.be.equal(1);
expect(await sortition.delayedStakeReadIndex()).to.be.equal(1);
- expect(await sortition.delayedStakes(1)).to.be.deep.equal([deployer, 2, PNK(1000), false]);
+ expect(await sortition.delayedStakes(1)).to.be.deep.equal([deployer, 2, PNK(1000)]);
});
});
describe("When stake is increased back to the previous amount", () => {
it("Should delay the stake increase", async () => {
balanceBefore = await pnk.balanceOf(deployer);
- expect(await sortition.latestDelayedStakeIndex(deployer, 2)).to.be.equal(0); // Deprecated. Always 0
await expect(core.setStake(2, PNK(2000))).to.emit(sortition, "StakeDelayed");
expect(await sortition.getJurorBalance(deployer, 2)).to.be.deep.equal([PNK(4000), 0, PNK(2000), 2]); // stake unchanged, delayed
});
@@ -244,11 +232,10 @@ describe("Staking", async () => {
});
it("Should store the delayed stake for later", async () => {
- expect(await sortition.latestDelayedStakeIndex(deployer, 2)).to.be.equal(0); // Deprecated. Always 0
expect(await sortition.delayedStakeWriteIndex()).to.be.equal(2);
expect(await sortition.delayedStakeReadIndex()).to.be.equal(1);
- expect(await sortition.delayedStakes(1)).to.be.deep.equal([deployer, 2, PNK(1000), false]);
- expect(await sortition.delayedStakes(2)).to.be.deep.equal([deployer, 2, PNK(2000), false]);
+ expect(await sortition.delayedStakes(1)).to.be.deep.equal([deployer, 2, PNK(1000)]);
+ expect(await sortition.delayedStakes(2)).to.be.deep.equal([deployer, 2, PNK(2000)]);
});
});
@@ -273,9 +260,8 @@ describe("Staking", async () => {
]); // stake unchanged, delayed
expect(await sortition.delayedStakeWriteIndex()).to.be.equal(2);
expect(await sortition.delayedStakeReadIndex()).to.be.equal(3);
- expect(await sortition.delayedStakes(1)).to.be.deep.equal([ethers.ZeroAddress, 0, 0, false]); // the 1st delayed stake got deleted
- expect(await sortition.delayedStakes(2)).to.be.deep.equal([ethers.ZeroAddress, 0, 0, false]); // the 2nd delayed stake got deleted
- expect(await sortition.latestDelayedStakeIndex(deployer, 2)).to.be.equal(0); // Deprecated. Always 0
+ expect(await sortition.delayedStakes(1)).to.be.deep.equal([ethers.ZeroAddress, 0, 0]); // the 1st delayed stake got deleted
+ expect(await sortition.delayedStakes(2)).to.be.deep.equal([ethers.ZeroAddress, 0, 0]); // the 2nd delayed stake got deleted
});
it("Should not transfer any PNK", async () => {
@@ -300,7 +286,6 @@ describe("Staking", async () => {
expect(await sortition.delayedStakeWriteIndex()).to.be.equal(0);
expect(await sortition.delayedStakeReadIndex()).to.be.equal(1);
await pnk.approve(core.target, PNK(1000));
- expect(await sortition.latestDelayedStakeIndex(deployer, 2)).to.be.equal(0); // Deprecated. Always 0
await expect(core.setStake(2, PNK(3000)))
.to.emit(sortition, "StakeDelayed")
.withArgs(deployer, 2, PNK(3000));
@@ -312,17 +297,15 @@ describe("Staking", async () => {
});
it("Should store the delayed stake for later", async () => {
- expect(await sortition.latestDelayedStakeIndex(deployer, 2)).to.be.equal(0); // Deprecated. Always 0
expect(await sortition.delayedStakeWriteIndex()).to.be.equal(1);
expect(await sortition.delayedStakeReadIndex()).to.be.equal(1);
- expect(await sortition.delayedStakes(1)).to.be.deep.equal([deployer, 2, PNK(3000), false]);
+ expect(await sortition.delayedStakes(1)).to.be.deep.equal([deployer, 2, PNK(3000)]);
});
});
describe("When stake is decreased back to the previous amount", () => {
it("Should cancel out the stake decrease back", async () => {
balanceBefore = await pnk.balanceOf(deployer);
- expect(await sortition.latestDelayedStakeIndex(deployer, 2)).to.be.equal(0); // Deprecated. Always 0
await expect(core.setStake(2, PNK(2000)))
.to.emit(sortition, "StakeDelayed")
.withArgs(deployer, 2, PNK(2000));
@@ -334,11 +317,10 @@ describe("Staking", async () => {
});
it("Should store the delayed stake for later", async () => {
- expect(await sortition.latestDelayedStakeIndex(deployer, 2)).to.be.equal(0); // Deprecated. Always 0
expect(await sortition.delayedStakeWriteIndex()).to.be.equal(2);
expect(await sortition.delayedStakeReadIndex()).to.be.equal(1);
- expect(await sortition.delayedStakes(1)).to.be.deep.equal([deployer, 2, PNK(3000), false]);
- expect(await sortition.delayedStakes(2)).to.be.deep.equal([deployer, 2, PNK(2000), false]);
+ expect(await sortition.delayedStakes(1)).to.be.deep.equal([deployer, 2, PNK(3000)]);
+ expect(await sortition.delayedStakes(2)).to.be.deep.equal([deployer, 2, PNK(2000)]);
});
});
@@ -361,9 +343,8 @@ describe("Staking", async () => {
]); // stake unchanged, delayed
expect(await sortition.delayedStakeWriteIndex()).to.be.equal(2);
expect(await sortition.delayedStakeReadIndex()).to.be.equal(3);
- expect(await sortition.delayedStakes(1)).to.be.deep.equal([ethers.ZeroAddress, 0, 0, false]); // the 1st delayed stake got deleted
- expect(await sortition.delayedStakes(2)).to.be.deep.equal([ethers.ZeroAddress, 0, 0, false]); // the 2nd delayed stake got deleted
- expect(await sortition.latestDelayedStakeIndex(deployer, 2)).to.be.equal(0); // Deprecated. Always 0
+ expect(await sortition.delayedStakes(1)).to.be.deep.equal([ethers.ZeroAddress, 0, 0]); // the 1st delayed stake got deleted
+ expect(await sortition.delayedStakes(2)).to.be.deep.equal([ethers.ZeroAddress, 0, 0]); // the 2nd delayed stake got deleted
});
it("Should not transfer any PNK", async () => {
@@ -393,11 +374,9 @@ describe("Staking", async () => {
await network.provider.send("evm_increaseTime", [2000]); // Wait for minStakingTime
await network.provider.send("evm_mine");
- const lookahead = await sortition.rngLookahead();
await sortition.passPhase(); // Staking -> Generating
- for (let index = 0; index < lookahead; index++) {
- await network.provider.send("evm_mine");
- }
+ await network.provider.send("evm_mine");
+
await vrfCoordinator.fulfillRandomWords(1, rng.target, []);
await sortition.passPhase(); // Generating -> Drawing
diff --git a/contracts/test/evidence/index.ts b/contracts/test/evidence/index.ts
index 30d79ab28..aa1cd0fbf 100644
--- a/contracts/test/evidence/index.ts
+++ b/contracts/test/evidence/index.ts
@@ -19,7 +19,6 @@ function getEmittedEvent(eventName: any, receipt: ContractTransactionReceipt): E
describe("Home Evidence contract", async () => {
const arbitrationFee = 1000n;
- const appealFee = arbitrationFee;
const arbitratorExtraData = ethers.AbiCoder.defaultAbiCoder().encode(
["uint256", "uint256"],
[1, 1] // courtId 1, minJurors 1
@@ -51,8 +50,8 @@ describe("Home Evidence contract", async () => {
fallbackToGlobal: true,
keepExistingDeployments: false,
});
- arbitrator = (await ethers.getContract("KlerosCore")) as KlerosCore;
- disputeTemplateRegistry = (await ethers.getContract("DisputeTemplateRegistry")) as DisputeTemplateRegistry;
+ arbitrator = await ethers.getContract("KlerosCore");
+ disputeTemplateRegistry = await ethers.getContract("DisputeTemplateRegistry");
const court = await arbitrator.courts(1);
await arbitrator.changeCourtParameters(
@@ -68,7 +67,7 @@ describe("Home Evidence contract", async () => {
const EvidenceModule = await ethers.getContractFactory("ModeratedEvidenceModule");
evidenceModule = await EvidenceModule.deploy(
arbitrator.target,
- deployer.address, // governor
+ deployer.address, // owner
disputeTemplateRegistry.target,
totalCostMultiplier,
initialDepositMultiplier,
@@ -81,10 +80,10 @@ describe("Home Evidence contract", async () => {
describe("Governance", async () => {
it("Should change parameters correctly", async () => {
- const newGovernor = await user2.getAddress();
- await evidenceModule.changeGovernor(newGovernor);
- expect(await evidenceModule.governor()).to.equal(newGovernor);
- await evidenceModule.connect(user2).changeGovernor(await deployer.getAddress());
+ const newOwner = await user2.getAddress();
+ await evidenceModule.changeOwner(newOwner);
+ expect(await evidenceModule.owner()).to.equal(newOwner);
+ await evidenceModule.connect(user2).changeOwner(await deployer.getAddress());
await evidenceModule.changeInitialDepositMultiplier(1);
expect(await evidenceModule.initialDepositMultiplier()).to.equal(1);
@@ -118,29 +117,29 @@ describe("Home Evidence contract", async () => {
expect(newArbitratorData.arbitratorExtraData).to.equal(newArbitratorExtraData, "Wrong extraData");
});
- it("Should revert if the caller is not the governor", async () => {
- await expect(evidenceModule.connect(user2).changeGovernor(await user2.getAddress())).to.be.revertedWith(
- "The caller must be the governor"
+ it("Should revert if the caller is not the owner", async () => {
+ await expect(evidenceModule.connect(user2).changeOwner(await user2.getAddress())).to.be.revertedWith(
+ "The caller must be the owner"
);
await expect(evidenceModule.connect(user2).changeInitialDepositMultiplier(0)).to.be.revertedWith(
- "The caller must be the governor"
+ "The caller must be the owner"
);
await expect(evidenceModule.connect(user2).changeTotalCostMultiplier(0)).to.be.revertedWith(
- "The caller must be the governor"
+ "The caller must be the owner"
);
await expect(evidenceModule.connect(user2).changeBondTimeout(0)).to.be.revertedWith(
- "The caller must be the governor"
+ "The caller must be the owner"
);
await expect(evidenceModule.connect(user2).changeDisputeTemplate(disputeTemplate, "")).to.be.revertedWith(
- "The caller must be the governor"
+ "The caller must be the owner"
);
await expect(evidenceModule.connect(user2).changeArbitratorExtraData(arbitratorExtraData)).to.be.revertedWith(
- "The caller must be the governor"
+ "The caller must be the owner"
);
});
});
@@ -155,9 +154,9 @@ describe("Home Evidence contract", async () => {
if (receipt === null) throw new Error("Receipt is null");
const evidenceID = ethers.solidityPackedKeccak256(["uint", "string"], [1234, newEvidence]);
- const [_arbitrator, _externalDisputeID, _party, _evidence] = getEmittedEvent("ModeratedEvidence", receipt).args;
+ const [_arbitrator, _disputeID, _party, _evidence] = getEmittedEvent("ModeratedEvidence", receipt).args;
expect(_arbitrator).to.equal(arbitrator.target, "Wrong arbitrator.");
- expect(_externalDisputeID).to.equal(1234, "Wrong external dispute ID.");
+ expect(_disputeID).to.equal(0, "Wrong dispute ID.");
expect(_party).to.equal(user1.address, "Wrong submitter.");
expect(_evidence).to.equal(newEvidence, "Wrong evidence message.");
@@ -262,14 +261,10 @@ describe("Home Evidence contract", async () => {
});
let receipt = await tx.wait();
if (receipt === null) throw new Error("Receipt is null");
- let [_arbitrator, _arbitrableDisputeID, _externalDisputeID, _templateId, _templateUri] = getEmittedEvent(
- "DisputeRequest",
- receipt
- ).args;
+ let [_arbitrator, _disputeID, _templateId, _templateUri] = getEmittedEvent("DisputeRequest", receipt).args;
expect(_arbitrator).to.equal(arbitrator.target, "Wrong arbitrator.");
- expect(_arbitrableDisputeID).to.equal(0, "Wrong dispute ID.");
+ expect(_disputeID).to.equal(0, "Wrong dispute ID.");
expect(_templateId).to.equal(1, "Wrong template ID.");
- expect(_externalDisputeID).to.equal(evidenceID, "Wrong external dispute ID.");
await expect(
evidenceModule.connect(user2).moderate(evidenceID, Party.Moderator, {
diff --git a/contracts/test/foundry/KlerosCore.t.sol b/contracts/test/foundry/KlerosCore.t.sol
deleted file mode 100644
index 20f8555a7..000000000
--- a/contracts/test/foundry/KlerosCore.t.sol
+++ /dev/null
@@ -1,2993 +0,0 @@
-// SPDX-License-Identifier: MIT
-pragma solidity ^0.8.24;
-
-import {Test} from "forge-std/Test.sol";
-import {console} from "forge-std/console.sol"; // Import the console for logging
-import {KlerosCoreMock, KlerosCoreBase} from "../../src/test/KlerosCoreMock.sol";
-import {IArbitratorV2} from "../../src/arbitration/KlerosCoreBase.sol";
-import {IDisputeKit} from "../../src/arbitration/interfaces/IDisputeKit.sol";
-import {DisputeKitClassic, DisputeKitClassicBase} from "../../src/arbitration/dispute-kits/DisputeKitClassic.sol";
-import {DisputeKitSybilResistant} from "../../src/arbitration/dispute-kits/DisputeKitSybilResistant.sol";
-import {ISortitionModule} from "../../src/arbitration/interfaces/ISortitionModule.sol";
-import {SortitionModuleMock, SortitionModuleBase} from "../../src/test/SortitionModuleMock.sol";
-import {UUPSProxy} from "../../src/proxy/UUPSProxy.sol";
-import {BlockHashRNG} from "../../src/rng/BlockHashRNG.sol";
-import {PNK} from "../../src/token/PNK.sol";
-import {TestERC20} from "../../src/token/TestERC20.sol";
-import {ArbitrableExample, IArbitrableV2} from "../../src/arbitration/arbitrables/ArbitrableExample.sol";
-import {DisputeTemplateRegistry} from "../../src/arbitration/DisputeTemplateRegistry.sol";
-import "../../src/libraries/Constants.sol";
-import {IKlerosCore, KlerosCoreSnapshotProxy} from "../../src/arbitration/view/KlerosCoreSnapshotProxy.sol";
-
-contract KlerosCoreTest is Test {
- event Initialized(uint64 version);
-
- KlerosCoreMock core;
- DisputeKitClassic disputeKit;
- SortitionModuleMock sortitionModule;
- BlockHashRNG rng;
- PNK pinakion;
- TestERC20 feeToken;
- TestERC20 wNative;
- ArbitrableExample arbitrable;
- DisputeTemplateRegistry registry;
- address governor;
- address guardian;
- address staker1;
- address staker2;
- address disputer;
- address crowdfunder1;
- address crowdfunder2;
- address other;
- address jurorProsecutionModule;
- uint256 minStake;
- uint256 alpha;
- uint256 feeForJuror;
- uint256 jurorsForCourtJump;
- bytes sortitionExtraData;
- bytes arbitratorExtraData;
- uint256[4] timesPerPeriod;
- bool hiddenVotes;
-
- uint256 totalSupply = 1000000 ether;
-
- uint256 minStakingTime;
- uint256 maxDrawingTime;
- uint256 rngLookahead;
-
- string templateData;
- string templateDataMappings;
-
- function setUp() public {
- KlerosCoreMock coreLogic = new KlerosCoreMock();
- SortitionModuleMock smLogic = new SortitionModuleMock();
- DisputeKitClassic dkLogic = new DisputeKitClassic();
- DisputeTemplateRegistry registryLogic = new DisputeTemplateRegistry();
- rng = new BlockHashRNG();
- pinakion = new PNK();
- feeToken = new TestERC20("Test", "TST");
- wNative = new TestERC20("wrapped ETH", "wETH");
-
- governor = msg.sender;
- guardian = vm.addr(1);
- staker1 = vm.addr(2);
- staker2 = vm.addr(3);
- disputer = vm.addr(4);
- crowdfunder1 = vm.addr(5);
- crowdfunder2 = vm.addr(6);
- vm.deal(disputer, 10 ether);
- vm.deal(crowdfunder1, 10 ether);
- vm.deal(crowdfunder2, 10 ether);
- jurorProsecutionModule = vm.addr(8);
- other = vm.addr(9);
- minStake = 1000;
- alpha = 10000;
- feeForJuror = 0.03 ether;
- jurorsForCourtJump = 511;
- timesPerPeriod = [60, 120, 180, 240];
-
- pinakion.transfer(msg.sender, totalSupply - 2 ether);
- pinakion.transfer(staker1, 1 ether);
- pinakion.transfer(staker2, 1 ether);
-
- sortitionExtraData = abi.encode(uint256(5));
- minStakingTime = 18;
- maxDrawingTime = 24;
- rngLookahead = 20;
- hiddenVotes = false;
-
- UUPSProxy proxyCore = new UUPSProxy(address(coreLogic), "");
-
- bytes memory initDataDk = abi.encodeWithSignature(
- "initialize(address,address,address)",
- governor,
- address(proxyCore),
- address(wNative)
- );
-
- UUPSProxy proxyDk = new UUPSProxy(address(dkLogic), initDataDk);
- disputeKit = DisputeKitClassic(address(proxyDk));
-
- bytes memory initDataSm = abi.encodeWithSignature(
- "initialize(address,address,uint256,uint256,address,uint256)",
- governor,
- address(proxyCore),
- minStakingTime,
- maxDrawingTime,
- rng,
- rngLookahead
- );
-
- UUPSProxy proxySm = new UUPSProxy(address(smLogic), initDataSm);
- sortitionModule = SortitionModuleMock(address(proxySm));
-
- core = KlerosCoreMock(address(proxyCore));
- core.initialize(
- governor,
- guardian,
- pinakion,
- jurorProsecutionModule,
- disputeKit,
- hiddenVotes,
- [minStake, alpha, feeForJuror, jurorsForCourtJump],
- timesPerPeriod,
- sortitionExtraData,
- sortitionModule,
- address(wNative)
- );
- vm.prank(staker1);
- pinakion.approve(address(core), 1 ether);
- vm.prank(staker2);
- pinakion.approve(address(core), 1 ether);
-
- templateData = "AAA";
- templateDataMappings = "BBB";
- arbitratorExtraData = abi.encodePacked(uint256(GENERAL_COURT), DEFAULT_NB_OF_JURORS, DISPUTE_KIT_CLASSIC);
-
- bytes memory initDataRegistry = abi.encodeWithSignature("initialize(address)", governor);
- UUPSProxy proxyRegistry = new UUPSProxy(address(registryLogic), initDataRegistry);
- registry = DisputeTemplateRegistry(address(proxyRegistry));
-
- arbitrable = new ArbitrableExample(
- core,
- templateData,
- templateDataMappings,
- arbitratorExtraData,
- registry,
- feeToken
- );
- }
-
- function test_initialize() public {
- assertEq(core.governor(), msg.sender, "Wrong governor");
- assertEq(core.guardian(), guardian, "Wrong guardian");
- assertEq(address(core.pinakion()), address(pinakion), "Wrong pinakion address");
- assertEq(core.jurorProsecutionModule(), jurorProsecutionModule, "Wrong jurorProsecutionModule address");
- assertEq(address(core.sortitionModule()), address(sortitionModule), "Wrong sortitionModule address");
- assertEq(core.getDisputeKitsLength(), 2, "Wrong DK array length");
- (
- uint96 courtParent,
- bool courtHiddenVotes,
- uint256 courtMinStake,
- uint256 courtAlpha,
- uint256 courtFeeForJuror,
- uint256 courtJurorsForCourtJump,
- bool courtDisabled
- ) = core.courts(FORKING_COURT);
- assertEq(courtParent, FORKING_COURT, "Wrong court parent");
- assertEq(courtHiddenVotes, false, "Wrong hiddenVotes value");
- assertEq(courtMinStake, 0, "Wrong minStake value");
- assertEq(courtAlpha, 0, "Wrong alpha value");
- assertEq(courtFeeForJuror, 0, "Wrong feeForJuror value");
- assertEq(courtJurorsForCourtJump, 0, "Wrong jurorsForCourtJump value");
- assertEq(courtDisabled, false, "Court should not be disabled");
- (
- courtParent,
- courtHiddenVotes,
- courtMinStake,
- courtAlpha,
- courtFeeForJuror,
- courtJurorsForCourtJump,
- courtDisabled
- ) = core.courts(GENERAL_COURT);
- assertEq(courtParent, FORKING_COURT, "Wrong court parent");
- assertEq(courtHiddenVotes, false, "Wrong hiddenVotes value");
- assertEq(courtMinStake, 1000, "Wrong minStake value");
- assertEq(courtAlpha, 10000, "Wrong alpha value");
- assertEq(courtFeeForJuror, 0.03 ether, "Wrong feeForJuror value");
- assertEq(courtJurorsForCourtJump, 511, "Wrong jurorsForCourtJump value");
- assertEq(courtDisabled, false, "Court should not be disabled");
-
- uint256[] memory children = core.getCourtChildren(GENERAL_COURT);
- assertEq(children.length, 0, "No children");
- uint256[4] memory courtTimesPerPeriod = core.getTimesPerPeriod(GENERAL_COURT);
- for (uint256 i = 0; i < 4; i++) {
- assertEq(courtTimesPerPeriod[i], timesPerPeriod[i], "Wrong times per period");
- }
-
- assertEq(address(core.disputeKits(NULL_DISPUTE_KIT)), address(0), "Wrong address NULL_DISPUTE_KIT");
- assertEq(
- address(core.disputeKits(DISPUTE_KIT_CLASSIC)),
- address(disputeKit),
- "Wrong address DISPUTE_KIT_CLASSIC"
- );
- assertEq(core.isSupported(FORKING_COURT, NULL_DISPUTE_KIT), false, "Forking court null dk should be false");
- assertEq(
- core.isSupported(FORKING_COURT, DISPUTE_KIT_CLASSIC),
- false,
- "Forking court classic dk should be false"
- );
- assertEq(core.isSupported(GENERAL_COURT, NULL_DISPUTE_KIT), false, "General court null dk should be false");
- assertEq(core.isSupported(GENERAL_COURT, DISPUTE_KIT_CLASSIC), true, "General court classic dk should be true");
- assertEq(core.paused(), false, "Wrong paused value");
-
- assertEq(pinakion.name(), "Pinakion", "Wrong token name");
- assertEq(pinakion.symbol(), "PNK", "Wrong token symbol");
- assertEq(pinakion.totalSupply(), 1000000 ether, "Wrong total supply");
- assertEq(pinakion.balanceOf(msg.sender), 999998 ether, "Wrong token balance of governor");
- assertEq(pinakion.balanceOf(staker1), 1 ether, "Wrong token balance of staker1");
- assertEq(pinakion.allowance(staker1, address(core)), 1 ether, "Wrong allowance for staker1");
- assertEq(pinakion.balanceOf(staker2), 1 ether, "Wrong token balance of staker2");
- assertEq(pinakion.allowance(staker2, address(core)), 1 ether, "Wrong allowance for staker2");
-
- assertEq(disputeKit.governor(), msg.sender, "Wrong DK governor");
- assertEq(address(disputeKit.core()), address(core), "Wrong core in DK");
-
- assertEq(sortitionModule.governor(), msg.sender, "Wrong SM governor");
- assertEq(address(sortitionModule.core()), address(core), "Wrong core in SM");
- assertEq(uint256(sortitionModule.phase()), uint256(ISortitionModule.Phase.staking), "Phase should be 0");
- assertEq(sortitionModule.minStakingTime(), 18, "Wrong minStakingTime");
- assertEq(sortitionModule.maxDrawingTime(), 24, "Wrong maxDrawingTime");
- assertEq(sortitionModule.lastPhaseChange(), block.timestamp, "Wrong lastPhaseChange");
- assertEq(sortitionModule.randomNumberRequestBlock(), 0, "randomNumberRequestBlock should be 0");
- assertEq(sortitionModule.disputesWithoutJurors(), 0, "disputesWithoutJurors should be 0");
- assertEq(address(sortitionModule.rng()), address(rng), "Wrong RNG address");
- assertEq(sortitionModule.randomNumber(), 0, "randomNumber should be 0");
- assertEq(sortitionModule.rngLookahead(), 20, "Wrong rngLookahead");
- assertEq(sortitionModule.delayedStakeWriteIndex(), 0, "delayedStakeWriteIndex should be 0");
- assertEq(sortitionModule.delayedStakeReadIndex(), 1, "Wrong delayedStakeReadIndex");
-
- (uint256 K, uint256 nodeLength) = sortitionModule.getSortitionProperties(bytes32(uint256(FORKING_COURT)));
- assertEq(K, 5, "Wrong tree K FORKING_COURT");
- assertEq(nodeLength, 1, "Wrong node length for created tree FORKING_COURT");
-
- (K, nodeLength) = sortitionModule.getSortitionProperties(bytes32(uint256(GENERAL_COURT)));
- assertEq(K, 5, "Wrong tree K GENERAL_COURT");
- assertEq(nodeLength, 1, "Wrong node length for created tree GENERAL_COURT");
- }
-
- function test_initialize_events() public {
- KlerosCoreMock coreLogic = new KlerosCoreMock();
- SortitionModuleMock smLogic = new SortitionModuleMock();
- DisputeKitClassic dkLogic = new DisputeKitClassic();
- rng = new BlockHashRNG();
- pinakion = new PNK();
-
- governor = msg.sender;
- guardian = vm.addr(1);
- staker1 = vm.addr(2);
- other = vm.addr(9);
- jurorProsecutionModule = vm.addr(8);
- minStake = 1000;
- alpha = 10000;
- feeForJuror = 0.03 ether;
- jurorsForCourtJump = 511;
- timesPerPeriod = [60, 120, 180, 240];
-
- pinakion.transfer(msg.sender, totalSupply - 1 ether);
- pinakion.transfer(staker1, 1 ether);
-
- sortitionExtraData = abi.encode(uint256(5));
- minStakingTime = 18;
- maxDrawingTime = 24;
- rngLookahead = 20;
- hiddenVotes = false;
-
- UUPSProxy proxyCore = new UUPSProxy(address(coreLogic), "");
-
- bytes memory initDataDk = abi.encodeWithSignature(
- "initialize(address,address,address)",
- governor,
- address(proxyCore),
- address(wNative)
- );
-
- UUPSProxy proxyDk = new UUPSProxy(address(dkLogic), initDataDk);
- disputeKit = DisputeKitClassic(address(proxyDk));
-
- bytes memory initDataSm = abi.encodeWithSignature(
- "initialize(address,address,uint256,uint256,address,uint256)",
- governor,
- address(proxyCore),
- minStakingTime,
- maxDrawingTime,
- rng,
- rngLookahead
- );
-
- UUPSProxy proxySm = new UUPSProxy(address(smLogic), initDataSm);
- sortitionModule = SortitionModuleMock(address(proxySm));
-
- core = KlerosCoreMock(address(proxyCore));
- vm.expectEmit(true, true, true, true);
- emit KlerosCoreBase.DisputeKitCreated(DISPUTE_KIT_CLASSIC, disputeKit);
- vm.expectEmit(true, true, true, true);
-
- uint256[] memory supportedDK = new uint256[](1);
- supportedDK[0] = DISPUTE_KIT_CLASSIC;
- emit KlerosCoreBase.CourtCreated(
- GENERAL_COURT,
- FORKING_COURT,
- false,
- 1000,
- 10000,
- 0.03 ether,
- 511,
- [uint256(60), uint256(120), uint256(180), uint256(240)], // Explicitly convert otherwise it throws
- supportedDK
- );
- vm.expectEmit(true, true, true, true);
- emit KlerosCoreBase.DisputeKitEnabled(GENERAL_COURT, DISPUTE_KIT_CLASSIC, true);
- core.initialize(
- governor,
- guardian,
- pinakion,
- jurorProsecutionModule,
- disputeKit,
- hiddenVotes,
- [minStake, alpha, feeForJuror, jurorsForCourtJump],
- timesPerPeriod,
- sortitionExtraData,
- sortitionModule,
- address(wNative)
- );
- }
-
- // ****************************************** //
- // * Governance test * //
- // ****************************************** //
-
- function test_pause() public {
- vm.expectRevert(KlerosCoreBase.GuardianOrGovernorOnly.selector);
- vm.prank(other);
- core.pause();
- // Note that we must explicitly switch to the governor/guardian address to make the call, otherwise Foundry treats UUPS proxy as msg.sender.
- vm.prank(guardian);
- vm.expectEmit(true, true, true, true);
- emit KlerosCoreBase.Paused();
- core.pause();
- assertEq(core.paused(), true, "Wrong paused value");
- // Switch between governor and guardian to test both. WhenNotPausedOnly modifier is triggered after governor's check.
- vm.prank(governor);
- vm.expectRevert(KlerosCoreBase.WhenNotPausedOnly.selector);
- core.pause();
- }
-
- function test_unpause() public {
- vm.expectRevert(KlerosCoreBase.GovernorOnly.selector);
- vm.prank(other);
- core.unpause();
-
- vm.expectRevert(KlerosCoreBase.WhenPausedOnly.selector);
- vm.prank(governor);
- core.unpause();
-
- vm.prank(governor);
- core.pause();
- vm.prank(governor);
- vm.expectEmit(true, true, true, true);
- emit KlerosCoreBase.Unpaused();
- core.unpause();
- assertEq(core.paused(), false, "Wrong paused value");
- }
-
- function test_executeGovernorProposal() public {
- bytes memory data = abi.encodeWithSignature("changeGovernor(address)", other);
- vm.expectRevert(KlerosCoreBase.GovernorOnly.selector);
- vm.prank(other);
- core.executeGovernorProposal(address(core), 0, data);
-
- vm.expectRevert(KlerosCoreBase.UnsuccessfulCall.selector);
- vm.prank(governor);
- core.executeGovernorProposal(address(core), 0, data); // It'll fail because the core is not its own governor
-
- vm.prank(governor);
- core.changeGovernor(payable(address(core)));
- vm.prank(address(core));
- core.executeGovernorProposal(address(core), 0, data);
- assertEq(core.governor(), other, "Wrong governor");
- }
-
- function test_changeGovernor() public {
- vm.expectRevert(KlerosCoreBase.GovernorOnly.selector);
- vm.prank(other);
- core.changeGovernor(payable(other));
- vm.prank(governor);
- core.changeGovernor(payable(other));
- assertEq(core.governor(), other, "Wrong governor");
- }
-
- function test_changeGuardian() public {
- vm.expectRevert(KlerosCoreBase.GovernorOnly.selector);
- vm.prank(other);
- core.changeGuardian(other);
- vm.prank(governor);
- core.changeGuardian(other);
- assertEq(core.guardian(), other, "Wrong guardian");
- }
-
- function test_changePinakion() public {
- PNK fakePNK = new PNK();
- vm.expectRevert(KlerosCoreBase.GovernorOnly.selector);
- vm.prank(other);
- core.changePinakion(fakePNK);
- vm.prank(governor);
- core.changePinakion(fakePNK);
- assertEq(address(core.pinakion()), address(fakePNK), "Wrong PNK");
- }
-
- function test_changeJurorProsecutionModule() public {
- vm.expectRevert(KlerosCoreBase.GovernorOnly.selector);
- vm.prank(other);
- core.changeJurorProsecutionModule(other);
- vm.prank(governor);
- core.changeJurorProsecutionModule(other);
- assertEq(core.jurorProsecutionModule(), other, "Wrong jurorProsecutionModule");
- }
-
- function test_changeSortitionModule() public {
- SortitionModuleMock fakeSM = new SortitionModuleMock();
- vm.expectRevert(KlerosCoreBase.GovernorOnly.selector);
- vm.prank(other);
- core.changeSortitionModule(fakeSM);
- vm.prank(governor);
- core.changeSortitionModule(fakeSM);
- assertEq(address(core.sortitionModule()), address(fakeSM), "Wrong sortitionModule");
- }
-
- function test_addNewDisputeKit() public {
- DisputeKitSybilResistant newDK = new DisputeKitSybilResistant();
- vm.expectRevert(KlerosCoreBase.GovernorOnly.selector);
- vm.prank(other);
- core.addNewDisputeKit(newDK);
- vm.prank(governor);
- vm.expectEmit(true, true, true, true);
- emit KlerosCoreBase.DisputeKitCreated(2, newDK);
- core.addNewDisputeKit(newDK);
- assertEq(address(core.disputeKits(2)), address(newDK), "Wrong address of new DK");
- assertEq(core.getDisputeKitsLength(), 3, "Wrong DK array length");
- }
-
- function test_createCourt() public {
- vm.expectRevert(KlerosCoreBase.GovernorOnly.selector);
- vm.prank(other);
- uint256[] memory supportedDK = new uint256[](2);
- supportedDK[0] = DISPUTE_KIT_CLASSIC;
- supportedDK[1] = 2; // New DK is added below.
- core.createCourt(
- GENERAL_COURT,
- true, // Hidden votes
- 2000, // min stake
- 10000, // alpha
- 0.03 ether, // fee for juror
- 50, // jurors for jump
- [uint256(10), uint256(20), uint256(30), uint256(40)], // Times per period
- abi.encode(uint256(4)), // Sortition extra data
- supportedDK
- );
-
- vm.expectRevert(KlerosCoreBase.MinStakeLowerThanParentCourt.selector);
- vm.prank(governor);
- core.createCourt(
- GENERAL_COURT,
- true, // Hidden votes
- 800, // min stake
- 10000, // alpha
- 0.03 ether, // fee for juror
- 50, // jurors for jump
- [uint256(10), uint256(20), uint256(30), uint256(40)], // Times per period
- abi.encode(uint256(4)), // Sortition extra data
- supportedDK
- );
-
- vm.expectRevert(KlerosCoreBase.UnsupportedDisputeKit.selector);
- vm.prank(governor);
- uint256[] memory emptySupportedDK = new uint256[](0);
- core.createCourt(
- GENERAL_COURT,
- true, // Hidden votes
- 2000, // min stake
- 10000, // alpha
- 0.03 ether, // fee for juror
- 50, // jurors for jump
- [uint256(10), uint256(20), uint256(30), uint256(40)], // Times per period
- abi.encode(uint256(4)), // Sortition extra data
- emptySupportedDK
- );
-
- vm.expectRevert(KlerosCoreBase.InvalidForkingCourtAsParent.selector);
- vm.prank(governor);
- core.createCourt(
- FORKING_COURT,
- true, // Hidden votes
- 2000, // min stake
- 10000, // alpha
- 0.03 ether, // fee for juror
- 50, // jurors for jump
- [uint256(10), uint256(20), uint256(30), uint256(40)], // Times per period
- abi.encode(uint256(4)), // Sortition extra data
- supportedDK
- );
-
- uint256[] memory badSupportedDK = new uint256[](2);
- badSupportedDK[0] = NULL_DISPUTE_KIT; // Include NULL_DK to check that it reverts
- badSupportedDK[1] = DISPUTE_KIT_CLASSIC;
- vm.expectRevert(KlerosCoreBase.WrongDisputeKitIndex.selector);
- vm.prank(governor);
- core.createCourt(
- GENERAL_COURT,
- true, // Hidden votes
- 2000, // min stake
- 10000, // alpha
- 0.03 ether, // fee for juror
- 50, // jurors for jump
- [uint256(10), uint256(20), uint256(30), uint256(40)], // Times per period
- abi.encode(uint256(4)), // Sortition extra data
- badSupportedDK
- );
-
- badSupportedDK[0] = DISPUTE_KIT_CLASSIC;
- badSupportedDK[1] = 2; // Check out of bounds index
- vm.expectRevert(KlerosCoreBase.WrongDisputeKitIndex.selector);
- vm.prank(governor);
- core.createCourt(
- GENERAL_COURT,
- true, // Hidden votes
- 2000, // min stake
- 10000, // alpha
- 0.03 ether, // fee for juror
- 50, // jurors for jump
- [uint256(10), uint256(20), uint256(30), uint256(40)], // Times per period
- abi.encode(uint256(4)), // Sortition extra data
- badSupportedDK
- );
-
- // Add new DK to check the requirement for classic DK
- DisputeKitSybilResistant newDK = new DisputeKitSybilResistant();
- vm.prank(governor);
- core.addNewDisputeKit(newDK);
- badSupportedDK = new uint256[](1);
- badSupportedDK[0] = 2; // Include only sybil resistant dk
- vm.expectRevert(KlerosCoreBase.MustSupportDisputeKitClassic.selector);
- vm.prank(governor);
- core.createCourt(
- GENERAL_COURT,
- true, // Hidden votes
- 2000, // min stake
- 10000, // alpha
- 0.03 ether, // fee for juror
- 50, // jurors for jump
- [uint256(10), uint256(20), uint256(30), uint256(40)], // Times per period
- abi.encode(uint256(4)), // Sortition extra data
- badSupportedDK
- );
-
- vm.prank(governor);
- vm.expectEmit(true, true, true, true);
- emit KlerosCoreBase.DisputeKitEnabled(2, DISPUTE_KIT_CLASSIC, true);
- vm.expectEmit(true, true, true, true);
- emit KlerosCoreBase.DisputeKitEnabled(2, 2, true);
- vm.expectEmit(true, true, true, true);
- emit KlerosCoreBase.CourtCreated(
- 2,
- GENERAL_COURT,
- true,
- 2000,
- 20000,
- 0.04 ether,
- 50,
- [uint256(10), uint256(20), uint256(30), uint256(40)], // Explicitly convert otherwise it throws
- supportedDK
- );
- core.createCourt(
- GENERAL_COURT,
- true, // Hidden votes
- 2000, // min stake
- 20000, // alpha
- 0.04 ether, // fee for juror
- 50, // jurors for jump
- [uint256(10), uint256(20), uint256(30), uint256(40)], // Times per period
- abi.encode(uint256(4)), // Sortition extra data
- supportedDK
- );
-
- (
- uint96 courtParent,
- bool courtHiddenVotes,
- uint256 courtMinStake,
- uint256 courtAlpha,
- uint256 courtFeeForJuror,
- uint256 courtJurorsForCourtJump,
- bool courtDisabled
- ) = core.courts(2);
- assertEq(courtParent, GENERAL_COURT, "Wrong court parent");
- assertEq(courtHiddenVotes, true, "Wrong hiddenVotes value");
- assertEq(courtMinStake, 2000, "Wrong minStake value");
- assertEq(courtAlpha, 20000, "Wrong alpha value");
- assertEq(courtFeeForJuror, 0.04 ether, "Wrong feeForJuror value");
- assertEq(courtJurorsForCourtJump, 50, "Wrong jurorsForCourtJump value");
- assertEq(courtDisabled, false, "Court should not be disabled");
-
- uint256[] memory children = core.getCourtChildren(2);
- assertEq(children.length, 0, "No children");
- uint256[4] memory courtTimesPerPeriod = core.getTimesPerPeriod(2);
- assertEq(courtTimesPerPeriod[0], uint256(10), "Wrong times per period 0");
- assertEq(courtTimesPerPeriod[1], uint256(20), "Wrong times per period 1");
- assertEq(courtTimesPerPeriod[2], uint256(30), "Wrong times per period 2");
- assertEq(courtTimesPerPeriod[3], uint256(40), "Wrong times per period 3");
-
- children = core.getCourtChildren(GENERAL_COURT); // Check that parent updated children
- assertEq(children.length, 1, "Wrong children count");
- assertEq(children[0], 2, "Wrong child id");
-
- (uint256 K, uint256 nodeLength) = sortitionModule.getSortitionProperties(bytes32(uint256(2)));
- assertEq(K, 4, "Wrong tree K of the new court");
- assertEq(nodeLength, 1, "Wrong node length for created tree of the new court");
- }
-
- function test_changeCourtParameters() public {
- // Create a 2nd court to check the minStake requirements
- vm.prank(governor);
- uint96 newCourtID = 2;
- uint256[] memory supportedDK = new uint256[](1);
- supportedDK[0] = DISPUTE_KIT_CLASSIC;
- core.createCourt(
- GENERAL_COURT,
- true, // Hidden votes
- 2000, // min stake
- 20000, // alpha
- 0.04 ether, // fee for juror
- 50, // jurors for jump
- [uint256(10), uint256(20), uint256(30), uint256(40)], // Times per period
- abi.encode(uint256(4)), // Sortition extra data
- supportedDK
- );
-
- vm.expectRevert(KlerosCoreBase.GovernorOnly.selector);
- vm.prank(other);
- core.changeCourtParameters(
- GENERAL_COURT,
- true, // Hidden votes
- 2000, // min stake
- 10000, // alpha
- 0.03 ether, // fee for juror
- 50, // jurors for jump
- [uint256(10), uint256(20), uint256(30), uint256(40)] // Times per period
- );
- vm.expectRevert(KlerosCoreBase.MinStakeLowerThanParentCourt.selector);
- vm.prank(governor);
- // Min stake of a parent became higher than of a child
- core.changeCourtParameters(
- GENERAL_COURT,
- true, // Hidden votes
- 3000, // min stake
- 10000, // alpha
- 0.03 ether, // fee for juror
- 50, // jurors for jump
- [uint256(10), uint256(20), uint256(30), uint256(40)] // Times per period
- );
- // Min stake of a child became lower than of a parent
- vm.expectRevert(KlerosCoreBase.MinStakeLowerThanParentCourt.selector);
- vm.prank(governor);
- core.changeCourtParameters(
- newCourtID,
- true, // Hidden votes
- 800, // min stake
- 10000, // alpha
- 0.03 ether, // fee for juror
- 50, // jurors for jump
- [uint256(10), uint256(20), uint256(30), uint256(40)] // Times per period
- );
-
- vm.prank(governor);
- vm.expectEmit(true, true, true, true);
- emit KlerosCoreBase.CourtModified(
- GENERAL_COURT,
- true,
- 2000,
- 20000,
- 0.04 ether,
- 50,
- [uint256(10), uint256(20), uint256(30), uint256(40)] // Explicitly convert otherwise it throws
- );
- core.changeCourtParameters(
- GENERAL_COURT,
- true, // Hidden votes
- 2000, // min stake
- 20000, // alpha
- 0.04 ether, // fee for juror
- 50, // jurors for jump
- [uint256(10), uint256(20), uint256(30), uint256(40)] // Times per period
- );
-
- (
- uint96 courtParent,
- bool courtHiddenVotes,
- uint256 courtMinStake,
- uint256 courtAlpha,
- uint256 courtFeeForJuror,
- uint256 courtJurorsForCourtJump,
- bool courtDisabled
- ) = core.courts(GENERAL_COURT);
- assertEq(courtHiddenVotes, true, "Wrong hiddenVotes value");
- assertEq(courtMinStake, 2000, "Wrong minStake value");
- assertEq(courtAlpha, 20000, "Wrong alpha value");
- assertEq(courtFeeForJuror, 0.04 ether, "Wrong feeForJuror value");
- assertEq(courtJurorsForCourtJump, 50, "Wrong jurorsForCourtJump value");
- assertEq(courtDisabled, false, "Court should not be disabled");
-
- uint256[4] memory courtTimesPerPeriod = core.getTimesPerPeriod(GENERAL_COURT);
- assertEq(courtTimesPerPeriod[0], uint256(10), "Wrong times per period 0");
- assertEq(courtTimesPerPeriod[1], uint256(20), "Wrong times per period 1");
- assertEq(courtTimesPerPeriod[2], uint256(30), "Wrong times per period 2");
- assertEq(courtTimesPerPeriod[3], uint256(40), "Wrong times per period 3");
- }
-
- function test_enableDisputeKits() public {
- DisputeKitSybilResistant newDK = new DisputeKitSybilResistant();
- uint256 newDkID = 2;
- vm.prank(governor);
- core.addNewDisputeKit(newDK);
-
- vm.expectRevert(KlerosCoreBase.GovernorOnly.selector);
- vm.prank(other);
- uint256[] memory supportedDK = new uint256[](1);
- supportedDK[0] = newDkID;
- core.enableDisputeKits(GENERAL_COURT, supportedDK, true);
-
- vm.expectRevert(KlerosCoreBase.WrongDisputeKitIndex.selector);
- vm.prank(governor);
- supportedDK[0] = NULL_DISPUTE_KIT;
- core.enableDisputeKits(GENERAL_COURT, supportedDK, true);
-
- vm.expectRevert(KlerosCoreBase.WrongDisputeKitIndex.selector);
- vm.prank(governor);
- supportedDK[0] = 3; // Out of bounds
- core.enableDisputeKits(GENERAL_COURT, supportedDK, true);
-
- vm.expectRevert(KlerosCoreBase.CannotDisableClassicDK.selector);
- vm.prank(governor);
- supportedDK[0] = DISPUTE_KIT_CLASSIC;
- core.enableDisputeKits(GENERAL_COURT, supportedDK, false);
-
- vm.prank(governor);
- vm.expectEmit(true, true, true, true);
- emit KlerosCoreBase.DisputeKitEnabled(GENERAL_COURT, newDkID, true);
- supportedDK[0] = newDkID;
- core.enableDisputeKits(GENERAL_COURT, supportedDK, true);
- assertEq(core.isSupported(GENERAL_COURT, newDkID), true, "New DK should be supported by General court");
-
- vm.prank(governor);
- vm.expectEmit(true, true, true, true);
- emit KlerosCoreBase.DisputeKitEnabled(GENERAL_COURT, newDkID, false);
- core.enableDisputeKits(GENERAL_COURT, supportedDK, false);
- assertEq(core.isSupported(GENERAL_COURT, newDkID), false, "New DK should be disabled in General court");
- }
-
- function test_changeAcceptedFeeTokens() public {
- vm.expectRevert(KlerosCoreBase.GovernorOnly.selector);
- vm.prank(other);
- core.changeAcceptedFeeTokens(feeToken, true);
-
- (bool accepted, , ) = core.currencyRates(feeToken);
- assertEq(accepted, false, "Token should not be accepted yet");
-
- vm.prank(governor);
- vm.expectEmit(true, true, true, true);
- emit IArbitratorV2.AcceptedFeeToken(feeToken, true);
- core.changeAcceptedFeeTokens(feeToken, true);
- (accepted, , ) = core.currencyRates(feeToken);
- assertEq(accepted, true, "Token should be accepted");
- }
-
- function test_changeCurrencyRates() public {
- vm.expectRevert(KlerosCoreBase.GovernorOnly.selector);
- vm.prank(other);
- core.changeCurrencyRates(feeToken, 100, 200);
-
- (, uint256 rateInEth, uint256 rateDecimals) = core.currencyRates(feeToken);
- assertEq(rateInEth, 0, "rateInEth should be 0");
- assertEq(rateDecimals, 0, "rateDecimals should be 0");
-
- vm.prank(governor);
- vm.expectEmit(true, true, true, true);
- emit IArbitratorV2.NewCurrencyRate(feeToken, 100, 200);
- core.changeCurrencyRates(feeToken, 100, 200);
-
- (, rateInEth, rateDecimals) = core.currencyRates(feeToken);
- assertEq(rateInEth, 100, "rateInEth is incorrect");
- assertEq(rateDecimals, 200, "rateDecimals is incorrect");
- }
-
- function test_extraDataToCourtIDMinJurorsDisputeKit() public {
- // Standard values
- bytes memory extraData = abi.encodePacked(uint256(GENERAL_COURT), DEFAULT_NB_OF_JURORS, DISPUTE_KIT_CLASSIC);
-
- (uint96 courtID, uint256 minJurors, uint256 disputeKitID) = core.extraDataToCourtIDMinJurorsDisputeKit(
- extraData
- );
- assertEq(courtID, GENERAL_COURT, "Wrong courtID");
- assertEq(minJurors, DEFAULT_NB_OF_JURORS, "Wrong minJurors");
- assertEq(disputeKitID, DISPUTE_KIT_CLASSIC, "Wrong disputeKitID");
-
- // Botched extraData. Values should fall into standard
- extraData = "0xfa";
-
- (courtID, minJurors, disputeKitID) = core.extraDataToCourtIDMinJurorsDisputeKit(extraData);
- assertEq(courtID, GENERAL_COURT, "Wrong courtID");
- assertEq(minJurors, DEFAULT_NB_OF_JURORS, "Wrong minJurors");
- assertEq(disputeKitID, DISPUTE_KIT_CLASSIC, "Wrong disputeKitID");
-
- // Custom values.
- vm.startPrank(governor);
- core.addNewDisputeKit(disputeKit);
- core.addNewDisputeKit(disputeKit);
- core.addNewDisputeKit(disputeKit);
- core.addNewDisputeKit(disputeKit);
- core.addNewDisputeKit(disputeKit);
- extraData = abi.encodePacked(uint256(50), uint256(41), uint256(6));
-
- (courtID, minJurors, disputeKitID) = core.extraDataToCourtIDMinJurorsDisputeKit(extraData);
- assertEq(courtID, GENERAL_COURT, "Wrong courtID"); // Value in extra data is out of scope so fall back
- assertEq(minJurors, 41, "Wrong minJurors");
- assertEq(disputeKitID, 6, "Wrong disputeKitID");
- }
-
- // *************************************** //
- // * Staking test * //
- // *************************************** //
-
- function test_setStake_increase() public {
- vm.prank(governor);
- core.pause();
- vm.expectRevert(KlerosCoreBase.WhenNotPausedOnly.selector);
- vm.prank(staker1);
- core.setStake(GENERAL_COURT, 1000);
- vm.prank(governor);
- core.unpause();
-
- vm.expectRevert(KlerosCoreBase.StakingNotPossibleInThisCourt.selector);
- vm.prank(staker1);
- core.setStake(FORKING_COURT, 1000);
-
- uint96 badCourtID = 2;
- vm.expectRevert(KlerosCoreBase.StakingNotPossibleInThisCourt.selector);
- vm.prank(staker1);
- core.setStake(badCourtID, 1000);
-
- vm.expectRevert(KlerosCoreBase.StakingLessThanCourtMinStake.selector);
- vm.prank(staker1);
- core.setStake(GENERAL_COURT, 800);
-
- vm.expectRevert(KlerosCoreBase.StakingZeroWhenNoStake.selector);
- vm.prank(staker1);
- core.setStake(GENERAL_COURT, 0);
-
- vm.prank(staker1);
- vm.expectEmit(true, true, true, true);
- emit SortitionModuleBase.StakeSet(staker1, GENERAL_COURT, 1001, 1001);
- core.setStake(GENERAL_COURT, 1001);
-
- (uint256 totalStaked, uint256 totalLocked, uint256 stakedInCourt, uint256 nbCourts) = sortitionModule
- .getJurorBalance(staker1, GENERAL_COURT);
- assertEq(totalStaked, 1001, "Wrong amount total staked");
- assertEq(totalLocked, 0, "Wrong amount locked");
- assertEq(stakedInCourt, 1001, "Wrong amount staked in court");
- assertEq(nbCourts, 1, "Wrong number of courts");
-
- uint96[] memory courts = sortitionModule.getJurorCourtIDs(staker1);
- assertEq(courts.length, 1, "Wrong courts count");
- assertEq(courts[0], GENERAL_COURT, "Wrong court id");
- assertEq(sortitionModule.isJurorStaked(staker1), true, "Juror should be staked");
-
- assertEq(pinakion.balanceOf(address(core)), 1001, "Wrong token balance of the core");
- assertEq(pinakion.balanceOf(staker1), 999999999999998999, "Wrong token balance of staker1"); // 1 eth - 1001 wei
- assertEq(pinakion.allowance(staker1, address(core)), 999999999999998999, "Wrong allowance for staker1");
-
- vm.expectRevert(KlerosCoreBase.StakingTransferFailed.selector); // This error will be caught because governor didn't approve any tokens for KlerosCore
- vm.prank(governor);
- core.setStake(GENERAL_COURT, 1000);
-
- // Increase stake one more time to verify the correct behavior
- vm.prank(staker1);
- vm.expectEmit(true, true, true, true);
- emit SortitionModuleBase.StakeSet(staker1, GENERAL_COURT, 2000, 2000);
- core.setStake(GENERAL_COURT, 2000);
-
- (totalStaked, totalLocked, stakedInCourt, nbCourts) = sortitionModule.getJurorBalance(staker1, GENERAL_COURT);
- assertEq(totalStaked, 2000, "Wrong amount total staked");
- assertEq(totalLocked, 0, "Wrong amount locked");
- assertEq(stakedInCourt, 2000, "Wrong amount staked in court");
- assertEq(nbCourts, 1, "Number of courts should not increase");
-
- assertEq(pinakion.balanceOf(address(core)), 2000, "Wrong token balance of the core");
- assertEq(pinakion.balanceOf(staker1), 999999999999998000, "Wrong token balance of staker1"); // 1 eth - 2000 wei
- assertEq(pinakion.allowance(staker1, address(core)), 999999999999998000, "Wrong allowance for staker1");
- }
-
- function test_setStake_decrease() public {
- vm.prank(staker1);
- core.setStake(GENERAL_COURT, 2000);
- assertEq(pinakion.balanceOf(address(core)), 2000, "Wrong token balance of the core");
- assertEq(pinakion.balanceOf(staker1), 999999999999998000, "Wrong token balance of staker1");
- assertEq(pinakion.allowance(staker1, address(core)), 999999999999998000, "Wrong allowance for staker1");
-
- vm.prank(staker1);
- core.setStake(GENERAL_COURT, 1500); // Decrease the stake to see if it's reflected correctly
- (uint256 totalStaked, uint256 totalLocked, uint256 stakedInCourt, uint256 nbCourts) = sortitionModule
- .getJurorBalance(staker1, GENERAL_COURT);
- assertEq(totalStaked, 1500, "Wrong amount total staked");
- assertEq(totalLocked, 0, "Wrong amount locked");
- assertEq(stakedInCourt, 1500, "Wrong amount staked in court");
- assertEq(nbCourts, 1, "Wrong number of courts");
-
- uint96[] memory courts = sortitionModule.getJurorCourtIDs(staker1);
- assertEq(courts.length, 1, "Wrong courts count");
- assertEq(courts[0], GENERAL_COURT, "Wrong court id");
- assertEq(sortitionModule.isJurorStaked(staker1), true, "Juror should be staked");
-
- assertEq(pinakion.balanceOf(address(core)), 1500, "Wrong token balance of the core");
- assertEq(pinakion.balanceOf(staker1), 999999999999998500, "Wrong token balance of staker1");
- assertEq(
- pinakion.allowance(staker1, address(core)),
- 999999999999998000,
- "Allowance should not change during withdrawal"
- );
-
- vm.prank(address(core));
- pinakion.transfer(staker1, 1); // Manually send 1 token to make the withdrawal fail
-
- vm.expectRevert(KlerosCoreBase.UnstakingTransferFailed.selector);
- vm.prank(staker1);
- core.setStake(GENERAL_COURT, 0);
-
- vm.prank(address(staker1));
- pinakion.transfer(address(core), 1); // Manually give the token back
- vm.prank(staker1);
- core.setStake(GENERAL_COURT, 0);
-
- (totalStaked, totalLocked, stakedInCourt, nbCourts) = sortitionModule.getJurorBalance(staker1, GENERAL_COURT);
- assertEq(totalStaked, 0, "Wrong amount total staked");
- assertEq(totalLocked, 0, "Wrong amount locked");
- assertEq(stakedInCourt, 0, "Wrong amount staked in court");
- assertEq(nbCourts, 0, "Wrong number of courts");
-
- courts = sortitionModule.getJurorCourtIDs(staker1);
- assertEq(courts.length, 0, "Wrong courts count");
- assertEq(sortitionModule.isJurorStaked(staker1), false, "Juror should not be staked");
-
- assertEq(pinakion.balanceOf(address(core)), 0, "Wrong token balance of the core");
- assertEq(pinakion.balanceOf(staker1), 1 ether, "Wrong token balance of staker1");
- assertEq(
- pinakion.allowance(staker1, address(core)),
- 999999999999998000,
- "Allowance should not change during withdrawal"
- );
- }
-
- function test_setStake_maxStakePathCheck() public {
- uint256[] memory supportedDK = new uint256[](1);
- supportedDK[0] = DISPUTE_KIT_CLASSIC;
-
- // Create 4 courts to check the require
- for (uint96 i = GENERAL_COURT; i <= 4; i++) {
- vm.prank(governor);
- core.createCourt(
- GENERAL_COURT,
- true,
- 2000,
- 20000,
- 0.04 ether,
- 50,
- [uint256(10), uint256(20), uint256(30), uint256(40)],
- abi.encode(uint256(4)),
- supportedDK
- );
- vm.prank(staker1);
- core.setStake(i, 2000);
- }
-
- uint96[] memory courts = sortitionModule.getJurorCourtIDs(staker1);
- assertEq(courts.length, 4, "Wrong courts count");
-
- uint96 excessiveCourtID = 5;
- vm.expectRevert(KlerosCoreBase.StakingInTooManyCourts.selector);
- vm.prank(staker1);
- core.setStake(excessiveCourtID, 2000);
- }
-
- function test_setStake_increaseDrawingPhase() public {
- // Set the stake and create a dispute to advance the phase
- vm.prank(staker1);
- core.setStake(GENERAL_COURT, 1000);
- vm.prank(disputer);
- arbitrable.createDispute{value: feeForJuror * DEFAULT_NB_OF_JURORS}("Action");
- assertEq(sortitionModule.disputesWithoutJurors(), 1, "Wrong disputesWithoutJurors count");
- vm.warp(block.timestamp + minStakingTime);
- sortitionModule.passPhase(); // Generating
- vm.roll(block.number + rngLookahead + 1);
- sortitionModule.passPhase(); // Drawing phase
-
- assertEq(pinakion.balanceOf(address(core)), 1000, "Wrong token balance of the core");
- assertEq(pinakion.balanceOf(staker1), 999999999999999000, "Wrong token balance of staker1");
- assertEq(uint256(sortitionModule.phase()), uint256(ISortitionModule.Phase.drawing), "Wrong phase");
-
- vm.prank(staker1);
- vm.expectEmit(true, true, true, true);
- emit SortitionModuleBase.StakeDelayed(staker1, GENERAL_COURT, 1500);
- core.setStake(GENERAL_COURT, 1500);
-
- uint256 delayedStakeId = sortitionModule.delayedStakeWriteIndex();
- assertEq(delayedStakeId, 1, "Wrong delayedStakeWriteIndex");
- assertEq(sortitionModule.delayedStakeReadIndex(), 1, "Wrong delayedStakeReadIndex");
- (address account, uint96 courtID, uint256 stake, bool alreadyTransferred) = sortitionModule.delayedStakes(
- delayedStakeId
- );
- assertEq(account, staker1, "Wrong staker account");
- assertEq(courtID, GENERAL_COURT, "Wrong court id");
- assertEq(stake, 1500, "Wrong amount staked in court");
- assertEq(alreadyTransferred, false, "Should be flagged as transferred");
-
- (uint256 totalStaked, uint256 totalLocked, uint256 stakedInCourt, uint256 nbCourts) = sortitionModule
- .getJurorBalance(staker1, GENERAL_COURT);
- assertEq(totalStaked, 1000, "Wrong amount total staked");
- assertEq(totalLocked, 0, "Wrong amount locked");
- assertEq(stakedInCourt, 1000, "Amount staked in court should not change until delayed stake is executed");
- assertEq(nbCourts, 1, "Wrong number of courts");
-
- uint96[] memory courts = sortitionModule.getJurorCourtIDs(staker1);
- assertEq(courts.length, 1, "Wrong courts count");
- assertEq(courts[0], GENERAL_COURT, "Wrong court id");
- assertEq(sortitionModule.isJurorStaked(staker1), true, "Juror should be staked");
-
- assertEq(pinakion.balanceOf(address(core)), 1000, "Wrong token balance of the core");
- assertEq(pinakion.balanceOf(staker1), 999999999999999000, "Wrong token balance of staker1");
- }
-
- function test_setStake_decreaseDrawingPhase() public {
- // Set the stake and create a dispute to advance the phase
- vm.prank(staker1);
- core.setStake(GENERAL_COURT, 2000);
- vm.prank(disputer);
- arbitrable.createDispute{value: feeForJuror * DEFAULT_NB_OF_JURORS}("Action");
- vm.warp(block.timestamp + minStakingTime);
- sortitionModule.passPhase(); // Generating
- vm.roll(block.number + rngLookahead + 1);
- sortitionModule.passPhase(); // Drawing phase
-
- assertEq(pinakion.balanceOf(address(core)), 2000, "Wrong token balance of the core");
- assertEq(pinakion.balanceOf(staker1), 999999999999998000, "Wrong token balance of staker1");
-
- vm.prank(staker1);
- vm.expectEmit(true, true, true, true);
- emit SortitionModuleBase.StakeDelayed(staker1, GENERAL_COURT, 1800);
- core.setStake(GENERAL_COURT, 1800);
-
- (uint256 totalStaked, , uint256 stakedInCourt, ) = sortitionModule.getJurorBalance(staker1, GENERAL_COURT);
- assertEq(totalStaked, 2000, "Total staked amount should not change");
- assertEq(stakedInCourt, 2000, "Amount staked in court should not change");
-
- assertEq(pinakion.balanceOf(address(core)), 2000, "Token balance of the core should not change");
- assertEq(pinakion.balanceOf(staker1), 999999999999998000, "Wrong token balance of staker1");
- }
-
- function test_setStake_LockedTokens() public {
- // Check that correct amount is taken when locked tokens amount exceeds the staked amount
- vm.prank(staker1);
- core.setStake(GENERAL_COURT, 10000);
- vm.prank(disputer);
- arbitrable.createDispute{value: feeForJuror * DEFAULT_NB_OF_JURORS}("Action");
- vm.warp(block.timestamp + minStakingTime);
- sortitionModule.passPhase(); // Generating
- vm.roll(block.number + rngLookahead + 1);
- sortitionModule.passPhase(); // Drawing phase
-
- uint256 disputeID = 0;
- core.draw(disputeID, DEFAULT_NB_OF_JURORS);
- (uint256 totalStaked, uint256 totalLocked, uint256 stakedInCourt, uint256 nbCourts) = sortitionModule
- .getJurorBalance(staker1, GENERAL_COURT);
- assertEq(totalStaked, 10000, "Wrong amount total staked");
- assertEq(totalLocked, 3000, "Wrong amount locked"); // 1000 per draw and the juror was drawn 3 times
- assertEq(stakedInCourt, 10000, "Wrong amount staked in court");
-
- sortitionModule.passPhase(); // Staking
-
- assertEq(pinakion.balanceOf(address(core)), 10000, "Wrong token balance of the core");
- assertEq(pinakion.balanceOf(staker1), 999999999999990000, "Wrong token balance of staker1");
-
- // Unstake to check that locked tokens won't be withdrawn
- vm.prank(staker1);
- core.setStake(GENERAL_COURT, 0);
-
- (totalStaked, totalLocked, stakedInCourt, nbCourts) = sortitionModule.getJurorBalance(staker1, GENERAL_COURT);
- assertEq(totalStaked, 3000, "Wrong amount total staked");
- assertEq(totalLocked, 3000, "Wrong amount locked");
- assertEq(stakedInCourt, 0, "Wrong amount staked in court");
- assertEq(nbCourts, 0, "Wrong amount staked in court");
-
- assertEq(pinakion.balanceOf(address(core)), 3000, "Wrong token balance of the core");
- assertEq(pinakion.balanceOf(staker1), 999999999999997000, "Wrong token balance of staker1");
-
- // Stake again to check the behaviour.
- vm.prank(staker1);
- core.setStake(GENERAL_COURT, 5000);
-
- (totalStaked, totalLocked, stakedInCourt, nbCourts) = sortitionModule.getJurorBalance(staker1, GENERAL_COURT);
- assertEq(totalStaked, 8000, "Wrong amount total staked"); // 5000 were added to the previous 3000.
- assertEq(totalLocked, 3000, "Wrong amount locked");
- assertEq(stakedInCourt, 5000, "Wrong amount staked in court");
- assertEq(nbCourts, 1, "Wrong amount staked in court");
-
- assertEq(pinakion.balanceOf(address(core)), 8000, "Wrong amount of tokens in Core");
- assertEq(pinakion.balanceOf(staker1), 999999999999992000, "Wrong token balance of staker1");
- }
-
- function test_executeDelayedStakes() public {
- // Stake as staker2 as well to diversify the execution of delayed stakes
- vm.prank(staker2);
- core.setStake(GENERAL_COURT, 10000);
-
- vm.expectRevert(bytes("No delayed stake to execute."));
- sortitionModule.executeDelayedStakes(5);
-
- // Set the stake and create a dispute to advance the phase
- vm.prank(disputer);
- arbitrable.createDispute{value: feeForJuror * DEFAULT_NB_OF_JURORS}("Action");
- vm.warp(block.timestamp + minStakingTime);
- sortitionModule.passPhase(); // Generating
- vm.roll(block.number + rngLookahead + 1);
- sortitionModule.passPhase(); // Drawing phase
- uint256 disputeID = 0;
- core.draw(disputeID, DEFAULT_NB_OF_JURORS);
-
- vm.expectRevert(bytes("Should be in Staking phase."));
- sortitionModule.executeDelayedStakes(5);
-
- // Create delayed stake
- vm.prank(staker1);
- vm.expectEmit(true, true, true, true);
- emit SortitionModuleBase.StakeDelayed(staker1, GENERAL_COURT, 1500);
- core.setStake(GENERAL_COURT, 1500);
-
- assertEq(pinakion.balanceOf(address(core)), 10000, "Wrong token balance of the core"); // Balance should not increase because the stake was delayed
- assertEq(pinakion.balanceOf(staker1), 1 ether, "Wrong token balance of staker1");
-
- // Create delayed stake for another staker
- vm.prank(staker2);
- vm.expectEmit(true, true, true, true);
- emit SortitionModuleBase.StakeDelayed(staker2, GENERAL_COURT, 0);
- core.setStake(GENERAL_COURT, 0);
- assertEq(pinakion.balanceOf(staker2), 999999999999990000, "Wrong token balance of staker2"); // Balance should not change since wrong phase
-
- // Create another delayed stake for staker1 on top of it to check the execution
- vm.prank(staker1);
- vm.expectEmit(true, true, true, true);
- emit SortitionModuleBase.StakeDelayed(staker1, GENERAL_COURT, 1800);
- core.setStake(GENERAL_COURT, 1800);
-
- assertEq(sortitionModule.delayedStakeWriteIndex(), 3, "Wrong delayedStakeWriteIndex");
- assertEq(sortitionModule.delayedStakeReadIndex(), 1, "Wrong delayedStakeReadIndex");
-
- (address account, uint96 courtID, uint256 stake, bool alreadyTransferred) = sortitionModule.delayedStakes(1);
-
- // Check each delayed stake
- assertEq(account, staker1, "Wrong staker account for the first delayed stake");
- assertEq(courtID, GENERAL_COURT, "Wrong court ID");
- assertEq(stake, 1500, "Wrong staking amount");
- assertEq(alreadyTransferred, false, "Should be false");
-
- (account, courtID, stake, alreadyTransferred) = sortitionModule.delayedStakes(2);
- assertEq(account, staker2, "Wrong staker2 account");
- assertEq(courtID, GENERAL_COURT, "Wrong court id for staker2");
- assertEq(stake, 0, "Wrong amount for delayed stake of staker2");
- assertEq(alreadyTransferred, false, "Should be false");
-
- (account, courtID, stake, alreadyTransferred) = sortitionModule.delayedStakes(3);
- assertEq(account, staker1, "Wrong staker1 account");
- assertEq(courtID, GENERAL_COURT, "Wrong court id for staker1");
- assertEq(stake, 1800, "Wrong amount for delayed stake of staker1");
- assertEq(alreadyTransferred, false, "Should be false");
-
- // So far the only amount transferred was 10000 by staker2. Staker 1 has two delayed stakes, for 1500 and 1800 pnk.
- assertEq(pinakion.balanceOf(address(core)), 10000, "Wrong token balance of the core");
- assertEq(pinakion.balanceOf(staker1), 1 ether, "Wrong token balance of staker1");
- assertEq(pinakion.balanceOf(staker2), 999999999999990000, "Wrong token balance of staker2");
-
- (uint256 totalStaked, uint256 totalLocked, uint256 stakedInCourt, uint256 nbCourts) = sortitionModule
- .getJurorBalance(staker1, GENERAL_COURT); // Only check the first staker to check how consecutive delayed stakes are handled.
- // Balances shouldn't be updated yet.
- assertEq(totalStaked, 0, "Wrong amount total staked");
- assertEq(totalLocked, 0, "Wrong amount locked");
- assertEq(stakedInCourt, 0, "Wrong amount staked in court");
- assertEq(nbCourts, 0, "Wrong number of courts");
-
- vm.warp(block.timestamp + minStakingTime);
- sortitionModule.passPhase(); // Staking. Delayed stakes can be executed now
-
- vm.prank(address(core));
- pinakion.transfer(governor, 10000); // Dispose of the tokens of 2nd staker to make the execution fail for the 2nd delayed stake
- assertEq(pinakion.balanceOf(address(core)), 0, "Wrong token balance of the core");
-
- // 2 events should be emitted but the 2nd stake supersedes the first one in the end.
- vm.expectEmit(true, true, true, true);
- emit SortitionModuleBase.StakeSet(staker1, GENERAL_COURT, 1500, 1500);
- vm.expectEmit(true, true, true, true);
- emit SortitionModuleBase.StakeSet(staker1, GENERAL_COURT, 1800, 1800);
- sortitionModule.executeDelayedStakes(20); // Deliberately ask for more iterations than needed
-
- assertEq(sortitionModule.delayedStakeWriteIndex(), 3, "Wrong delayedStakeWriteIndex");
- assertEq(sortitionModule.delayedStakeReadIndex(), 4, "Wrong delayedStakeReadIndex");
-
- // Check that delayed stakes are nullified
- for (uint i = 2; i <= sortitionModule.delayedStakeWriteIndex(); i++) {
- (account, courtID, stake, alreadyTransferred) = sortitionModule.delayedStakes(i);
-
- assertEq(account, address(0), "Wrong staker account after delayed stake deletion");
- assertEq(courtID, 0, "Court id should be nullified");
- assertEq(stake, 0, "No amount to stake");
- assertEq(alreadyTransferred, false, "Should be false");
- }
-
- assertEq(pinakion.balanceOf(staker1), 999999999999998200, "Wrong token balance of staker1");
-
- (totalStaked, totalLocked, stakedInCourt, nbCourts) = sortitionModule.getJurorBalance(staker1, GENERAL_COURT);
- assertEq(totalStaked, 1800, "Wrong amount total staked");
- assertEq(totalLocked, 0, "Wrong amount locked");
- assertEq(stakedInCourt, 1800, "Wrong amount staked in court");
- assertEq(nbCourts, 1, "Wrong amount staked in court");
-
- // Staker2 not getting the tokens back indicates that his delayed stake was skipped and the flow wasn't disrupted
- assertEq(pinakion.balanceOf(staker2), 999999999999990000, "Wrong token balance of staker2");
- }
-
- function test_setStakeBySortitionModule() public {
- // Note that functionality of this function was checked during delayed stakes execution
- vm.expectRevert(KlerosCoreBase.SortitionModuleOnly.selector);
- vm.prank(governor);
- core.setStakeBySortitionModule(staker1, GENERAL_COURT, 1000);
- }
-
- function test_setStake_snapshotProxyCheck() public {
- vm.prank(staker1);
- core.setStake(GENERAL_COURT, 12346);
-
- KlerosCoreSnapshotProxy snapshotProxy = new KlerosCoreSnapshotProxy(governor, IKlerosCore(address(core)));
- assertEq(snapshotProxy.name(), "Staked Pinakion", "Wrong name of the proxy token");
- assertEq(snapshotProxy.symbol(), "stPNK", "Wrong symbol of the proxy token");
- assertEq(snapshotProxy.decimals(), 18, "Wrong decimals of the proxy token");
- assertEq(snapshotProxy.governor(), msg.sender, "Wrong governor");
- assertEq(address(snapshotProxy.core()), address(core), "Wrong core in snapshot proxy");
- assertEq(snapshotProxy.balanceOf(staker1), 12346, "Wrong stPNK balance");
-
- vm.prank(other);
- vm.expectRevert(bytes("Access not allowed: Governor only."));
- snapshotProxy.changeCore(IKlerosCore(other));
- vm.prank(governor);
- snapshotProxy.changeCore(IKlerosCore(other));
- assertEq(address(snapshotProxy.core()), other, "Wrong core in snapshot proxy after change");
-
- vm.prank(other);
- vm.expectRevert(bytes("Access not allowed: Governor only."));
- snapshotProxy.changeGovernor(other);
- vm.prank(governor);
- snapshotProxy.changeGovernor(other);
- assertEq(snapshotProxy.governor(), other, "Wrong governor after change");
- }
-
- // *************************************** //
- // * Disputes * //
- // *************************************** //
-
- function test_createDispute_eth() public {
- // Create a new court and DK to test non-standard extra data
- uint256 newFee = 0.01 ether;
- uint96 newCourtID = 2;
- uint256 newNbJurors = 4;
- uint256 newDkID = 2;
- uint256[] memory supportedDK = new uint256[](1);
- supportedDK[0] = DISPUTE_KIT_CLASSIC;
- bytes memory newExtraData = abi.encodePacked(uint256(newCourtID), newNbJurors, newDkID);
-
- vm.prank(governor);
- core.addNewDisputeKit(disputeKit); // Just add the same dk to avoid dealing with initialization
- vm.prank(governor);
- core.createCourt(
- GENERAL_COURT,
- true, // Hidden votes
- 2000, // min stake
- 20000, // alpha
- newFee, // fee for juror
- 50, // jurors for jump
- [uint256(10), uint256(20), uint256(30), uint256(40)], // Times per period
- abi.encode(uint256(4)), // Sortition extra data
- supportedDK
- );
-
- arbitrable.changeArbitratorExtraData(newExtraData);
-
- vm.expectRevert(KlerosCoreBase.ArbitrationFeesNotEnough.selector);
- vm.prank(disputer);
- arbitrable.createDispute{value: newFee * newNbJurors - 1}("Action");
-
- vm.expectRevert(KlerosCoreBase.DisputeKitNotSupportedByCourt.selector);
- vm.prank(disputer);
- arbitrable.createDispute{value: 0.04 ether}("Action");
-
- vm.prank(governor);
- supportedDK = new uint256[](1);
- supportedDK[0] = newDkID;
- core.enableDisputeKits(newCourtID, supportedDK, true);
-
- uint256 disputeID = 0;
- uint256 nbChoices = 2;
- vm.prank(disputer);
- vm.expectEmit(true, true, true, true);
- emit DisputeKitClassicBase.DisputeCreation(disputeID, nbChoices, newExtraData);
- vm.expectEmit(true, true, true, true);
- emit IArbitratorV2.DisputeCreation(disputeID, arbitrable);
- arbitrable.createDispute{value: 0.04 ether}("Action");
-
- assertEq(sortitionModule.disputesWithoutJurors(), 1, "Wrong disputesWithoutJurors count");
- (
- uint96 courtID,
- IArbitrableV2 arbitrated,
- KlerosCoreBase.Period period,
- bool ruled,
- uint256 lastPeriodChange
- ) = core.disputes(disputeID);
-
- assertEq(courtID, newCourtID, "Wrong court ID");
- assertEq(address(arbitrated), address(arbitrable), "Wrong arbitrable");
- assertEq(uint256(period), uint256(KlerosCoreBase.Period.evidence), "Wrong period");
- assertEq(ruled, false, "Should not be ruled");
- assertEq(lastPeriodChange, block.timestamp, "Wrong lastPeriodChange");
-
- KlerosCoreBase.Round memory round = core.getRoundInfo(disputeID, 0);
- assertEq(round.disputeKitID, newDkID, "Wrong DK ID");
- assertEq(round.pnkAtStakePerJuror, 4000, "Wrong pnkAtStakePerJuror"); // minStake * alpha / divisor = 2000 * 20000/10000
- assertEq(round.totalFeesForJurors, 0.04 ether, "Wrong totalFeesForJurors");
- assertEq(round.nbVotes, 4, "Wrong nbVotes");
- assertEq(round.repartitions, 0, "repartitions should be 0");
- assertEq(round.pnkPenalties, 0, "pnkPenalties should be 0");
- assertEq(round.sumFeeRewardPaid, 0, "sumFeeRewardPaid should be 0");
- assertEq(round.sumPnkRewardPaid, 0, "sumPnkRewardPaid should be 0");
- assertEq(address(round.feeToken), address(0), "feeToken should be 0");
- assertEq(round.drawIterations, 0, "drawIterations should be 0");
-
- (uint256 numberOfChoices, bool jumped, bytes memory extraData) = disputeKit.disputes(disputeID);
-
- assertEq(numberOfChoices, 2, "Wrong numberOfChoices");
- assertEq(jumped, false, "jumped should be false");
- assertEq(extraData, newExtraData, "Wrong extra data");
- assertEq(disputeKit.coreDisputeIDToLocal(0), disputeID, "Wrong local disputeID");
- assertEq(disputeKit.coreDisputeIDToActive(0), true, "Wrong disputes length");
-
- (
- uint256 winningChoice,
- bool tied,
- uint256 totalVoted,
- uint256 totalCommited,
- uint256 nbVoters,
- uint256 choiceCount
- ) = disputeKit.getRoundInfo(0, 0, 0);
- assertEq(winningChoice, 0, "winningChoice should be 0");
- assertEq(tied, true, "tied should be true");
- assertEq(totalVoted, 0, "totalVoted should be 0");
- assertEq(totalCommited, 0, "totalCommited should be 0");
- assertEq(nbVoters, 0, "nbVoters should be 0");
- assertEq(choiceCount, 0, "choiceCount should be 0");
- }
-
- function test_createDispute_tokens() public {
- feeToken.transfer(disputer, 1 ether);
- vm.prank(disputer);
- feeToken.approve(address(arbitrable), 1 ether);
-
- vm.expectRevert(KlerosCoreBase.TokenNotAccepted.selector);
- vm.prank(disputer);
- arbitrable.createDispute("Action", 0.18 ether);
-
- vm.prank(governor);
- core.changeAcceptedFeeTokens(feeToken, true);
- vm.prank(governor);
- core.changeCurrencyRates(feeToken, 500, 3);
-
- vm.expectRevert(KlerosCoreBase.ArbitrationFeesNotEnough.selector);
- vm.prank(disputer);
- arbitrable.createDispute("Action", 0.18 ether - 1);
-
- vm.expectRevert(KlerosCoreBase.TransferFailed.selector);
- vm.prank(address(arbitrable)); // Bypass createDispute in arbitrable to avoid transfer checks there and make the arbitrable call KC directly
- core.createDispute(2, arbitratorExtraData, feeToken, 0.18 ether);
-
- assertEq(core.arbitrationCost(arbitratorExtraData, feeToken), 0.18 ether, "Wrong token cost");
- vm.prank(disputer);
- arbitrable.createDispute("Action", 0.18 ether);
-
- KlerosCoreBase.Round memory round = core.getRoundInfo(0, 0);
- assertEq(round.totalFeesForJurors, 0.18 ether, "Wrong totalFeesForJurors");
- assertEq(round.nbVotes, 3, "Wrong nbVotes");
- assertEq(address(round.feeToken), address(feeToken), "Wrong feeToken");
-
- assertEq(feeToken.balanceOf(address(core)), 0.18 ether, "Wrong token balance of the core");
- assertEq(feeToken.balanceOf(disputer), 0.82 ether, "Wrong token balance of the disputer");
- }
-
- function test_draw() public {
- uint256 disputeID = 0;
- uint256 roundID = 0;
-
- vm.prank(staker1);
- core.setStake(GENERAL_COURT, 1500);
- vm.prank(disputer);
- arbitrable.createDispute{value: feeForJuror * DEFAULT_NB_OF_JURORS}("Action");
- vm.warp(block.timestamp + minStakingTime);
- sortitionModule.passPhase(); // Generating
- vm.roll(block.number + rngLookahead + 1);
- sortitionModule.passPhase(); // Drawing phase
-
- vm.expectEmit(true, true, true, true);
- emit SortitionModuleBase.StakeLocked(staker1, 1000, false);
- vm.expectEmit(true, true, true, true);
- emit KlerosCoreBase.Draw(staker1, disputeID, roundID, 0); // VoteID = 0
-
- core.draw(disputeID, DEFAULT_NB_OF_JURORS); // Do 3 iterations and see that the juror will get drawn 3 times despite low stake.
-
- (uint256 totalStaked, uint256 totalLocked, uint256 stakedInCourt, ) = sortitionModule.getJurorBalance(
- staker1,
- GENERAL_COURT
- );
- assertEq(totalStaked, 1500, "Wrong amount total staked");
- assertEq(totalLocked, 3000, "Wrong amount locked"); // 1000 per draw
- assertEq(stakedInCourt, 1500, "Wrong amount staked in court");
- assertEq(sortitionModule.disputesWithoutJurors(), 0, "Wrong disputesWithoutJurors count");
-
- for (uint256 i = 0; i < DEFAULT_NB_OF_JURORS; i++) {
- (address account, bytes32 commit, uint256 choice, bool voted) = disputeKit.getVoteInfo(0, 0, i);
- assertEq(account, staker1, "Wrong drawn account");
- assertEq(commit, bytes32(0), "Commit should be empty");
- assertEq(choice, 0, "Choice should be empty");
- assertEq(voted, false, "Voted should be false");
- }
- }
-
- function test_draw_noEmptyAddresses() public {
- uint256 disputeID = 0;
- uint256 roundID = 0;
-
- vm.prank(disputer);
- arbitrable.createDispute{value: feeForJuror * DEFAULT_NB_OF_JURORS}("Action");
- vm.warp(block.timestamp + minStakingTime);
- sortitionModule.passPhase(); // Generating
- vm.roll(block.number + rngLookahead + 1);
- sortitionModule.passPhase(); // Drawing phase
-
- core.draw(disputeID, DEFAULT_NB_OF_JURORS); // No one is staked so check that the empty addresses are not drawn.
-
- KlerosCoreBase.Round memory round = core.getRoundInfo(disputeID, roundID);
- assertEq(round.drawIterations, 3, "Wrong drawIterations number");
-
- (, , , , uint256 nbVoters, ) = disputeKit.getRoundInfo(disputeID, roundID, 0);
- assertEq(nbVoters, 0, "nbVoters should be 0");
- }
-
- function test_draw_parentCourts() public {
- uint96 newCourtID = 2;
- uint256 disputeID = 0;
- uint256 roundID = 0;
-
- // Create a child court and stake exclusively there to check that parent courts hold drawing power.
- vm.prank(governor);
- uint256[] memory supportedDK = new uint256[](1);
- supportedDK[0] = DISPUTE_KIT_CLASSIC;
- core.createCourt(
- GENERAL_COURT,
- true, // Hidden votes
- 1000, // min stake
- 10000, // alpha
- 0.03 ether, // fee for juror
- 50, // jurors for jump
- [uint256(10), uint256(20), uint256(30), uint256(40)], // Times per period
- sortitionExtraData, // Sortition extra data
- supportedDK
- );
-
- uint256[] memory children = core.getCourtChildren(GENERAL_COURT);
- assertEq(children.length, 1, "Wrong children count");
- assertEq(children[0], 2, "Wrong child ID");
-
- vm.prank(staker1);
- core.setStake(newCourtID, 3000);
- vm.prank(disputer);
- arbitrable.createDispute{value: feeForJuror * DEFAULT_NB_OF_JURORS}("Action"); // Dispute uses general court by default
- vm.warp(block.timestamp + minStakingTime);
- sortitionModule.passPhase(); // Generating
- vm.roll(block.number + rngLookahead + 1);
- sortitionModule.passPhase(); // Drawing phase
-
- (uint96 courtID, , , , ) = core.disputes(disputeID);
- assertEq(courtID, GENERAL_COURT, "Wrong court ID of the dispute");
-
- vm.expectEmit(true, true, true, true);
- emit KlerosCoreBase.Draw(staker1, disputeID, roundID, 0);
- vm.expectEmit(true, true, true, true);
- emit KlerosCoreBase.Draw(staker1, disputeID, roundID, 1);
- vm.expectEmit(true, true, true, true);
- emit KlerosCoreBase.Draw(staker1, disputeID, roundID, 2);
- core.draw(disputeID, DEFAULT_NB_OF_JURORS);
-
- assertEq(sortitionModule.disputesWithoutJurors(), 0, "Wrong disputesWithoutJurors count");
-
- KlerosCoreBase.Round memory round = core.getRoundInfo(disputeID, roundID);
- assertEq(round.drawIterations, 3, "Wrong drawIterations number");
-
- (, , , , uint256 nbVoters, ) = disputeKit.getRoundInfo(disputeID, roundID, 0);
- assertEq(nbVoters, 3, "nbVoters should be 3");
- }
-
- function test_castCommit() public {
- // Change hidden votes in general court
- uint256 disputeID = 0;
- vm.prank(governor);
- core.changeCourtParameters(
- GENERAL_COURT,
- true, // Hidden votes
- 1000, // min stake
- 10000, // alpha
- 0.03 ether, // fee for juror
- 511, // jurors for jump
- [uint256(60), uint256(120), uint256(180), uint256(240)] // Times per period
- );
-
- vm.prank(staker1);
- core.setStake(GENERAL_COURT, 10000);
- vm.prank(disputer);
- arbitrable.createDispute{value: feeForJuror * DEFAULT_NB_OF_JURORS}("Action");
- vm.warp(block.timestamp + minStakingTime);
- sortitionModule.passPhase(); // Generating
- vm.roll(block.number + rngLookahead + 1);
- sortitionModule.passPhase(); // Drawing phase
- core.draw(disputeID, DEFAULT_NB_OF_JURORS);
-
- uint256 YES = 1;
- uint256 salt = 123455678;
- uint256[] memory voteIDs = new uint256[](1);
- voteIDs[0] = 0;
- bytes32 commit;
- vm.prank(staker1);
- vm.expectRevert(bytes("The dispute should be in Commit period."));
- disputeKit.castCommit(disputeID, voteIDs, commit);
-
- vm.expectRevert(KlerosCoreBase.EvidenceNotPassedAndNotAppeal.selector);
- core.passPeriod(disputeID);
- vm.warp(block.timestamp + timesPerPeriod[0]);
-
- vm.expectEmit(true, true, true, true);
- emit KlerosCoreBase.NewPeriod(disputeID, KlerosCoreBase.Period.commit);
- core.passPeriod(disputeID);
-
- (, , KlerosCoreBase.Period period, , uint256 lastPeriodChange) = core.disputes(disputeID);
-
- assertEq(uint256(period), uint256(KlerosCoreBase.Period.commit), "Wrong period");
- assertEq(lastPeriodChange, block.timestamp, "Wrong lastPeriodChange");
-
- vm.prank(staker1);
- vm.expectRevert(bytes("Empty commit."));
- disputeKit.castCommit(disputeID, voteIDs, commit);
-
- commit = keccak256(abi.encodePacked(YES, salt));
-
- vm.prank(other);
- vm.expectRevert(bytes("The caller has to own the vote."));
- disputeKit.castCommit(disputeID, voteIDs, commit);
-
- vm.prank(staker1);
- vm.expectEmit(true, true, true, true);
- emit DisputeKitClassicBase.CommitCast(disputeID, staker1, voteIDs, commit);
- disputeKit.castCommit(disputeID, voteIDs, commit);
-
- (, , , uint256 totalCommited, uint256 nbVoters, uint256 choiceCount) = disputeKit.getRoundInfo(disputeID, 0, 0);
- assertEq(totalCommited, 1, "totalCommited should be 1");
- assertEq(disputeKit.areCommitsAllCast(disputeID), false, "Commits should not all be cast");
-
- (, bytes32 commitStored, , ) = disputeKit.getVoteInfo(0, 0, 0);
- assertEq(commitStored, keccak256(abi.encodePacked(YES, salt)), "Incorrect commit");
-
- voteIDs = new uint256[](2); // Create the leftover votes subset
- voteIDs[0] = 1;
- voteIDs[1] = 2;
-
- vm.prank(staker1);
- vm.expectEmit(true, true, true, true);
- emit DisputeKitClassicBase.CommitCast(disputeID, staker1, voteIDs, commit);
- disputeKit.castCommit(disputeID, voteIDs, commit);
-
- (, , , totalCommited, nbVoters, choiceCount) = disputeKit.getRoundInfo(disputeID, 0, 0);
- assertEq(totalCommited, DEFAULT_NB_OF_JURORS, "totalCommited should be 3");
- assertEq(disputeKit.areCommitsAllCast(disputeID), true, "Commits should all be cast");
-
- for (uint256 i = 1; i < DEFAULT_NB_OF_JURORS; i++) {
- (, commitStored, , ) = disputeKit.getVoteInfo(0, 0, i);
- assertEq(commitStored, keccak256(abi.encodePacked(YES, salt)), "Incorrect commit");
- }
-
- // Check reveal in the next period
- core.passPeriod(disputeID);
-
- // Check the require with the wrong choice and then with the wrong salt
- vm.prank(staker1);
- vm.expectRevert(bytes("The vote hash must match the commitment in courts with hidden votes."));
- disputeKit.castVote(disputeID, voteIDs, 2, salt, "XYZ");
-
- vm.prank(staker1);
- vm.expectRevert(bytes("The vote hash must match the commitment in courts with hidden votes."));
- disputeKit.castVote(disputeID, voteIDs, YES, salt - 1, "XYZ");
-
- vm.prank(staker1);
- disputeKit.castVote(disputeID, voteIDs, YES, salt, "XYZ");
-
- for (uint256 i = 1; i < DEFAULT_NB_OF_JURORS; i++) {
- // 0 voteID was skipped when casting a vote
- (address account, , uint256 choice, bool voted) = disputeKit.getVoteInfo(0, 0, i);
- assertEq(account, staker1, "Wrong drawn account");
- assertEq(choice, YES, "Wrong choice");
- assertEq(voted, true, "Voted should be true");
- }
- }
-
- function test_castCommit_timeoutCheck() public {
- // Change hidden votes in general court
- uint256 disputeID = 0;
- vm.prank(governor);
- core.changeCourtParameters(
- GENERAL_COURT,
- true, // Hidden votes
- 1000, // min stake
- 10000, // alpha
- 0.03 ether, // fee for juror
- 511, // jurors for jump
- [uint256(60), uint256(120), uint256(180), uint256(240)] // Times per period
- );
-
- vm.prank(staker1);
- core.setStake(GENERAL_COURT, 10000);
- vm.prank(disputer);
- arbitrable.createDispute{value: feeForJuror * DEFAULT_NB_OF_JURORS}("Action");
- vm.warp(block.timestamp + minStakingTime);
- sortitionModule.passPhase(); // Generating
- vm.roll(block.number + rngLookahead + 1);
- sortitionModule.passPhase(); // Drawing phase
- core.draw(disputeID, DEFAULT_NB_OF_JURORS);
-
- vm.warp(block.timestamp + timesPerPeriod[0]);
- core.passPeriod(disputeID); // Commit
-
- vm.expectRevert(KlerosCoreBase.CommitPeriodNotPassed.selector);
- core.passPeriod(disputeID);
-
- vm.warp(block.timestamp + timesPerPeriod[1]);
- vm.expectEmit(true, true, true, true);
- emit KlerosCoreBase.NewPeriod(disputeID, KlerosCoreBase.Period.vote);
- core.passPeriod(disputeID);
- }
-
- function test_castVote() public {
- uint256 disputeID = 0;
-
- vm.prank(staker1);
- core.setStake(GENERAL_COURT, 10000);
- vm.prank(disputer);
- arbitrable.createDispute{value: feeForJuror * DEFAULT_NB_OF_JURORS}("Action");
- vm.warp(block.timestamp + minStakingTime);
- sortitionModule.passPhase(); // Generating
- vm.roll(block.number + rngLookahead + 1);
- sortitionModule.passPhase(); // Drawing phase
-
- core.draw(disputeID, DEFAULT_NB_OF_JURORS - 1); // Draw less to check the require later
- vm.warp(block.timestamp + timesPerPeriod[0]);
-
- uint256[] memory voteIDs = new uint256[](0);
- vm.prank(staker1);
- vm.expectRevert(bytes("The dispute should be in Vote period."));
- disputeKit.castVote(disputeID, voteIDs, 2, 0, "XYZ"); // Leave salt empty as not needed
-
- vm.expectRevert(KlerosCoreBase.DisputeStillDrawing.selector);
- core.passPeriod(disputeID);
-
- core.draw(disputeID, 1); // Draw the last juror
-
- vm.expectEmit(true, true, true, true);
- emit KlerosCoreBase.NewPeriod(disputeID, KlerosCoreBase.Period.vote);
- core.passPeriod(disputeID); // Vote
-
- (, , KlerosCoreBase.Period period, , uint256 lastPeriodChange) = core.disputes(disputeID);
-
- assertEq(uint256(period), uint256(KlerosCoreBase.Period.vote), "Wrong period");
- assertEq(lastPeriodChange, block.timestamp, "Wrong lastPeriodChange");
-
- vm.prank(staker1);
- vm.expectRevert(bytes("No voteID provided"));
- disputeKit.castVote(disputeID, voteIDs, 2, 0, "XYZ");
-
- voteIDs = new uint256[](1);
- voteIDs[0] = 0; // Split vote IDs to see how the winner changes
- vm.prank(staker1);
- vm.expectRevert(bytes("Choice out of bounds"));
- disputeKit.castVote(disputeID, voteIDs, 2 + 1, 0, "XYZ");
-
- vm.prank(other);
- vm.expectRevert(bytes("The juror has to own the vote."));
- disputeKit.castVote(disputeID, voteIDs, 2, 0, "XYZ");
-
- vm.prank(staker1);
- vm.expectEmit(true, true, true, true);
- emit IDisputeKit.VoteCast(disputeID, staker1, voteIDs, 2, "XYZ");
- disputeKit.castVote(disputeID, voteIDs, 2, 0, "XYZ");
-
- vm.prank(staker1);
- vm.expectRevert(bytes("Vote already cast."));
- disputeKit.castVote(disputeID, voteIDs, 2, 0, "XYZ");
-
- (
- uint256 winningChoice,
- bool tied,
- uint256 totalVoted,
- uint256 totalCommited,
- ,
- uint256 choiceCount
- ) = disputeKit.getRoundInfo(disputeID, 0, 2);
- assertEq(winningChoice, 2, "Wrong winning choice");
- assertEq(tied, false, "tied should be false");
- assertEq(totalVoted, 1, "totalVoted should be 1");
- assertEq(totalCommited, 0, "totalCommited should be 0");
- assertEq(choiceCount, 1, "choiceCount should be 1");
-
- (address account, bytes32 commit, uint256 choice, bool voted) = disputeKit.getVoteInfo(0, 0, 0); // Dispute - Round - VoteID
- assertEq(account, staker1, "Wrong drawn account");
- assertEq(commit, bytes32(0), "Commit should be empty");
- assertEq(choice, 2, "Choice should be 2");
- assertEq(voted, true, "Voted should be true");
-
- assertEq(disputeKit.isVoteActive(0, 0, 0), true, "Vote should be active"); // Dispute - Round - VoteID
-
- voteIDs = new uint256[](1);
- voteIDs[0] = 1; // Cast another vote to check the tie.
-
- vm.prank(staker1);
- vm.expectEmit(true, true, true, true);
- emit IDisputeKit.VoteCast(disputeID, staker1, voteIDs, 1, "XYZZ");
- disputeKit.castVote(disputeID, voteIDs, 1, 0, "XYZZ");
-
- (, tied, totalVoted, , , choiceCount) = disputeKit.getRoundInfo(disputeID, 0, 1);
- assertEq(tied, true, "tied should be true");
- assertEq(totalVoted, 2, "totalVoted should be 2");
- assertEq(choiceCount, 1, "choiceCount should be 1 for first choice");
-
- vm.expectRevert(KlerosCoreBase.VotePeriodNotPassed.selector);
- core.passPeriod(disputeID);
-
- voteIDs = new uint256[](1);
- voteIDs[0] = 2; // Cast another vote to declare a new winner.
-
- vm.prank(staker1);
- vm.expectEmit(true, true, true, true);
- emit IDisputeKit.VoteCast(disputeID, staker1, voteIDs, 1, "XYZZ");
- disputeKit.castVote(disputeID, voteIDs, 1, 0, "XYZZ");
-
- (winningChoice, tied, totalVoted, , , choiceCount) = disputeKit.getRoundInfo(disputeID, 0, 1);
- assertEq(winningChoice, 1, "Wrong winning choice");
- assertEq(tied, false, "tied should be false");
- assertEq(totalVoted, 3, "totalVoted should be 3");
- assertEq(choiceCount, 2, "choiceCount should be 2 for first choice");
- assertEq(disputeKit.areVotesAllCast(disputeID), true, "Votes should all be cast");
- }
-
- function test_castVote_timeoutCheck() public {
- // Change hidden votes in general court
- uint256 disputeID = 0;
- vm.prank(staker1);
- core.setStake(GENERAL_COURT, 10000);
- vm.prank(disputer);
- arbitrable.createDispute{value: feeForJuror * DEFAULT_NB_OF_JURORS}("Action");
- vm.warp(block.timestamp + minStakingTime);
- sortitionModule.passPhase(); // Generating
- vm.roll(block.number + rngLookahead + 1);
- sortitionModule.passPhase(); // Drawing phase
- core.draw(disputeID, DEFAULT_NB_OF_JURORS);
-
- vm.warp(block.timestamp + timesPerPeriod[0]);
- core.passPeriod(disputeID); // Votes
-
- vm.expectRevert(KlerosCoreBase.VotePeriodNotPassed.selector);
- core.passPeriod(disputeID);
-
- vm.warp(block.timestamp + timesPerPeriod[2]);
- vm.expectEmit(true, true, true, true);
- emit KlerosCoreBase.AppealPossible(disputeID, arbitrable);
- vm.expectEmit(true, true, true, true);
- emit KlerosCoreBase.NewPeriod(disputeID, KlerosCoreBase.Period.appeal);
- core.passPeriod(disputeID);
- }
-
- function test_castVote_rulingCheck() public {
- // Change hidden votes in general court
- uint256 disputeID = 0;
- vm.prank(staker1);
- core.setStake(GENERAL_COURT, 10000);
- vm.prank(disputer);
- arbitrable.createDispute{value: feeForJuror * DEFAULT_NB_OF_JURORS}("Action");
- vm.warp(block.timestamp + minStakingTime);
- sortitionModule.passPhase(); // Generating
- vm.roll(block.number + rngLookahead + 1);
- sortitionModule.passPhase(); // Drawing phase
- core.draw(disputeID, DEFAULT_NB_OF_JURORS);
-
- vm.warp(block.timestamp + timesPerPeriod[0]);
- core.passPeriod(disputeID); // Votes
-
- uint256[] memory voteIDs = new uint256[](3);
- voteIDs[0] = 0;
- voteIDs[1] = 1;
- voteIDs[2] = 2;
-
- vm.prank(staker1);
- disputeKit.castVote(disputeID, voteIDs, 1, 0, "XYZZ");
-
- (uint256 ruling, bool tied, bool overridden) = disputeKit.currentRuling(disputeID);
- assertEq(ruling, 1, "Wrong ruling");
- assertEq(tied, false, "Not tied");
- assertEq(overridden, false, "Not overridden");
- }
-
- function test_castVote_quickPassPeriod() public {
- // Change hidden votes in general court
- uint256 disputeID = 0;
- vm.prank(governor);
- core.changeCourtParameters(
- GENERAL_COURT,
- true, // Hidden votes
- 1000, // min stake
- 10000, // alpha
- 0.03 ether, // fee for juror
- 511, // jurors for jump
- [uint256(60), uint256(120), uint256(180), uint256(240)] // Times per period
- );
-
- vm.prank(staker1);
- core.setStake(GENERAL_COURT, 10000);
- vm.prank(disputer);
- arbitrable.createDispute{value: feeForJuror * DEFAULT_NB_OF_JURORS}("Action");
- vm.warp(block.timestamp + minStakingTime);
- sortitionModule.passPhase(); // Generating
- vm.roll(block.number + rngLookahead + 1);
- sortitionModule.passPhase(); // Drawing phase
- core.draw(disputeID, DEFAULT_NB_OF_JURORS);
-
- uint256 YES = 1;
- uint256 salt = 123455678;
- uint256[] memory voteIDs = new uint256[](1);
- voteIDs[0] = 0;
- bytes32 commit;
-
- vm.warp(block.timestamp + timesPerPeriod[0]);
- core.passPeriod(disputeID);
-
- commit = keccak256(abi.encodePacked(YES, salt));
-
- vm.prank(staker1);
- disputeKit.castCommit(disputeID, voteIDs, commit);
-
- (, , , uint256 totalCommited, uint256 nbVoters, uint256 choiceCount) = disputeKit.getRoundInfo(disputeID, 0, 0);
- assertEq(totalCommited, 1, "totalCommited should be 1");
- assertEq(disputeKit.areCommitsAllCast(disputeID), false, "Commits should not all be cast");
-
- vm.warp(block.timestamp + timesPerPeriod[1]);
- core.passPeriod(disputeID);
-
- vm.prank(staker1);
- disputeKit.castVote(disputeID, voteIDs, YES, salt, "XYZ");
-
- (, , uint256 totalVoted, , , ) = disputeKit.getRoundInfo(disputeID, 0, 0);
- assertEq(totalVoted, 1, "totalVoted should be 1");
- assertEq(disputeKit.areVotesAllCast(disputeID), true, "Every committed vote was cast");
-
- // Should pass period by counting only committed votes.
- vm.expectEmit(true, true, true, true);
- emit KlerosCoreBase.NewPeriod(disputeID, KlerosCoreBase.Period.appeal);
- core.passPeriod(disputeID);
- }
-
- function test_appeal_fundOneSide() public {
- uint256 disputeID = 0;
- vm.deal(address(disputeKit), 1 ether);
- vm.deal(staker1, 1 ether);
-
- vm.prank(staker1);
- core.setStake(GENERAL_COURT, 10000);
- vm.prank(disputer);
- arbitrable.createDispute{value: feeForJuror * DEFAULT_NB_OF_JURORS}("Action");
- vm.warp(block.timestamp + minStakingTime);
- sortitionModule.passPhase(); // Generating
- vm.roll(block.number + rngLookahead + 1);
- sortitionModule.passPhase(); // Drawing phase
-
- core.draw(disputeID, DEFAULT_NB_OF_JURORS);
- vm.warp(block.timestamp + timesPerPeriod[0]);
- core.passPeriod(disputeID); // Vote
-
- uint256[] memory voteIDs = new uint256[](3);
- voteIDs[0] = 0;
- voteIDs[1] = 1;
- voteIDs[2] = 2;
-
- vm.prank(staker1);
- disputeKit.castVote(disputeID, voteIDs, 2, 0, "XYZ");
-
- (uint256 start, uint256 end) = core.appealPeriod(0);
- assertEq(start, 0, "Appeal period start should be 0");
- assertEq(end, 0, "Appeal period end should be 0");
-
- // Simulate the call from dispute kit to check the requires unrelated to caller
- vm.prank(address(disputeKit));
- vm.expectRevert(KlerosCoreBase.DisputeNotAppealable.selector);
- core.appeal{value: 0.21 ether}(disputeID, 2, arbitratorExtraData);
-
- vm.expectEmit(true, true, true, true);
- emit KlerosCoreBase.AppealPossible(disputeID, arbitrable);
- vm.expectEmit(true, true, true, true);
- emit KlerosCoreBase.NewPeriod(disputeID, KlerosCoreBase.Period.appeal);
- core.passPeriod(disputeID);
-
- (, , KlerosCoreBase.Period period, , uint256 lastPeriodChange) = core.disputes(disputeID);
- (start, end) = core.appealPeriod(0);
- assertEq(uint256(period), uint256(KlerosCoreBase.Period.appeal), "Wrong period");
- assertEq(lastPeriodChange, block.timestamp, "Wrong lastPeriodChange");
- assertEq(core.appealCost(0), 0.21 ether, "Wrong appealCost");
- assertEq(start, lastPeriodChange, "Appeal period start is incorrect");
- assertEq(end, lastPeriodChange + timesPerPeriod[3], "Appeal period end is incorrect");
-
- vm.expectRevert(KlerosCoreBase.AppealPeriodNotPassed.selector);
- core.passPeriod(disputeID);
-
- // Simulate the call from dispute kit to check the requires unrelated to caller
- vm.prank(address(disputeKit));
- vm.expectRevert(KlerosCoreBase.AppealFeesNotEnough.selector);
- core.appeal{value: 0.21 ether - 1}(disputeID, 2, arbitratorExtraData);
- vm.deal(address(disputeKit), 0); // Nullify the balance so it doesn't get in the way.
-
- vm.prank(staker1);
- vm.expectRevert(KlerosCoreBase.DisputeKitOnly.selector);
- core.appeal{value: 0.21 ether}(disputeID, 2, arbitratorExtraData);
-
- vm.prank(crowdfunder1);
- vm.expectRevert(bytes("There is no such ruling to fund."));
- disputeKit.fundAppeal(disputeID, 3);
-
- vm.prank(crowdfunder1);
- vm.expectEmit(true, true, true, true);
- emit DisputeKitClassicBase.Contribution(disputeID, 0, 1, crowdfunder1, 0.21 ether);
- disputeKit.fundAppeal{value: 0.21 ether}(disputeID, 1); // Fund the losing choice. Total cost will be 0.63 (0.21 + 0.21 * (20000/10000))
-
- assertEq(crowdfunder1.balance, 9.79 ether, "Wrong balance of the crowdfunder");
- assertEq(address(disputeKit).balance, 0.21 ether, "Wrong balance of the DK");
- assertEq((disputeKit.getFundedChoices(disputeID)).length, 0, "No funded choices");
-
- vm.prank(crowdfunder1);
- vm.expectEmit(true, true, true, true);
- emit DisputeKitClassicBase.Contribution(disputeID, 0, 1, crowdfunder1, 0.42 ether);
- vm.expectEmit(true, true, true, true);
- emit DisputeKitClassicBase.ChoiceFunded(disputeID, 0, 1);
- disputeKit.fundAppeal{value: 5 ether}(disputeID, 1); // Deliberately overpay to check reimburse
-
- assertEq(crowdfunder1.balance, 9.37 ether, "Wrong balance of the crowdfunder");
- assertEq(address(disputeKit).balance, 0.63 ether, "Wrong balance of the DK");
- assertEq((disputeKit.getFundedChoices(disputeID)).length, 1, "One choice should be funded");
- assertEq((disputeKit.getFundedChoices(disputeID))[0], 1, "Incorrect funded choice");
-
- vm.prank(crowdfunder1);
- vm.expectRevert(bytes("Appeal fee is already paid."));
- disputeKit.fundAppeal(disputeID, 1);
- }
-
- function test_appeal_timeoutCheck() public {
- uint256 disputeID = 0;
-
- vm.prank(staker1);
- core.setStake(GENERAL_COURT, 10000);
- vm.prank(disputer);
- arbitrable.createDispute{value: feeForJuror * DEFAULT_NB_OF_JURORS}("Action");
- vm.warp(block.timestamp + minStakingTime);
- sortitionModule.passPhase(); // Generating
- vm.roll(block.number + rngLookahead + 1);
- sortitionModule.passPhase(); // Drawing phase
-
- core.draw(disputeID, DEFAULT_NB_OF_JURORS);
- vm.warp(block.timestamp + timesPerPeriod[0]);
- core.passPeriod(disputeID); // Vote
-
- uint256[] memory voteIDs = new uint256[](3);
- voteIDs[0] = 0;
- voteIDs[1] = 1;
- voteIDs[2] = 2;
-
- vm.prank(staker1);
- disputeKit.castVote(disputeID, voteIDs, 2, 0, "XYZ");
-
- vm.prank(crowdfunder1);
- vm.expectRevert(bytes("Appeal period is over.")); // Appeal period not started yet
- disputeKit.fundAppeal{value: 0.1 ether}(disputeID, 1);
- core.passPeriod(disputeID);
-
- (uint256 start, uint256 end) = core.appealPeriod(0);
-
- vm.prank(crowdfunder1);
- vm.warp(block.timestamp + ((end - start) / 2 + 1));
- vm.expectRevert(bytes("Appeal period is over for loser"));
- disputeKit.fundAppeal{value: 0.1 ether}(disputeID, 1); // Losing choice
-
- disputeKit.fundAppeal(disputeID, 2); // Winning choice funding should not revert yet
-
- vm.prank(crowdfunder1);
- vm.warp(block.timestamp + (end - start) / 2); // Warp one more to cover the whole period
- vm.expectRevert(bytes("Appeal period is over."));
- disputeKit.fundAppeal{value: 0.1 ether}(disputeID, 2);
- }
-
- function test_appeal_fullFundingNoSwitch() public {
- uint256 disputeID = 0;
-
- vm.prank(staker1);
- core.setStake(GENERAL_COURT, 20000);
- vm.prank(disputer);
- arbitrable.createDispute{value: feeForJuror * DEFAULT_NB_OF_JURORS}("Action");
- vm.warp(block.timestamp + minStakingTime);
- sortitionModule.passPhase(); // Generating
- vm.roll(block.number + rngLookahead + 1);
- sortitionModule.passPhase(); // Drawing phase
-
- core.draw(disputeID, DEFAULT_NB_OF_JURORS);
- vm.warp(block.timestamp + timesPerPeriod[0]);
- core.passPeriod(disputeID); // Vote
-
- uint256[] memory voteIDs = new uint256[](3);
- voteIDs[0] = 0;
- voteIDs[1] = 1;
- voteIDs[2] = 2;
-
- vm.prank(staker1);
- disputeKit.castVote(disputeID, voteIDs, 2, 0, "XYZ");
-
- core.passPeriod(disputeID); // Appeal
-
- vm.prank(crowdfunder1);
- disputeKit.fundAppeal{value: 0.63 ether}(disputeID, 1);
-
- vm.prank(crowdfunder2);
- vm.expectEmit(true, true, true, true);
- emit KlerosCoreBase.AppealDecision(disputeID, arbitrable);
- vm.expectEmit(true, true, true, true);
- emit KlerosCoreBase.NewPeriod(disputeID, KlerosCoreBase.Period.evidence);
- disputeKit.fundAppeal{value: 0.42 ether}(disputeID, 2);
-
- assertEq((disputeKit.getFundedChoices(disputeID)).length, 0, "No funded choices in the fresh round");
- (uint256 ruling, bool tied, bool overridden) = disputeKit.currentRuling(disputeID);
- assertEq(ruling, 0, "Should be 0 ruling in the fresh round");
- assertEq(tied, true, "Should be tied");
- assertEq(overridden, false, "Not overridden");
-
- assertEq(address(disputeKit).balance, 0.84 ether, "Wrong balance of the DK"); // 0.63 + 0.42 - 0.21
- assertEq(address(core).balance, 0.3 ether, "Wrong balance of the core"); // 0.09 arbFee + 0.21 appealFee
-
- assertEq(sortitionModule.disputesWithoutJurors(), 1, "Wrong disputesWithoutJurors count after appeal");
- assertEq(core.getNumberOfRounds(disputeID), 2, "Wrong number of rounds");
-
- (, , KlerosCoreBase.Period period, , uint256 lastPeriodChange) = core.disputes(disputeID);
- assertEq(uint256(period), uint256(KlerosCoreBase.Period.evidence), "Wrong period");
- assertEq(lastPeriodChange, block.timestamp, "Wrong lastPeriodChange");
-
- KlerosCoreBase.Round memory round = core.getRoundInfo(disputeID, 1); // Check the new round
- assertEq(round.pnkAtStakePerJuror, 1000, "Wrong pnkAtStakePerJuror");
- assertEq(round.totalFeesForJurors, 0.21 ether, "Wrong totalFeesForJurors");
- assertEq(round.nbVotes, 7, "Wrong nbVotes");
-
- core.draw(disputeID, 7);
- emit KlerosCoreBase.NewPeriod(disputeID, KlerosCoreBase.Period.vote); // Check that we don't have to wait for the timeout to pass the evidence period after appeal
- core.passPeriod(disputeID);
- }
-
- function test_appeal_fullFundingDKCourtSwitch() public {
- uint256 disputeID = 0;
- DisputeKitClassic dkLogic = new DisputeKitClassic();
- // Create a new DK and court to check the switch
- bytes memory initDataDk = abi.encodeWithSignature(
- "initialize(address,address,address)",
- governor,
- address(core),
- address(wNative)
- );
-
- UUPSProxy proxyDk = new UUPSProxy(address(dkLogic), initDataDk);
- DisputeKitClassic newDisputeKit = DisputeKitClassic(address(proxyDk));
-
- uint96 newCourtID = 2;
- uint256 newDkID = 2;
- uint256[] memory supportedDK = new uint256[](1);
- supportedDK[0] = DISPUTE_KIT_CLASSIC;
- bytes memory newExtraData = abi.encodePacked(uint256(newCourtID), DEFAULT_NB_OF_JURORS, newDkID);
-
- vm.prank(governor);
- core.addNewDisputeKit(newDisputeKit);
- vm.prank(governor);
- core.createCourt(
- GENERAL_COURT,
- hiddenVotes,
- minStake,
- alpha,
- feeForJuror,
- 3, // jurors for jump. Low number to ensure jump after the first appeal
- [uint256(60), uint256(120), uint256(180), uint256(240)], // Times per period
- sortitionExtraData,
- supportedDK
- );
-
- arbitrable.changeArbitratorExtraData(newExtraData);
-
- vm.prank(governor);
- supportedDK = new uint256[](1);
- supportedDK[0] = newDkID;
- core.enableDisputeKits(newCourtID, supportedDK, true);
-
- vm.prank(staker1);
- core.setStake(newCourtID, 20000);
- vm.prank(disputer);
- arbitrable.createDispute{value: feeForJuror * DEFAULT_NB_OF_JURORS}("Action");
- vm.warp(block.timestamp + minStakingTime);
- sortitionModule.passPhase(); // Generating
- vm.roll(block.number + rngLookahead + 1);
- sortitionModule.passPhase(); // Drawing phase
-
- KlerosCoreBase.Round memory round = core.getRoundInfo(disputeID, 0);
- assertEq(round.disputeKitID, newDkID, "Wrong DK ID");
-
- core.draw(disputeID, DEFAULT_NB_OF_JURORS);
- vm.warp(block.timestamp + timesPerPeriod[0]);
- core.passPeriod(disputeID); // Vote
-
- uint256[] memory voteIDs = new uint256[](3);
- voteIDs[0] = 0;
- voteIDs[1] = 1;
- voteIDs[2] = 2;
-
- vm.prank(staker1);
- newDisputeKit.castVote(disputeID, voteIDs, 2, 0, "XYZ");
-
- core.passPeriod(disputeID); // Appeal
-
- vm.prank(crowdfunder1);
- newDisputeKit.fundAppeal{value: 0.63 ether}(disputeID, 1);
- vm.prank(crowdfunder2);
-
- assertEq(core.isDisputeKitJumping(disputeID), true, "Should be jumping");
-
- vm.expectEmit(true, true, true, true);
- emit KlerosCoreBase.CourtJump(disputeID, 1, newCourtID, GENERAL_COURT);
- vm.expectEmit(true, true, true, true);
- emit KlerosCoreBase.DisputeKitJump(disputeID, 1, newDkID, DISPUTE_KIT_CLASSIC);
- vm.expectEmit(true, true, true, true);
- emit DisputeKitClassicBase.DisputeCreation(disputeID, 2, newExtraData);
- vm.expectEmit(true, true, true, true);
- emit KlerosCoreBase.AppealDecision(disputeID, arbitrable);
- vm.expectEmit(true, true, true, true);
- emit KlerosCoreBase.NewPeriod(disputeID, KlerosCoreBase.Period.evidence);
- newDisputeKit.fundAppeal{value: 0.42 ether}(disputeID, 2);
-
- (, bool jumped, ) = newDisputeKit.disputes(disputeID);
- assertEq(jumped, true, "jumped should be true");
- assertEq(
- (newDisputeKit.getFundedChoices(disputeID)).length,
- 2,
- "No fresh round created so the number of funded choices should be 2"
- );
-
- round = core.getRoundInfo(disputeID, 1);
- assertEq(round.disputeKitID, DISPUTE_KIT_CLASSIC, "Wrong DK ID");
- assertEq(sortitionModule.disputesWithoutJurors(), 1, "Wrong disputesWithoutJurors count");
- (uint96 courtID, , , , ) = core.disputes(disputeID);
- assertEq(courtID, GENERAL_COURT, "Wrong court ID");
-
- (, jumped, ) = disputeKit.disputes(disputeID);
- assertEq(jumped, false, "jumped should be false in the DK that dispute jumped to");
-
- // Check jump modifier
- vm.prank(address(core));
- vm.expectRevert(bytes("Dispute jumped to a parent DK!"));
- newDisputeKit.draw(disputeID, 1);
-
- // And check that draw in the new round works
- vm.expectEmit(true, true, true, true);
- emit KlerosCoreBase.Draw(staker1, disputeID, 1, 0); // roundID = 1 VoteID = 0
- core.draw(disputeID, 1);
-
- (address account, , , ) = disputeKit.getVoteInfo(disputeID, 1, 0);
- assertEq(account, staker1, "Wrong drawn account in the classic DK");
- }
-
- function test_appeal_quickPassPeriod() public {
- uint256 disputeID = 0;
-
- vm.prank(staker1);
- core.setStake(GENERAL_COURT, 10000);
- vm.prank(disputer);
- arbitrable.createDispute{value: feeForJuror * DEFAULT_NB_OF_JURORS}("Action");
- vm.warp(block.timestamp + minStakingTime);
- sortitionModule.passPhase(); // Generating
- vm.roll(block.number + rngLookahead + 1);
- sortitionModule.passPhase(); // Drawing phase
-
- core.draw(disputeID, DEFAULT_NB_OF_JURORS);
- vm.warp(block.timestamp + timesPerPeriod[0]);
- core.passPeriod(disputeID); // Vote
-
- uint256[] memory voteIDs = new uint256[](3);
- voteIDs[0] = 0;
- voteIDs[1] = 1;
- voteIDs[2] = 2;
-
- vm.prank(staker1);
- disputeKit.castVote(disputeID, voteIDs, 2, 0, "XYZ");
-
- core.passPeriod(disputeID); // Appeal
-
- vm.warp(block.timestamp + timesPerPeriod[3] / 2);
-
- // Should pass to execution period without waiting for the 2nd half of the appeal.
- vm.expectEmit(true, true, true, true);
- emit KlerosCoreBase.NewPeriod(disputeID, KlerosCoreBase.Period.execution);
- core.passPeriod(disputeID);
- }
-
- function test_execute() public {
- uint256 disputeID = 0;
-
- vm.prank(staker1);
- core.setStake(GENERAL_COURT, 1500);
- vm.prank(disputer);
- arbitrable.createDispute{value: feeForJuror * DEFAULT_NB_OF_JURORS}("Action");
- vm.warp(block.timestamp + minStakingTime);
- sortitionModule.passPhase(); // Generating
- vm.roll(block.number + rngLookahead + 1);
- sortitionModule.passPhase(); // Drawing phase
-
- // Split the stakers' votes. The first staker will get VoteID 0 and the second will take the rest.
- core.draw(disputeID, 1);
-
- vm.warp(block.timestamp + maxDrawingTime);
- sortitionModule.passPhase(); // Staking phase to stake the 2nd voter
- vm.prank(staker2);
- core.setStake(GENERAL_COURT, 20000);
- vm.warp(block.timestamp + minStakingTime);
- sortitionModule.passPhase(); // Generating
- vm.roll(block.number + rngLookahead + 1);
- sortitionModule.passPhase(); // Drawing phase
-
- core.draw(disputeID, 2); // Assign leftover votes to staker2
-
- vm.warp(block.timestamp + timesPerPeriod[0]);
- core.passPeriod(disputeID); // Vote
-
- uint256[] memory voteIDs = new uint256[](1);
- voteIDs[0] = 0;
- vm.prank(staker1);
- disputeKit.castVote(disputeID, voteIDs, 1, 0, "XYZ"); // Staker1 only got 1 vote because of low stake
-
- voteIDs = new uint256[](2);
- voteIDs[0] = 1;
- voteIDs[1] = 2;
- vm.prank(staker2);
- disputeKit.castVote(disputeID, voteIDs, 2, 0, "XYZ");
- core.passPeriod(disputeID); // Appeal
-
- vm.expectRevert(KlerosCoreBase.NotExecutionPeriod.selector);
- core.execute(disputeID, 0, 1);
-
- vm.warp(block.timestamp + timesPerPeriod[3]);
- core.passPeriod(disputeID); // Execution
-
- vm.prank(governor);
- core.pause();
- vm.expectRevert(KlerosCoreBase.WhenNotPausedOnly.selector);
- core.execute(disputeID, 0, 1);
- vm.prank(governor);
- core.unpause();
-
- assertEq(disputeKit.getCoherentCount(disputeID, 0), 2, "Wrong coherent count");
- // dispute, round, voteID, feeForJuror (not used in classic DK), pnkPerJuror (not used in classic DK)
- assertEq(disputeKit.getDegreeOfCoherence(disputeID, 0, 0, 0, 0), 0, "Wrong degree of coherence 0 vote ID");
- assertEq(disputeKit.getDegreeOfCoherence(disputeID, 0, 1, 0, 0), 10000, "Wrong degree of coherence 1 vote ID");
- assertEq(disputeKit.getDegreeOfCoherence(disputeID, 0, 2, 0, 0), 10000, "Wrong degree of coherence 2 vote ID");
-
- vm.expectEmit(true, true, true, true);
- emit SortitionModuleBase.StakeLocked(staker1, 1000, true);
- vm.expectEmit(true, true, true, true);
- emit KlerosCoreBase.TokenAndETHShift(staker1, disputeID, 0, 0, -int256(1000), 0, IERC20(address(0)));
- // Check iterations for the winning staker to see the shifts
- vm.expectEmit(true, true, true, true);
- emit SortitionModuleBase.StakeLocked(staker2, 0, true);
- vm.expectEmit(true, true, true, true);
- emit KlerosCoreBase.TokenAndETHShift(staker2, disputeID, 0, 10000, 0, 0, IERC20(address(0)));
- vm.expectEmit(true, true, true, true);
- emit SortitionModuleBase.StakeLocked(staker2, 0, true);
- vm.expectEmit(true, true, true, true);
- emit KlerosCoreBase.TokenAndETHShift(staker2, disputeID, 0, 10000, 0, 0, IERC20(address(0)));
- core.execute(disputeID, 0, 3); // Do 3 iterations to check penalties first
-
- (uint256 totalStaked, uint256 totalLocked, , ) = sortitionModule.getJurorBalance(staker1, GENERAL_COURT);
- assertEq(totalStaked, 500, "totalStaked should be penalized"); // 1500 - 1000
- assertEq(totalLocked, 0, "Tokens should be released for staker1");
- (, totalLocked, , ) = sortitionModule.getJurorBalance(staker2, GENERAL_COURT);
- assertEq(totalLocked, 2000, "Tokens should still be locked for staker2");
-
- KlerosCoreBase.Round memory round = core.getRoundInfo(disputeID, 0);
- assertEq(round.repartitions, 3, "Wrong repartitions");
- assertEq(round.pnkPenalties, 1000, "Wrong pnkPenalties");
-
- vm.expectEmit(true, true, true, true);
- emit SortitionModuleBase.StakeLocked(staker1, 0, true);
- vm.expectEmit(true, true, true, true);
- emit KlerosCoreBase.TokenAndETHShift(staker1, disputeID, 0, 0, 0, 0, IERC20(address(0)));
- // Check iterations for the winning staker to see the shifts
- vm.expectEmit(true, true, true, true);
- emit SortitionModuleBase.StakeLocked(staker2, 1000, true);
- vm.expectEmit(true, true, true, true);
- emit KlerosCoreBase.TokenAndETHShift(staker2, disputeID, 0, 10000, 500, 0.045 ether, IERC20(address(0)));
- vm.expectEmit(true, true, true, true);
- emit SortitionModuleBase.StakeLocked(staker2, 1000, true);
- vm.expectEmit(true, true, true, true);
- emit KlerosCoreBase.TokenAndETHShift(staker2, disputeID, 0, 10000, 500, 0.045 ether, IERC20(address(0)));
- core.execute(disputeID, 0, 10); // Finish the iterations. We need only 3 but check that it corrects the count.
-
- (, totalLocked, , ) = sortitionModule.getJurorBalance(staker2, GENERAL_COURT);
- assertEq(totalLocked, 0, "Tokens should be unlocked for staker2");
-
- round = core.getRoundInfo(disputeID, 0);
- assertEq(round.repartitions, 6, "Wrong repartitions");
- assertEq(round.pnkPenalties, 1000, "Wrong pnkPenalties");
- assertEq(round.sumFeeRewardPaid, 0.09 ether, "Wrong sumFeeRewardPaid");
- assertEq(round.sumPnkRewardPaid, 1000, "Wrong sumPnkRewardPaid");
-
- assertEq(address(core).balance, 0, "Wrong balance of the core");
- assertEq(staker1.balance, 0, "Wrong balance of the staker1");
- assertEq(staker2.balance, 0.09 ether, "Wrong balance of the staker2");
-
- assertEq(pinakion.balanceOf(address(core)), 20500, "Wrong token balance of the core"); // Was 21500. 1000 was transferred to staker2
- assertEq(pinakion.balanceOf(staker1), 999999999999998500, "Wrong token balance of staker1");
- assertEq(pinakion.balanceOf(staker2), 999999999999981000, "Wrong token balance of staker2"); // 20k stake and 1k added as a reward, thus -19k from the default
- }
-
- function test_execute_NoCoherence() public {
- uint256 disputeID = 0;
-
- vm.prank(staker1);
- core.setStake(GENERAL_COURT, 20000);
- vm.prank(disputer);
- arbitrable.createDispute{value: feeForJuror * DEFAULT_NB_OF_JURORS}("Action");
- vm.warp(block.timestamp + minStakingTime);
- sortitionModule.passPhase(); // Generating
- vm.roll(block.number + rngLookahead + 1);
- sortitionModule.passPhase(); // Drawing phase
-
- core.draw(disputeID, DEFAULT_NB_OF_JURORS);
-
- vm.warp(block.timestamp + timesPerPeriod[0]);
- core.passPeriod(disputeID); // Vote
-
- vm.warp(block.timestamp + timesPerPeriod[2]); // Don't vote at all so no one is coherent
- core.passPeriod(disputeID); // Appeal
-
- vm.warp(block.timestamp + timesPerPeriod[3]);
- core.passPeriod(disputeID); // Execution
-
- assertEq(disputeKit.getCoherentCount(disputeID, 0), 0, "Wrong coherent count");
- // dispute, round, voteID, feeForJuror (not used in classic DK), pnkPerJuror (not used in classic DK)
- assertEq(disputeKit.getDegreeOfCoherence(disputeID, 0, 0, 0, 0), 0, "Wrong degree of coherence 0 vote ID");
- assertEq(disputeKit.getDegreeOfCoherence(disputeID, 0, 1, 0, 0), 0, "Wrong degree of coherence 1 vote ID");
- assertEq(disputeKit.getDegreeOfCoherence(disputeID, 0, 2, 0, 0), 0, "Wrong degree of coherence 2 vote ID");
-
- uint256 governorBalance = governor.balance;
- uint256 governorTokenBalance = pinakion.balanceOf(governor);
-
- vm.expectEmit(true, true, true, true);
- emit KlerosCoreBase.LeftoverRewardSent(disputeID, 0, 3000, 0.09 ether, IERC20(address(0)));
- core.execute(disputeID, 0, 3);
-
- KlerosCoreBase.Round memory round = core.getRoundInfo(disputeID, 0);
- assertEq(round.pnkPenalties, 3000, "Wrong pnkPenalties");
- assertEq(round.sumFeeRewardPaid, 0, "Wrong sumFeeRewardPaid");
- assertEq(round.sumPnkRewardPaid, 0, "Wrong sumPnkRewardPaid");
-
- assertEq(address(core).balance, 0, "Wrong balance of the core");
- assertEq(staker1.balance, 0, "Wrong balance of the staker1");
- assertEq(governor.balance, governorBalance + 0.09 ether, "Wrong balance of the governor");
-
- assertEq(pinakion.balanceOf(address(core)), 17000, "Wrong token balance of the core");
- assertEq(pinakion.balanceOf(staker1), 999999999999980000, "Wrong token balance of staker1");
- assertEq(pinakion.balanceOf(governor), governorTokenBalance + 3000, "Wrong token balance of governor");
- }
-
- function test_execute_UnstakeInactive() public {
- // Create a 2nd court so unstaking is done in multiple courts.
- vm.prank(governor);
- uint256[] memory supportedDK = new uint256[](1);
- supportedDK[0] = DISPUTE_KIT_CLASSIC;
- core.createCourt(
- GENERAL_COURT,
- true, // Hidden votes
- 1000, // min stake
- 10000, // alpha
- 0.03 ether, // fee for juror
- 50, // jurors for jump
- [uint256(10), uint256(20), uint256(30), uint256(40)], // Times per period
- sortitionExtraData, // Sortition extra data
- supportedDK
- );
-
- uint256 disputeID = 0;
- uint96 newCourtID = 2;
-
- vm.prank(staker1);
- core.setStake(GENERAL_COURT, 20000);
- vm.prank(staker1);
- core.setStake(newCourtID, 20000);
- (, , , uint256 nbCourts) = sortitionModule.getJurorBalance(staker1, GENERAL_COURT);
- assertEq(nbCourts, 2, "Wrong number of courts");
-
- assertEq(pinakion.balanceOf(address(core)), 40000, "Wrong token balance of the core");
- assertEq(pinakion.balanceOf(staker1), 999999999999960000, "Wrong token balance of staker1");
-
- vm.prank(disputer);
- arbitrable.createDispute{value: feeForJuror * DEFAULT_NB_OF_JURORS}("Action");
- vm.warp(block.timestamp + minStakingTime);
- sortitionModule.passPhase(); // Generating
- vm.roll(block.number + rngLookahead + 1);
- sortitionModule.passPhase(); // Drawing phase
-
- core.draw(disputeID, DEFAULT_NB_OF_JURORS);
-
- sortitionModule.passPhase(); // Staking phase. Change to staking so we don't have to deal with delayed stakes.
-
- vm.warp(block.timestamp + timesPerPeriod[0]);
- core.passPeriod(disputeID); // Vote
-
- vm.warp(block.timestamp + timesPerPeriod[2]); // Don't vote at all so no one is coherent
- core.passPeriod(disputeID); // Appeal
-
- vm.warp(block.timestamp + timesPerPeriod[3]);
- core.passPeriod(disputeID); // Execution
-
- uint256 governorTokenBalance = pinakion.balanceOf(governor);
-
- // Note that these events are emitted only after the first iteration of execute() therefore the juror has been penalized only for 1000 PNK her.
- vm.expectEmit(true, true, true, true);
- emit SortitionModuleBase.StakeSet(staker1, newCourtID, 0, 19000); // Starting with 40000 we first nullify the stake and remove 20000 and then remove penalty once since there was only first iteration (40000 - 20000 - 1000)
- vm.expectEmit(true, true, true, true);
- emit SortitionModuleBase.StakeSet(staker1, GENERAL_COURT, 0, 2000); // 2000 PNK should remain in balance to cover penalties since the first 1000 of locked pnk was already unlocked
- core.execute(disputeID, 0, 3);
-
- assertEq(pinakion.balanceOf(address(core)), 0, "Wrong token balance of the core");
- assertEq(pinakion.balanceOf(staker1), 999999999999997000, "Wrong token balance of staker1"); // 3000 locked PNK was withheld by the contract and given to governor.
- assertEq(pinakion.balanceOf(governor), governorTokenBalance + 3000, "Wrong token balance of governor");
-
- (, , , nbCourts) = sortitionModule.getJurorBalance(staker1, GENERAL_COURT);
- assertEq(nbCourts, 0, "Should unstake from all courts");
- }
-
- function test_execute_UnstakeInsolvent() public {
- uint256 disputeID = 0;
-
- vm.prank(staker1);
- core.setStake(GENERAL_COURT, 1000);
-
- assertEq(pinakion.balanceOf(address(core)), 1000, "Wrong token balance of the core");
- assertEq(pinakion.balanceOf(staker1), 999999999999999000, "Wrong token balance of staker1");
-
- vm.prank(disputer);
- arbitrable.createDispute{value: feeForJuror * DEFAULT_NB_OF_JURORS}("Action");
- vm.warp(block.timestamp + minStakingTime);
- sortitionModule.passPhase(); // Generating
- vm.roll(block.number + rngLookahead + 1);
- sortitionModule.passPhase(); // Drawing phase
-
- core.draw(disputeID, DEFAULT_NB_OF_JURORS);
-
- (uint256 totalStaked, uint256 totalLocked, , uint256 nbCourts) = sortitionModule.getJurorBalance(
- staker1,
- GENERAL_COURT
- );
- assertEq(totalStaked, 1000, "Wrong totalStaked");
- assertEq(totalLocked, 3000, "totalLocked should exceed totalStaked"); // Juror only staked 1000 but was drawn 3x of minStake (3000 locked)
- assertEq(nbCourts, 1, "Wrong number of courts");
-
- sortitionModule.passPhase(); // Staking phase. Change to staking so we don't have to deal with delayed stakes.
-
- vm.warp(block.timestamp + timesPerPeriod[0]);
- core.passPeriod(disputeID); // Vote
-
- uint256[] memory voteIDs = new uint256[](1);
- voteIDs[0] = 0;
- vm.prank(staker1);
- disputeKit.castVote(disputeID, voteIDs, 1, 0, "XYZ"); // 1 incoherent vote should make the juror insolvent
-
- voteIDs = new uint256[](2);
- voteIDs[0] = 1;
- voteIDs[1] = 2;
- vm.prank(staker1);
- disputeKit.castVote(disputeID, voteIDs, 2, 0, "XYZ");
-
- core.passPeriod(disputeID); // Appeal
-
- vm.warp(block.timestamp + timesPerPeriod[3]);
- core.passPeriod(disputeID); // Execution
-
- vm.expectEmit(true, true, true, true);
- emit SortitionModuleBase.StakeSet(staker1, GENERAL_COURT, 0, 0); // Juror should have no stake left and should be unstaked from the court automatically.
- core.execute(disputeID, 0, 6);
-
- assertEq(pinakion.balanceOf(address(core)), 0, "Wrong token balance of the core");
- assertEq(pinakion.balanceOf(staker1), 1 ether, "Wrong token balance of staker1"); // The juror should have his penalty back as a reward
-
- (, , , nbCourts) = sortitionModule.getJurorBalance(staker1, GENERAL_COURT);
- assertEq(nbCourts, 0, "Should unstake from all courts");
- }
-
- function test_execute_withdrawLeftoverPNK() public {
- // Return the previously locked tokens
- uint256 disputeID = 0;
-
- vm.prank(staker1);
- core.setStake(GENERAL_COURT, 1000);
- vm.prank(disputer);
- arbitrable.createDispute{value: feeForJuror * DEFAULT_NB_OF_JURORS}("Action");
- vm.warp(block.timestamp + minStakingTime);
- sortitionModule.passPhase(); // Generating
- vm.roll(block.number + rngLookahead + 1);
- sortitionModule.passPhase(); // Drawing phase
-
- core.draw(disputeID, DEFAULT_NB_OF_JURORS);
-
- sortitionModule.passPhase(); // Staking. Pass the phase so the juror can unstake before execution
-
- vm.warp(block.timestamp + timesPerPeriod[0]);
- core.passPeriod(disputeID); // Vote
-
- uint256[] memory voteIDs = new uint256[](3);
- voteIDs[0] = 0;
- voteIDs[1] = 1;
- voteIDs[2] = 2;
- vm.prank(staker1);
- disputeKit.castVote(disputeID, voteIDs, 2, 0, "XYZ");
-
- core.passPeriod(disputeID); // Appeal
-
- vm.warp(block.timestamp + timesPerPeriod[3]);
- core.passPeriod(disputeID); // Execution
-
- vm.prank(staker1);
- core.setStake(GENERAL_COURT, 0); // Set stake to 0 to check if it will be withdrawn later.
-
- (uint256 totalStaked, uint256 totalLocked, uint256 stakedInCourt, uint256 nbCourts) = sortitionModule
- .getJurorBalance(staker1, GENERAL_COURT);
- assertEq(totalStaked, 1000, "Wrong amount staked");
- assertEq(totalLocked, 3000, "Wrong amount locked");
- assertEq(stakedInCourt, 0, "Should be unstaked");
- assertEq(nbCourts, 0, "Should be 0 courts");
-
- assertEq(pinakion.balanceOf(address(core)), 1000, "Wrong token balance of the core");
- assertEq(pinakion.balanceOf(staker1), 999999999999999000, "Wrong token balance of staker1");
-
- vm.expectRevert(bytes("Not eligible for withdrawal."));
- sortitionModule.withdrawLeftoverPNK(staker1);
-
- vm.expectEmit(true, true, true, true);
- emit SortitionModuleBase.LeftoverPNK(staker1, 1000);
- core.execute(disputeID, 0, 6);
-
- (totalStaked, totalLocked, , ) = sortitionModule.getJurorBalance(staker1, GENERAL_COURT);
- assertEq(totalStaked, 1000, "Wrong amount staked");
- assertEq(totalLocked, 0, "Should be fully unlocked");
-
- KlerosCoreBase.Round memory round = core.getRoundInfo(disputeID, 0);
- assertEq(round.pnkPenalties, 0, "Wrong pnkPenalties");
- assertEq(round.sumFeeRewardPaid, 0.09 ether, "Wrong sumFeeRewardPaid");
- assertEq(round.sumPnkRewardPaid, 0, "Wrong sumPnkRewardPaid"); // No penalty so no rewards in pnk
-
- // Execute() shouldn't withdraw the tokens.
- assertEq(pinakion.balanceOf(address(core)), 1000, "Wrong token balance of the core");
- assertEq(pinakion.balanceOf(staker1), 999999999999999000, "Wrong token balance of staker1");
-
- vm.expectRevert(KlerosCoreBase.SortitionModuleOnly.selector);
- vm.prank(governor);
- core.transferBySortitionModule(staker1, 1000);
-
- vm.expectEmit(true, true, true, true);
- emit SortitionModuleBase.LeftoverPNKWithdrawn(staker1, 1000);
- sortitionModule.withdrawLeftoverPNK(staker1);
-
- (totalStaked, , , ) = sortitionModule.getJurorBalance(staker1, GENERAL_COURT);
- assertEq(totalStaked, 0, "Should be unstaked fully");
-
- // Check that everything is withdrawn now
- assertEq(pinakion.balanceOf(address(core)), 0, "Core balance should be empty");
- assertEq(pinakion.balanceOf(staker1), 1 ether, "All PNK should be withdrawn");
- }
-
- function test_execute_feeToken() public {
- uint256 disputeID = 0;
-
- feeToken.transfer(disputer, 1 ether);
- vm.prank(disputer);
- feeToken.approve(address(arbitrable), 1 ether);
-
- vm.prank(governor);
- core.changeAcceptedFeeTokens(feeToken, true);
- vm.prank(governor);
- core.changeCurrencyRates(feeToken, 500, 3);
-
- vm.prank(disputer);
- arbitrable.createDispute("Action", 0.18 ether);
-
- vm.prank(staker1);
- core.setStake(GENERAL_COURT, 20000);
- vm.warp(block.timestamp + minStakingTime);
- sortitionModule.passPhase(); // Generating
- vm.roll(block.number + rngLookahead + 1);
- sortitionModule.passPhase(); // Drawing phase
-
- core.draw(disputeID, DEFAULT_NB_OF_JURORS);
-
- vm.warp(block.timestamp + timesPerPeriod[0]);
- core.passPeriod(disputeID); // Vote
-
- uint256[] memory voteIDs = new uint256[](3);
- voteIDs[0] = 0;
- voteIDs[1] = 1;
- voteIDs[2] = 2;
- vm.prank(staker1);
- disputeKit.castVote(disputeID, voteIDs, 1, 0, "XYZ"); // Staker1 only got 1 vote because of low stake
-
- core.passPeriod(disputeID); // Appeal
-
- vm.warp(block.timestamp + timesPerPeriod[3]);
- core.passPeriod(disputeID); // Execution
-
- // Check only once per penalty and per reward
- vm.expectEmit(true, true, true, true);
- emit KlerosCoreBase.TokenAndETHShift(staker1, disputeID, 0, 10000, 0, 0, feeToken);
- vm.expectEmit(true, true, true, true);
- emit KlerosCoreBase.TokenAndETHShift(staker1, disputeID, 0, 10000, 0, 0.06 ether, feeToken);
- core.execute(disputeID, 0, 6);
-
- KlerosCoreBase.Round memory round = core.getRoundInfo(disputeID, 0);
- assertEq(round.sumFeeRewardPaid, 0.18 ether, "Wrong sumFeeRewardPaid");
-
- assertEq(feeToken.balanceOf(address(core)), 0, "Wrong fee token balance of the core");
- assertEq(feeToken.balanceOf(staker1), 0.18 ether, "Wrong fee token balance of staker1");
- assertEq(feeToken.balanceOf(disputer), 0.82 ether, "Wrong fee token balance of disputer");
- }
-
- function test_execute_NoCoherence_feeToken() public {
- uint256 disputeID = 0;
-
- feeToken.transfer(disputer, 1 ether);
- vm.prank(disputer);
- feeToken.approve(address(arbitrable), 1 ether);
-
- vm.prank(governor);
- core.changeAcceptedFeeTokens(feeToken, true);
- vm.prank(governor);
- core.changeCurrencyRates(feeToken, 500, 3);
-
- vm.prank(disputer);
- arbitrable.createDispute("Action", 0.18 ether);
-
- vm.prank(staker1);
- core.setStake(GENERAL_COURT, 20000);
- vm.warp(block.timestamp + minStakingTime);
- sortitionModule.passPhase(); // Generating
- vm.roll(block.number + rngLookahead + 1);
- sortitionModule.passPhase(); // Drawing phase
-
- core.draw(disputeID, DEFAULT_NB_OF_JURORS);
-
- vm.warp(block.timestamp + timesPerPeriod[0]);
- core.passPeriod(disputeID); // Vote
-
- vm.warp(block.timestamp + timesPerPeriod[2]); // Don't vote at all so no one is coherent
- core.passPeriod(disputeID); // Appeal
-
- vm.warp(block.timestamp + timesPerPeriod[3]);
- core.passPeriod(disputeID); // Execution
-
- vm.expectEmit(true, true, true, true);
- emit KlerosCoreBase.LeftoverRewardSent(disputeID, 0, 3000, 0.18 ether, feeToken);
- core.execute(disputeID, 0, 10); // Put more iterations to check that they're capped
-
- KlerosCoreBase.Round memory round = core.getRoundInfo(disputeID, 0);
- assertEq(round.pnkPenalties, 3000, "Wrong pnkPenalties");
- assertEq(round.sumFeeRewardPaid, 0, "Wrong sumFeeRewardPaid");
- assertEq(round.sumPnkRewardPaid, 0, "Wrong sumPnkRewardPaid");
- assertEq(round.repartitions, 3, "Wrong repartitions");
-
- assertEq(feeToken.balanceOf(address(core)), 0, "Wrong token balance of the core");
- assertEq(feeToken.balanceOf(staker1), 0, "Wrong token balance of staker1");
- assertEq(feeToken.balanceOf(disputer), 0.82 ether, "Wrong token balance of disputer");
- assertEq(feeToken.balanceOf(governor), 0.18 ether, "Wrong token balance of governor");
- }
-
- function test_executeRuling() public {
- uint256 disputeID = 0;
-
- vm.prank(staker1);
- core.setStake(GENERAL_COURT, 20000);
- vm.prank(disputer);
- arbitrable.createDispute{value: feeForJuror * DEFAULT_NB_OF_JURORS}("Action");
- vm.warp(block.timestamp + minStakingTime);
- sortitionModule.passPhase(); // Generating
- vm.roll(block.number + rngLookahead + 1);
- sortitionModule.passPhase(); // Drawing phase
-
- core.draw(disputeID, DEFAULT_NB_OF_JURORS);
- vm.warp(block.timestamp + timesPerPeriod[0]);
- core.passPeriod(disputeID); // Vote
-
- uint256[] memory voteIDs = new uint256[](3);
- voteIDs[0] = 0;
- voteIDs[1] = 1;
- voteIDs[2] = 2;
-
- vm.prank(staker1);
- disputeKit.castVote(disputeID, voteIDs, 2, 0, "XYZ");
- core.passPeriod(disputeID); // Appeal
-
- vm.expectRevert(KlerosCoreBase.NotExecutionPeriod.selector);
- core.executeRuling(disputeID);
-
- vm.warp(block.timestamp + timesPerPeriod[3]);
- vm.expectEmit(true, true, true, true);
- emit KlerosCoreBase.NewPeriod(disputeID, KlerosCoreBase.Period.execution);
- core.passPeriod(disputeID); // Execution
-
- (, , KlerosCoreBase.Period period, , uint256 lastPeriodChange) = core.disputes(disputeID);
- assertEq(uint256(period), uint256(KlerosCoreBase.Period.execution), "Wrong period");
- assertEq(lastPeriodChange, block.timestamp, "Wrong lastPeriodChange");
-
- vm.expectRevert(KlerosCoreBase.DisputePeriodIsFinal.selector);
- core.passPeriod(disputeID);
-
- vm.expectEmit(true, true, true, true);
- emit IArbitratorV2.Ruling(arbitrable, disputeID, 2); // Winning choice = 2
- vm.expectEmit(true, true, true, true);
- emit IArbitrableV2.Ruling(core, disputeID, 2);
- core.executeRuling(disputeID);
-
- vm.expectRevert(KlerosCoreBase.RulingAlreadyExecuted.selector);
- core.executeRuling(disputeID);
-
- (, , , bool ruled, ) = core.disputes(disputeID);
- assertEq(ruled, true, "Should be ruled");
- }
-
- function test_executeRuling_appealSwitch() public {
- // Check that the ruling switches if only one side was funded
- uint256 disputeID = 0;
-
- vm.prank(staker1);
- core.setStake(GENERAL_COURT, 20000);
- vm.prank(disputer);
- arbitrable.createDispute{value: feeForJuror * DEFAULT_NB_OF_JURORS}("Action");
- vm.warp(block.timestamp + minStakingTime);
- sortitionModule.passPhase(); // Generating
- vm.roll(block.number + rngLookahead + 1);
- sortitionModule.passPhase(); // Drawing phase
-
- core.draw(disputeID, DEFAULT_NB_OF_JURORS);
- vm.warp(block.timestamp + timesPerPeriod[0]);
- core.passPeriod(disputeID); // Vote
-
- uint256[] memory voteIDs = new uint256[](3);
- voteIDs[0] = 0;
- voteIDs[1] = 1;
- voteIDs[2] = 2;
-
- vm.prank(staker1);
- disputeKit.castVote(disputeID, voteIDs, 2, 0, "XYZ");
- core.passPeriod(disputeID); // Appeal
-
- vm.prank(crowdfunder1);
- disputeKit.fundAppeal{value: 0.63 ether}(disputeID, 1); // Fund the losing choice
-
- vm.warp(block.timestamp + timesPerPeriod[3]);
- core.passPeriod(disputeID); // Execution
-
- vm.expectEmit(true, true, true, true);
- emit IArbitratorV2.Ruling(arbitrable, disputeID, 1); // Winning choice is switched to 1
- vm.expectEmit(true, true, true, true);
- emit IArbitrableV2.Ruling(core, disputeID, 1);
- core.executeRuling(disputeID);
-
- (uint256 ruling, bool tied, bool overridden) = disputeKit.currentRuling(disputeID);
- assertEq(ruling, 1, "Wrong ruling");
- assertEq(tied, false, "Not tied");
- assertEq(overridden, true, "Should be overridden");
- }
-
- function test_withdrawFeesAndRewards() public {
- uint256 disputeID = 0;
-
- vm.prank(staker1);
- core.setStake(GENERAL_COURT, 20000);
- vm.prank(disputer);
- arbitrable.createDispute{value: feeForJuror * DEFAULT_NB_OF_JURORS}("Action");
- vm.warp(block.timestamp + minStakingTime);
- sortitionModule.passPhase(); // Generating
- vm.roll(block.number + rngLookahead + 1);
- sortitionModule.passPhase(); // Drawing phase
-
- core.draw(disputeID, DEFAULT_NB_OF_JURORS);
- vm.warp(block.timestamp + timesPerPeriod[0]);
- core.passPeriod(disputeID); // Vote
-
- uint256[] memory voteIDs = new uint256[](3);
- voteIDs[0] = 0;
- voteIDs[1] = 1;
- voteIDs[2] = 2;
-
- vm.prank(staker1);
- disputeKit.castVote(disputeID, voteIDs, 2, 0, "XYZ");
- core.passPeriod(disputeID); // Appeal
-
- vm.prank(crowdfunder1);
- disputeKit.fundAppeal{value: 0.63 ether}(disputeID, 1); // Fund the losing choice. The ruling will be overridden here
- vm.prank(crowdfunder2);
- disputeKit.fundAppeal{value: 0.41 ether}(disputeID, 2); // Underpay a bit to not create an appeal and withdraw the funded sum fully
-
- vm.warp(block.timestamp + timesPerPeriod[3]);
- core.passPeriod(disputeID); // Execution
-
- vm.expectRevert(bytes("Dispute should be resolved."));
- disputeKit.withdrawFeesAndRewards(disputeID, payable(staker1), 0, 1);
-
- core.executeRuling(disputeID);
-
- vm.prank(governor);
- core.pause();
- vm.expectRevert(bytes("Core is paused"));
- disputeKit.withdrawFeesAndRewards(disputeID, payable(staker1), 0, 1);
- vm.prank(governor);
- core.unpause();
-
- assertEq(crowdfunder1.balance, 9.37 ether, "Wrong balance of the crowdfunder1");
- assertEq(crowdfunder2.balance, 9.59 ether, "Wrong balance of the crowdfunder2");
- assertEq(address(disputeKit).balance, 1.04 ether, "Wrong balance of the DK");
-
- vm.expectEmit(true, true, true, true);
- emit DisputeKitClassicBase.Withdrawal(disputeID, 0, 1, crowdfunder1, 0.63 ether);
- disputeKit.withdrawFeesAndRewards(disputeID, payable(crowdfunder1), 0, 1);
-
- vm.expectEmit(true, true, true, true);
- emit DisputeKitClassicBase.Withdrawal(disputeID, 0, 2, crowdfunder2, 0.41 ether);
- disputeKit.withdrawFeesAndRewards(disputeID, payable(crowdfunder2), 0, 2);
-
- assertEq(crowdfunder1.balance, 10 ether, "Wrong balance of the crowdfunder1");
- assertEq(crowdfunder2.balance, 10 ether, "Wrong balance of the crowdfunder2");
- assertEq(address(disputeKit).balance, 0, "Wrong balance of the DK");
- }
-
- function test_castVote_differentDK() public {
- DisputeKitClassic dkLogic = new DisputeKitClassic();
- // Create a new DK to check castVote.
- bytes memory initDataDk = abi.encodeWithSignature(
- "initialize(address,address,address)",
- governor,
- address(core),
- address(wNative)
- );
-
- UUPSProxy proxyDk = new UUPSProxy(address(dkLogic), initDataDk);
- DisputeKitClassic newDisputeKit = DisputeKitClassic(address(proxyDk));
-
- vm.prank(governor);
- core.addNewDisputeKit(newDisputeKit);
-
- uint256 newDkID = 2;
- uint256[] memory supportedDK = new uint256[](1);
- bytes memory newExtraData = abi.encodePacked(uint256(GENERAL_COURT), DEFAULT_NB_OF_JURORS, newDkID);
-
- vm.prank(governor);
- vm.expectEmit(true, true, true, true);
- emit KlerosCoreBase.DisputeKitEnabled(GENERAL_COURT, newDkID, true);
- supportedDK[0] = newDkID;
- core.enableDisputeKits(GENERAL_COURT, supportedDK, true);
- assertEq(core.isSupported(GENERAL_COURT, newDkID), true, "New DK should be supported by General court");
-
- vm.prank(staker1);
- core.setStake(GENERAL_COURT, 20000);
-
- // Create one dispute for the old DK and two disputes for the new DK.
- vm.prank(disputer);
- arbitrable.createDispute{value: feeForJuror * DEFAULT_NB_OF_JURORS}("Action");
-
- arbitrable.changeArbitratorExtraData(newExtraData);
-
- vm.prank(disputer);
- arbitrable.createDispute{value: feeForJuror * DEFAULT_NB_OF_JURORS}("Action");
-
- vm.prank(disputer);
- arbitrable.createDispute{value: feeForJuror * DEFAULT_NB_OF_JURORS}("Action");
-
- uint256 disputeID = 2; // Use the latest dispute for reference. This is the ID in the core contract
-
- vm.warp(block.timestamp + minStakingTime);
- sortitionModule.passPhase(); // Generating
- vm.roll(block.number + rngLookahead + 1);
- sortitionModule.passPhase(); // Drawing phase
-
- KlerosCoreBase.Round memory round = core.getRoundInfo(disputeID, 0);
- assertEq(round.disputeKitID, newDkID, "Wrong DK ID");
-
- core.draw(disputeID, DEFAULT_NB_OF_JURORS);
- // Draw jurors for the old DK as well to prepare round.votes array
- core.draw(0, DEFAULT_NB_OF_JURORS);
-
- vm.warp(block.timestamp + timesPerPeriod[0]);
- core.passPeriod(disputeID); // Vote
-
- // Check that the new DK has the info but not the old one.
-
- assertEq(disputeKit.coreDisputeIDToActive(disputeID), false, "Should be false for old DK");
-
- // This is the DK where dispute was created. Core dispute points to index 1 because new DK has two disputes.
- assertEq(newDisputeKit.coreDisputeIDToLocal(disputeID), 1, "Wrong local dispute ID for new DK");
- assertEq(newDisputeKit.coreDisputeIDToActive(disputeID), true, "Should be active for new DK");
- (uint256 numberOfChoices, , bytes memory extraData) = newDisputeKit.disputes(1);
- assertEq(numberOfChoices, 2, "Wrong numberOfChoices in new DK");
- assertEq(extraData, newExtraData, "Wrong extra data");
-
- uint256[] memory voteIDs = new uint256[](3);
- voteIDs[0] = 0;
- voteIDs[1] = 1;
- voteIDs[2] = 2;
-
- // Deliberately cast votes using the old DK to see if the exception will be caught.
- vm.prank(staker1);
- vm.expectRevert(bytes("Not active for core dispute ID"));
- disputeKit.castVote(disputeID, voteIDs, 2, 0, "XYZ");
-
- // And check the new DK.
- vm.prank(staker1);
- newDisputeKit.castVote(disputeID, voteIDs, 2, 0, "XYZ");
-
- (
- uint256 winningChoice,
- bool tied,
- uint256 totalVoted,
- uint256 totalCommited,
- ,
- uint256 choiceCount
- ) = newDisputeKit.getRoundInfo(disputeID, 0, 2);
- assertEq(winningChoice, 2, "Wrong winning choice");
- assertEq(tied, false, "tied should be false");
- assertEq(totalVoted, 3, "totalVoted should be 3");
- assertEq(totalCommited, 0, "totalCommited should be 0");
- assertEq(choiceCount, 3, "choiceCount should be 3");
- }
-}
diff --git a/contracts/test/foundry/KlerosCore_Appeals.t.sol b/contracts/test/foundry/KlerosCore_Appeals.t.sol
new file mode 100644
index 000000000..c14ccfb43
--- /dev/null
+++ b/contracts/test/foundry/KlerosCore_Appeals.t.sol
@@ -0,0 +1,936 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.24;
+
+import {KlerosCore_TestBase} from "./KlerosCore_TestBase.sol";
+import {KlerosCore} from "../../src/arbitration/KlerosCore.sol";
+import {DisputeKitClassic, DisputeKitClassicBase} from "../../src/arbitration/dispute-kits/DisputeKitClassic.sol";
+import {UUPSProxy} from "../../src/proxy/UUPSProxy.sol";
+import "../../src/libraries/Constants.sol";
+
+/// @title KlerosCore_AppealsTest
+/// @dev Tests for KlerosCore appeal system, funding, and court/DK jumping
+contract KlerosCore_AppealsTest is KlerosCore_TestBase {
+ function test_appeal_fundOneSide() public {
+ uint256 disputeID = 0;
+ vm.deal(address(disputeKit), 1 ether);
+ vm.deal(staker1, 1 ether);
+
+ vm.prank(staker1);
+ core.setStake(GENERAL_COURT, 10000);
+ vm.prank(disputer);
+ arbitrable.createDispute{value: feeForJuror * DEFAULT_NB_OF_JURORS}("Action");
+ vm.warp(block.timestamp + minStakingTime);
+ sortitionModule.passPhase(); // Generating
+ vm.warp(block.timestamp + rngLookahead);
+ sortitionModule.passPhase(); // Drawing phase
+
+ core.draw(disputeID, DEFAULT_NB_OF_JURORS);
+ vm.warp(block.timestamp + timesPerPeriod[0]);
+ core.passPeriod(disputeID); // Vote
+
+ uint256[] memory voteIDs = new uint256[](3);
+ voteIDs[0] = 0;
+ voteIDs[1] = 1;
+ voteIDs[2] = 2;
+
+ vm.prank(staker1);
+ disputeKit.castVote(disputeID, voteIDs, 2, 0, "XYZ");
+
+ (uint256 start, uint256 end) = core.appealPeriod(0);
+ assertEq(start, 0, "Appeal period start should be 0");
+ assertEq(end, 0, "Appeal period end should be 0");
+
+ // Simulate the call from dispute kit to check the requires unrelated to caller
+ vm.prank(address(disputeKit));
+ vm.expectRevert(KlerosCore.DisputeNotAppealable.selector);
+ core.appeal{value: 0.21 ether}(disputeID, 2, arbitratorExtraData);
+
+ vm.expectEmit(true, true, true, true);
+ emit KlerosCore.AppealPossible(disputeID, arbitrable);
+ vm.expectEmit(true, true, true, true);
+ emit KlerosCore.NewPeriod(disputeID, KlerosCore.Period.appeal);
+ core.passPeriod(disputeID);
+
+ (, , KlerosCore.Period period, , uint256 lastPeriodChange) = core.disputes(disputeID);
+ (start, end) = core.appealPeriod(0);
+ assertEq(uint256(period), uint256(KlerosCore.Period.appeal), "Wrong period");
+ assertEq(lastPeriodChange, block.timestamp, "Wrong lastPeriodChange");
+ assertEq(core.appealCost(0), 0.21 ether, "Wrong appealCost");
+ assertEq(start, lastPeriodChange, "Appeal period start is incorrect");
+ assertEq(end, lastPeriodChange + timesPerPeriod[3], "Appeal period end is incorrect");
+
+ vm.expectRevert(KlerosCore.AppealPeriodNotPassed.selector);
+ core.passPeriod(disputeID);
+
+ // Simulate the call from dispute kit to check the requires unrelated to caller
+ vm.prank(address(disputeKit));
+ vm.expectRevert(KlerosCore.AppealFeesNotEnough.selector);
+ core.appeal{value: 0.21 ether - 1}(disputeID, 2, arbitratorExtraData);
+ vm.deal(address(disputeKit), 0); // Nullify the balance so it doesn't get in the way.
+
+ vm.prank(staker1);
+ vm.expectRevert(KlerosCore.DisputeKitOnly.selector);
+ core.appeal{value: 0.21 ether}(disputeID, 2, arbitratorExtraData);
+
+ vm.prank(crowdfunder1);
+ vm.expectRevert(DisputeKitClassicBase.ChoiceOutOfBounds.selector);
+ disputeKit.fundAppeal(disputeID, 3);
+
+ vm.prank(crowdfunder1);
+ vm.expectEmit(true, true, true, true);
+ emit DisputeKitClassicBase.Contribution(disputeID, 0, 1, crowdfunder1, 0.21 ether);
+ disputeKit.fundAppeal{value: 0.21 ether}(disputeID, 1); // Fund the losing choice. Total cost will be 0.63 (0.21 + 0.21 * (20000/10000))
+
+ assertEq(crowdfunder1.balance, 9.79 ether, "Wrong balance of the crowdfunder");
+ assertEq(address(disputeKit).balance, 0.21 ether, "Wrong balance of the DK");
+ assertEq((disputeKit.getFundedChoices(disputeID)).length, 0, "No funded choices");
+
+ vm.prank(crowdfunder1);
+ vm.expectEmit(true, true, true, true);
+ emit DisputeKitClassicBase.Contribution(disputeID, 0, 1, crowdfunder1, 0.42 ether);
+ vm.expectEmit(true, true, true, true);
+ emit DisputeKitClassicBase.ChoiceFunded(disputeID, 0, 1);
+ disputeKit.fundAppeal{value: 5 ether}(disputeID, 1); // Deliberately overpay to check reimburse
+
+ assertEq(crowdfunder1.balance, 9.37 ether, "Wrong balance of the crowdfunder");
+ assertEq(address(disputeKit).balance, 0.63 ether, "Wrong balance of the DK");
+ assertEq((disputeKit.getFundedChoices(disputeID)).length, 1, "One choice should be funded");
+ assertEq((disputeKit.getFundedChoices(disputeID))[0], 1, "Incorrect funded choice");
+
+ vm.prank(crowdfunder1);
+ vm.expectRevert(DisputeKitClassicBase.AppealFeeIsAlreadyPaid.selector);
+ disputeKit.fundAppeal(disputeID, 1);
+ }
+
+ function test_appeal_timeoutCheck() public {
+ uint256 disputeID = 0;
+
+ vm.prank(staker1);
+ core.setStake(GENERAL_COURT, 10000);
+ vm.prank(disputer);
+ arbitrable.createDispute{value: feeForJuror * DEFAULT_NB_OF_JURORS}("Action");
+ vm.warp(block.timestamp + minStakingTime);
+ sortitionModule.passPhase(); // Generating
+ vm.warp(block.timestamp + rngLookahead);
+ sortitionModule.passPhase(); // Drawing phase
+
+ core.draw(disputeID, DEFAULT_NB_OF_JURORS);
+ vm.warp(block.timestamp + timesPerPeriod[0]);
+ core.passPeriod(disputeID); // Vote
+
+ uint256[] memory voteIDs = new uint256[](3);
+ voteIDs[0] = 0;
+ voteIDs[1] = 1;
+ voteIDs[2] = 2;
+
+ vm.prank(staker1);
+ disputeKit.castVote(disputeID, voteIDs, 2, 0, "XYZ");
+
+ vm.prank(crowdfunder1);
+ vm.expectRevert(DisputeKitClassicBase.NotAppealPeriod.selector);
+ disputeKit.fundAppeal{value: 0.1 ether}(disputeID, 1);
+ core.passPeriod(disputeID);
+
+ (uint256 start, uint256 end) = core.appealPeriod(0);
+
+ vm.prank(crowdfunder1);
+ vm.warp(block.timestamp + ((end - start) / 2 + 1));
+ vm.expectRevert(DisputeKitClassicBase.NotAppealPeriodForLoser.selector);
+ disputeKit.fundAppeal{value: 0.1 ether}(disputeID, 1); // Losing choice
+
+ disputeKit.fundAppeal(disputeID, 2); // Winning choice funding should not revert yet
+
+ vm.prank(crowdfunder1);
+ vm.warp(block.timestamp + (end - start) / 2); // Warp one more to cover the whole period
+ vm.expectRevert(DisputeKitClassicBase.NotAppealPeriod.selector);
+ disputeKit.fundAppeal{value: 0.1 ether}(disputeID, 2);
+ }
+
+ function test_appeal_fullFundingNoJump() public {
+ uint256 disputeID = 0;
+
+ vm.prank(staker1);
+ core.setStake(GENERAL_COURT, 20000);
+ vm.prank(disputer);
+ arbitrable.createDispute{value: feeForJuror * DEFAULT_NB_OF_JURORS}("Action");
+ vm.warp(block.timestamp + minStakingTime);
+ sortitionModule.passPhase(); // Generating
+ vm.warp(block.timestamp + rngLookahead);
+ sortitionModule.passPhase(); // Drawing phase
+
+ core.draw(disputeID, DEFAULT_NB_OF_JURORS);
+ vm.warp(block.timestamp + timesPerPeriod[0]);
+ core.passPeriod(disputeID); // Vote
+
+ uint256[] memory voteIDs = new uint256[](3);
+ voteIDs[0] = 0;
+ voteIDs[1] = 1;
+ voteIDs[2] = 2;
+
+ vm.prank(staker1);
+ disputeKit.castVote(disputeID, voteIDs, 2, 0, "XYZ");
+
+ core.passPeriod(disputeID); // Appeal
+
+ vm.prank(crowdfunder1);
+ disputeKit.fundAppeal{value: 0.63 ether}(disputeID, 1);
+
+ vm.prank(crowdfunder2);
+ vm.expectEmit(true, true, true, true);
+ emit KlerosCore.AppealDecision(disputeID, arbitrable);
+ vm.expectEmit(true, true, true, true);
+ emit KlerosCore.NewPeriod(disputeID, KlerosCore.Period.evidence);
+ disputeKit.fundAppeal{value: 0.42 ether}(disputeID, 2);
+
+ assertEq((disputeKit.getFundedChoices(disputeID)).length, 0, "No funded choices in the fresh round");
+ (uint256 ruling, bool tied, bool overridden) = disputeKit.currentRuling(disputeID);
+ assertEq(ruling, 0, "Should be 0 ruling in the fresh round");
+ assertEq(tied, true, "Should be tied");
+ assertEq(overridden, false, "Not overridden");
+
+ assertEq(address(disputeKit).balance, 0.84 ether, "Wrong balance of the DK"); // 0.63 + 0.42 - 0.21
+ assertEq(address(core).balance, 0.3 ether, "Wrong balance of the core"); // 0.09 arbFee + 0.21 appealFee
+
+ assertEq(sortitionModule.disputesWithoutJurors(), 1, "Wrong disputesWithoutJurors count after appeal");
+ assertEq(core.getNumberOfRounds(disputeID), 2, "Wrong number of rounds");
+
+ (, , KlerosCore.Period period, , uint256 lastPeriodChange) = core.disputes(disputeID);
+ assertEq(uint256(period), uint256(KlerosCore.Period.evidence), "Wrong period");
+ assertEq(lastPeriodChange, block.timestamp, "Wrong lastPeriodChange");
+
+ KlerosCore.Round memory round = core.getRoundInfo(disputeID, 1); // Check the new round
+ assertEq(round.pnkAtStakePerJuror, 1000, "Wrong pnkAtStakePerJuror");
+ assertEq(round.totalFeesForJurors, 0.21 ether, "Wrong totalFeesForJurors");
+ assertEq(round.nbVotes, 7, "Wrong nbVotes");
+
+ core.draw(disputeID, 7);
+ emit KlerosCore.NewPeriod(disputeID, KlerosCore.Period.vote); // Check that we don't have to wait for the timeout to pass the evidence period after appeal
+ core.passPeriod(disputeID);
+ }
+
+ function test_appeal_fullFundingCourtJumpAndDKJumpToClassic() public {
+ // Setup: dk2 supported by court2 with dk2._jumpDisputeKitID == DISPUTE_KIT_CLASSIC
+ // Ensure that court2 jumps to GENERAL_COURT and dk2 jumps to DISPUTE_KIT_CLASSIC
+ uint256 disputeID = 0;
+ DisputeKitClassic dkLogic = new DisputeKitClassic();
+ // Create a new DK and court to check the jump
+ bytes memory initDataDk = abi.encodeWithSignature(
+ "initialize(address,address,address,uint256)",
+ owner,
+ address(core),
+ address(wNative),
+ DISPUTE_KIT_CLASSIC
+ );
+
+ UUPSProxy proxyDk = new UUPSProxy(address(dkLogic), initDataDk);
+ DisputeKitClassic newDisputeKit = DisputeKitClassic(address(proxyDk));
+
+ uint96 newCourtID = 2;
+ uint256 newDkID = 2;
+ uint256[] memory supportedDK = new uint256[](1);
+ supportedDK[0] = DISPUTE_KIT_CLASSIC;
+ bytes memory newExtraData = abi.encodePacked(uint256(newCourtID), DEFAULT_NB_OF_JURORS, newDkID);
+
+ vm.prank(owner);
+ core.addNewDisputeKit(newDisputeKit);
+ vm.prank(owner);
+ core.createCourt(
+ GENERAL_COURT,
+ hiddenVotes,
+ minStake,
+ alpha,
+ feeForJuror,
+ 3, // jurors for jump. Low number to ensure jump after the first appeal
+ [uint256(60), uint256(120), uint256(180), uint256(240)], // Times per period
+ sortitionExtraData,
+ supportedDK
+ );
+
+ arbitrable.changeArbitratorExtraData(newExtraData);
+
+ vm.prank(owner);
+ supportedDK = new uint256[](1);
+ supportedDK[0] = newDkID;
+ core.enableDisputeKits(newCourtID, supportedDK, true);
+ assertEq(core.isSupported(newCourtID, newDkID), true, "New DK should be supported by new court");
+
+ vm.prank(staker1);
+ core.setStake(newCourtID, 20000);
+ vm.prank(disputer);
+ arbitrable.createDispute{value: feeForJuror * DEFAULT_NB_OF_JURORS}("Action");
+ vm.warp(block.timestamp + minStakingTime);
+ sortitionModule.passPhase(); // Generating
+ vm.warp(block.timestamp + rngLookahead);
+ sortitionModule.passPhase(); // Drawing phase
+
+ KlerosCore.Round memory round = core.getRoundInfo(disputeID, 0);
+ assertEq(round.disputeKitID, newDkID, "Wrong DK ID");
+
+ core.draw(disputeID, DEFAULT_NB_OF_JURORS);
+ vm.warp(block.timestamp + timesPerPeriod[0]);
+ core.passPeriod(disputeID); // Vote
+
+ uint256[] memory voteIDs = new uint256[](3);
+ voteIDs[0] = 0;
+ voteIDs[1] = 1;
+ voteIDs[2] = 2;
+
+ vm.prank(staker1);
+ newDisputeKit.castVote(disputeID, voteIDs, 2, 0, "XYZ");
+
+ core.passPeriod(disputeID); // Appeal
+
+ vm.prank(crowdfunder1);
+ newDisputeKit.fundAppeal{value: 0.63 ether}(disputeID, 1);
+
+ assertEq(core.isDisputeKitJumping(disputeID), true, "Should be jumping");
+
+ vm.expectEmit(true, true, true, true);
+ emit KlerosCore.CourtJump(disputeID, 1, newCourtID, GENERAL_COURT);
+ vm.expectEmit(true, true, true, true);
+ emit KlerosCore.DisputeKitJump(disputeID, 1, newDkID, DISPUTE_KIT_CLASSIC);
+ vm.expectEmit(true, true, true, true);
+ emit DisputeKitClassicBase.DisputeCreation(disputeID, 2, newExtraData);
+ vm.expectEmit(true, true, true, true);
+ emit KlerosCore.AppealDecision(disputeID, arbitrable);
+ vm.expectEmit(true, true, true, true);
+ emit KlerosCore.NewPeriod(disputeID, KlerosCore.Period.evidence);
+ vm.prank(crowdfunder2);
+ newDisputeKit.fundAppeal{value: 0.42 ether}(disputeID, 2);
+
+ (, bool currentRound) = newDisputeKit.coreDisputeIDToActive(disputeID);
+ assertEq(currentRound, false, "round should be jumped");
+ assertEq(
+ (newDisputeKit.getFundedChoices(disputeID)).length,
+ 2,
+ "No fresh round created so the number of funded choices should be 2"
+ );
+
+ round = core.getRoundInfo(disputeID, 1);
+ assertEq(round.disputeKitID, DISPUTE_KIT_CLASSIC, "Wrong DK ID");
+ assertEq(sortitionModule.disputesWithoutJurors(), 1, "Wrong disputesWithoutJurors count");
+ (uint96 courtID, , , , ) = core.disputes(disputeID);
+ assertEq(courtID, GENERAL_COURT, "Wrong court ID");
+
+ (, currentRound) = disputeKit.coreDisputeIDToActive(disputeID);
+ assertEq(currentRound, true, "round should be active in the DK that dispute jumped to");
+
+ // Check jump modifier
+ vm.prank(address(core));
+ vm.expectRevert(DisputeKitClassicBase.DisputeJumpedToAnotherDisputeKit.selector);
+ newDisputeKit.draw(disputeID, 1);
+
+ // And check that draw in the new round works
+ vm.expectEmit(true, true, true, true);
+ emit KlerosCore.Draw(staker1, disputeID, 1, 0); // roundID = 1 VoteID = 0
+ core.draw(disputeID, 1);
+
+ (address account, , , ) = disputeKit.getVoteInfo(disputeID, 1, 0);
+ assertEq(account, staker1, "Wrong drawn account in the classic DK");
+ }
+
+ function test_appeal_fullFundingCourtJumpAndDKJumpToNonClassic() public {
+ // Setup:
+ // dk2 supported by GENERAL_COURT, which is a non-DISPUTE_KIT_CLASSIC
+ // dk3 supported by court2, with dk3._jumpDisputeKitID == dk2
+ // Ensure that court2 jumps to GENERAL_COURT and dk3 jumps to dk2
+ uint256 disputeID = 0;
+ uint96 newCourtID = 2;
+ uint256 dkID2 = 2;
+ uint256 dkID3 = 3;
+
+ DisputeKitClassic dkLogic = new DisputeKitClassic();
+
+ bytes memory initDataDk2 = abi.encodeWithSignature(
+ "initialize(address,address,address,uint256)",
+ owner,
+ address(core),
+ address(wNative),
+ DISPUTE_KIT_CLASSIC
+ );
+ UUPSProxy proxyDk2 = new UUPSProxy(address(dkLogic), initDataDk2);
+ DisputeKitClassic disputeKit2 = DisputeKitClassic(address(proxyDk2));
+
+ bytes memory initDataDk3 = abi.encodeWithSignature(
+ "initialize(address,address,address,uint256)",
+ owner,
+ address(core),
+ address(wNative),
+ dkID2
+ );
+ UUPSProxy proxyDk3 = new UUPSProxy(address(dkLogic), initDataDk3);
+ DisputeKitClassic disputeKit3 = DisputeKitClassic(address(proxyDk3));
+
+ vm.prank(owner);
+ core.addNewDisputeKit(disputeKit2);
+ vm.prank(owner);
+ core.addNewDisputeKit(disputeKit3);
+
+ uint256[] memory supportedDK = new uint256[](2);
+ supportedDK[0] = DISPUTE_KIT_CLASSIC;
+ supportedDK[1] = dkID3;
+ vm.prank(owner);
+ core.createCourt(
+ GENERAL_COURT,
+ hiddenVotes,
+ minStake,
+ alpha,
+ feeForJuror,
+ 3, // jurors for jump. Low number to ensure jump after the first appeal
+ [uint256(60), uint256(120), uint256(180), uint256(240)], // Times per period
+ sortitionExtraData,
+ supportedDK
+ );
+ assertEq(core.isSupported(newCourtID, dkID3), true, "dkID3 should be supported by new court");
+
+ vm.prank(owner);
+ supportedDK[0] = DISPUTE_KIT_CLASSIC;
+ supportedDK[1] = dkID2;
+ core.enableDisputeKits(GENERAL_COURT, supportedDK, true);
+ assertEq(core.isSupported(GENERAL_COURT, dkID2), true, "dkID2 should be supported by GENERAL_COURT");
+
+ bytes memory newExtraData = abi.encodePacked(uint256(newCourtID), DEFAULT_NB_OF_JURORS, dkID3);
+ arbitrable.changeArbitratorExtraData(newExtraData);
+
+ vm.prank(staker1);
+ core.setStake(newCourtID, 20000);
+ vm.prank(disputer);
+ arbitrable.createDispute{value: feeForJuror * DEFAULT_NB_OF_JURORS}("Action");
+ vm.warp(block.timestamp + minStakingTime);
+ sortitionModule.passPhase(); // Generating
+ vm.warp(block.timestamp + rngLookahead);
+ sortitionModule.passPhase(); // Drawing phase
+
+ KlerosCore.Round memory round = core.getRoundInfo(disputeID, 0);
+ assertEq(round.disputeKitID, dkID3, "Wrong DK ID");
+
+ core.draw(disputeID, DEFAULT_NB_OF_JURORS);
+ vm.warp(block.timestamp + timesPerPeriod[0]);
+ core.passPeriod(disputeID); // Vote
+
+ uint256[] memory voteIDs = new uint256[](3);
+ voteIDs[0] = 0;
+ voteIDs[1] = 1;
+ voteIDs[2] = 2;
+
+ vm.prank(staker1);
+ disputeKit3.castVote(disputeID, voteIDs, 2, 0, "XYZ");
+
+ core.passPeriod(disputeID); // Appeal
+
+ vm.prank(crowdfunder1);
+ disputeKit3.fundAppeal{value: 0.63 ether}(disputeID, 1);
+
+ assertEq(core.isDisputeKitJumping(disputeID), true, "Should be jumping");
+
+ vm.expectEmit(true, true, true, true);
+ emit KlerosCore.CourtJump(disputeID, 1, newCourtID, GENERAL_COURT);
+ vm.expectEmit(true, true, true, true);
+ emit KlerosCore.DisputeKitJump(disputeID, 1, dkID3, dkID2);
+ vm.expectEmit(true, true, true, true);
+ emit DisputeKitClassicBase.DisputeCreation(disputeID, 2, newExtraData);
+ vm.expectEmit(true, true, true, true);
+ emit KlerosCore.AppealDecision(disputeID, arbitrable);
+ vm.expectEmit(true, true, true, true);
+ emit KlerosCore.NewPeriod(disputeID, KlerosCore.Period.evidence);
+ vm.prank(crowdfunder2);
+ disputeKit3.fundAppeal{value: 0.42 ether}(disputeID, 2);
+
+ (, bool currentRound) = disputeKit3.coreDisputeIDToActive(disputeID);
+ assertEq(currentRound, false, "round should be jumped");
+ assertEq(
+ (disputeKit3.getFundedChoices(disputeID)).length,
+ 2,
+ "No fresh round created so the number of funded choices should be 2"
+ );
+
+ round = core.getRoundInfo(disputeID, 1);
+ assertEq(round.disputeKitID, dkID2, "Wrong DK ID");
+ assertEq(sortitionModule.disputesWithoutJurors(), 1, "Wrong disputesWithoutJurors count");
+ (uint96 courtID, , , , ) = core.disputes(disputeID);
+ assertEq(courtID, GENERAL_COURT, "Wrong court ID");
+
+ (, currentRound) = disputeKit2.coreDisputeIDToActive(disputeID);
+ assertEq(currentRound, true, "round should be active in the DK that dispute jumped to");
+
+ // Check jump modifier
+ vm.prank(address(core));
+ vm.expectRevert(DisputeKitClassicBase.DisputeJumpedToAnotherDisputeKit.selector);
+ disputeKit3.draw(disputeID, 1);
+
+ // And check that draw in the new round works
+ vm.expectEmit(true, true, true, true);
+ emit KlerosCore.Draw(staker1, disputeID, 1, 0); // roundID = 1 VoteID = 0
+ core.draw(disputeID, 1);
+
+ (address account, , , ) = disputeKit2.getVoteInfo(disputeID, 1, 0);
+ assertEq(account, staker1, "Wrong drawn account in the classic DK");
+ }
+
+ function test_appeal_recurringDK() public {
+ // Test the behaviour when dispute jumps from DK3 to DK2 and then back to DK3 again.
+
+ // Setup: create 2 more courts to facilitate appeal jump. Create 2 more DK.
+ // Set General Court as parent to court2, and court2 as parent to court3. dk2 as jump DK for dk3, and dk3 as jump DK for dk2.
+ // Ensure DK2 is supported by Court2 and DK3 is supported by court3.
+ // Preemptively add DK3 support for General court.
+
+ // Initial dispute starts with Court3, DK3.
+ // Jumps to Court2, DK2.
+ // Then jumps to General Court, DK3.
+ uint256 disputeID = 0;
+
+ uint96 courtID2 = 2;
+ uint96 courtID3 = 3;
+
+ uint256 dkID2 = 2;
+ uint256 dkID3 = 3;
+
+ DisputeKitClassic dkLogic = new DisputeKitClassic();
+
+ bytes memory initDataDk2 = abi.encodeWithSignature(
+ "initialize(address,address,address,uint256)",
+ owner,
+ address(core),
+ address(wNative),
+ dkID3
+ );
+ UUPSProxy proxyDk2 = new UUPSProxy(address(dkLogic), initDataDk2);
+ DisputeKitClassic disputeKit2 = DisputeKitClassic(address(proxyDk2));
+
+ bytes memory initDataDk3 = abi.encodeWithSignature(
+ "initialize(address,address,address,uint256)",
+ owner,
+ address(core),
+ address(wNative),
+ dkID2
+ );
+ UUPSProxy proxyDk3 = new UUPSProxy(address(dkLogic), initDataDk3);
+ DisputeKitClassic disputeKit3 = DisputeKitClassic(address(proxyDk3));
+
+ vm.prank(owner);
+ core.addNewDisputeKit(disputeKit2);
+ vm.prank(owner);
+ core.addNewDisputeKit(disputeKit3);
+
+ uint256[] memory supportedDK = new uint256[](2);
+ supportedDK[0] = DISPUTE_KIT_CLASSIC;
+ supportedDK[1] = dkID2;
+ vm.prank(owner);
+ core.createCourt(
+ GENERAL_COURT,
+ hiddenVotes,
+ minStake,
+ alpha,
+ feeForJuror,
+ 7, // jurors for jump. Minimal number to ensure jump after the first appeal
+ [uint256(60), uint256(120), uint256(180), uint256(240)], // Times per period
+ sortitionExtraData,
+ supportedDK
+ );
+ assertEq(core.isSupported(courtID2, dkID2), true, "dkID2 should be supported by Court2");
+
+ (uint96 courtParent, , , , , uint256 courtJurorsForCourtJump) = core.courts(courtID2);
+ assertEq(courtParent, GENERAL_COURT, "Wrong court parent for court2");
+ assertEq(courtJurorsForCourtJump, 7, "Wrong jurors for jump value for court2");
+
+ supportedDK = new uint256[](2);
+ supportedDK[0] = DISPUTE_KIT_CLASSIC;
+ supportedDK[1] = dkID3;
+ vm.prank(owner);
+ core.createCourt(
+ courtID2,
+ hiddenVotes,
+ minStake,
+ alpha,
+ feeForJuror,
+ 3, // jurors for jump. Minimal number to ensure jump after the first appeal
+ [uint256(60), uint256(120), uint256(180), uint256(240)], // Times per period
+ sortitionExtraData,
+ supportedDK
+ );
+ assertEq(core.isSupported(courtID3, dkID3), true, "dkID3 should be supported by Court3");
+
+ (courtParent, , , , , courtJurorsForCourtJump) = core.courts(courtID3);
+ assertEq(courtParent, courtID2, "Wrong court parent for court3");
+ assertEq(courtJurorsForCourtJump, 3, "Wrong jurors for jump value for court3");
+
+ vm.prank(owner);
+ supportedDK[0] = DISPUTE_KIT_CLASSIC;
+ supportedDK[1] = dkID3;
+ core.enableDisputeKits(GENERAL_COURT, supportedDK, true);
+ assertEq(core.isSupported(GENERAL_COURT, dkID3), true, "dkID3 should be supported by GENERAL_COURT");
+
+ bytes memory newExtraData = abi.encodePacked(uint256(courtID3), DEFAULT_NB_OF_JURORS, dkID3);
+ arbitrable.changeArbitratorExtraData(newExtraData);
+
+ vm.prank(staker1);
+ core.setStake(courtID3, 20000);
+ vm.prank(disputer);
+ arbitrable.createDispute{value: feeForJuror * DEFAULT_NB_OF_JURORS}("Action");
+ vm.warp(block.timestamp + minStakingTime);
+ sortitionModule.passPhase(); // Generating
+ vm.warp(block.timestamp + rngLookahead);
+ sortitionModule.passPhase(); // Drawing phase
+
+ // Round1 //
+
+ KlerosCore.Round memory round = core.getRoundInfo(disputeID, 0);
+ assertEq(round.disputeKitID, dkID3, "Wrong DK ID");
+
+ assertEq(disputeKit3.coreDisputeIDToLocal(disputeID), 0, "Wrong local dispute ID to core dispute ID");
+ assertEq(disputeKit3.getNumberOfRounds(0), 1, "Wrong number of rounds dk3"); // local dispute id
+ (, uint256 localRoundID) = disputeKit3.getLocalDisputeRoundID(disputeID, 0);
+ assertEq(localRoundID, 0, "Wrong local round ID dk3");
+
+ (bool disputeActive, bool currentRound) = disputeKit3.coreDisputeIDToActive(0);
+ assertEq(disputeActive, true, "dispute should be active for dk3");
+ assertEq(currentRound, true, "round should be active in dk3");
+
+ core.draw(disputeID, DEFAULT_NB_OF_JURORS);
+ vm.warp(block.timestamp + timesPerPeriod[0]);
+ core.passPeriod(disputeID); // Vote
+
+ uint256[] memory voteIDs = new uint256[](3);
+ voteIDs[0] = 0;
+ voteIDs[1] = 1;
+ voteIDs[2] = 2;
+
+ vm.prank(staker1);
+ disputeKit3.castVote(disputeID, voteIDs, 2, 0, "XYZ");
+
+ core.passPeriod(disputeID); // Appeal
+
+ vm.prank(crowdfunder1);
+ disputeKit3.fundAppeal{value: 0.63 ether}(disputeID, 1);
+
+ assertEq(core.isDisputeKitJumping(disputeID), true, "Should be jumping");
+
+ vm.expectEmit(true, true, true, true);
+ emit KlerosCore.CourtJump(disputeID, 1, courtID3, courtID2);
+ vm.expectEmit(true, true, true, true);
+ emit KlerosCore.DisputeKitJump(disputeID, 1, dkID3, dkID2);
+ vm.expectEmit(true, true, true, true);
+ emit DisputeKitClassicBase.DisputeCreation(disputeID, 2, newExtraData);
+ vm.expectEmit(true, true, true, true);
+ emit KlerosCore.AppealDecision(disputeID, arbitrable);
+ vm.expectEmit(true, true, true, true);
+ emit KlerosCore.NewPeriod(disputeID, KlerosCore.Period.evidence);
+ vm.prank(crowdfunder2);
+ disputeKit3.fundAppeal{value: 0.42 ether}(disputeID, 2);
+
+ // Round2 //
+
+ (disputeActive, currentRound) = disputeKit3.coreDisputeIDToActive(0);
+ assertEq(disputeActive, true, "dispute should still be active for dk3");
+ assertEq(currentRound, false, "round should be jumped in dk3");
+ assertEq(
+ (disputeKit3.getFundedChoices(disputeID)).length,
+ 2,
+ "No fresh round created so the number of funded choices should be 2"
+ );
+ assertEq(disputeKit3.coreDisputeIDToLocal(disputeID), 0, "core to local ID should not change for dk3");
+ assertEq(disputeKit3.getNumberOfRounds(0), 1, "Wrong number of rounds dk3"); // local dispute id
+ (, localRoundID) = disputeKit3.getLocalDisputeRoundID(disputeID, 0);
+ assertEq(localRoundID, 0, "Local round ID should not change dk3");
+
+ round = core.getRoundInfo(disputeID, 1);
+ assertEq(round.disputeKitID, dkID2, "Wrong DK ID");
+ assertEq(sortitionModule.disputesWithoutJurors(), 1, "Wrong disputesWithoutJurors count");
+ (uint96 courtID, , , , ) = core.disputes(disputeID);
+ assertEq(courtID, courtID2, "Wrong court ID after jump");
+
+ (disputeActive, currentRound) = disputeKit2.coreDisputeIDToActive(0);
+ assertEq(disputeActive, true, "dispute should be active for dk2");
+ assertEq(currentRound, true, "round should be active in the DK that dispute jumped to");
+ assertEq(disputeKit2.coreDisputeIDToLocal(disputeID), 0, "Wrong local dispute ID to core dispute ID dk2");
+ assertEq(disputeKit2.getNumberOfRounds(0), 1, "Wrong number of rounds dk2"); // local dispute id
+ (, localRoundID) = disputeKit2.getLocalDisputeRoundID(disputeID, 1);
+ assertEq(localRoundID, 0, "Wrong local round ID for dk2");
+
+ vm.prank(address(core));
+ vm.expectRevert(DisputeKitClassicBase.DisputeJumpedToAnotherDisputeKit.selector);
+ disputeKit3.draw(disputeID, 1);
+
+ core.draw(disputeID, 7); // New round requires 7 jurors
+ vm.warp(block.timestamp + timesPerPeriod[0]);
+ core.passPeriod(disputeID); // Vote
+
+ voteIDs = new uint256[](7);
+ for (uint256 i = 0; i < voteIDs.length; i++) {
+ voteIDs[i] = i;
+ }
+
+ vm.prank(staker1);
+ vm.expectRevert(DisputeKitClassicBase.DisputeJumpedToAnotherDisputeKit.selector);
+ disputeKit3.castVote(disputeID, voteIDs, 2, 0, "XYZ");
+
+ vm.prank(staker1);
+ disputeKit2.castVote(disputeID, voteIDs, 2, 0, "XYZ");
+
+ core.passPeriod(disputeID); // Appeal
+
+ vm.prank(crowdfunder1);
+ vm.expectRevert(DisputeKitClassicBase.DisputeJumpedToAnotherDisputeKit.selector);
+ disputeKit3.fundAppeal{value: 1.35 ether}(disputeID, 1);
+
+ assertEq(core.isDisputeKitJumping(disputeID), true, "Should be jumping");
+
+ vm.prank(crowdfunder1);
+ // appealCost is 0.45. (0.03 * 15)
+ disputeKit2.fundAppeal{value: 1.35 ether}(disputeID, 1); // 0.45 + (0.45 * 20000/10000).
+
+ vm.expectEmit(true, true, true, true);
+ emit KlerosCore.CourtJump(disputeID, 2, courtID2, GENERAL_COURT);
+ vm.expectEmit(true, true, true, true);
+ emit KlerosCore.DisputeKitJump(disputeID, 2, dkID2, dkID3);
+ vm.prank(crowdfunder2);
+ disputeKit2.fundAppeal{value: 0.9 ether}(disputeID, 2); // 0.45 + (0.45 * 10000/10000).
+
+ // Round3 //
+
+ (disputeActive, currentRound) = disputeKit2.coreDisputeIDToActive(0);
+ assertEq(disputeActive, true, "dispute should still be active for dk2");
+ assertEq(currentRound, false, "round should be jumped in dk2");
+ assertEq(
+ (disputeKit2.getFundedChoices(disputeID)).length,
+ 2,
+ "No fresh round created so the number of funded choices should be 2 for dk2"
+ );
+ assertEq(
+ disputeKit3.getFundedChoices(disputeID).length,
+ 0,
+ "Should be 0 funded choices in dk3 because fresh round"
+ );
+ assertEq(disputeKit3.coreDisputeIDToLocal(disputeID), 0, "core to local ID should stay the same for dk3");
+ assertEq(disputeKit3.getNumberOfRounds(0), 2, "Wrong number of rounds dk3 round3"); // local dispute id
+ (, localRoundID) = disputeKit3.getLocalDisputeRoundID(disputeID, 2);
+ assertEq(localRoundID, 1, "Wrong local round id for dk3 round3");
+
+ round = core.getRoundInfo(disputeID, 2);
+ assertEq(round.disputeKitID, dkID3, "Wrong DK ID");
+ assertEq(sortitionModule.disputesWithoutJurors(), 1, "Wrong disputesWithoutJurors count");
+ (courtID, , , , ) = core.disputes(disputeID);
+ assertEq(courtID, GENERAL_COURT, "Wrong court ID after jump");
+
+ (disputeActive, currentRound) = disputeKit3.coreDisputeIDToActive(0); // local dispute id
+ assertEq(disputeActive, true, "dispute should still be active for dk3");
+ assertEq(currentRound, true, "round should be active in the DK that dispute jumped to");
+
+ assertEq(
+ disputeKit2.coreDisputeIDToLocal(disputeID),
+ 0,
+ "Wrong local dispute ID to core dispute ID dk2 round3"
+ );
+ assertEq(disputeKit2.getNumberOfRounds(0), 1, "Wrong number of rounds dk2 round3"); // local dispute id
+ (, localRoundID) = disputeKit2.getLocalDisputeRoundID(disputeID, 1);
+ assertEq(localRoundID, 0, "Wrong local round ID for dk2 round3");
+
+ vm.prank(address(core));
+ vm.expectRevert(DisputeKitClassicBase.DisputeJumpedToAnotherDisputeKit.selector);
+ disputeKit2.draw(disputeID, 1);
+
+ core.draw(disputeID, 15); // New round requires 15 jurors
+ vm.warp(block.timestamp + timesPerPeriod[0]);
+ core.passPeriod(disputeID); // Vote
+
+ voteIDs = new uint256[](15);
+ for (uint256 i = 0; i < voteIDs.length; i++) {
+ voteIDs[i] = i;
+ }
+
+ vm.prank(staker1);
+ vm.expectRevert(DisputeKitClassicBase.DisputeJumpedToAnotherDisputeKit.selector);
+ disputeKit2.castVote(disputeID, voteIDs, 2, 0, "XYZ");
+
+ vm.prank(staker1);
+ disputeKit3.castVote(disputeID, voteIDs, 2, 0, "XYZ");
+
+ vm.warp(block.timestamp + timesPerPeriod[2]);
+ core.passPeriod(disputeID); // Appeal
+
+ vm.warp(block.timestamp + timesPerPeriod[3]);
+ core.passPeriod(disputeID); // Execution
+
+ core.executeRuling(disputeID); // winning choice is 2
+
+ // Appeal Rewards //
+ disputeKit3.withdrawFeesAndRewards(disputeID, payable(crowdfunder1), 1); // wrong side, no reward
+
+ vm.expectEmit();
+ emit DisputeKitClassicBase.Withdrawal(disputeID, 2, payable(crowdfunder2), 0.84 ether);
+ disputeKit3.withdrawFeesAndRewards(disputeID, payable(crowdfunder2), 2); // REWARDS
+
+ disputeKit2.withdrawFeesAndRewards(disputeID, payable(crowdfunder1), 1); // wrong DK, no reward
+
+ vm.expectEmit();
+ emit DisputeKitClassicBase.Withdrawal(disputeID, 2, payable(crowdfunder2), 1.8 ether);
+ disputeKit2.withdrawFeesAndRewards(disputeID, payable(crowdfunder2), 2); // REWARDS
+
+ vm.expectRevert(DisputeKitClassicBase.DisputeUnknownInThisDisputeKit.selector);
+ disputeKit.withdrawFeesAndRewards(disputeID, payable(crowdfunder1), 1); // wrong DK, no reward
+
+ vm.expectRevert(DisputeKitClassicBase.DisputeUnknownInThisDisputeKit.selector);
+ disputeKit.withdrawFeesAndRewards(disputeID, payable(crowdfunder2), 2); // wrong DK, no reward
+ }
+
+ function test_appeal_quickPassPeriod() public {
+ uint256 disputeID = 0;
+
+ vm.prank(staker1);
+ core.setStake(GENERAL_COURT, 10000);
+ vm.prank(disputer);
+ arbitrable.createDispute{value: feeForJuror * DEFAULT_NB_OF_JURORS}("Action");
+ vm.warp(block.timestamp + minStakingTime);
+ sortitionModule.passPhase(); // Generating
+ vm.warp(block.timestamp + rngLookahead);
+ sortitionModule.passPhase(); // Drawing phase
+
+ core.draw(disputeID, DEFAULT_NB_OF_JURORS);
+ vm.warp(block.timestamp + timesPerPeriod[0]);
+ core.passPeriod(disputeID); // Vote
+
+ uint256[] memory voteIDs = new uint256[](3);
+ voteIDs[0] = 0;
+ voteIDs[1] = 1;
+ voteIDs[2] = 2;
+
+ vm.prank(staker1);
+ disputeKit.castVote(disputeID, voteIDs, 2, 0, "XYZ");
+
+ core.passPeriod(disputeID); // Appeal
+
+ vm.warp(block.timestamp + timesPerPeriod[3] / 2);
+
+ // Should pass to execution period without waiting for the 2nd half of the appeal.
+ vm.expectEmit(true, true, true, true);
+ emit KlerosCore.NewPeriod(disputeID, KlerosCore.Period.execution);
+ core.passPeriod(disputeID);
+ }
+
+ function testFuzz_appeal(uint256 numberOfOptions, uint256 choice1, uint256 choice2, uint256 choice3) public {
+ uint256 disputeID = 0;
+
+ arbitrable.changeNumberOfRulingOptions(numberOfOptions);
+
+ // Have only 2 options for 3 jurors to create a majority
+ vm.assume(choice1 <= numberOfOptions);
+ vm.assume(choice2 <= numberOfOptions);
+ vm.assume(choice3 <= numberOfOptions); // Will be used for appeal
+
+ vm.prank(staker1);
+ core.setStake(GENERAL_COURT, 2000);
+ vm.prank(disputer);
+ arbitrable.createDispute{value: feeForJuror * DEFAULT_NB_OF_JURORS}("Action");
+
+ (uint256 numberOfChoices, ) = disputeKit.disputes(disputeID);
+
+ assertEq(numberOfChoices, numberOfOptions, "Wrong numberOfChoices");
+
+ vm.warp(block.timestamp + minStakingTime);
+ sortitionModule.passPhase(); // Generating
+ vm.warp(block.timestamp + rngLookahead);
+ sortitionModule.passPhase(); // Drawing phase
+
+ // Split the stakers' votes. The first staker will get VoteID 0 and the second will take the rest.
+ core.draw(disputeID, 1);
+
+ vm.warp(block.timestamp + maxDrawingTime);
+ sortitionModule.passPhase(); // Staking phase to stake the 2nd voter
+ vm.prank(staker2);
+ core.setStake(GENERAL_COURT, 20000);
+ vm.warp(block.timestamp + minStakingTime);
+ sortitionModule.passPhase(); // Generating
+ vm.warp(block.timestamp + rngLookahead);
+ sortitionModule.passPhase(); // Drawing phase
+
+ core.draw(disputeID, 2); // Assign leftover votes to staker2
+
+ vm.warp(block.timestamp + timesPerPeriod[0]);
+ core.passPeriod(disputeID); // Vote
+
+ uint256[] memory voteIDs = new uint256[](1);
+ voteIDs[0] = 0;
+ vm.prank(staker1);
+ disputeKit.castVote(disputeID, voteIDs, choice1, 0, "XYZ"); // Staker1 only got 1 vote because of low stake
+
+ voteIDs = new uint256[](2);
+ voteIDs[0] = 1;
+ voteIDs[1] = 2;
+ vm.prank(staker2);
+ disputeKit.castVote(disputeID, voteIDs, choice2, 0, "XYZ");
+ core.passPeriod(disputeID); // Appeal
+
+ vm.assume(choice3 != choice2);
+ vm.prank(crowdfunder1);
+ disputeKit.fundAppeal{value: 0.63 ether}(disputeID, choice3); // Fund the losing choice. Total cost will be 0.63 (0.21 + 0.21 * (20000/10000))
+
+ assertEq((disputeKit.getFundedChoices(disputeID)).length, 1, "1 choice should be funded");
+
+ vm.prank(crowdfunder1);
+ disputeKit.fundAppeal{value: 0.42 ether}(disputeID, choice2); // Fund the winning choice. Total cost will be 0.42 (0.21 + 0.21 * (10000/10000))
+
+ assertEq((disputeKit.getFundedChoices(disputeID)).length, 0, "No funded choices in a fresh round");
+ }
+
+ function testFuzz_fundAppeal_msgValue(uint256 appealValue) public {
+ uint256 disputeID = 0;
+
+ vm.assume(appealValue <= 10 ether);
+ vm.deal(crowdfunder1, 10 ether);
+
+ vm.prank(staker1);
+ core.setStake(GENERAL_COURT, 2000);
+ vm.prank(disputer);
+ arbitrable.createDispute{value: feeForJuror * DEFAULT_NB_OF_JURORS}("Action");
+
+ vm.warp(block.timestamp + minStakingTime);
+ sortitionModule.passPhase(); // Generating
+ vm.warp(block.timestamp + rngLookahead);
+ sortitionModule.passPhase(); // Drawing phase
+
+ // Split the stakers' votes. The first staker will get VoteID 0 and the second will take the rest.
+ core.draw(disputeID, 1);
+
+ vm.warp(block.timestamp + maxDrawingTime);
+ sortitionModule.passPhase(); // Staking phase to stake the 2nd voter
+ vm.prank(staker2);
+ core.setStake(GENERAL_COURT, 20000);
+ vm.warp(block.timestamp + minStakingTime);
+ sortitionModule.passPhase(); // Generating
+ vm.warp(block.timestamp + rngLookahead);
+ sortitionModule.passPhase(); // Drawing phase
+
+ core.draw(disputeID, 2); // Assign leftover votes to staker2
+
+ vm.warp(block.timestamp + timesPerPeriod[0]);
+ core.passPeriod(disputeID); // Vote
+
+ uint256[] memory voteIDs = new uint256[](1);
+ voteIDs[0] = 0;
+ vm.prank(staker1);
+ disputeKit.castVote(disputeID, voteIDs, 1, 0, "XYZ"); // Staker1 only got 1 vote because of low stake
+
+ voteIDs = new uint256[](2);
+ voteIDs[0] = 1;
+ voteIDs[1] = 2;
+ vm.prank(staker2);
+ disputeKit.castVote(disputeID, voteIDs, 2, 0, "XYZ");
+ core.passPeriod(disputeID); // Appeal
+
+ vm.prank(crowdfunder1);
+ disputeKit.fundAppeal{value: appealValue}(disputeID, 1); // Fund the losing choice
+
+ if (appealValue >= 0.63 ether) {
+ // 0.63 eth is the required amount for losing side.
+ assertEq((disputeKit.getFundedChoices(disputeID)).length, 1, "One choice should be funded");
+ // Dispute kit shouldn't demand more value than necessary
+ assertEq(crowdfunder1.balance, 9.37 ether, "Wrong balance of the crowdfunder");
+ assertEq(address(disputeKit).balance, 0.63 ether, "Wrong balance of the DK");
+ } else {
+ assertEq((disputeKit.getFundedChoices(disputeID)).length, 0, "No choices should be funded");
+ assertEq(crowdfunder1.balance, 10 ether - appealValue, "Wrong balance of the crowdfunder");
+ assertEq(address(disputeKit).balance, appealValue, "Wrong balance of the DK");
+ }
+ }
+}
diff --git a/contracts/test/foundry/KlerosCore_Disputes.t.sol b/contracts/test/foundry/KlerosCore_Disputes.t.sol
new file mode 100644
index 000000000..93c4c0757
--- /dev/null
+++ b/contracts/test/foundry/KlerosCore_Disputes.t.sol
@@ -0,0 +1,196 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.24;
+
+import {KlerosCore_TestBase} from "./KlerosCore_TestBase.sol";
+import {KlerosCore} from "../../src/arbitration/KlerosCore.sol";
+import {IArbitratorV2} from "../../src/arbitration/KlerosCore.sol";
+import {DisputeKitClassicBase} from "../../src/arbitration/dispute-kits/DisputeKitClassicBase.sol";
+import {IArbitrableV2} from "../../src/arbitration/arbitrables/ArbitrableExample.sol";
+import "../../src/libraries/Constants.sol";
+
+/// @title KlerosCore_DisputesTest
+/// @dev Tests for KlerosCore dispute creation and management
+/// forge-lint: disable-next-item(erc20-unchecked-transfer)
+contract KlerosCore_DisputesTest is KlerosCore_TestBase {
+ function test_createDispute_eth() public {
+ // Create a new court and DK to test non-standard extra data
+ uint256 newFee = 0.01 ether;
+ uint96 newCourtID = 2;
+ uint256 newNbJurors = 4;
+ uint256 newDkID = 2;
+ uint256[] memory supportedDK = new uint256[](1);
+ supportedDK[0] = DISPUTE_KIT_CLASSIC;
+ bytes memory newExtraData = abi.encodePacked(uint256(newCourtID), newNbJurors, newDkID);
+
+ vm.prank(owner);
+ core.addNewDisputeKit(disputeKit); // Just add the same dk to avoid dealing with initialization
+ vm.prank(owner);
+ core.createCourt(
+ GENERAL_COURT,
+ true, // Hidden votes
+ 2000, // min stake
+ 20000, // alpha
+ newFee, // fee for juror
+ 50, // jurors for jump
+ [uint256(10), uint256(20), uint256(30), uint256(40)], // Times per period
+ abi.encode(uint256(4)), // Sortition extra data
+ supportedDK
+ );
+
+ arbitrable.changeArbitratorExtraData(newExtraData);
+
+ vm.expectRevert(KlerosCore.ArbitrationFeesNotEnough.selector);
+ vm.prank(disputer);
+ arbitrable.createDispute{value: newFee * newNbJurors - 1}("Action");
+
+ vm.expectRevert(KlerosCore.DisputeKitNotSupportedByCourt.selector);
+ vm.prank(disputer);
+ arbitrable.createDispute{value: 0.04 ether}("Action");
+
+ vm.prank(owner);
+ supportedDK = new uint256[](1);
+ supportedDK[0] = newDkID;
+ core.enableDisputeKits(newCourtID, supportedDK, true);
+
+ uint256 disputeID = 0;
+ uint256 nbChoices = 2;
+ vm.prank(disputer);
+ vm.expectEmit(true, true, true, true);
+ emit DisputeKitClassicBase.DisputeCreation(disputeID, nbChoices, newExtraData);
+ vm.expectEmit(true, true, true, true);
+ emit IArbitratorV2.DisputeCreation(disputeID, arbitrable);
+ arbitrable.createDispute{value: 0.04 ether}("Action");
+
+ assertEq(sortitionModule.disputesWithoutJurors(), 1, "Wrong disputesWithoutJurors count");
+ (
+ uint96 courtID,
+ IArbitrableV2 arbitrated,
+ KlerosCore.Period period,
+ bool ruled,
+ uint256 lastPeriodChange
+ ) = core.disputes(disputeID);
+
+ assertEq(courtID, newCourtID, "Wrong court ID");
+ assertEq(address(arbitrated), address(arbitrable), "Wrong arbitrable");
+ assertEq(uint256(period), uint256(KlerosCore.Period.evidence), "Wrong period");
+ assertEq(ruled, false, "Should not be ruled");
+ assertEq(lastPeriodChange, block.timestamp, "Wrong lastPeriodChange");
+
+ KlerosCore.Round memory round = core.getRoundInfo(disputeID, 0);
+ assertEq(round.disputeKitID, newDkID, "Wrong DK ID");
+ assertEq(round.pnkAtStakePerJuror, 4000, "Wrong pnkAtStakePerJuror"); // minStake * alpha / divisor = 2000 * 20000/10000
+ assertEq(round.totalFeesForJurors, 0.04 ether, "Wrong totalFeesForJurors");
+ assertEq(round.nbVotes, 4, "Wrong nbVotes");
+ assertEq(round.repartitions, 0, "repartitions should be 0");
+ assertEq(round.pnkPenalties, 0, "pnkPenalties should be 0");
+ assertEq(round.sumFeeRewardPaid, 0, "sumFeeRewardPaid should be 0");
+ assertEq(round.sumPnkRewardPaid, 0, "sumPnkRewardPaid should be 0");
+ assertEq(address(round.feeToken), address(0), "feeToken should be 0");
+ assertEq(round.drawIterations, 0, "drawIterations should be 0");
+
+ (uint256 numberOfChoices, bytes memory extraData) = disputeKit.disputes(disputeID);
+ assertEq(numberOfChoices, 2, "Wrong numberOfChoices");
+ assertEq(extraData, newExtraData, "Wrong extra data");
+
+ (bool dispute, bool currentRound) = disputeKit.coreDisputeIDToActive(0);
+ assertEq(dispute, true, "Dispute should be active in this DK");
+ assertEq(currentRound, true, "Current round should be active in this DK");
+
+ assertEq(disputeKit.coreDisputeIDToLocal(0), disputeID, "Wrong local disputeID");
+
+ (
+ uint256 winningChoice,
+ bool tied,
+ uint256 totalVoted,
+ uint256 totalCommited,
+ uint256 nbVoters,
+ uint256 choiceCount
+ ) = disputeKit.getRoundInfo(0, 0, 0);
+ assertEq(winningChoice, 0, "winningChoice should be 0");
+ assertEq(tied, true, "tied should be true");
+ assertEq(totalVoted, 0, "totalVoted should be 0");
+ assertEq(totalCommited, 0, "totalCommited should be 0");
+ assertEq(nbVoters, 0, "nbVoters should be 0");
+ assertEq(choiceCount, 0, "choiceCount should be 0");
+ }
+
+ function test_createDispute_tokens() public {
+ feeToken.transfer(disputer, 1 ether);
+ vm.prank(disputer);
+ feeToken.approve(address(arbitrable), 1 ether);
+
+ vm.expectRevert(KlerosCore.TokenNotAccepted.selector);
+ vm.prank(disputer);
+ arbitrable.createDispute("Action", 0.18 ether);
+
+ vm.prank(owner);
+ core.changeAcceptedFeeTokens(feeToken, true);
+ vm.prank(owner);
+ core.changeCurrencyRates(feeToken, 500, 3);
+
+ vm.expectRevert(KlerosCore.ArbitrationFeesNotEnough.selector);
+ vm.prank(disputer);
+ arbitrable.createDispute("Action", 0.18 ether - 1);
+
+ vm.expectRevert(KlerosCore.TransferFailed.selector);
+ vm.prank(address(arbitrable)); // Bypass createDispute in arbitrable to avoid transfer checks there and make the arbitrable call KC directly
+ core.createDispute(2, arbitratorExtraData, feeToken, 0.18 ether);
+
+ assertEq(core.arbitrationCost(arbitratorExtraData, feeToken), 0.18 ether, "Wrong token cost");
+ vm.prank(disputer);
+ arbitrable.createDispute("Action", 0.18 ether);
+
+ KlerosCore.Round memory round = core.getRoundInfo(0, 0);
+ assertEq(round.totalFeesForJurors, 0.18 ether, "Wrong totalFeesForJurors");
+ assertEq(round.nbVotes, 3, "Wrong nbVotes");
+ assertEq(address(round.feeToken), address(feeToken), "Wrong feeToken");
+
+ assertEq(feeToken.balanceOf(address(core)), 0.18 ether, "Wrong token balance of the core");
+ assertEq(feeToken.balanceOf(disputer), 0.82 ether, "Wrong token balance of the disputer");
+ }
+
+ function testFuzz_createDispute_msgValue(uint256 disputeValue) public {
+ uint256 disputeID = 0;
+ uint256 arbitrationCost = core.arbitrationCost(arbitratorExtraData);
+
+ // Cap it to 10 eth, so the number of jurors is not astronomical.
+ vm.assume(disputeValue >= arbitrationCost && disputeValue <= 10 ether);
+ vm.deal(disputer, 10 ether);
+
+ vm.prank(staker1);
+ core.setStake(GENERAL_COURT, 2000);
+ vm.prank(disputer);
+ arbitrable.createDispute{value: disputeValue}("Action");
+
+ KlerosCore.Round memory round = core.getRoundInfo(disputeID, 0);
+ assertEq(round.totalFeesForJurors, disputeValue, "Wrong totalFeesForJurors");
+ assertEq(round.nbVotes, disputeValue / feeForJuror, "Wrong nbVotes");
+
+ vm.warp(block.timestamp + minStakingTime);
+ sortitionModule.passPhase(); // Generating
+ vm.warp(block.timestamp + rngLookahead);
+ sortitionModule.passPhase(); // Drawing phase
+
+ core.draw(disputeID, disputeValue / feeForJuror);
+
+ vm.warp(block.timestamp + timesPerPeriod[0]);
+ core.passPeriod(disputeID); // Vote
+
+ uint256[] memory voteIDs = new uint256[](disputeValue / feeForJuror);
+ for (uint256 i = 0; i < voteIDs.length; i++) {
+ voteIDs[i] = i;
+ }
+
+ vm.prank(staker1);
+ disputeKit.castVote(disputeID, voteIDs, 1, 0, "XYZ");
+
+ core.passPeriod(disputeID); // Appeal
+
+ vm.warp(block.timestamp + timesPerPeriod[3]);
+ core.passPeriod(disputeID); // Execution
+
+ vm.expectEmit(true, true, true, true);
+ emit IArbitrableV2.Ruling(IArbitratorV2(address(core)), disputeID, 1);
+ core.executeRuling(disputeID);
+ }
+}
diff --git a/contracts/test/foundry/KlerosCore_Drawing.t.sol b/contracts/test/foundry/KlerosCore_Drawing.t.sol
new file mode 100644
index 000000000..a1242009f
--- /dev/null
+++ b/contracts/test/foundry/KlerosCore_Drawing.t.sol
@@ -0,0 +1,227 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.24;
+
+import {KlerosCore_TestBase} from "./KlerosCore_TestBase.sol";
+import {KlerosCore} from "../../src/arbitration/KlerosCore.sol";
+import {SortitionModule} from "../../src/arbitration/SortitionModule.sol";
+import {ISortitionModule} from "../../src/arbitration/interfaces/ISortitionModule.sol";
+import {Vm} from "forge-std/Vm.sol";
+import "../../src/libraries/Constants.sol";
+
+/// @title KlerosCore_DrawingTest
+/// @dev Tests for KlerosCore jury drawing and selection mechanisms
+contract KlerosCore_DrawingTest is KlerosCore_TestBase {
+ function test_draw() public {
+ uint256 disputeID = 0;
+ uint256 roundID = 0;
+
+ vm.prank(staker1);
+ core.setStake(GENERAL_COURT, 1500);
+ vm.prank(disputer);
+ arbitrable.createDispute{value: feeForJuror * DEFAULT_NB_OF_JURORS}("Action");
+ vm.warp(block.timestamp + minStakingTime);
+ sortitionModule.passPhase(); // Generating
+ vm.warp(block.timestamp + rngLookahead);
+ sortitionModule.passPhase(); // Drawing phase
+
+ vm.expectEmit(true, true, true, true);
+ emit SortitionModule.StakeLocked(staker1, 1000, false);
+ vm.expectEmit(true, true, true, true);
+ emit KlerosCore.Draw(staker1, disputeID, roundID, 0); // VoteID = 0
+
+ core.draw(disputeID, DEFAULT_NB_OF_JURORS); // Do 3 iterations and see that the juror will get drawn 3 times despite low stake.
+
+ (uint256 totalStaked, uint256 totalLocked, uint256 stakedInCourt, ) = sortitionModule.getJurorBalance(
+ staker1,
+ GENERAL_COURT
+ );
+ assertEq(totalStaked, 1500, "Wrong amount total staked");
+ assertEq(totalLocked, 3000, "Wrong amount locked"); // 1000 per draw
+ assertEq(stakedInCourt, 1500, "Wrong amount staked in court");
+ assertEq(sortitionModule.disputesWithoutJurors(), 0, "Wrong disputesWithoutJurors count");
+
+ for (uint256 i = 0; i < DEFAULT_NB_OF_JURORS; i++) {
+ (address account, bytes32 commit, uint256 choice, bool voted) = disputeKit.getVoteInfo(0, 0, i);
+ assertEq(account, staker1, "Wrong drawn account");
+ assertEq(commit, bytes32(0), "Commit should be empty");
+ assertEq(choice, 0, "Choice should be empty");
+ assertEq(voted, false, "Voted should be false");
+ }
+
+ // Try drawing even more...
+ vm.recordLogs();
+ core.draw(disputeID, DEFAULT_NB_OF_JURORS); // Should not revert, nor draw any juror, nor change state.
+ Vm.Log[] memory entries = vm.getRecordedLogs();
+
+ // Verify no Draw events were emitted
+ bytes32 drawEventSignature = keccak256("Draw(address,uint256,uint256,uint256)");
+ for (uint256 i = 0; i < entries.length; i++) {
+ assertFalse(entries[i].topics[0] == drawEventSignature, "Draw event should not be emitted");
+ }
+
+ assertEq(totalStaked, 1500, "Wrong amount total staked");
+ assertEq(totalLocked, 3000, "Wrong amount locked");
+ assertEq(stakedInCourt, 1500, "Wrong amount staked in court");
+ assertEq(sortitionModule.disputesWithoutJurors(), 0, "Wrong disputesWithoutJurors count");
+ }
+
+ function test_draw_noEmptyAddresses() public {
+ uint256 disputeID = 0;
+ uint256 roundID = 0;
+
+ vm.prank(disputer);
+ arbitrable.createDispute{value: feeForJuror * DEFAULT_NB_OF_JURORS}("Action");
+ vm.warp(block.timestamp + minStakingTime);
+ sortitionModule.passPhase(); // Generating
+ vm.warp(block.timestamp + rngLookahead);
+ sortitionModule.passPhase(); // Drawing phase
+
+ core.draw(disputeID, DEFAULT_NB_OF_JURORS); // No one is staked so check that the empty addresses are not drawn.
+
+ KlerosCore.Round memory round = core.getRoundInfo(disputeID, roundID);
+ assertEq(round.drawIterations, 3, "Wrong drawIterations number");
+
+ (, , , , uint256 nbVoters, ) = disputeKit.getRoundInfo(disputeID, roundID, 0);
+ assertEq(nbVoters, 0, "nbVoters should be 0");
+ }
+
+ function test_draw_parentCourts() public {
+ uint96 newCourtID = 2;
+ uint256 disputeID = 0;
+ uint256 roundID = 0;
+
+ // Create a child court and stake exclusively there to check that parent courts hold drawing power.
+ vm.prank(owner);
+ uint256[] memory supportedDK = new uint256[](1);
+ supportedDK[0] = DISPUTE_KIT_CLASSIC;
+ core.createCourt(
+ GENERAL_COURT,
+ true, // Hidden votes
+ 1000, // min stake
+ 10000, // alpha
+ 0.03 ether, // fee for juror
+ 50, // jurors for jump
+ [uint256(10), uint256(20), uint256(30), uint256(40)], // Times per period
+ sortitionExtraData, // Sortition extra data
+ supportedDK
+ );
+
+ uint256[] memory children = core.getCourtChildren(GENERAL_COURT);
+ assertEq(children.length, 1, "Wrong children count");
+ assertEq(children[0], 2, "Wrong child ID");
+
+ vm.prank(staker1);
+ core.setStake(newCourtID, 3000);
+ vm.prank(disputer);
+ arbitrable.createDispute{value: feeForJuror * DEFAULT_NB_OF_JURORS}("Action"); // Dispute uses general court by default
+ vm.warp(block.timestamp + minStakingTime);
+ sortitionModule.passPhase(); // Generating
+ vm.warp(block.timestamp + rngLookahead);
+ sortitionModule.passPhase(); // Drawing phase
+
+ (uint96 courtID, , , , ) = core.disputes(disputeID);
+ assertEq(courtID, GENERAL_COURT, "Wrong court ID of the dispute");
+
+ vm.expectEmit(true, true, true, true);
+ emit KlerosCore.Draw(staker1, disputeID, roundID, 0);
+ vm.expectEmit(true, true, true, true);
+ emit KlerosCore.Draw(staker1, disputeID, roundID, 1);
+ vm.expectEmit(true, true, true, true);
+ emit KlerosCore.Draw(staker1, disputeID, roundID, 2);
+ core.draw(disputeID, DEFAULT_NB_OF_JURORS);
+
+ assertEq(sortitionModule.disputesWithoutJurors(), 0, "Wrong disputesWithoutJurors count");
+
+ KlerosCore.Round memory round = core.getRoundInfo(disputeID, roundID);
+ assertEq(round.drawIterations, 3, "Wrong drawIterations number");
+
+ (, , , , uint256 nbVoters, ) = disputeKit.getRoundInfo(disputeID, roundID, 0);
+ assertEq(nbVoters, 3, "nbVoters should be 3");
+ }
+
+ function testFuzz_drawIterations(uint256 iterations) public {
+ uint256 disputeID = 0;
+ uint256 roundID = 0;
+
+ vm.prank(staker1);
+ core.setStake(GENERAL_COURT, 2000);
+ vm.prank(disputer);
+ arbitrable.createDispute{value: feeForJuror * DEFAULT_NB_OF_JURORS}("Action");
+ vm.warp(block.timestamp + minStakingTime);
+ sortitionModule.passPhase(); // Generating
+ vm.warp(block.timestamp + rngLookahead);
+ sortitionModule.passPhase(); // Drawing phase
+
+ core.draw(disputeID, iterations);
+
+ uint256 iterationsCount;
+ uint256 disputesWithoutJurors;
+ if (iterations < DEFAULT_NB_OF_JURORS) {
+ iterationsCount = iterations;
+ disputesWithoutJurors = 1;
+ } else {
+ iterationsCount = DEFAULT_NB_OF_JURORS;
+ disputesWithoutJurors = 0;
+ }
+
+ KlerosCore.Round memory round = core.getRoundInfo(disputeID, roundID);
+ assertEq(round.drawIterations, iterationsCount, "Wrong drawIterations number");
+ assertEq(round.nbVotes, DEFAULT_NB_OF_JURORS, "Wrong nbVotes");
+
+ (uint256 totalStaked, uint256 totalLocked, uint256 stakedInCourt, ) = sortitionModule.getJurorBalance(
+ staker1,
+ GENERAL_COURT
+ );
+ uint256 pnkAtStake = (minStake * alpha) / ONE_BASIS_POINT;
+ assertEq(totalStaked, 2000, "Wrong amount total staked");
+ assertEq(totalLocked, pnkAtStake * iterationsCount, "Wrong amount locked"); // 1000 per draw
+ assertEq(stakedInCourt, 2000, "Wrong amount staked in court");
+ assertEq(sortitionModule.disputesWithoutJurors(), disputesWithoutJurors, "Wrong disputesWithoutJurors count");
+ }
+
+ function testFuzz_drawIterations_nbJurors(uint256 iterations, uint256 disputeValue) public {
+ uint256 disputeID = 0;
+ uint256 roundID = 0;
+
+ uint256 arbitrationCost = core.arbitrationCost(arbitratorExtraData);
+ // Cap it to 10 eth, so the number of jurors is not astronomical.
+ vm.assume(disputeValue >= arbitrationCost && disputeValue <= 10 ether);
+ vm.deal(disputer, 10 ether);
+
+ vm.prank(staker1);
+ core.setStake(GENERAL_COURT, 2000);
+ vm.prank(disputer);
+ arbitrable.createDispute{value: disputeValue}("Action");
+ vm.warp(block.timestamp + minStakingTime);
+ sortitionModule.passPhase(); // Generating
+ vm.warp(block.timestamp + rngLookahead);
+ sortitionModule.passPhase(); // Drawing phase
+
+ core.draw(disputeID, iterations);
+
+ KlerosCore.Round memory round = core.getRoundInfo(disputeID, roundID);
+ assertEq(round.totalFeesForJurors, disputeValue, "Wrong totalFeesForJurors");
+ assertEq(round.nbVotes, disputeValue / feeForJuror, "Wrong nbVotes");
+
+ uint256 iterationsCount;
+ uint256 disputesWithoutJurors;
+ if (iterations < round.nbVotes) {
+ iterationsCount = iterations;
+ disputesWithoutJurors = 1;
+ } else {
+ iterationsCount = round.nbVotes;
+ disputesWithoutJurors = 0;
+ }
+
+ assertEq(round.drawIterations, iterationsCount, "Wrong drawIterations number");
+ (uint256 totalStaked, uint256 totalLocked, uint256 stakedInCourt, ) = sortitionModule.getJurorBalance(
+ staker1,
+ GENERAL_COURT
+ );
+ uint256 pnkAtStake = (minStake * alpha) / ONE_BASIS_POINT;
+ assertEq(totalStaked, 2000, "Wrong amount total staked");
+ assertEq(totalLocked, pnkAtStake * iterationsCount, "Wrong amount locked");
+ assertEq(stakedInCourt, 2000, "Wrong amount staked in court");
+ assertEq(sortitionModule.disputesWithoutJurors(), disputesWithoutJurors, "Wrong disputesWithoutJurors count");
+ }
+}
diff --git a/contracts/test/foundry/KlerosCore_Execution.t.sol b/contracts/test/foundry/KlerosCore_Execution.t.sol
new file mode 100644
index 000000000..81dd723a0
--- /dev/null
+++ b/contracts/test/foundry/KlerosCore_Execution.t.sol
@@ -0,0 +1,850 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.24;
+
+import {KlerosCore_TestBase} from "./KlerosCore_TestBase.sol";
+import {KlerosCore} from "../../src/arbitration/KlerosCore.sol";
+import {SortitionModule} from "../../src/arbitration/SortitionModule.sol";
+import {DisputeKitClassicBase} from "../../src/arbitration/dispute-kits/DisputeKitClassicBase.sol";
+import {IArbitratorV2, IArbitrableV2} from "../../src/arbitration/KlerosCore.sol";
+import {IERC20} from "../../src/libraries/SafeERC20.sol";
+import "../../src/libraries/Constants.sol";
+
+/// @title KlerosCore_ExecutionTest
+/// @dev Tests for KlerosCore execution, rewards, and ruling finalization
+/// forge-lint: disable-next-item(erc20-unchecked-transfer)
+contract KlerosCore_ExecutionTest is KlerosCore_TestBase {
+ function test_execute() public {
+ uint256 disputeID = 0;
+
+ vm.prank(staker1);
+ core.setStake(GENERAL_COURT, 2000);
+ vm.prank(disputer);
+ arbitrable.createDispute{value: feeForJuror * DEFAULT_NB_OF_JURORS}("Action");
+ vm.warp(block.timestamp + minStakingTime);
+ sortitionModule.passPhase(); // Generating
+ vm.warp(block.timestamp + rngLookahead);
+ sortitionModule.passPhase(); // Drawing phase
+
+ // Split the stakers' votes. The first staker will get VoteID 0 and the second will take the rest.
+ core.draw(disputeID, 1);
+
+ vm.warp(block.timestamp + maxDrawingTime);
+ sortitionModule.passPhase(); // Staking phase to stake the 2nd voter
+ vm.prank(staker2);
+ core.setStake(GENERAL_COURT, 20000);
+ vm.warp(block.timestamp + minStakingTime);
+ sortitionModule.passPhase(); // Generating
+ vm.warp(block.timestamp + rngLookahead);
+ sortitionModule.passPhase(); // Drawing phase
+
+ core.draw(disputeID, 2); // Assign leftover votes to staker2
+
+ vm.warp(block.timestamp + timesPerPeriod[0]);
+ core.passPeriod(disputeID); // Vote
+
+ uint256[] memory voteIDs = new uint256[](1);
+ voteIDs[0] = 0;
+ vm.prank(staker1);
+ disputeKit.castVote(disputeID, voteIDs, 1, 0, "XYZ"); // Staker1 only got 1 vote because of low stake
+
+ voteIDs = new uint256[](2);
+ voteIDs[0] = 1;
+ voteIDs[1] = 2;
+ vm.prank(staker2);
+ disputeKit.castVote(disputeID, voteIDs, 2, 0, "XYZ");
+ core.passPeriod(disputeID); // Appeal
+
+ vm.expectRevert(KlerosCore.NotExecutionPeriod.selector);
+ core.execute(disputeID, 0, 1);
+
+ vm.warp(block.timestamp + timesPerPeriod[3]);
+ core.passPeriod(disputeID); // Execution
+
+ vm.prank(owner);
+ core.pause();
+ vm.expectRevert(KlerosCore.WhenNotPausedOnly.selector);
+ core.execute(disputeID, 0, 1);
+ vm.prank(owner);
+ core.unpause();
+
+ assertEq(disputeKit.getCoherentCount(disputeID, 0), 2, "Wrong coherent count");
+
+ uint256 pnkCoherence;
+ uint256 feeCoherence;
+ // dispute, round, voteID, feeForJuror (not used in classic DK), pnkPerJuror (not used in classic DK)
+ (pnkCoherence, feeCoherence) = disputeKit.getDegreeOfCoherenceReward(disputeID, 0, 0, 0, 0);
+ assertEq(pnkCoherence, 0, "Wrong reward pnk coherence 0 vote ID");
+ assertEq(feeCoherence, 0, "Wrong reward fee coherence 0 vote ID");
+
+ (pnkCoherence, feeCoherence) = disputeKit.getDegreeOfCoherenceReward(disputeID, 0, 1, 0, 0);
+ assertEq(pnkCoherence, 10000, "Wrong reward pnk coherence 1 vote ID");
+ assertEq(feeCoherence, 10000, "Wrong reward fee coherence 1 vote ID");
+
+ (pnkCoherence, feeCoherence) = disputeKit.getDegreeOfCoherenceReward(disputeID, 0, 2, 0, 0);
+ assertEq(pnkCoherence, 10000, "Wrong reward pnk coherence 2 vote ID");
+ assertEq(feeCoherence, 10000, "Wrong reward fee coherence 2 vote ID");
+
+ assertEq(disputeKit.getDegreeOfCoherencePenalty(disputeID, 0, 0, 0, 0), 0, "Wrong penalty coherence 0 vote ID");
+ assertEq(
+ disputeKit.getDegreeOfCoherencePenalty(disputeID, 0, 1, 0, 0),
+ 10000,
+ "Wrong penalty coherence 1 vote ID"
+ );
+ assertEq(
+ disputeKit.getDegreeOfCoherencePenalty(disputeID, 0, 2, 0, 0),
+ 10000,
+ "Wrong penalty coherence 2 vote ID"
+ );
+
+ vm.expectEmit(true, true, true, true);
+ emit SortitionModule.StakeLocked(staker1, 1000, true);
+ vm.expectEmit(true, true, true, true);
+ emit KlerosCore.JurorRewardPenalty(staker1, disputeID, 0, 0, 0, -int256(1000), 0, IERC20(address(0))); // penalties
+ // Check iterations for the winning staker to see the shifts
+ vm.expectEmit(true, true, true, true);
+ emit SortitionModule.StakeLocked(staker2, 0, true);
+ core.execute(disputeID, 0, 3); // Do 3 iterations to check penalties first
+
+ (uint256 totalStaked, uint256 totalLocked, , ) = sortitionModule.getJurorBalance(staker1, GENERAL_COURT);
+ assertEq(totalStaked, 1000, "totalStaked should be penalized"); // 2000 - 1000
+ assertEq(totalLocked, 0, "Tokens should be released for staker1");
+ (, totalLocked, , ) = sortitionModule.getJurorBalance(staker2, GENERAL_COURT);
+ assertEq(totalLocked, 2000, "Tokens should still be locked for staker2");
+
+ KlerosCore.Round memory round = core.getRoundInfo(disputeID, 0);
+ assertEq(round.repartitions, 3, "Wrong repartitions");
+ assertEq(round.pnkPenalties, 1000, "Wrong pnkPenalties");
+
+ vm.expectEmit(true, true, true, true);
+ emit SortitionModule.StakeLocked(staker1, 0, true);
+ // Check iterations for the winning staker to see the shifts
+ vm.expectEmit(true, true, true, true);
+ emit SortitionModule.StakeLocked(staker2, 1000, true);
+ vm.expectEmit(true, true, true, true);
+ emit KlerosCore.JurorRewardPenalty(staker2, disputeID, 0, 10000, 10000, 500, 0.045 ether, IERC20(address(0))); // rewards
+ vm.expectEmit(true, true, true, true);
+ emit SortitionModule.StakeLocked(staker2, 1000, true);
+ vm.expectEmit(true, true, true, true);
+ emit KlerosCore.JurorRewardPenalty(staker2, disputeID, 0, 10000, 10000, 500, 0.045 ether, IERC20(address(0))); // rewards
+ core.execute(disputeID, 0, 10); // Finish the iterations. We need only 3 but check that it corrects the count.
+
+ (, totalLocked, , ) = sortitionModule.getJurorBalance(staker2, GENERAL_COURT);
+ assertEq(totalLocked, 0, "Tokens should be unlocked for staker2");
+
+ round = core.getRoundInfo(disputeID, 0);
+ assertEq(round.repartitions, 6, "Wrong repartitions");
+ assertEq(round.pnkPenalties, 1000, "Wrong pnkPenalties");
+ assertEq(round.sumFeeRewardPaid, 0.09 ether, "Wrong sumFeeRewardPaid");
+ assertEq(round.sumPnkRewardPaid, 1000, "Wrong sumPnkRewardPaid");
+
+ assertEq(address(core).balance, 0, "Wrong balance of the core");
+ assertEq(staker1.balance, 0, "Wrong balance of the staker1");
+ assertEq(staker2.balance, 0.09 ether, "Wrong balance of the staker2");
+
+ assertEq(pinakion.balanceOf(address(core)), 22000, "Wrong token balance of the core"); // Was 21500. 1000 was transferred to staker2
+ assertEq(pinakion.balanceOf(staker1), 999999999999998000, "Wrong token balance of staker1");
+ assertEq(pinakion.balanceOf(staker2), 999999999999980000, "Wrong token balance of staker2"); // 20k stake and 1k added as a reward, thus -19k from the default
+ }
+
+ function test_execute_NoCoherence() public {
+ uint256 disputeID = 0;
+
+ vm.prank(staker1);
+ core.setStake(GENERAL_COURT, 20000);
+ vm.prank(disputer);
+ arbitrable.createDispute{value: feeForJuror * DEFAULT_NB_OF_JURORS}("Action");
+ vm.warp(block.timestamp + minStakingTime);
+ sortitionModule.passPhase(); // Generating
+ vm.warp(block.timestamp + rngLookahead);
+ sortitionModule.passPhase(); // Drawing phase
+
+ core.draw(disputeID, DEFAULT_NB_OF_JURORS);
+
+ vm.warp(block.timestamp + timesPerPeriod[0]);
+ core.passPeriod(disputeID); // Vote
+
+ vm.warp(block.timestamp + timesPerPeriod[2]); // Don't vote at all so no one is coherent
+ core.passPeriod(disputeID); // Appeal
+
+ vm.warp(block.timestamp + timesPerPeriod[3]);
+ core.passPeriod(disputeID); // Execution
+
+ assertEq(disputeKit.getCoherentCount(disputeID, 0), 0, "Wrong coherent count");
+
+ uint256 pnkCoherence;
+ uint256 feeCoherence;
+ // dispute, round, voteID, feeForJuror (not used in classic DK), pnkPerJuror (not used in classic DK)
+ (pnkCoherence, feeCoherence) = disputeKit.getDegreeOfCoherenceReward(disputeID, 0, 0, 0, 0);
+ assertEq(pnkCoherence, 0, "Wrong reward pnk coherence 0 vote ID");
+ assertEq(feeCoherence, 0, "Wrong reward fee coherence 0 vote ID");
+
+ (pnkCoherence, feeCoherence) = disputeKit.getDegreeOfCoherenceReward(disputeID, 0, 1, 0, 0);
+ assertEq(pnkCoherence, 0, "Wrong reward pnk coherence 1 vote ID");
+ assertEq(feeCoherence, 0, "Wrong reward fee coherence 1 vote ID");
+
+ (pnkCoherence, feeCoherence) = disputeKit.getDegreeOfCoherenceReward(disputeID, 0, 2, 0, 0);
+ assertEq(pnkCoherence, 0, "Wrong reward pnk coherence 2 vote ID");
+ assertEq(feeCoherence, 0, "Wrong reward fee coherence 2 vote ID");
+
+ assertEq(disputeKit.getDegreeOfCoherencePenalty(disputeID, 0, 0, 0, 0), 0, "Wrong penalty coherence 0 vote ID");
+ assertEq(disputeKit.getDegreeOfCoherencePenalty(disputeID, 0, 1, 0, 0), 0, "Wrong penalty coherence 1 vote ID");
+ assertEq(disputeKit.getDegreeOfCoherencePenalty(disputeID, 0, 2, 0, 0), 0, "Wrong penalty coherence 2 vote ID");
+
+ uint256 ownerBalance = owner.balance;
+ uint256 ownerTokenBalance = pinakion.balanceOf(owner);
+
+ vm.expectEmit(true, true, true, true);
+ emit KlerosCore.LeftoverRewardSent(disputeID, 0, 3000, 0.09 ether, IERC20(address(0)));
+ core.execute(disputeID, 0, 3);
+
+ KlerosCore.Round memory round = core.getRoundInfo(disputeID, 0);
+ assertEq(round.pnkPenalties, 3000, "Wrong pnkPenalties");
+ assertEq(round.sumFeeRewardPaid, 0, "Wrong sumFeeRewardPaid");
+ assertEq(round.sumPnkRewardPaid, 0, "Wrong sumPnkRewardPaid");
+
+ assertEq(address(core).balance, 0, "Wrong balance of the core");
+ assertEq(staker1.balance, 0, "Wrong balance of the staker1");
+ assertEq(owner.balance, ownerBalance + 0.09 ether, "Wrong balance of the owner");
+
+ assertEq(pinakion.balanceOf(address(core)), 0, "Wrong token balance of the core"); // The inactive juror got unstaked regardless of the phase (`noDelay` is true)
+ assertEq(pinakion.balanceOf(staker1), 999999999999997000, "Wrong token balance of staker1");
+ assertEq(pinakion.balanceOf(owner), ownerTokenBalance + 3000, "Wrong token balance of owner");
+ }
+
+ function test_execute_UnstakeInactive() public {
+ // Create a 2nd court so unstaking is done in multiple courts.
+ vm.prank(owner);
+ uint256[] memory supportedDK = new uint256[](1);
+ supportedDK[0] = DISPUTE_KIT_CLASSIC;
+ core.createCourt(
+ GENERAL_COURT,
+ true, // Hidden votes
+ 1000, // min stake
+ 10000, // alpha
+ 0.03 ether, // fee for juror
+ 50, // jurors for jump
+ [uint256(10), uint256(20), uint256(30), uint256(40)], // Times per period
+ sortitionExtraData, // Sortition extra data
+ supportedDK
+ );
+
+ uint256 disputeID = 0;
+ uint96 newCourtID = 2;
+
+ vm.prank(staker1);
+ core.setStake(GENERAL_COURT, 20000);
+ vm.prank(staker1);
+ core.setStake(newCourtID, 20000);
+ (, , , uint256 nbCourts) = sortitionModule.getJurorBalance(staker1, GENERAL_COURT);
+ assertEq(nbCourts, 2, "Wrong number of courts");
+
+ assertEq(pinakion.balanceOf(address(core)), 40000, "Wrong token balance of the core");
+ assertEq(pinakion.balanceOf(staker1), 999999999999960000, "Wrong token balance of staker1");
+
+ vm.prank(disputer);
+ arbitrable.createDispute{value: feeForJuror * DEFAULT_NB_OF_JURORS}("Action");
+ vm.warp(block.timestamp + minStakingTime);
+ sortitionModule.passPhase(); // Generating
+ vm.warp(block.timestamp + rngLookahead);
+ sortitionModule.passPhase(); // Drawing phase
+
+ core.draw(disputeID, DEFAULT_NB_OF_JURORS);
+
+ sortitionModule.passPhase(); // Staking phase. Change to staking so we don't have to deal with delayed stakes.
+
+ vm.warp(block.timestamp + timesPerPeriod[0]);
+ core.passPeriod(disputeID); // Vote
+
+ vm.warp(block.timestamp + timesPerPeriod[2]); // Don't vote at all so no one is coherent
+ core.passPeriod(disputeID); // Appeal
+
+ vm.warp(block.timestamp + timesPerPeriod[3]);
+ core.passPeriod(disputeID); // Execution
+
+ uint256 ownerTokenBalance = pinakion.balanceOf(owner);
+
+ // Note that these events are emitted only after the first iteration of execute() therefore the juror has been penalized only for 1000 PNK her.
+ vm.expectEmit(true, true, true, true);
+ emit SortitionModule.StakeSet(staker1, newCourtID, 19000, 39000); // 1000 PNK penalty for voteID 0
+ vm.expectEmit(true, true, true, true);
+ emit SortitionModule.StakeSet(staker1, newCourtID, 0, 20000); // Starting with 40000 we first nullify the stake and remove 19000 and then remove penalty once since there was only first iteration (40000 - 20000 - 1000)
+ vm.expectEmit(true, true, true, true);
+ emit SortitionModule.StakeSet(staker1, GENERAL_COURT, 0, 2000); // 2000 PNK should remain in balance to cover penalties since the first 1000 of locked pnk was already unlocked
+ core.execute(disputeID, 0, 3);
+
+ assertEq(pinakion.balanceOf(address(core)), 0, "Wrong token balance of the core");
+ assertEq(pinakion.balanceOf(staker1), 999999999999997000, "Wrong token balance of staker1"); // 3000 locked PNK was withheld by the contract and given to owner.
+ assertEq(pinakion.balanceOf(owner), ownerTokenBalance + 3000, "Wrong token balance of owner");
+
+ (, , , nbCourts) = sortitionModule.getJurorBalance(staker1, GENERAL_COURT);
+ assertEq(nbCourts, 0, "Should unstake from all courts");
+ }
+
+ function test_execute_UnstakeInsolvent() public {
+ uint256 disputeID = 0;
+
+ vm.prank(staker1);
+ core.setStake(GENERAL_COURT, 1000);
+
+ assertEq(pinakion.balanceOf(address(core)), 1000, "Wrong token balance of the core");
+ assertEq(pinakion.balanceOf(staker1), 999999999999999000, "Wrong token balance of staker1");
+
+ vm.prank(disputer);
+ arbitrable.createDispute{value: feeForJuror * DEFAULT_NB_OF_JURORS}("Action");
+ vm.warp(block.timestamp + minStakingTime);
+ sortitionModule.passPhase(); // Generating
+ vm.warp(block.timestamp + rngLookahead);
+ sortitionModule.passPhase(); // Drawing phase
+
+ core.draw(disputeID, DEFAULT_NB_OF_JURORS);
+
+ (uint256 totalStaked, uint256 totalLocked, , uint256 nbCourts) = sortitionModule.getJurorBalance(
+ staker1,
+ GENERAL_COURT
+ );
+ assertEq(totalStaked, 1000, "Wrong totalStaked");
+ assertEq(totalLocked, 3000, "totalLocked should exceed totalStaked"); // Juror only staked 1000 but was drawn 3x of minStake (3000 locked)
+ assertEq(nbCourts, 1, "Wrong number of courts");
+
+ sortitionModule.passPhase(); // Staking phase. Change to staking so we don't have to deal with delayed stakes.
+
+ vm.warp(block.timestamp + timesPerPeriod[0]);
+ core.passPeriod(disputeID); // Vote
+
+ uint256[] memory voteIDs = new uint256[](1);
+ voteIDs[0] = 0;
+ vm.prank(staker1);
+ disputeKit.castVote(disputeID, voteIDs, 1, 0, "XYZ"); // 1 incoherent vote should make the juror insolvent
+
+ voteIDs = new uint256[](2);
+ voteIDs[0] = 1;
+ voteIDs[1] = 2;
+ vm.prank(staker1);
+ disputeKit.castVote(disputeID, voteIDs, 2, 0, "XYZ");
+
+ core.passPeriod(disputeID); // Appeal
+
+ vm.warp(block.timestamp + timesPerPeriod[3]);
+ core.passPeriod(disputeID); // Execution
+
+ vm.expectEmit(true, true, true, true);
+ emit SortitionModule.StakeSet(staker1, GENERAL_COURT, 0, 0); // Juror should have no stake left and should be unstaked from the court automatically.
+ core.execute(disputeID, 0, 6);
+
+ assertEq(pinakion.balanceOf(address(core)), 0, "Wrong token balance of the core");
+ assertEq(pinakion.balanceOf(staker1), 1 ether, "Wrong token balance of staker1"); // The juror should have his penalty back as a reward
+
+ (, , , nbCourts) = sortitionModule.getJurorBalance(staker1, GENERAL_COURT);
+ assertEq(nbCourts, 0, "Should unstake from all courts");
+ }
+
+ function test_execute_UnstakeBelowMinStake() public {
+ uint256 disputeID = 0;
+
+ vm.prank(staker1);
+ core.setStake(GENERAL_COURT, 1200);
+
+ vm.prank(staker2);
+ core.setStake(GENERAL_COURT, 10000);
+
+ assertEq(pinakion.balanceOf(address(core)), 11200, "Wrong token balance of the core");
+ assertEq(pinakion.balanceOf(staker1), 999999999999998800, "Wrong token balance of staker1");
+ assertEq(pinakion.balanceOf(staker2), 999999999999990000, "Wrong token balance of staker2");
+
+ vm.prank(disputer);
+ arbitrable.createDispute{value: feeForJuror * DEFAULT_NB_OF_JURORS}("Action");
+ vm.warp(block.timestamp + minStakingTime);
+ sortitionModule.passPhase(); // Generating
+ vm.warp(block.timestamp + rngLookahead);
+ sortitionModule.passPhase(); // Drawing phase
+
+ core.draw(disputeID, DEFAULT_NB_OF_JURORS);
+
+ (uint256 totalStaked, uint256 totalLocked, , uint256 nbCourts) = sortitionModule.getJurorBalance(
+ staker1,
+ GENERAL_COURT
+ );
+ assertEq(totalStaked, 1200, "Wrong totalStaked");
+ assertEq(totalLocked, 1000, "Wrong totalLocked"); // Juror only staked 1000 but will fall below minStake with a bad vote
+ assertEq(nbCourts, 1, "Wrong number of courts");
+
+ sortitionModule.passPhase(); // Staking phase. Change to staking so we don't have to deal with delayed stakes.
+
+ vm.warp(block.timestamp + timesPerPeriod[0]);
+ core.passPeriod(disputeID); // Vote
+
+ uint256[] memory voteIDs = new uint256[](1);
+ voteIDs[0] = 0;
+ vm.prank(staker1);
+ disputeKit.castVote(disputeID, voteIDs, 1, 0, "XYZ"); // 1 incoherent vote should make the juror's stake below minStake
+
+ voteIDs = new uint256[](2);
+ voteIDs[0] = 1;
+ voteIDs[1] = 2;
+ vm.prank(staker2);
+ disputeKit.castVote(disputeID, voteIDs, 2, 0, "XYZ");
+
+ core.passPeriod(disputeID); // Appeal
+
+ vm.warp(block.timestamp + timesPerPeriod[3]);
+ core.passPeriod(disputeID); // Execution
+
+ vm.expectEmit(true, true, true, true);
+ emit SortitionModule.StakeSet(staker1, GENERAL_COURT, 0, 0); // Juror balance should be below minStake and should be unstaked from the court automatically.
+ core.execute(disputeID, 0, 6);
+
+ assertEq(pinakion.balanceOf(address(core)), 11000, "Wrong token balance of the core");
+ assertEq(pinakion.balanceOf(staker1), 1 ether - 1000, "Wrong token balance of staker1"); // The juror should have his penalty back as a reward
+ assertEq(pinakion.balanceOf(staker2), 999999999999990000, "Wrong token balance of staker2"); // No change
+
+ (totalStaked, totalLocked, , nbCourts) = sortitionModule.getJurorBalance(staker1, GENERAL_COURT);
+ assertEq(totalStaked, 0, "Wrong staker1 totalStaked");
+ assertEq(totalLocked, 0, "Wrong staker1 totalLocked");
+ assertEq(nbCourts, 0, "Wrong staker1 nbCourts");
+
+ (totalStaked, totalLocked, , nbCourts) = sortitionModule.getJurorBalance(staker2, GENERAL_COURT);
+ assertEq(totalStaked, 11000, "Wrong staker2 totalStaked");
+ assertEq(totalLocked, 0, "Wrong staker2 totalLocked");
+ assertEq(nbCourts, 1, "Wrong staker2 nbCourts");
+ }
+
+ function test_execute_withdrawLeftoverPNK() public {
+ // Return the previously locked tokens
+ uint256 disputeID = 0;
+
+ vm.prank(staker1);
+ core.setStake(GENERAL_COURT, 1000);
+ vm.prank(disputer);
+ arbitrable.createDispute{value: feeForJuror * DEFAULT_NB_OF_JURORS}("Action");
+ vm.warp(block.timestamp + minStakingTime);
+ sortitionModule.passPhase(); // Generating
+ vm.warp(block.timestamp + rngLookahead);
+ sortitionModule.passPhase(); // Drawing phase
+
+ core.draw(disputeID, DEFAULT_NB_OF_JURORS);
+
+ sortitionModule.passPhase(); // Staking. Pass the phase so the juror can unstake before execution
+
+ vm.warp(block.timestamp + timesPerPeriod[0]);
+ core.passPeriod(disputeID); // Vote
+
+ uint256[] memory voteIDs = new uint256[](3);
+ voteIDs[0] = 0;
+ voteIDs[1] = 1;
+ voteIDs[2] = 2;
+ vm.prank(staker1);
+ disputeKit.castVote(disputeID, voteIDs, 2, 0, "XYZ");
+
+ core.passPeriod(disputeID); // Appeal
+
+ vm.warp(block.timestamp + timesPerPeriod[3]);
+ core.passPeriod(disputeID); // Execution
+
+ vm.prank(staker1);
+ core.setStake(GENERAL_COURT, 0); // Set stake to 0 to check if it will be withdrawn later.
+
+ (uint256 totalStaked, uint256 totalLocked, uint256 stakedInCourt, uint256 nbCourts) = sortitionModule
+ .getJurorBalance(staker1, GENERAL_COURT);
+ assertEq(totalStaked, 1000, "Wrong amount staked");
+ assertEq(totalLocked, 3000, "Wrong amount locked");
+ assertEq(stakedInCourt, 0, "Should be unstaked");
+ assertEq(nbCourts, 0, "Should be 0 courts");
+
+ assertEq(pinakion.balanceOf(address(core)), 1000, "Wrong token balance of the core");
+ assertEq(pinakion.balanceOf(staker1), 999999999999999000, "Wrong token balance of staker1");
+
+ vm.expectRevert(SortitionModule.NotEligibleForWithdrawal.selector);
+ sortitionModule.withdrawLeftoverPNK(staker1);
+
+ vm.expectEmit(true, true, true, true);
+ emit SortitionModule.LeftoverPNK(staker1, 1000);
+ core.execute(disputeID, 0, 6);
+
+ (totalStaked, totalLocked, , ) = sortitionModule.getJurorBalance(staker1, GENERAL_COURT);
+ assertEq(totalStaked, 1000, "Wrong amount staked");
+ assertEq(totalLocked, 0, "Should be fully unlocked");
+
+ KlerosCore.Round memory round = core.getRoundInfo(disputeID, 0);
+ assertEq(round.pnkPenalties, 0, "Wrong pnkPenalties");
+ assertEq(round.sumFeeRewardPaid, 0.09 ether, "Wrong sumFeeRewardPaid");
+ assertEq(round.sumPnkRewardPaid, 0, "Wrong sumPnkRewardPaid"); // No penalty so no rewards in pnk
+
+ // Execute() shouldn't withdraw the tokens.
+ assertEq(pinakion.balanceOf(address(core)), 1000, "Wrong token balance of the core");
+ assertEq(pinakion.balanceOf(staker1), 999999999999999000, "Wrong token balance of staker1");
+
+ vm.expectRevert(KlerosCore.SortitionModuleOnly.selector);
+ vm.prank(owner);
+ core.transferBySortitionModule(staker1, 1000);
+
+ vm.expectEmit(true, true, true, true);
+ emit SortitionModule.LeftoverPNKWithdrawn(staker1, 1000);
+ sortitionModule.withdrawLeftoverPNK(staker1);
+
+ (totalStaked, , , ) = sortitionModule.getJurorBalance(staker1, GENERAL_COURT);
+ assertEq(totalStaked, 0, "Should be unstaked fully");
+
+ // Check that everything is withdrawn now
+ assertEq(pinakion.balanceOf(address(core)), 0, "Core balance should be empty");
+ assertEq(pinakion.balanceOf(staker1), 1 ether, "All PNK should be withdrawn");
+ }
+
+ function test_execute_feeToken() public {
+ uint256 disputeID = 0;
+
+ feeToken.transfer(disputer, 1 ether);
+ vm.prank(disputer);
+ feeToken.approve(address(arbitrable), 1 ether);
+
+ vm.prank(owner);
+ core.changeAcceptedFeeTokens(feeToken, true);
+ vm.prank(owner);
+ core.changeCurrencyRates(feeToken, 500, 3);
+
+ vm.prank(disputer);
+ arbitrable.createDispute("Action", 0.18 ether);
+
+ vm.prank(staker1);
+ core.setStake(GENERAL_COURT, 20000);
+ vm.warp(block.timestamp + minStakingTime);
+ sortitionModule.passPhase(); // Generating
+ vm.warp(block.timestamp + rngLookahead);
+ sortitionModule.passPhase(); // Drawing phase
+
+ core.draw(disputeID, DEFAULT_NB_OF_JURORS);
+
+ vm.warp(block.timestamp + timesPerPeriod[0]);
+ core.passPeriod(disputeID); // Vote
+
+ uint256[] memory voteIDs = new uint256[](3);
+ voteIDs[0] = 0;
+ voteIDs[1] = 1;
+ voteIDs[2] = 2;
+ vm.prank(staker1);
+ disputeKit.castVote(disputeID, voteIDs, 1, 0, "XYZ"); // Staker1 only got 1 vote because of low stake
+
+ core.passPeriod(disputeID); // Appeal
+
+ vm.warp(block.timestamp + timesPerPeriod[3]);
+ core.passPeriod(disputeID); // Execution
+
+ // Check only once per penalty and per reward
+ vm.expectEmit(true, true, true, true);
+ emit KlerosCore.JurorRewardPenalty(staker1, disputeID, 0, 10000, 10000, 0, 0.06 ether, feeToken); // rewards
+ core.execute(disputeID, 0, 6);
+
+ KlerosCore.Round memory round = core.getRoundInfo(disputeID, 0);
+ assertEq(round.sumFeeRewardPaid, 0.18 ether, "Wrong sumFeeRewardPaid");
+
+ assertEq(feeToken.balanceOf(address(core)), 0, "Wrong fee token balance of the core");
+ assertEq(feeToken.balanceOf(staker1), 0.18 ether, "Wrong fee token balance of staker1");
+ assertEq(feeToken.balanceOf(disputer), 0.82 ether, "Wrong fee token balance of disputer");
+ }
+
+ function test_execute_NoCoherence_feeToken() public {
+ uint256 disputeID = 0;
+
+ feeToken.transfer(disputer, 1 ether);
+ vm.prank(disputer);
+ feeToken.approve(address(arbitrable), 1 ether);
+
+ vm.prank(owner);
+ core.changeAcceptedFeeTokens(feeToken, true);
+ vm.prank(owner);
+ core.changeCurrencyRates(feeToken, 500, 3);
+
+ vm.prank(disputer);
+ arbitrable.createDispute("Action", 0.18 ether);
+
+ vm.prank(staker1);
+ core.setStake(GENERAL_COURT, 20000);
+ vm.warp(block.timestamp + minStakingTime);
+ sortitionModule.passPhase(); // Generating
+ vm.warp(block.timestamp + rngLookahead);
+ sortitionModule.passPhase(); // Drawing phase
+
+ core.draw(disputeID, DEFAULT_NB_OF_JURORS);
+
+ vm.warp(block.timestamp + timesPerPeriod[0]);
+ core.passPeriod(disputeID); // Vote
+
+ vm.warp(block.timestamp + timesPerPeriod[2]); // Don't vote at all so no one is coherent
+ core.passPeriod(disputeID); // Appeal
+
+ vm.warp(block.timestamp + timesPerPeriod[3]);
+ core.passPeriod(disputeID); // Execution
+
+ vm.expectEmit(true, true, true, true);
+ emit KlerosCore.LeftoverRewardSent(disputeID, 0, 3000, 0.18 ether, feeToken);
+ core.execute(disputeID, 0, 10); // Put more iterations to check that they're capped
+
+ KlerosCore.Round memory round = core.getRoundInfo(disputeID, 0);
+ assertEq(round.pnkPenalties, 3000, "Wrong pnkPenalties");
+ assertEq(round.sumFeeRewardPaid, 0, "Wrong sumFeeRewardPaid");
+ assertEq(round.sumPnkRewardPaid, 0, "Wrong sumPnkRewardPaid");
+ assertEq(round.repartitions, 3, "Wrong repartitions");
+
+ assertEq(feeToken.balanceOf(address(core)), 0, "Wrong token balance of the core");
+ assertEq(feeToken.balanceOf(staker1), 0, "Wrong token balance of staker1");
+ assertEq(feeToken.balanceOf(disputer), 0.82 ether, "Wrong token balance of disputer");
+ assertEq(feeToken.balanceOf(owner), 0.18 ether, "Wrong token balance of owner");
+ }
+
+ function test_executeRuling() public {
+ uint256 disputeID = 0;
+
+ vm.prank(staker1);
+ core.setStake(GENERAL_COURT, 20000);
+ vm.prank(disputer);
+ arbitrable.createDispute{value: feeForJuror * DEFAULT_NB_OF_JURORS}("Action");
+ vm.warp(block.timestamp + minStakingTime);
+ sortitionModule.passPhase(); // Generating
+ vm.warp(block.timestamp + rngLookahead);
+ sortitionModule.passPhase(); // Drawing phase
+
+ core.draw(disputeID, DEFAULT_NB_OF_JURORS);
+ vm.warp(block.timestamp + timesPerPeriod[0]);
+ core.passPeriod(disputeID); // Vote
+
+ uint256[] memory voteIDs = new uint256[](3);
+ voteIDs[0] = 0;
+ voteIDs[1] = 1;
+ voteIDs[2] = 2;
+
+ vm.prank(staker1);
+ disputeKit.castVote(disputeID, voteIDs, 2, 0, "XYZ");
+ core.passPeriod(disputeID); // Appeal
+
+ vm.expectRevert(KlerosCore.NotExecutionPeriod.selector);
+ core.executeRuling(disputeID);
+
+ vm.warp(block.timestamp + timesPerPeriod[3]);
+ vm.expectEmit(true, true, true, true);
+ emit KlerosCore.NewPeriod(disputeID, KlerosCore.Period.execution);
+ core.passPeriod(disputeID); // Execution
+
+ (, , KlerosCore.Period period, , uint256 lastPeriodChange) = core.disputes(disputeID);
+ assertEq(uint256(period), uint256(KlerosCore.Period.execution), "Wrong period");
+ assertEq(lastPeriodChange, block.timestamp, "Wrong lastPeriodChange");
+
+ vm.expectRevert(KlerosCore.DisputePeriodIsFinal.selector);
+ core.passPeriod(disputeID);
+
+ vm.expectEmit(true, true, true, true);
+ emit IArbitratorV2.Ruling(arbitrable, disputeID, 2); // Winning choice = 2
+ vm.expectEmit(true, true, true, true);
+ emit IArbitrableV2.Ruling(core, disputeID, 2);
+ core.executeRuling(disputeID);
+
+ vm.expectRevert(KlerosCore.RulingAlreadyExecuted.selector);
+ core.executeRuling(disputeID);
+
+ (, , , bool ruled, ) = core.disputes(disputeID);
+ assertEq(ruled, true, "Should be ruled");
+ }
+
+ function test_executeRuling_appealSwitch() public {
+ // Check that the ruling switches if only one side was funded
+ uint256 disputeID = 0;
+
+ vm.prank(staker1);
+ core.setStake(GENERAL_COURT, 20000);
+ vm.prank(disputer);
+ arbitrable.createDispute{value: feeForJuror * DEFAULT_NB_OF_JURORS}("Action");
+ vm.warp(block.timestamp + minStakingTime);
+ sortitionModule.passPhase(); // Generating
+ vm.warp(block.timestamp + rngLookahead);
+ sortitionModule.passPhase(); // Drawing phase
+
+ core.draw(disputeID, DEFAULT_NB_OF_JURORS);
+ vm.warp(block.timestamp + timesPerPeriod[0]);
+ core.passPeriod(disputeID); // Vote
+
+ uint256[] memory voteIDs = new uint256[](3);
+ voteIDs[0] = 0;
+ voteIDs[1] = 1;
+ voteIDs[2] = 2;
+
+ vm.prank(staker1);
+ disputeKit.castVote(disputeID, voteIDs, 2, 0, "XYZ");
+ core.passPeriod(disputeID); // Appeal
+
+ vm.prank(crowdfunder1);
+ disputeKit.fundAppeal{value: 0.63 ether}(disputeID, 1); // Fund the losing choice
+
+ vm.warp(block.timestamp + timesPerPeriod[3]);
+ core.passPeriod(disputeID); // Execution
+
+ vm.expectEmit(true, true, true, true);
+ emit IArbitratorV2.Ruling(arbitrable, disputeID, 1); // Winning choice is switched to 1
+ vm.expectEmit(true, true, true, true);
+ emit IArbitrableV2.Ruling(core, disputeID, 1);
+ core.executeRuling(disputeID);
+
+ (uint256 ruling, bool tied, bool overridden) = disputeKit.currentRuling(disputeID);
+ assertEq(ruling, 1, "Wrong ruling");
+ assertEq(tied, false, "Not tied");
+ assertEq(overridden, true, "Should be overridden");
+ }
+
+ function test_withdrawFeesAndRewards() public {
+ uint256 disputeID = 0;
+
+ vm.prank(staker1);
+ core.setStake(GENERAL_COURT, 20000);
+ vm.prank(disputer);
+ arbitrable.createDispute{value: feeForJuror * DEFAULT_NB_OF_JURORS}("Action");
+ vm.warp(block.timestamp + minStakingTime);
+ sortitionModule.passPhase(); // Generating
+ vm.warp(block.timestamp + rngLookahead);
+ sortitionModule.passPhase(); // Drawing phase
+
+ core.draw(disputeID, DEFAULT_NB_OF_JURORS);
+ vm.warp(block.timestamp + timesPerPeriod[0]);
+ core.passPeriod(disputeID); // Vote
+
+ uint256[] memory voteIDs = new uint256[](3);
+ voteIDs[0] = 0;
+ voteIDs[1] = 1;
+ voteIDs[2] = 2;
+
+ vm.prank(staker1);
+ disputeKit.castVote(disputeID, voteIDs, 2, 0, "XYZ");
+ core.passPeriod(disputeID); // Appeal
+
+ vm.prank(crowdfunder1);
+ disputeKit.fundAppeal{value: 0.63 ether}(disputeID, 1); // Fund the losing choice. The ruling will be overridden here
+ vm.prank(crowdfunder2);
+ disputeKit.fundAppeal{value: 0.41 ether}(disputeID, 2); // Underpay a bit to not create an appeal and withdraw the funded sum fully
+
+ vm.warp(block.timestamp + timesPerPeriod[3]);
+ core.passPeriod(disputeID); // Execution
+
+ vm.expectRevert(DisputeKitClassicBase.DisputeNotResolved.selector);
+ disputeKit.withdrawFeesAndRewards(disputeID, payable(staker1), 1);
+
+ core.executeRuling(disputeID);
+
+ vm.prank(owner);
+ core.pause();
+ vm.expectRevert(DisputeKitClassicBase.CoreIsPaused.selector);
+ disputeKit.withdrawFeesAndRewards(disputeID, payable(staker1), 1);
+ vm.prank(owner);
+ core.unpause();
+
+ assertEq(crowdfunder1.balance, 9.37 ether, "Wrong balance of the crowdfunder1");
+ assertEq(crowdfunder2.balance, 9.59 ether, "Wrong balance of the crowdfunder2");
+ assertEq(address(disputeKit).balance, 1.04 ether, "Wrong balance of the DK");
+
+ vm.expectEmit(true, true, true, true);
+ emit DisputeKitClassicBase.Withdrawal(disputeID, 1, crowdfunder1, 0.63 ether);
+ disputeKit.withdrawFeesAndRewards(disputeID, payable(crowdfunder1), 1);
+
+ vm.expectEmit(true, true, true, true);
+ emit DisputeKitClassicBase.Withdrawal(disputeID, 2, crowdfunder2, 0.41 ether);
+ disputeKit.withdrawFeesAndRewards(disputeID, payable(crowdfunder2), 2);
+
+ assertEq(crowdfunder1.balance, 10 ether, "Wrong balance of the crowdfunder1");
+ assertEq(crowdfunder2.balance, 10 ether, "Wrong balance of the crowdfunder2");
+ assertEq(address(disputeKit).balance, 0, "Wrong balance of the DK");
+ }
+
+ function testFuzz_executeIterations(uint256 iterations) public {
+ uint256 disputeID = 0;
+ uint256 roundID = 0;
+
+ vm.prank(staker1);
+ core.setStake(GENERAL_COURT, 2000);
+ vm.prank(disputer);
+ arbitrable.createDispute{value: feeForJuror * DEFAULT_NB_OF_JURORS}("Action");
+ vm.warp(block.timestamp + minStakingTime);
+ sortitionModule.passPhase(); // Generating
+ vm.warp(block.timestamp + rngLookahead);
+ sortitionModule.passPhase(); // Drawing phase
+
+ core.draw(disputeID, 3);
+
+ vm.warp(block.timestamp + timesPerPeriod[0]);
+ core.passPeriod(disputeID); // Vote
+
+ uint256[] memory voteIDs = new uint256[](3);
+ voteIDs[0] = 0;
+ voteIDs[1] = 1;
+ voteIDs[2] = 2;
+ vm.prank(staker1);
+ disputeKit.castVote(disputeID, voteIDs, 1, roundID, "XYZ");
+
+ core.passPeriod(disputeID); // Appeal
+
+ vm.warp(block.timestamp + timesPerPeriod[3]);
+ core.passPeriod(disputeID); // Execution
+
+ core.execute(disputeID, roundID, iterations);
+
+ uint256 iterationsCount = iterations < DEFAULT_NB_OF_JURORS * 2 ? iterations : DEFAULT_NB_OF_JURORS * 2;
+
+ KlerosCore.Round memory round = core.getRoundInfo(disputeID, roundID);
+ assertEq(round.repartitions, iterationsCount, "Wrong repartitions");
+ }
+
+ function testFuzz_executeIterations_nbJurors(uint256 iterations, uint256 disputeValue) public {
+ uint256 disputeID = 0;
+ uint256 roundID = 0;
+
+ uint256 arbitrationCost = core.arbitrationCost(arbitratorExtraData);
+ // Cap it to 10 eth, so the number of jurors is not astronomical.
+ vm.assume(disputeValue >= arbitrationCost && disputeValue <= 10 ether);
+ vm.deal(disputer, 10 ether);
+
+ vm.prank(staker1);
+ core.setStake(GENERAL_COURT, 2000);
+ vm.prank(disputer);
+ arbitrable.createDispute{value: disputeValue}("Action");
+ vm.warp(block.timestamp + minStakingTime);
+ sortitionModule.passPhase(); // Generating
+ vm.warp(block.timestamp + rngLookahead);
+ sortitionModule.passPhase(); // Drawing phase
+
+ uint256 nbJurors = disputeValue / feeForJuror;
+
+ core.draw(disputeID, nbJurors);
+
+ KlerosCore.Round memory round = core.getRoundInfo(disputeID, roundID);
+ assertEq(round.totalFeesForJurors, disputeValue, "Wrong totalFeesForJurors");
+ assertEq(round.nbVotes, nbJurors, "Wrong nbVotes");
+
+ vm.warp(block.timestamp + timesPerPeriod[0]);
+ core.passPeriod(disputeID); // Vote
+
+ uint256[] memory voteIDs = new uint256[](nbJurors);
+ for (uint256 i = 0; i < voteIDs.length; i++) {
+ voteIDs[i] = i;
+ }
+
+ vm.prank(staker1);
+ disputeKit.castVote(disputeID, voteIDs, 1, 0, "XYZ");
+
+ core.passPeriod(disputeID); // Appeal
+
+ vm.warp(block.timestamp + timesPerPeriod[3]);
+ core.passPeriod(disputeID); // Execution
+
+ core.execute(disputeID, roundID, iterations);
+
+ uint256 iterationsCount = iterations < nbJurors * 2 ? iterations : nbJurors * 2;
+ round = core.getRoundInfo(disputeID, roundID);
+
+ assertEq(round.repartitions, iterationsCount, "Wrong repartitions");
+
+ (uint256 totalStaked, uint256 totalLocked, uint256 stakedInCourt, ) = sortitionModule.getJurorBalance(
+ staker1,
+ GENERAL_COURT
+ );
+
+ uint256 pnkAtStake = (minStake * alpha) / ONE_BASIS_POINT;
+ uint256 unlockedTokens = iterationsCount < nbJurors ? 0 : (iterationsCount - nbJurors) * pnkAtStake;
+ assertEq(totalStaked, 2000, "Wrong amount total staked");
+ assertEq(totalLocked, (pnkAtStake * nbJurors) - unlockedTokens, "Wrong amount locked");
+ assertEq(stakedInCourt, 2000, "Wrong amount staked in court");
+ }
+}
diff --git a/contracts/test/foundry/KlerosCore_Governance.t.sol b/contracts/test/foundry/KlerosCore_Governance.t.sol
new file mode 100644
index 000000000..7c803c058
--- /dev/null
+++ b/contracts/test/foundry/KlerosCore_Governance.t.sol
@@ -0,0 +1,472 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.24;
+
+import {KlerosCore_TestBase} from "./KlerosCore_TestBase.sol";
+import {KlerosCore} from "../../src/arbitration/KlerosCore.sol";
+import {IArbitratorV2} from "../../src/arbitration/KlerosCore.sol";
+import {DisputeKitSybilResistant} from "../../src/arbitration/dispute-kits/DisputeKitSybilResistant.sol";
+import {SortitionModuleMock} from "../../src/test/SortitionModuleMock.sol";
+import {PNK} from "../../src/token/PNK.sol";
+import "../../src/libraries/Constants.sol";
+
+/// @title KlerosCore_GovernanceTest
+/// @dev Tests for KlerosCore governance functions (owner/guardian operations)
+contract KlerosCore_GovernanceTest is KlerosCore_TestBase {
+ function test_pause() public {
+ vm.expectRevert(KlerosCore.GuardianOrOwnerOnly.selector);
+ vm.prank(other);
+ core.pause();
+ // Note that we must explicitly switch to the owner/guardian address to make the call, otherwise Foundry treats UUPS proxy as msg.sender.
+ vm.prank(guardian);
+ vm.expectEmit(true, true, true, true);
+ emit KlerosCore.Paused();
+ core.pause();
+ assertEq(core.paused(), true, "Wrong paused value");
+ // Switch between owner and guardian to test both. WhenNotPausedOnly modifier is triggered after owner's check.
+ vm.prank(owner);
+ vm.expectRevert(KlerosCore.WhenNotPausedOnly.selector);
+ core.pause();
+ }
+
+ function test_unpause() public {
+ vm.expectRevert(KlerosCore.OwnerOnly.selector);
+ vm.prank(other);
+ core.unpause();
+
+ vm.expectRevert(KlerosCore.WhenPausedOnly.selector);
+ vm.prank(owner);
+ core.unpause();
+
+ vm.prank(owner);
+ core.pause();
+ vm.prank(owner);
+ vm.expectEmit(true, true, true, true);
+ emit KlerosCore.Unpaused();
+ core.unpause();
+ assertEq(core.paused(), false, "Wrong paused value");
+ }
+
+ function test_executeOwnerProposal() public {
+ bytes memory data = abi.encodeWithSignature("changeOwner(address)", other);
+ vm.expectRevert(KlerosCore.OwnerOnly.selector);
+ vm.prank(other);
+ core.executeOwnerProposal(address(core), 0, data);
+
+ vm.expectRevert(KlerosCore.UnsuccessfulCall.selector);
+ vm.prank(owner);
+ core.executeOwnerProposal(address(core), 0, data); // It'll fail because the core is not its own owner
+
+ vm.prank(owner);
+ core.changeOwner(payable(address(core)));
+ vm.prank(address(core));
+ core.executeOwnerProposal(address(core), 0, data);
+ assertEq(core.owner(), other, "Wrong owner");
+ }
+
+ function test_changeOwner() public {
+ vm.expectRevert(KlerosCore.OwnerOnly.selector);
+ vm.prank(other);
+ core.changeOwner(payable(other));
+ vm.prank(owner);
+ core.changeOwner(payable(other));
+ assertEq(core.owner(), other, "Wrong owner");
+ }
+
+ function test_changeGuardian() public {
+ vm.expectRevert(KlerosCore.OwnerOnly.selector);
+ vm.prank(other);
+ core.changeGuardian(other);
+ vm.prank(owner);
+ core.changeGuardian(other);
+ assertEq(core.guardian(), other, "Wrong guardian");
+ }
+
+ function test_changePinakion() public {
+ PNK fakePNK = new PNK();
+ vm.expectRevert(KlerosCore.OwnerOnly.selector);
+ vm.prank(other);
+ core.changePinakion(fakePNK);
+ vm.prank(owner);
+ core.changePinakion(fakePNK);
+ assertEq(address(core.pinakion()), address(fakePNK), "Wrong PNK");
+ }
+
+ function test_changeJurorProsecutionModule() public {
+ vm.expectRevert(KlerosCore.OwnerOnly.selector);
+ vm.prank(other);
+ core.changeJurorProsecutionModule(other);
+ vm.prank(owner);
+ core.changeJurorProsecutionModule(other);
+ assertEq(core.jurorProsecutionModule(), other, "Wrong jurorProsecutionModule");
+ }
+
+ function test_changeSortitionModule() public {
+ SortitionModuleMock fakeSM = new SortitionModuleMock();
+ vm.expectRevert(KlerosCore.OwnerOnly.selector);
+ vm.prank(other);
+ core.changeSortitionModule(fakeSM);
+ vm.prank(owner);
+ core.changeSortitionModule(fakeSM);
+ assertEq(address(core.sortitionModule()), address(fakeSM), "Wrong sortitionModule");
+ }
+
+ function test_addNewDisputeKit() public {
+ DisputeKitSybilResistant newDK = new DisputeKitSybilResistant();
+ vm.expectRevert(KlerosCore.OwnerOnly.selector);
+ vm.prank(other);
+ core.addNewDisputeKit(newDK);
+ vm.prank(owner);
+ vm.expectEmit(true, true, true, true);
+ emit KlerosCore.DisputeKitCreated(2, newDK);
+ core.addNewDisputeKit(newDK);
+ assertEq(address(core.disputeKits(2)), address(newDK), "Wrong address of new DK");
+ assertEq(core.getDisputeKitsLength(), 3, "Wrong DK array length");
+ }
+
+ function test_createCourt() public {
+ vm.expectRevert(KlerosCore.OwnerOnly.selector);
+ vm.prank(other);
+ uint256[] memory supportedDK = new uint256[](2);
+ supportedDK[0] = DISPUTE_KIT_CLASSIC;
+ supportedDK[1] = 2; // New DK is added below.
+ core.createCourt(
+ GENERAL_COURT,
+ true, // Hidden votes
+ 2000, // min stake
+ 10000, // alpha
+ 0.03 ether, // fee for juror
+ 50, // jurors for jump
+ [uint256(10), uint256(20), uint256(30), uint256(40)], // Times per period
+ abi.encode(uint256(4)), // Sortition extra data
+ supportedDK
+ );
+
+ vm.expectRevert(KlerosCore.MinStakeLowerThanParentCourt.selector);
+ vm.prank(owner);
+ core.createCourt(
+ GENERAL_COURT,
+ true, // Hidden votes
+ 800, // min stake
+ 10000, // alpha
+ 0.03 ether, // fee for juror
+ 50, // jurors for jump
+ [uint256(10), uint256(20), uint256(30), uint256(40)], // Times per period
+ abi.encode(uint256(4)), // Sortition extra data
+ supportedDK
+ );
+
+ vm.expectRevert(KlerosCore.UnsupportedDisputeKit.selector);
+ vm.prank(owner);
+ uint256[] memory emptySupportedDK = new uint256[](0);
+ core.createCourt(
+ GENERAL_COURT,
+ true, // Hidden votes
+ 2000, // min stake
+ 10000, // alpha
+ 0.03 ether, // fee for juror
+ 50, // jurors for jump
+ [uint256(10), uint256(20), uint256(30), uint256(40)], // Times per period
+ abi.encode(uint256(4)), // Sortition extra data
+ emptySupportedDK
+ );
+
+ vm.expectRevert(KlerosCore.InvalidForkingCourtAsParent.selector);
+ vm.prank(owner);
+ core.createCourt(
+ FORKING_COURT,
+ true, // Hidden votes
+ 2000, // min stake
+ 10000, // alpha
+ 0.03 ether, // fee for juror
+ 50, // jurors for jump
+ [uint256(10), uint256(20), uint256(30), uint256(40)], // Times per period
+ abi.encode(uint256(4)), // Sortition extra data
+ supportedDK
+ );
+
+ uint256[] memory badSupportedDK = new uint256[](2);
+ badSupportedDK[0] = NULL_DISPUTE_KIT; // Include NULL_DK to check that it reverts
+ badSupportedDK[1] = DISPUTE_KIT_CLASSIC;
+ vm.expectRevert(KlerosCore.WrongDisputeKitIndex.selector);
+ vm.prank(owner);
+ core.createCourt(
+ GENERAL_COURT,
+ true, // Hidden votes
+ 2000, // min stake
+ 10000, // alpha
+ 0.03 ether, // fee for juror
+ 50, // jurors for jump
+ [uint256(10), uint256(20), uint256(30), uint256(40)], // Times per period
+ abi.encode(uint256(4)), // Sortition extra data
+ badSupportedDK
+ );
+
+ badSupportedDK[0] = DISPUTE_KIT_CLASSIC;
+ badSupportedDK[1] = 2; // Check out of bounds index
+ vm.expectRevert(KlerosCore.WrongDisputeKitIndex.selector);
+ vm.prank(owner);
+ core.createCourt(
+ GENERAL_COURT,
+ true, // Hidden votes
+ 2000, // min stake
+ 10000, // alpha
+ 0.03 ether, // fee for juror
+ 50, // jurors for jump
+ [uint256(10), uint256(20), uint256(30), uint256(40)], // Times per period
+ abi.encode(uint256(4)), // Sortition extra data
+ badSupportedDK
+ );
+
+ // Add new DK to check the requirement for classic DK
+ DisputeKitSybilResistant newDK = new DisputeKitSybilResistant();
+ vm.prank(owner);
+ core.addNewDisputeKit(newDK);
+ badSupportedDK = new uint256[](1);
+ badSupportedDK[0] = 2; // Include only sybil resistant dk
+ vm.expectRevert(KlerosCore.MustSupportDisputeKitClassic.selector);
+ vm.prank(owner);
+ core.createCourt(
+ GENERAL_COURT,
+ true, // Hidden votes
+ 2000, // min stake
+ 10000, // alpha
+ 0.03 ether, // fee for juror
+ 50, // jurors for jump
+ [uint256(10), uint256(20), uint256(30), uint256(40)], // Times per period
+ abi.encode(uint256(4)), // Sortition extra data
+ badSupportedDK
+ );
+
+ vm.prank(owner);
+ vm.expectEmit(true, true, true, true);
+ emit KlerosCore.DisputeKitEnabled(2, DISPUTE_KIT_CLASSIC, true);
+ vm.expectEmit(true, true, true, true);
+ emit KlerosCore.DisputeKitEnabled(2, 2, true);
+ vm.expectEmit(true, true, true, true);
+ emit KlerosCore.CourtCreated(
+ 2,
+ GENERAL_COURT,
+ true,
+ 2000,
+ 20000,
+ 0.04 ether,
+ 50,
+ [uint256(10), uint256(20), uint256(30), uint256(40)], // Explicitly convert otherwise it throws
+ supportedDK
+ );
+ core.createCourt(
+ GENERAL_COURT,
+ true, // Hidden votes
+ 2000, // min stake
+ 20000, // alpha
+ 0.04 ether, // fee for juror
+ 50, // jurors for jump
+ [uint256(10), uint256(20), uint256(30), uint256(40)], // Times per period
+ abi.encode(uint256(4)), // Sortition extra data
+ supportedDK
+ );
+
+ _assertCourtParameters(2, GENERAL_COURT, true, 2000, 20000, 0.04 ether, 50);
+
+ uint256[] memory children = core.getCourtChildren(2);
+ assertEq(children.length, 0, "No children");
+ _assertTimesPerPeriod(2, [uint256(10), uint256(20), uint256(30), uint256(40)]);
+
+ children = core.getCourtChildren(GENERAL_COURT); // Check that parent updated children
+ assertEq(children.length, 1, "Wrong children count");
+ assertEq(children[0], 2, "Wrong child id");
+
+ (uint256 K, uint256 nodeLength) = sortitionModule.getSortitionProperties(bytes32(uint256(2)));
+ assertEq(K, 4, "Wrong tree K of the new court");
+ assertEq(nodeLength, 1, "Wrong node length for created tree of the new court");
+ }
+
+ function test_changeCourtParameters() public {
+ // Create a 2nd court to check the minStake requirements
+ vm.prank(owner);
+ uint96 newCourtID = 2;
+ uint256[] memory supportedDK = new uint256[](1);
+ supportedDK[0] = DISPUTE_KIT_CLASSIC;
+ core.createCourt(
+ GENERAL_COURT,
+ true, // Hidden votes
+ 2000, // min stake
+ 20000, // alpha
+ 0.04 ether, // fee for juror
+ 50, // jurors for jump
+ [uint256(10), uint256(20), uint256(30), uint256(40)], // Times per period
+ abi.encode(uint256(4)), // Sortition extra data
+ supportedDK
+ );
+
+ vm.expectRevert(KlerosCore.OwnerOnly.selector);
+ vm.prank(other);
+ core.changeCourtParameters(
+ GENERAL_COURT,
+ true, // Hidden votes
+ 2000, // min stake
+ 10000, // alpha
+ 0.03 ether, // fee for juror
+ 50, // jurors for jump
+ [uint256(10), uint256(20), uint256(30), uint256(40)] // Times per period
+ );
+ vm.expectRevert(abi.encodeWithSelector(KlerosCore.MinStakeHigherThanChildCourt.selector, newCourtID));
+ vm.prank(owner);
+ // Min stake of a parent became higher than of a child
+ core.changeCourtParameters(
+ GENERAL_COURT,
+ true, // Hidden votes
+ 3000, // min stake
+ 10000, // alpha
+ 0.03 ether, // fee for juror
+ 50, // jurors for jump
+ [uint256(10), uint256(20), uint256(30), uint256(40)] // Times per period
+ );
+ // Min stake of a child became lower than of a parent
+ vm.expectRevert(KlerosCore.MinStakeLowerThanParentCourt.selector);
+ vm.prank(owner);
+ core.changeCourtParameters(
+ newCourtID,
+ true, // Hidden votes
+ 800, // min stake
+ 10000, // alpha
+ 0.03 ether, // fee for juror
+ 50, // jurors for jump
+ [uint256(10), uint256(20), uint256(30), uint256(40)] // Times per period
+ );
+
+ vm.prank(owner);
+ vm.expectEmit(true, true, true, true);
+ emit KlerosCore.CourtModified(
+ GENERAL_COURT,
+ true,
+ 2000,
+ 20000,
+ 0.04 ether,
+ 50,
+ [uint256(10), uint256(20), uint256(30), uint256(40)] // Explicitly convert otherwise it throws
+ );
+ core.changeCourtParameters(
+ GENERAL_COURT,
+ true, // Hidden votes
+ 2000, // min stake
+ 20000, // alpha
+ 0.04 ether, // fee for juror
+ 50, // jurors for jump
+ [uint256(10), uint256(20), uint256(30), uint256(40)] // Times per period
+ );
+
+ _assertCourtParameters(GENERAL_COURT, FORKING_COURT, true, 2000, 20000, 0.04 ether, 50);
+ _assertTimesPerPeriod(GENERAL_COURT, [uint256(10), uint256(20), uint256(30), uint256(40)]);
+ }
+
+ function test_enableDisputeKits() public {
+ DisputeKitSybilResistant newDK = new DisputeKitSybilResistant();
+ uint256 newDkID = 2;
+ vm.prank(owner);
+ core.addNewDisputeKit(newDK);
+
+ vm.expectRevert(KlerosCore.OwnerOnly.selector);
+ vm.prank(other);
+ uint256[] memory supportedDK = new uint256[](1);
+ supportedDK[0] = newDkID;
+ core.enableDisputeKits(GENERAL_COURT, supportedDK, true);
+
+ vm.expectRevert(KlerosCore.WrongDisputeKitIndex.selector);
+ vm.prank(owner);
+ supportedDK[0] = NULL_DISPUTE_KIT;
+ core.enableDisputeKits(GENERAL_COURT, supportedDK, true);
+
+ vm.expectRevert(KlerosCore.WrongDisputeKitIndex.selector);
+ vm.prank(owner);
+ supportedDK[0] = 3; // Out of bounds
+ core.enableDisputeKits(GENERAL_COURT, supportedDK, true);
+
+ vm.expectRevert(KlerosCore.CannotDisableClassicDK.selector);
+ vm.prank(owner);
+ supportedDK[0] = DISPUTE_KIT_CLASSIC;
+ core.enableDisputeKits(GENERAL_COURT, supportedDK, false);
+
+ vm.prank(owner);
+ vm.expectEmit(true, true, true, true);
+ emit KlerosCore.DisputeKitEnabled(GENERAL_COURT, newDkID, true);
+ supportedDK[0] = newDkID;
+ core.enableDisputeKits(GENERAL_COURT, supportedDK, true);
+ assertEq(core.isSupported(GENERAL_COURT, newDkID), true, "New DK should be supported by General court");
+
+ vm.prank(owner);
+ vm.expectEmit(true, true, true, true);
+ emit KlerosCore.DisputeKitEnabled(GENERAL_COURT, newDkID, false);
+ core.enableDisputeKits(GENERAL_COURT, supportedDK, false);
+ assertEq(core.isSupported(GENERAL_COURT, newDkID), false, "New DK should be disabled in General court");
+ }
+
+ function test_changeAcceptedFeeTokens() public {
+ vm.expectRevert(KlerosCore.OwnerOnly.selector);
+ vm.prank(other);
+ core.changeAcceptedFeeTokens(feeToken, true);
+
+ (bool accepted, , ) = core.currencyRates(feeToken);
+ assertEq(accepted, false, "Token should not be accepted yet");
+
+ vm.prank(owner);
+ vm.expectEmit(true, true, true, true);
+ emit IArbitratorV2.AcceptedFeeToken(feeToken, true);
+ core.changeAcceptedFeeTokens(feeToken, true);
+ (accepted, , ) = core.currencyRates(feeToken);
+ assertEq(accepted, true, "Token should be accepted");
+ }
+
+ function test_changeCurrencyRates() public {
+ vm.expectRevert(KlerosCore.OwnerOnly.selector);
+ vm.prank(other);
+ core.changeCurrencyRates(feeToken, 100, 200);
+
+ (, uint256 rateInEth, uint256 rateDecimals) = core.currencyRates(feeToken);
+ assertEq(rateInEth, 0, "rateInEth should be 0");
+ assertEq(rateDecimals, 0, "rateDecimals should be 0");
+
+ vm.prank(owner);
+ vm.expectEmit(true, true, true, true);
+ emit IArbitratorV2.NewCurrencyRate(feeToken, 100, 200);
+ core.changeCurrencyRates(feeToken, 100, 200);
+
+ (, rateInEth, rateDecimals) = core.currencyRates(feeToken);
+ assertEq(rateInEth, 100, "rateInEth is incorrect");
+ assertEq(rateDecimals, 200, "rateDecimals is incorrect");
+ }
+
+ function test_extraDataToCourtIDMinJurorsDisputeKit() public {
+ // Standard values
+ bytes memory extraData = abi.encodePacked(uint256(GENERAL_COURT), DEFAULT_NB_OF_JURORS, DISPUTE_KIT_CLASSIC);
+
+ (uint96 courtID, uint256 minJurors, uint256 disputeKitID) = core.extraDataToCourtIDMinJurorsDisputeKit(
+ extraData
+ );
+ assertEq(courtID, GENERAL_COURT, "Wrong courtID");
+ assertEq(minJurors, DEFAULT_NB_OF_JURORS, "Wrong minJurors");
+ assertEq(disputeKitID, DISPUTE_KIT_CLASSIC, "Wrong disputeKitID");
+
+ // Botched extraData. Values should fall into standard
+ extraData = "0xfa";
+
+ (courtID, minJurors, disputeKitID) = core.extraDataToCourtIDMinJurorsDisputeKit(extraData);
+ assertEq(courtID, GENERAL_COURT, "Wrong courtID");
+ assertEq(minJurors, DEFAULT_NB_OF_JURORS, "Wrong minJurors");
+ assertEq(disputeKitID, DISPUTE_KIT_CLASSIC, "Wrong disputeKitID");
+
+ // Custom values.
+ vm.startPrank(owner);
+ core.addNewDisputeKit(disputeKit);
+ core.addNewDisputeKit(disputeKit);
+ core.addNewDisputeKit(disputeKit);
+ core.addNewDisputeKit(disputeKit);
+ core.addNewDisputeKit(disputeKit);
+ extraData = abi.encodePacked(uint256(50), uint256(41), uint256(6));
+
+ (courtID, minJurors, disputeKitID) = core.extraDataToCourtIDMinJurorsDisputeKit(extraData);
+ assertEq(courtID, GENERAL_COURT, "Wrong courtID"); // Value in extra data is out of scope so fall back
+ assertEq(minJurors, 41, "Wrong minJurors");
+ assertEq(disputeKitID, 6, "Wrong disputeKitID");
+ }
+}
diff --git a/contracts/test/foundry/KlerosCore_Initialization.t.sol b/contracts/test/foundry/KlerosCore_Initialization.t.sol
new file mode 100644
index 000000000..3aa316c0d
--- /dev/null
+++ b/contracts/test/foundry/KlerosCore_Initialization.t.sol
@@ -0,0 +1,182 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.24;
+
+import {KlerosCore_TestBase} from "./KlerosCore_TestBase.sol";
+import {KlerosCore, IERC721} from "../../src/arbitration/KlerosCore.sol";
+import {KlerosCoreMock} from "../../src/test/KlerosCoreMock.sol";
+import {DisputeKitClassic} from "../../src/arbitration/dispute-kits/DisputeKitClassic.sol";
+import {SortitionModuleMock} from "../../src/test/SortitionModuleMock.sol";
+import {UUPSProxy} from "../../src/proxy/UUPSProxy.sol";
+import {BlockHashRNG} from "../../src/rng/BlockHashRNG.sol";
+import {ISortitionModule} from "../../src/arbitration/interfaces/ISortitionModule.sol";
+import {PNK} from "../../src/token/PNK.sol";
+import "../../src/libraries/Constants.sol";
+
+/// @title KlerosCore_InitializationTest
+/// @dev Tests for KlerosCore initialization and basic configuration
+/// forge-lint: disable-next-item(erc20-unchecked-transfer)
+contract KlerosCore_InitializationTest is KlerosCore_TestBase {
+ function test_initialize() public view {
+ assertEq(core.owner(), msg.sender, "Wrong owner");
+ assertEq(core.guardian(), guardian, "Wrong guardian");
+ assertEq(address(core.pinakion()), address(pinakion), "Wrong pinakion address");
+ assertEq(core.jurorProsecutionModule(), jurorProsecutionModule, "Wrong jurorProsecutionModule address");
+ assertEq(address(core.sortitionModule()), address(sortitionModule), "Wrong sortitionModule address");
+ assertEq(core.getDisputeKitsLength(), 2, "Wrong DK array length");
+
+ _assertCourtParameters(FORKING_COURT, FORKING_COURT, false, 0, 0, 0, 0);
+ _assertCourtParameters(GENERAL_COURT, FORKING_COURT, false, 1000, 10000, 0.03 ether, 511);
+
+ uint256[] memory children = core.getCourtChildren(GENERAL_COURT);
+ assertEq(children.length, 0, "No children");
+ _assertTimesPerPeriod(GENERAL_COURT, timesPerPeriod);
+
+ assertEq(address(core.disputeKits(NULL_DISPUTE_KIT)), address(0), "Wrong address NULL_DISPUTE_KIT");
+ assertEq(
+ address(core.disputeKits(DISPUTE_KIT_CLASSIC)),
+ address(disputeKit),
+ "Wrong address DISPUTE_KIT_CLASSIC"
+ );
+ assertEq(core.isSupported(FORKING_COURT, NULL_DISPUTE_KIT), false, "Forking court null dk should be false");
+ assertEq(
+ core.isSupported(FORKING_COURT, DISPUTE_KIT_CLASSIC),
+ false,
+ "Forking court classic dk should be false"
+ );
+ assertEq(core.isSupported(GENERAL_COURT, NULL_DISPUTE_KIT), false, "General court null dk should be false");
+ assertEq(core.isSupported(GENERAL_COURT, DISPUTE_KIT_CLASSIC), true, "General court classic dk should be true");
+ assertEq(core.paused(), false, "Wrong paused value");
+ assertEq(core.wNative(), address(wNative), "Wrong wNative");
+ assertEq(address(core.jurorNft()), address(0), "Wrong jurorNft");
+ assertEq(core.arbitrableWhitelistEnabled(), false, "Wrong arbitrableWhitelistEnabled");
+
+ assertEq(pinakion.name(), "Pinakion", "Wrong token name");
+ assertEq(pinakion.symbol(), "PNK", "Wrong token symbol");
+ assertEq(pinakion.totalSupply(), 1000000 ether, "Wrong total supply");
+ assertEq(pinakion.balanceOf(msg.sender), 999998 ether, "Wrong token balance of owner");
+ assertEq(pinakion.balanceOf(staker1), 1 ether, "Wrong token balance of staker1");
+ assertEq(pinakion.allowance(staker1, address(core)), 1 ether, "Wrong allowance for staker1");
+ assertEq(pinakion.balanceOf(staker2), 1 ether, "Wrong token balance of staker2");
+ assertEq(pinakion.allowance(staker2, address(core)), 1 ether, "Wrong allowance for staker2");
+
+ assertEq(disputeKit.owner(), msg.sender, "Wrong DK owner");
+ assertEq(disputeKit.getJumpDisputeKitID(), DISPUTE_KIT_CLASSIC, "Wrong jump DK");
+ assertEq(disputeKit.jumpDisputeKitID(), DISPUTE_KIT_CLASSIC, "Wrong jump DK storage var");
+ assertEq(address(disputeKit.core()), address(core), "Wrong core in DK");
+
+ assertEq(sortitionModule.owner(), msg.sender, "Wrong SM owner");
+ assertEq(address(sortitionModule.core()), address(core), "Wrong core in SM");
+ assertEq(uint256(sortitionModule.phase()), uint256(ISortitionModule.Phase.staking), "Phase should be 0");
+ assertEq(sortitionModule.minStakingTime(), 18, "Wrong minStakingTime");
+ assertEq(sortitionModule.maxDrawingTime(), 24, "Wrong maxDrawingTime");
+ assertEq(sortitionModule.lastPhaseChange(), block.timestamp, "Wrong lastPhaseChange");
+ assertEq(sortitionModule.disputesWithoutJurors(), 0, "disputesWithoutJurors should be 0");
+ assertEq(address(sortitionModule.rng()), address(rng), "Wrong RNG address");
+ assertEq(sortitionModule.randomNumber(), 0, "randomNumber should be 0");
+ assertEq(sortitionModule.delayedStakeWriteIndex(), 0, "delayedStakeWriteIndex should be 0");
+ assertEq(sortitionModule.delayedStakeReadIndex(), 1, "Wrong delayedStakeReadIndex");
+ assertEq(sortitionModule.maxStakePerJuror(), type(uint256).max, "Wrong maxStakePerJuror");
+ assertEq(sortitionModule.maxTotalStaked(), type(uint256).max, "Wrong maxTotalStaked");
+ assertEq(sortitionModule.totalStaked(), 0, "Wrong totalStaked");
+
+ (uint256 K, uint256 nodeLength) = sortitionModule.getSortitionProperties(bytes32(uint256(FORKING_COURT)));
+ assertEq(K, 5, "Wrong tree K FORKING_COURT");
+ assertEq(nodeLength, 1, "Wrong node length for created tree FORKING_COURT");
+
+ (K, nodeLength) = sortitionModule.getSortitionProperties(bytes32(uint256(GENERAL_COURT)));
+ assertEq(K, 5, "Wrong tree K GENERAL_COURT");
+ assertEq(nodeLength, 1, "Wrong node length for created tree GENERAL_COURT");
+ }
+
+ function test_initialize_events() public {
+ KlerosCoreMock coreLogic = new KlerosCoreMock();
+ SortitionModuleMock smLogic = new SortitionModuleMock();
+ DisputeKitClassic dkLogic = new DisputeKitClassic();
+ PNK newPinakion = new PNK();
+
+ address newOwner = msg.sender;
+ address newGuardian = vm.addr(1);
+ address newStaker1 = vm.addr(2);
+ address newJurorProsecutionModule = vm.addr(8);
+ uint256 newMinStake = 1000;
+ uint256 newAlpha = 10000;
+ uint256 newFeeForJuror = 0.03 ether;
+ uint256 newJurorsForCourtJump = 511;
+ uint256[4] memory newTimesPerPeriod = [uint256(60), uint256(120), uint256(180), uint256(240)];
+
+ newPinakion.transfer(msg.sender, totalSupply - 1 ether);
+ newPinakion.transfer(newStaker1, 1 ether);
+
+ bytes memory newSortitionExtraData = abi.encode(uint256(5));
+ uint256 newMinStakingTime = 18;
+ uint256 newMaxDrawingTime = 24;
+ bool newHiddenVotes = false;
+
+ uint256 newRngLookahead = 20;
+ BlockHashRNG newRng = new BlockHashRNG(msg.sender, address(sortitionModule), newRngLookahead);
+
+ UUPSProxy proxyCore = new UUPSProxy(address(coreLogic), "");
+
+ bytes memory initDataDk = abi.encodeWithSignature(
+ "initialize(address,address,address,uint256)",
+ newOwner,
+ address(proxyCore),
+ address(wNative),
+ DISPUTE_KIT_CLASSIC
+ );
+
+ UUPSProxy proxyDk = new UUPSProxy(address(dkLogic), initDataDk);
+ DisputeKitClassic newDisputeKit = DisputeKitClassic(address(proxyDk));
+
+ bytes memory initDataSm = abi.encodeWithSignature(
+ "initialize(address,address,uint256,uint256,address,uint256,uint256)",
+ newOwner,
+ address(proxyCore),
+ newMinStakingTime,
+ newMaxDrawingTime,
+ newRng,
+ type(uint256).max,
+ type(uint256).max
+ );
+
+ UUPSProxy proxySm = new UUPSProxy(address(smLogic), initDataSm);
+ SortitionModuleMock newSortitionModule = SortitionModuleMock(address(proxySm));
+ vm.prank(newOwner);
+ newRng.changeConsumer(address(newSortitionModule));
+
+ KlerosCoreMock newCore = KlerosCoreMock(address(proxyCore));
+ vm.expectEmit(true, true, true, true);
+ emit KlerosCore.DisputeKitCreated(DISPUTE_KIT_CLASSIC, newDisputeKit);
+ vm.expectEmit(true, true, true, true);
+
+ uint256[] memory supportedDK = new uint256[](1);
+ supportedDK[0] = DISPUTE_KIT_CLASSIC;
+ emit KlerosCore.CourtCreated(
+ GENERAL_COURT,
+ FORKING_COURT,
+ false,
+ 1000,
+ 10000,
+ 0.03 ether,
+ 511,
+ [uint256(60), uint256(120), uint256(180), uint256(240)], // Explicitly convert otherwise it throws
+ supportedDK
+ );
+ vm.expectEmit(true, true, true, true);
+ emit KlerosCore.DisputeKitEnabled(GENERAL_COURT, DISPUTE_KIT_CLASSIC, true);
+ newCore.initialize(
+ newOwner,
+ newGuardian,
+ newPinakion,
+ newJurorProsecutionModule,
+ newDisputeKit,
+ newHiddenVotes,
+ [newMinStake, newAlpha, newFeeForJuror, newJurorsForCourtJump],
+ newTimesPerPeriod,
+ newSortitionExtraData,
+ newSortitionModule,
+ address(wNative),
+ IERC721(address(0))
+ );
+ }
+}
diff --git a/contracts/test/foundry/KlerosCore_RNG.t.sol b/contracts/test/foundry/KlerosCore_RNG.t.sol
new file mode 100644
index 000000000..0afd0ba43
--- /dev/null
+++ b/contracts/test/foundry/KlerosCore_RNG.t.sol
@@ -0,0 +1,121 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.24;
+
+import {KlerosCore_TestBase} from "./KlerosCore_TestBase.sol";
+import {SortitionModule} from "../../src/arbitration/SortitionModule.sol";
+import {RNGWithFallback, IRNG} from "../../src/rng/RNGWithFallback.sol";
+import {RNGMock} from "../../src/test/RNGMock.sol";
+import "../../src/libraries/Constants.sol";
+
+/// @title KlerosCore_RNGTest
+/// @dev Tests for KlerosCore random number generation and fallback mechanisms
+contract KlerosCore_RNGTest is KlerosCore_TestBase {
+ function test_RNGFallback() public {
+ RNGWithFallback rngFallback;
+ uint256 fallbackTimeout = 100;
+ RNGMock rngMock = new RNGMock();
+ rngFallback = new RNGWithFallback(msg.sender, address(sortitionModule), fallbackTimeout, rngMock);
+ assertEq(rngFallback.owner(), msg.sender, "Wrong owner");
+ assertEq(rngFallback.consumer(), address(sortitionModule), "Wrong sortition module address");
+ assertEq(address(rngFallback.rng()), address(rngMock), "Wrong RNG in fallback contract");
+ assertEq(rngFallback.fallbackTimeoutSeconds(), fallbackTimeout, "Wrong fallback timeout");
+ assertEq(rngFallback.requestTimestamp(), 0, "Request timestamp should be 0");
+
+ vm.prank(owner);
+ sortitionModule.changeRandomNumberGenerator(rngFallback);
+ assertEq(address(sortitionModule.rng()), address(rngFallback), "Wrong RNG address");
+
+ vm.prank(staker1);
+ core.setStake(GENERAL_COURT, 20000);
+ vm.prank(disputer);
+ arbitrable.createDispute{value: feeForJuror * DEFAULT_NB_OF_JURORS}("Action");
+ vm.warp(block.timestamp + minStakingTime);
+
+ sortitionModule.passPhase(); // Generating
+ assertEq(rngFallback.requestTimestamp(), block.timestamp, "Wrong request timestamp");
+
+ vm.expectRevert(SortitionModule.RandomNumberNotReady.selector);
+ sortitionModule.passPhase();
+
+ vm.warp(block.timestamp + fallbackTimeout + 1);
+
+ // Pass several blocks too to see that correct block.number is still picked up.
+ vm.roll(block.number + 5);
+
+ vm.expectEmit(true, true, true, true);
+ emit RNGWithFallback.RNGFallback();
+ sortitionModule.passPhase(); // Drawing phase
+
+ assertEq(sortitionModule.randomNumber(), uint256(blockhash(block.number - 1)), "Wrong random number");
+ }
+
+ function test_RNGFallback_happyPath() public {
+ RNGWithFallback rngFallback;
+ uint256 fallbackTimeout = 100;
+ RNGMock rngMock = new RNGMock();
+ rngFallback = new RNGWithFallback(msg.sender, address(sortitionModule), fallbackTimeout, rngMock);
+
+ vm.prank(owner);
+ sortitionModule.changeRandomNumberGenerator(rngFallback);
+ assertEq(address(sortitionModule.rng()), address(rngFallback), "Wrong RNG address");
+
+ vm.prank(staker1);
+ core.setStake(GENERAL_COURT, 20000);
+ vm.prank(disputer);
+ arbitrable.createDispute{value: feeForJuror * DEFAULT_NB_OF_JURORS}("Action");
+ vm.warp(block.timestamp + minStakingTime);
+
+ assertEq(rngFallback.requestTimestamp(), 0, "Request timestamp should be 0");
+
+ sortitionModule.passPhase(); // Generating
+ assertEq(rngFallback.requestTimestamp(), block.timestamp, "Wrong request timestamp");
+
+ rngMock.setRN(123);
+
+ sortitionModule.passPhase(); // Drawing phase
+ assertEq(sortitionModule.randomNumber(), 123, "Wrong random number");
+ }
+
+ function test_RNGFallback_sanityChecks() public {
+ RNGWithFallback rngFallback;
+ uint256 fallbackTimeout = 100;
+ RNGMock rngMock = new RNGMock();
+ rngFallback = new RNGWithFallback(msg.sender, address(sortitionModule), fallbackTimeout, rngMock);
+
+ vm.expectRevert(IRNG.ConsumerOnly.selector);
+ vm.prank(owner);
+ rngFallback.requestRandomness();
+
+ vm.expectRevert(IRNG.ConsumerOnly.selector);
+ vm.prank(owner);
+ rngFallback.receiveRandomness();
+
+ vm.expectRevert(IRNG.OwnerOnly.selector);
+ vm.prank(other);
+ rngFallback.changeOwner(other);
+ vm.prank(owner);
+ rngFallback.changeOwner(other);
+ assertEq(rngFallback.owner(), other, "Wrong owner");
+
+ // Change owner back for convenience
+ vm.prank(other);
+ rngFallback.changeOwner(owner);
+
+ vm.expectRevert(IRNG.OwnerOnly.selector);
+ vm.prank(other);
+ rngFallback.changeConsumer(other);
+ vm.prank(owner);
+ rngFallback.changeConsumer(other);
+ assertEq(rngFallback.consumer(), other, "Wrong consumer");
+
+ vm.expectRevert(IRNG.OwnerOnly.selector);
+ vm.prank(other);
+ rngFallback.changeFallbackTimeout(5);
+
+ vm.prank(owner);
+ vm.expectEmit(true, true, true, true);
+ emit RNGWithFallback.FallbackTimeoutChanged(5);
+ rngFallback.changeFallbackTimeout(5);
+ assertEq(rngFallback.fallbackTimeoutSeconds(), 5, "Wrong fallback timeout");
+ }
+}
diff --git a/contracts/test/foundry/KlerosCore_Staking.t.sol b/contracts/test/foundry/KlerosCore_Staking.t.sol
new file mode 100644
index 000000000..b44bbfab2
--- /dev/null
+++ b/contracts/test/foundry/KlerosCore_Staking.t.sol
@@ -0,0 +1,621 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.24;
+
+import {KlerosCore_TestBase} from "./KlerosCore_TestBase.sol";
+import {KlerosCore} from "../../src/arbitration/KlerosCore.sol";
+import {SortitionModule} from "../../src/arbitration/SortitionModule.sol";
+import {ISortitionModule} from "../../src/arbitration/interfaces/ISortitionModule.sol";
+import {IKlerosCore, KlerosCoreSnapshotProxy} from "../../src/arbitration/view/KlerosCoreSnapshotProxy.sol";
+import "../../src/libraries/Constants.sol";
+import {console} from "forge-std/console.sol";
+
+/// @title KlerosCore_StakingTest
+/// @dev Tests for KlerosCore staking mechanics and stake management
+/// forge-lint: disable-next-item(erc20-unchecked-transfer)
+contract KlerosCore_StakingTest is KlerosCore_TestBase {
+ function test_setStake_increase() public {
+ vm.prank(owner);
+ core.pause();
+ vm.expectRevert(KlerosCore.WhenNotPausedOnly.selector);
+ vm.prank(staker1);
+ core.setStake(GENERAL_COURT, 1000);
+ vm.prank(owner);
+ core.unpause();
+
+ vm.expectRevert(KlerosCore.StakingNotPossibleInThisCourt.selector);
+ vm.prank(staker1);
+ core.setStake(FORKING_COURT, 1000);
+
+ uint96 badCourtID = 2;
+ vm.expectRevert(KlerosCore.StakingNotPossibleInThisCourt.selector);
+ vm.prank(staker1);
+ core.setStake(badCourtID, 1000);
+
+ vm.expectRevert(KlerosCore.StakingLessThanCourtMinStake.selector);
+ vm.prank(staker1);
+ core.setStake(GENERAL_COURT, 800);
+
+ vm.expectRevert(KlerosCore.StakingZeroWhenNoStake.selector);
+ vm.prank(staker1);
+ core.setStake(GENERAL_COURT, 0);
+
+ vm.prank(staker1);
+ vm.expectEmit(true, true, true, true);
+ emit SortitionModule.StakeSet(staker1, GENERAL_COURT, 1001, 1001);
+ core.setStake(GENERAL_COURT, 1001);
+
+ (uint256 totalStaked, uint256 totalLocked, uint256 stakedInCourt, uint256 nbCourts) = sortitionModule
+ .getJurorBalance(staker1, GENERAL_COURT);
+ assertEq(totalStaked, 1001, "Wrong amount total staked");
+ assertEq(totalLocked, 0, "Wrong amount locked");
+ assertEq(stakedInCourt, 1001, "Wrong amount staked in court");
+ assertEq(nbCourts, 1, "Wrong number of courts");
+
+ uint96[] memory courts = sortitionModule.getJurorCourtIDs(staker1);
+ assertEq(courts.length, 1, "Wrong courts count");
+ assertEq(courts[0], GENERAL_COURT, "Wrong court id");
+ assertEq(sortitionModule.isJurorStaked(staker1), true, "Juror should be staked");
+
+ assertEq(pinakion.balanceOf(address(core)), 1001, "Wrong token balance of the core");
+ assertEq(pinakion.balanceOf(staker1), 999999999999998999, "Wrong token balance of staker1"); // 1 eth - 1001 wei
+ assertEq(pinakion.allowance(staker1, address(core)), 999999999999998999, "Wrong allowance for staker1");
+
+ vm.expectRevert(KlerosCore.StakingTransferFailed.selector); // This error will be caught because owner didn't approve any tokens for KlerosCore
+ vm.prank(owner);
+ core.setStake(GENERAL_COURT, 1000);
+
+ // Increase stake one more time to verify the correct behavior
+ vm.prank(staker1);
+ vm.expectEmit(true, true, true, true);
+ emit SortitionModule.StakeSet(staker1, GENERAL_COURT, 2000, 2000);
+ core.setStake(GENERAL_COURT, 2000);
+
+ (totalStaked, totalLocked, stakedInCourt, nbCourts) = sortitionModule.getJurorBalance(staker1, GENERAL_COURT);
+ assertEq(totalStaked, 2000, "Wrong amount total staked");
+ assertEq(totalLocked, 0, "Wrong amount locked");
+ assertEq(stakedInCourt, 2000, "Wrong amount staked in court");
+ assertEq(nbCourts, 1, "Number of courts should not increase");
+
+ assertEq(pinakion.balanceOf(address(core)), 2000, "Wrong token balance of the core");
+ assertEq(pinakion.balanceOf(staker1), 999999999999998000, "Wrong token balance of staker1"); // 1 eth - 2000 wei
+ assertEq(pinakion.allowance(staker1, address(core)), 999999999999998000, "Wrong allowance for staker1");
+ }
+
+ function test_setStake_decrease() public {
+ vm.prank(staker1);
+ core.setStake(GENERAL_COURT, 2000);
+ assertEq(pinakion.balanceOf(address(core)), 2000, "Wrong token balance of the core");
+ assertEq(pinakion.balanceOf(staker1), 999999999999998000, "Wrong token balance of staker1");
+ assertEq(pinakion.allowance(staker1, address(core)), 999999999999998000, "Wrong allowance for staker1");
+
+ vm.prank(staker1);
+ core.setStake(GENERAL_COURT, 1500); // Decrease the stake to see if it's reflected correctly
+ (uint256 totalStaked, uint256 totalLocked, uint256 stakedInCourt, uint256 nbCourts) = sortitionModule
+ .getJurorBalance(staker1, GENERAL_COURT);
+ assertEq(totalStaked, 1500, "Wrong amount total staked");
+ assertEq(totalLocked, 0, "Wrong amount locked");
+ assertEq(stakedInCourt, 1500, "Wrong amount staked in court");
+ assertEq(nbCourts, 1, "Wrong number of courts");
+
+ uint96[] memory courts = sortitionModule.getJurorCourtIDs(staker1);
+ assertEq(courts.length, 1, "Wrong courts count");
+ assertEq(courts[0], GENERAL_COURT, "Wrong court id");
+ assertEq(sortitionModule.isJurorStaked(staker1), true, "Juror should be staked");
+
+ assertEq(pinakion.balanceOf(address(core)), 1500, "Wrong token balance of the core");
+ assertEq(pinakion.balanceOf(staker1), 999999999999998500, "Wrong token balance of staker1");
+ assertEq(
+ pinakion.allowance(staker1, address(core)),
+ 999999999999998000,
+ "Allowance should not change during withdrawal"
+ );
+
+ vm.prank(address(core));
+ pinakion.transfer(staker1, 1); // Manually send 1 token to make the withdrawal fail
+
+ vm.expectRevert(KlerosCore.UnstakingTransferFailed.selector);
+ vm.prank(staker1);
+ core.setStake(GENERAL_COURT, 0);
+
+ vm.prank(address(staker1));
+ pinakion.transfer(address(core), 1); // Manually give the token back
+ vm.prank(staker1);
+ core.setStake(GENERAL_COURT, 0);
+
+ (totalStaked, totalLocked, stakedInCourt, nbCourts) = sortitionModule.getJurorBalance(staker1, GENERAL_COURT);
+ assertEq(totalStaked, 0, "Wrong amount total staked");
+ assertEq(totalLocked, 0, "Wrong amount locked");
+ assertEq(stakedInCourt, 0, "Wrong amount staked in court");
+ assertEq(nbCourts, 0, "Wrong number of courts");
+
+ courts = sortitionModule.getJurorCourtIDs(staker1);
+ assertEq(courts.length, 0, "Wrong courts count");
+ assertEq(sortitionModule.isJurorStaked(staker1), false, "Juror should not be staked");
+
+ assertEq(pinakion.balanceOf(address(core)), 0, "Wrong token balance of the core");
+ assertEq(pinakion.balanceOf(staker1), 1 ether, "Wrong token balance of staker1");
+ assertEq(
+ pinakion.allowance(staker1, address(core)),
+ 999999999999998000,
+ "Allowance should not change during withdrawal"
+ );
+ }
+
+ function test_setStake_maxStakePathCheck() public {
+ uint256[] memory supportedDK = new uint256[](1);
+ supportedDK[0] = DISPUTE_KIT_CLASSIC;
+
+ // Create 4 courts to check the require
+ for (uint96 i = GENERAL_COURT; i <= 4; i++) {
+ vm.prank(owner);
+ core.createCourt(
+ GENERAL_COURT,
+ true,
+ 2000,
+ 20000,
+ 0.04 ether,
+ 50,
+ [uint256(10), uint256(20), uint256(30), uint256(40)],
+ abi.encode(uint256(4)),
+ supportedDK
+ );
+ vm.prank(staker1);
+ core.setStake(i, 2000);
+ }
+
+ uint96[] memory courts = sortitionModule.getJurorCourtIDs(staker1);
+ assertEq(courts.length, 4, "Wrong courts count");
+
+ uint96 excessiveCourtID = 5;
+ vm.expectRevert(KlerosCore.StakingInTooManyCourts.selector);
+ vm.prank(staker1);
+ core.setStake(excessiveCourtID, 2000);
+ }
+
+ function test_setStake_increaseDrawingPhase() public {
+ // Set the stake and create a dispute to advance the phase
+ vm.prank(staker1);
+ core.setStake(GENERAL_COURT, 1000);
+ vm.prank(disputer);
+ arbitrable.createDispute{value: feeForJuror * DEFAULT_NB_OF_JURORS}("Action");
+ assertEq(sortitionModule.disputesWithoutJurors(), 1, "Wrong disputesWithoutJurors count");
+ vm.warp(block.timestamp + minStakingTime);
+ sortitionModule.passPhase(); // Generating
+ vm.warp(block.timestamp + rngLookahead);
+ sortitionModule.passPhase(); // Drawing phase
+
+ assertEq(pinakion.balanceOf(address(core)), 1000, "Wrong token balance of the core");
+ assertEq(pinakion.balanceOf(staker1), 999999999999999000, "Wrong token balance of staker1");
+ assertEq(uint256(sortitionModule.phase()), uint256(ISortitionModule.Phase.drawing), "Wrong phase");
+
+ vm.prank(staker1);
+ vm.expectEmit(true, true, true, true);
+ emit SortitionModule.StakeDelayed(staker1, GENERAL_COURT, 1500);
+ core.setStake(GENERAL_COURT, 1500);
+
+ uint256 delayedStakeId = sortitionModule.delayedStakeWriteIndex();
+ assertEq(delayedStakeId, 1, "Wrong delayedStakeWriteIndex");
+ assertEq(sortitionModule.delayedStakeReadIndex(), 1, "Wrong delayedStakeReadIndex");
+ (address account, uint96 courtID, uint256 stake) = sortitionModule.delayedStakes(delayedStakeId);
+ assertEq(account, staker1, "Wrong staker account");
+ assertEq(courtID, GENERAL_COURT, "Wrong court id");
+ assertEq(stake, 1500, "Wrong amount staked in court");
+
+ (uint256 totalStaked, uint256 totalLocked, uint256 stakedInCourt, uint256 nbCourts) = sortitionModule
+ .getJurorBalance(staker1, GENERAL_COURT);
+ assertEq(totalStaked, 1000, "Wrong amount total staked");
+ assertEq(totalLocked, 0, "Wrong amount locked");
+ assertEq(stakedInCourt, 1000, "Amount staked in court should not change until delayed stake is executed");
+ assertEq(nbCourts, 1, "Wrong number of courts");
+
+ uint96[] memory courts = sortitionModule.getJurorCourtIDs(staker1);
+ assertEq(courts.length, 1, "Wrong courts count");
+ assertEq(courts[0], GENERAL_COURT, "Wrong court id");
+ assertEq(sortitionModule.isJurorStaked(staker1), true, "Juror should be staked");
+
+ assertEq(pinakion.balanceOf(address(core)), 1000, "Wrong token balance of the core");
+ assertEq(pinakion.balanceOf(staker1), 999999999999999000, "Wrong token balance of staker1");
+ }
+
+ function test_setStake_decreaseDrawingPhase() public {
+ // Set the stake and create a dispute to advance the phase
+ vm.prank(staker1);
+ core.setStake(GENERAL_COURT, 2000);
+ vm.prank(disputer);
+ arbitrable.createDispute{value: feeForJuror * DEFAULT_NB_OF_JURORS}("Action");
+ vm.warp(block.timestamp + minStakingTime);
+ sortitionModule.passPhase(); // Generating
+ vm.warp(block.timestamp + rngLookahead);
+ sortitionModule.passPhase(); // Drawing phase
+
+ assertEq(pinakion.balanceOf(address(core)), 2000, "Wrong token balance of the core");
+ assertEq(pinakion.balanceOf(staker1), 999999999999998000, "Wrong token balance of staker1");
+
+ vm.prank(staker1);
+ vm.expectEmit(true, true, true, true);
+ emit SortitionModule.StakeDelayed(staker1, GENERAL_COURT, 1800);
+ core.setStake(GENERAL_COURT, 1800);
+
+ (uint256 totalStaked, , uint256 stakedInCourt, ) = sortitionModule.getJurorBalance(staker1, GENERAL_COURT);
+ assertEq(totalStaked, 2000, "Total staked amount should not change");
+ assertEq(stakedInCourt, 2000, "Amount staked in court should not change");
+
+ assertEq(pinakion.balanceOf(address(core)), 2000, "Token balance of the core should not change");
+ assertEq(pinakion.balanceOf(staker1), 999999999999998000, "Wrong token balance of staker1");
+ }
+
+ function test_setStake_LockedTokens() public {
+ // Check that correct amount is taken when locked tokens amount exceeds the staked amount
+ vm.prank(staker1);
+ core.setStake(GENERAL_COURT, 10000);
+ vm.prank(disputer);
+ arbitrable.createDispute{value: feeForJuror * DEFAULT_NB_OF_JURORS}("Action");
+ vm.warp(block.timestamp + minStakingTime);
+ sortitionModule.passPhase(); // Generating
+ vm.warp(block.timestamp + rngLookahead);
+ sortitionModule.passPhase(); // Drawing phase
+
+ uint256 disputeID = 0;
+ core.draw(disputeID, DEFAULT_NB_OF_JURORS);
+ (uint256 totalStaked, uint256 totalLocked, uint256 stakedInCourt, uint256 nbCourts) = sortitionModule
+ .getJurorBalance(staker1, GENERAL_COURT);
+ assertEq(totalStaked, 10000, "Wrong amount total staked");
+ assertEq(totalLocked, 3000, "Wrong amount locked"); // 1000 per draw and the juror was drawn 3 times
+ assertEq(stakedInCourt, 10000, "Wrong amount staked in court");
+
+ sortitionModule.passPhase(); // Staking
+
+ assertEq(pinakion.balanceOf(address(core)), 10000, "Wrong token balance of the core");
+ assertEq(pinakion.balanceOf(staker1), 999999999999990000, "Wrong token balance of staker1");
+
+ // Unstake to check that locked tokens won't be withdrawn
+ vm.prank(staker1);
+ core.setStake(GENERAL_COURT, 0);
+
+ (totalStaked, totalLocked, stakedInCourt, nbCourts) = sortitionModule.getJurorBalance(staker1, GENERAL_COURT);
+ assertEq(totalStaked, 3000, "Wrong amount total staked");
+ assertEq(totalLocked, 3000, "Wrong amount locked");
+ assertEq(stakedInCourt, 0, "Wrong amount staked in court");
+ assertEq(nbCourts, 0, "Wrong amount staked in court");
+
+ assertEq(pinakion.balanceOf(address(core)), 3000, "Wrong token balance of the core");
+ assertEq(pinakion.balanceOf(staker1), 999999999999997000, "Wrong token balance of staker1");
+
+ // Stake again to check the behaviour.
+ vm.prank(staker1);
+ core.setStake(GENERAL_COURT, 5000);
+
+ (totalStaked, totalLocked, stakedInCourt, nbCourts) = sortitionModule.getJurorBalance(staker1, GENERAL_COURT);
+ assertEq(totalStaked, 8000, "Wrong amount total staked"); // 5000 were added to the previous 3000.
+ assertEq(totalLocked, 3000, "Wrong amount locked");
+ assertEq(stakedInCourt, 5000, "Wrong amount staked in court");
+ assertEq(nbCourts, 1, "Wrong amount staked in court");
+
+ assertEq(pinakion.balanceOf(address(core)), 8000, "Wrong amount of tokens in Core");
+ assertEq(pinakion.balanceOf(staker1), 999999999999992000, "Wrong token balance of staker1");
+ }
+
+ function test_executeDelayedStakes() public {
+ // Stake as staker2 as well to diversify the execution of delayed stakes
+ vm.prank(staker2);
+ core.setStake(GENERAL_COURT, 10000);
+
+ vm.expectRevert(SortitionModule.NoDelayedStakeToExecute.selector);
+ sortitionModule.executeDelayedStakes(5);
+
+ // Set the stake and create a dispute to advance the phase
+ vm.prank(disputer);
+ arbitrable.createDispute{value: feeForJuror * DEFAULT_NB_OF_JURORS}("Action");
+ vm.warp(block.timestamp + minStakingTime);
+ sortitionModule.passPhase(); // Generating
+ vm.warp(block.timestamp + rngLookahead);
+ sortitionModule.passPhase(); // Drawing phase
+ uint256 disputeID = 0;
+ core.draw(disputeID, DEFAULT_NB_OF_JURORS);
+
+ vm.expectRevert(SortitionModule.NotStakingPhase.selector);
+ sortitionModule.executeDelayedStakes(5);
+
+ // Create delayed stake
+ vm.prank(staker1);
+ vm.expectEmit(true, true, true, true);
+ emit SortitionModule.StakeDelayed(staker1, GENERAL_COURT, 1500);
+ core.setStake(GENERAL_COURT, 1500);
+
+ assertEq(pinakion.balanceOf(address(core)), 10000, "Wrong token balance of the core"); // Balance should not increase because the stake was delayed
+ assertEq(pinakion.balanceOf(staker1), 1 ether, "Wrong token balance of staker1");
+
+ // Create delayed stake for another staker
+ vm.prank(staker2);
+ vm.expectEmit(true, true, true, true);
+ emit SortitionModule.StakeDelayed(staker2, GENERAL_COURT, 0);
+ core.setStake(GENERAL_COURT, 0);
+ assertEq(pinakion.balanceOf(staker2), 999999999999990000, "Wrong token balance of staker2"); // Balance should not change since wrong phase
+
+ // Create another delayed stake for staker1 on top of it to check the execution
+ vm.prank(staker1);
+ vm.expectEmit(true, true, true, true);
+ emit SortitionModule.StakeDelayed(staker1, GENERAL_COURT, 1800);
+ core.setStake(GENERAL_COURT, 1800);
+
+ assertEq(sortitionModule.delayedStakeWriteIndex(), 3, "Wrong delayedStakeWriteIndex");
+ assertEq(sortitionModule.delayedStakeReadIndex(), 1, "Wrong delayedStakeReadIndex");
+
+ (address account, uint96 courtID, uint256 stake) = sortitionModule.delayedStakes(1);
+
+ // Check each delayed stake
+ assertEq(account, staker1, "Wrong staker account for the first delayed stake");
+ assertEq(courtID, GENERAL_COURT, "Wrong court ID");
+ assertEq(stake, 1500, "Wrong staking amount");
+
+ (account, courtID, stake) = sortitionModule.delayedStakes(2);
+ assertEq(account, staker2, "Wrong staker2 account");
+ assertEq(courtID, GENERAL_COURT, "Wrong court id for staker2");
+ assertEq(stake, 0, "Wrong amount for delayed stake of staker2");
+
+ (account, courtID, stake) = sortitionModule.delayedStakes(3);
+ assertEq(account, staker1, "Wrong staker1 account");
+ assertEq(courtID, GENERAL_COURT, "Wrong court id for staker1");
+ assertEq(stake, 1800, "Wrong amount for delayed stake of staker1");
+
+ // So far the only amount transferred was 10000 by staker2. Staker 1 has two delayed stakes, for 1500 and 1800 pnk.
+ assertEq(pinakion.balanceOf(address(core)), 10000, "Wrong token balance of the core");
+ assertEq(pinakion.balanceOf(staker1), 1 ether, "Wrong token balance of staker1");
+ assertEq(pinakion.balanceOf(staker2), 999999999999990000, "Wrong token balance of staker2");
+
+ (uint256 totalStaked, uint256 totalLocked, uint256 stakedInCourt, uint256 nbCourts) = sortitionModule
+ .getJurorBalance(staker1, GENERAL_COURT); // Only check the first staker to check how consecutive delayed stakes are handled.
+ // Balances shouldn't be updated yet.
+ assertEq(totalStaked, 0, "Wrong amount total staked");
+ assertEq(totalLocked, 0, "Wrong amount locked");
+ assertEq(stakedInCourt, 0, "Wrong amount staked in court");
+ assertEq(nbCourts, 0, "Wrong number of courts");
+
+ vm.warp(block.timestamp + maxDrawingTime);
+ sortitionModule.passPhase(); // Staking. Delayed stakes can be executed now
+
+ vm.prank(address(core));
+ pinakion.transfer(owner, 10000); // Dispose of the tokens of 2nd staker to make the execution fail for the 2nd delayed stake
+ assertEq(pinakion.balanceOf(address(core)), 0, "Wrong token balance of the core");
+
+ // 2 events should be emitted but the 2nd stake supersedes the first one in the end.
+ vm.expectEmit(true, true, true, true);
+ emit SortitionModule.StakeSet(staker1, GENERAL_COURT, 1500, 1500);
+ vm.expectEmit(true, true, true, true);
+ emit SortitionModule.StakeSet(staker1, GENERAL_COURT, 1800, 1800);
+ sortitionModule.executeDelayedStakes(20); // Deliberately ask for more iterations than needed
+
+ assertEq(sortitionModule.delayedStakeWriteIndex(), 3, "Wrong delayedStakeWriteIndex");
+ assertEq(sortitionModule.delayedStakeReadIndex(), 4, "Wrong delayedStakeReadIndex");
+
+ // Check that delayed stakes are nullified
+ for (uint i = 2; i <= sortitionModule.delayedStakeWriteIndex(); i++) {
+ (account, courtID, stake) = sortitionModule.delayedStakes(i);
+
+ assertEq(account, address(0), "Wrong staker account after delayed stake deletion");
+ assertEq(courtID, 0, "Court id should be nullified");
+ assertEq(stake, 0, "No amount to stake");
+ }
+
+ assertEq(pinakion.balanceOf(staker1), 999999999999998200, "Wrong token balance of staker1");
+
+ (totalStaked, totalLocked, stakedInCourt, nbCourts) = sortitionModule.getJurorBalance(staker1, GENERAL_COURT);
+ assertEq(totalStaked, 1800, "Wrong amount total staked");
+ assertEq(totalLocked, 0, "Wrong amount locked");
+ assertEq(stakedInCourt, 1800, "Wrong amount staked in court");
+ assertEq(nbCourts, 1, "Wrong amount staked in court");
+
+ // Staker2 not getting the tokens back indicates that his delayed stake was skipped and the flow wasn't disrupted
+ assertEq(pinakion.balanceOf(staker2), 999999999999990000, "Wrong token balance of staker2");
+ }
+
+ function test_setStakeBySortitionModule() public {
+ // Note that functionality of this function was checked during delayed stakes execution
+ vm.expectRevert(KlerosCore.SortitionModuleOnly.selector);
+ vm.prank(owner);
+ core.setStakeBySortitionModule(staker1, GENERAL_COURT, 1000);
+ }
+
+ function test_setStake_snapshotProxyCheck() public {
+ vm.prank(staker1);
+ core.setStake(GENERAL_COURT, 12346);
+
+ KlerosCoreSnapshotProxy snapshotProxy = new KlerosCoreSnapshotProxy(owner, IKlerosCore(address(core)));
+ assertEq(snapshotProxy.name(), "Staked Pinakion", "Wrong name of the proxy token");
+ assertEq(snapshotProxy.symbol(), "stPNK", "Wrong symbol of the proxy token");
+ assertEq(snapshotProxy.decimals(), 18, "Wrong decimals of the proxy token");
+ assertEq(snapshotProxy.owner(), msg.sender, "Wrong owner");
+ assertEq(address(snapshotProxy.core()), address(core), "Wrong core in snapshot proxy");
+ assertEq(snapshotProxy.balanceOf(staker1), 12346, "Wrong stPNK balance");
+
+ vm.prank(other);
+ vm.expectRevert(KlerosCoreSnapshotProxy.OwnerOnly.selector);
+ snapshotProxy.changeCore(IKlerosCore(other));
+ vm.prank(owner);
+ snapshotProxy.changeCore(IKlerosCore(other));
+ assertEq(address(snapshotProxy.core()), other, "Wrong core in snapshot proxy after change");
+
+ vm.prank(other);
+ vm.expectRevert(KlerosCoreSnapshotProxy.OwnerOnly.selector);
+ snapshotProxy.changeOwner(other);
+ vm.prank(owner);
+ snapshotProxy.changeOwner(other);
+ assertEq(snapshotProxy.owner(), other, "Wrong owner after change");
+ }
+
+ function testFuzz_setStake(uint256 firstStake, uint256 secondStake) public {
+ uint256 stakerSupply = totalSupply / 10;
+
+ vm.prank(owner);
+ pinakion.transfer(staker1, stakerSupply - 1 ether); // 1 eth was transferred in the initial setup so offset that value.
+ vm.assume(firstStake >= minStake && firstStake <= stakerSupply);
+ vm.assume(secondStake >= minStake && secondStake <= stakerSupply);
+
+ vm.prank(staker1);
+ pinakion.approve(address(core), firstStake);
+
+ vm.prank(staker1);
+ vm.expectEmit(true, true, true, true);
+ emit SortitionModule.StakeSet(staker1, GENERAL_COURT, firstStake, firstStake);
+ core.setStake(GENERAL_COURT, firstStake);
+
+ (uint256 totalStaked, uint256 totalLocked, uint256 stakedInCourt, uint256 nbCourts) = sortitionModule
+ .getJurorBalance(staker1, GENERAL_COURT);
+ assertEq(totalStaked, firstStake, "Wrong amount total staked");
+ assertEq(totalLocked, 0, "Wrong amount locked");
+ assertEq(stakedInCourt, firstStake, "Wrong amount staked in court");
+ assertEq(nbCourts, 1, "Wrong number of courts");
+
+ uint96[] memory courts = sortitionModule.getJurorCourtIDs(staker1);
+ assertEq(courts.length, 1, "Wrong courts count");
+ assertEq(courts[0], GENERAL_COURT, "Wrong court id");
+ assertEq(sortitionModule.isJurorStaked(staker1), true, "Juror should be staked");
+
+ assertEq(pinakion.balanceOf(address(core)), firstStake, "Wrong token balance of the core");
+ assertEq(pinakion.balanceOf(staker1), stakerSupply - firstStake, "Wrong token balance of staker1");
+ assertEq(pinakion.allowance(staker1, address(core)), 0, "Allowance should be spent for staker1");
+
+ // Change the stake and see if everything is correct.
+ vm.prank(staker1);
+ pinakion.approve(address(core), secondStake);
+
+ vm.prank(staker1);
+ vm.expectEmit(true, true, true, true);
+ emit SortitionModule.StakeSet(staker1, GENERAL_COURT, secondStake, secondStake);
+ core.setStake(GENERAL_COURT, secondStake);
+
+ (totalStaked, totalLocked, stakedInCourt, nbCourts) = sortitionModule.getJurorBalance(staker1, GENERAL_COURT);
+ assertEq(totalStaked, secondStake, "Wrong amount total staked secondStake");
+ assertEq(totalLocked, 0, "Wrong amount locked secondStake");
+ assertEq(stakedInCourt, secondStake, "Wrong amount staked in court secondStake");
+ assertEq(nbCourts, 1, "Number of courts should not increase secondStake");
+
+ assertEq(pinakion.balanceOf(address(core)), secondStake, "Wrong token balance of the core secondStake");
+ assertEq(pinakion.balanceOf(staker1), stakerSupply - secondStake, "Wrong token balance of staker1 secondStake");
+
+ bool stakeIncrease = secondStake > firstStake;
+ // If stake decrease new allowance won't be spent, if it increases it will only spent (secondStake - firstStake) difference.
+ uint256 newAllowance = stakeIncrease ? firstStake : secondStake;
+ assertEq(pinakion.allowance(staker1, address(core)), newAllowance, "Incorrect allowance secondStake");
+ }
+
+ function testFuzz_setStake_differentCourts(uint256 firstStake, uint256 secondStake) public {
+ uint256 stakerSupply = totalSupply / 10;
+
+ vm.prank(owner);
+ uint256[] memory supportedDK = new uint256[](1);
+ supportedDK[0] = DISPUTE_KIT_CLASSIC;
+ core.createCourt(
+ GENERAL_COURT,
+ hiddenVotes,
+ minStake,
+ alpha,
+ feeForJuror,
+ jurorsForCourtJump,
+ timesPerPeriod, // Times per period
+ sortitionExtraData, // Sortition extra data
+ supportedDK
+ );
+
+ uint96 newCourtID = 2;
+
+ vm.prank(owner);
+ pinakion.transfer(staker1, stakerSupply - 1 ether); // 1 eth was transferred in the initial setup so offset that value.
+ vm.assume(firstStake >= minStake && firstStake <= stakerSupply / 2); // Split the supply into two because courts are different now
+ vm.assume(secondStake >= minStake && secondStake <= stakerSupply / 2);
+
+ vm.prank(staker1);
+ pinakion.approve(address(core), firstStake);
+
+ vm.prank(staker1);
+ vm.expectEmit(true, true, true, true);
+ emit SortitionModule.StakeSet(staker1, GENERAL_COURT, firstStake, firstStake);
+ core.setStake(GENERAL_COURT, firstStake);
+
+ (uint256 totalStaked, uint256 totalLocked, uint256 stakedInCourt, uint256 nbCourts) = sortitionModule
+ .getJurorBalance(staker1, GENERAL_COURT);
+ assertEq(totalStaked, firstStake, "Wrong amount total staked");
+ assertEq(totalLocked, 0, "Wrong amount locked");
+ assertEq(stakedInCourt, firstStake, "Wrong amount staked in court");
+ assertEq(nbCourts, 1, "Wrong number of courts");
+
+ uint96[] memory courts = sortitionModule.getJurorCourtIDs(staker1);
+ assertEq(courts.length, 1, "Wrong courts count");
+ assertEq(courts[0], GENERAL_COURT, "Wrong court id");
+ assertEq(sortitionModule.isJurorStaked(staker1), true, "Juror should be staked");
+
+ assertEq(pinakion.balanceOf(address(core)), firstStake, "Wrong token balance of the core");
+ assertEq(pinakion.balanceOf(staker1), stakerSupply - firstStake, "Wrong token balance of staker1");
+ assertEq(pinakion.allowance(staker1, address(core)), 0, "Allowance should be spent for staker1");
+
+ // Stake the juror in a different court.
+ vm.prank(staker1);
+ pinakion.approve(address(core), secondStake);
+
+ vm.prank(staker1);
+ vm.expectEmit(true, true, true, true);
+ emit SortitionModule.StakeSet(staker1, newCourtID, secondStake, firstStake + secondStake);
+ core.setStake(newCourtID, secondStake);
+
+ (totalStaked, totalLocked, stakedInCourt, nbCourts) = sortitionModule.getJurorBalance(staker1, newCourtID);
+ assertEq(totalStaked, secondStake + firstStake, "Wrong amount total staked secondStake");
+ assertEq(totalLocked, 0, "Wrong amount locked secondStake");
+ assertEq(stakedInCourt, secondStake, "Wrong amount staked in court secondStake");
+ assertEq(nbCourts, 2, "Number of courts should increase");
+
+ assertEq(
+ pinakion.balanceOf(address(core)),
+ secondStake + firstStake,
+ "Wrong token balance of the core secondStake"
+ );
+ assertEq(
+ pinakion.balanceOf(staker1),
+ stakerSupply - secondStake - firstStake,
+ "Wrong token balance of staker1 secondStake"
+ );
+
+ assertEq(pinakion.allowance(staker1, address(core)), 0, "Allowance should be spent for staker1 secondStake");
+ }
+
+ function testFuzz_delayedStakes(uint256 iterations) public {
+ // Test with large numbers but do not trigger possible overflow
+ vm.assume(iterations < 2 ** 128);
+
+ vm.prank(disputer);
+ arbitrable.createDispute{value: feeForJuror * DEFAULT_NB_OF_JURORS}("Action");
+ vm.warp(block.timestamp + minStakingTime);
+ sortitionModule.passPhase(); // Generating
+ vm.warp(block.timestamp + rngLookahead);
+ sortitionModule.passPhase(); // Drawing phase
+ uint256 disputeID = 0;
+ core.draw(disputeID, DEFAULT_NB_OF_JURORS);
+
+ // Create delayed stakes
+ vm.prank(staker1);
+ core.setStake(GENERAL_COURT, 1500);
+
+ vm.prank(staker1);
+ core.setStake(GENERAL_COURT, 2500);
+
+ vm.prank(staker1);
+ core.setStake(GENERAL_COURT, 3500);
+
+ // Create delayed stake for another staker
+ vm.prank(staker2);
+ core.setStake(GENERAL_COURT, 1000);
+
+ assertEq(sortitionModule.delayedStakeWriteIndex(), 4, "Wrong delayedStakeWriteIndex");
+ assertEq(sortitionModule.delayedStakeReadIndex(), 1, "Wrong delayedStakeReadIndex");
+
+ vm.warp(block.timestamp + maxDrawingTime);
+ sortitionModule.passPhase(); // Staking. Delayed stakes can be executed now
+
+ sortitionModule.executeDelayedStakes(iterations);
+
+ uint256 actualIterations = iterations > 4 ? sortitionModule.delayedStakeWriteIndex() : iterations;
+ uint256 newDelayedStakeReadIndex = 1 + actualIterations;
+
+ assertEq(sortitionModule.delayedStakeWriteIndex(), 4, "Wrong delayedStakeWriteIndex");
+ assertEq(sortitionModule.delayedStakeReadIndex(), newDelayedStakeReadIndex, "Wrong delayedStakeReadIndex");
+ }
+}
diff --git a/contracts/test/foundry/KlerosCore_TestBase.sol b/contracts/test/foundry/KlerosCore_TestBase.sol
new file mode 100644
index 000000000..991cd7469
--- /dev/null
+++ b/contracts/test/foundry/KlerosCore_TestBase.sol
@@ -0,0 +1,253 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.24;
+
+import {Test} from "forge-std/Test.sol";
+import {console} from "forge-std/console.sol"; // Import the console for logging
+import {KlerosCoreMock, KlerosCore, IERC721} from "../../src/test/KlerosCoreMock.sol";
+import {IArbitratorV2} from "../../src/arbitration/KlerosCore.sol";
+import {IDisputeKit} from "../../src/arbitration/interfaces/IDisputeKit.sol";
+import {DisputeKitClassic, DisputeKitClassicBase} from "../../src/arbitration/dispute-kits/DisputeKitClassic.sol";
+import {DisputeKitSybilResistant} from "../../src/arbitration/dispute-kits/DisputeKitSybilResistant.sol";
+import {ISortitionModule} from "../../src/arbitration/interfaces/ISortitionModule.sol";
+import {SortitionModuleMock, SortitionModule} from "../../src/test/SortitionModuleMock.sol";
+import {UUPSProxy} from "../../src/proxy/UUPSProxy.sol";
+import {BlockHashRNG} from "../../src/rng/BlockHashRNG.sol";
+import {RNGWithFallback, IRNG} from "../../src/rng/RNGWithFallback.sol";
+import {RNGMock} from "../../src/test/RNGMock.sol";
+import {PNK} from "../../src/token/PNK.sol";
+import {TestERC20} from "../../src/token/TestERC20.sol";
+import {ArbitrableExample, IArbitrableV2} from "../../src/arbitration/arbitrables/ArbitrableExample.sol";
+import {DisputeTemplateRegistry} from "../../src/arbitration/DisputeTemplateRegistry.sol";
+import "../../src/libraries/Constants.sol";
+import {IKlerosCore, KlerosCoreSnapshotProxy} from "../../src/arbitration/view/KlerosCoreSnapshotProxy.sol";
+
+/// @title KlerosCore_TestBase
+/// @dev Abstract base contract for KlerosCore tests containing shared setup and utilities
+/// forge-lint: disable-next-item(erc20-unchecked-transfer)
+abstract contract KlerosCore_TestBase is Test {
+ event Initialized(uint64 version);
+
+ // ************************************* //
+ // * Test Contracts * //
+ // ************************************* //
+
+ KlerosCoreMock core;
+ DisputeKitClassic disputeKit;
+ SortitionModuleMock sortitionModule;
+ BlockHashRNG rng;
+ PNK pinakion;
+ TestERC20 feeToken;
+ TestERC20 wNative;
+ ArbitrableExample arbitrable;
+ DisputeTemplateRegistry registry;
+
+ // ************************************* //
+ // * Test Accounts * //
+ // ************************************* //
+
+ address owner;
+ address guardian;
+ address staker1;
+ address staker2;
+ address disputer;
+ address crowdfunder1;
+ address crowdfunder2;
+ address other;
+ address jurorProsecutionModule;
+
+ // ************************************* //
+ // * Test Parameters * //
+ // ************************************* //
+
+ uint256 minStake;
+ uint256 alpha;
+ uint256 feeForJuror;
+ uint256 jurorsForCourtJump;
+ bytes sortitionExtraData;
+ bytes arbitratorExtraData;
+ uint256[4] timesPerPeriod;
+ bool hiddenVotes;
+ uint256 totalSupply = 1000000 ether;
+ uint256 minStakingTime;
+ uint256 maxDrawingTime;
+ uint256 rngLookahead; // Time in seconds
+ string templateData;
+ string templateDataMappings;
+
+ function setUp() public virtual {
+ KlerosCoreMock coreLogic = new KlerosCoreMock();
+ SortitionModuleMock smLogic = new SortitionModuleMock();
+ DisputeKitClassic dkLogic = new DisputeKitClassic();
+ DisputeTemplateRegistry registryLogic = new DisputeTemplateRegistry();
+ pinakion = new PNK();
+ feeToken = new TestERC20("Test", "TST");
+ wNative = new TestERC20("wrapped ETH", "wETH");
+
+ owner = msg.sender;
+ guardian = vm.addr(1);
+ staker1 = vm.addr(2);
+ staker2 = vm.addr(3);
+ disputer = vm.addr(4);
+ crowdfunder1 = vm.addr(5);
+ crowdfunder2 = vm.addr(6);
+ vm.deal(disputer, 10 ether);
+ vm.deal(crowdfunder1, 10 ether);
+ vm.deal(crowdfunder2, 10 ether);
+ jurorProsecutionModule = vm.addr(8);
+ other = vm.addr(9);
+ minStake = 1000;
+ alpha = 10000;
+ feeForJuror = 0.03 ether;
+ jurorsForCourtJump = 511;
+ timesPerPeriod = [60, 120, 180, 240];
+
+ pinakion.transfer(msg.sender, totalSupply - 2 ether);
+ pinakion.transfer(staker1, 1 ether);
+ pinakion.transfer(staker2, 1 ether);
+
+ sortitionExtraData = abi.encode(uint256(5));
+ minStakingTime = 18;
+ maxDrawingTime = 24;
+ hiddenVotes = false;
+
+ rngLookahead = 30;
+ rng = new BlockHashRNG(msg.sender, address(sortitionModule), rngLookahead);
+
+ UUPSProxy proxyCore = new UUPSProxy(address(coreLogic), "");
+
+ bytes memory initDataDk = abi.encodeWithSignature(
+ "initialize(address,address,address,uint256)",
+ owner,
+ address(proxyCore),
+ address(wNative),
+ DISPUTE_KIT_CLASSIC
+ );
+
+ UUPSProxy proxyDk = new UUPSProxy(address(dkLogic), initDataDk);
+ disputeKit = DisputeKitClassic(address(proxyDk));
+
+ bytes memory initDataSm = abi.encodeWithSignature(
+ "initialize(address,address,uint256,uint256,address,uint256,uint256)",
+ owner,
+ address(proxyCore),
+ minStakingTime,
+ maxDrawingTime,
+ rng,
+ type(uint256).max,
+ type(uint256).max
+ );
+
+ UUPSProxy proxySm = new UUPSProxy(address(smLogic), initDataSm);
+ sortitionModule = SortitionModuleMock(address(proxySm));
+ vm.prank(owner);
+ rng.changeConsumer(address(sortitionModule));
+
+ core = KlerosCoreMock(address(proxyCore));
+ core.initialize(
+ owner,
+ guardian,
+ pinakion,
+ jurorProsecutionModule,
+ disputeKit,
+ hiddenVotes,
+ [minStake, alpha, feeForJuror, jurorsForCourtJump],
+ timesPerPeriod,
+ sortitionExtraData,
+ sortitionModule,
+ address(wNative),
+ IERC721(address(0))
+ );
+ vm.prank(staker1);
+ pinakion.approve(address(core), 1 ether);
+ vm.prank(staker2);
+ pinakion.approve(address(core), 1 ether);
+
+ templateData = "AAA";
+ templateDataMappings = "BBB";
+ arbitratorExtraData = abi.encodePacked(uint256(GENERAL_COURT), DEFAULT_NB_OF_JURORS, DISPUTE_KIT_CLASSIC);
+
+ bytes memory initDataRegistry = abi.encodeWithSignature("initialize(address)", owner);
+ UUPSProxy proxyRegistry = new UUPSProxy(address(registryLogic), initDataRegistry);
+ registry = DisputeTemplateRegistry(address(proxyRegistry));
+
+ arbitrable = new ArbitrableExample(
+ core,
+ templateData,
+ templateDataMappings,
+ arbitratorExtraData,
+ registry,
+ feeToken
+ );
+ }
+
+ // ************************************* //
+ // * Helper Functions * //
+ // ************************************* //
+
+ /// @dev Helper function to create a new dispute kit
+ function _createNewDisputeKit() internal returns (DisputeKitSybilResistant) {
+ return new DisputeKitSybilResistant();
+ }
+
+ /// @dev Helper function to create a new court with standard parameters
+ function _createStandardCourt(
+ uint96 parent,
+ uint256 minStakeValue,
+ uint256 alphaValue,
+ uint256 feeForJurorValue,
+ uint256 jurorsForJumpValue
+ ) internal returns (uint96) {
+ uint256[] memory supportedDK = new uint256[](1);
+ supportedDK[0] = DISPUTE_KIT_CLASSIC;
+
+ vm.prank(owner);
+ core.createCourt(
+ parent,
+ hiddenVotes,
+ minStakeValue,
+ alphaValue,
+ feeForJurorValue,
+ jurorsForJumpValue,
+ timesPerPeriod,
+ sortitionExtraData,
+ supportedDK
+ );
+
+ return uint96(core.getCourtChildren(parent)[core.getCourtChildren(parent).length - 1]);
+ }
+
+ /// @dev Helper function to check court parameters
+ function _assertCourtParameters(
+ uint96 courtId,
+ uint96 expectedParent,
+ bool expectedHiddenVotes,
+ uint256 expectedMinStake,
+ uint256 expectedAlpha,
+ uint256 expectedFeeForJuror,
+ uint256 expectedJurorsForJump
+ ) internal view {
+ (
+ uint96 courtParent,
+ bool courtHiddenVotes,
+ uint256 courtMinStake,
+ uint256 courtAlpha,
+ uint256 courtFeeForJuror,
+ uint256 courtJurorsForCourtJump
+ ) = core.courts(courtId);
+
+ assertEq(courtParent, expectedParent, "Wrong court parent");
+ assertEq(courtHiddenVotes, expectedHiddenVotes, "Wrong hiddenVotes value");
+ assertEq(courtMinStake, expectedMinStake, "Wrong minStake value");
+ assertEq(courtAlpha, expectedAlpha, "Wrong alpha value");
+ assertEq(courtFeeForJuror, expectedFeeForJuror, "Wrong feeForJuror value");
+ assertEq(courtJurorsForCourtJump, expectedJurorsForJump, "Wrong jurorsForCourtJump value");
+ }
+
+ /// @dev Helper function to check times per period
+ function _assertTimesPerPeriod(uint96 courtId, uint256[4] memory expectedTimes) internal view {
+ uint256[4] memory courtTimesPerPeriod = core.getTimesPerPeriod(courtId);
+ for (uint256 i = 0; i < 4; i++) {
+ assertEq(courtTimesPerPeriod[i], expectedTimes[i], "Wrong times per period");
+ }
+ }
+}
diff --git a/contracts/test/foundry/KlerosCore_Voting.t.sol b/contracts/test/foundry/KlerosCore_Voting.t.sol
new file mode 100644
index 000000000..5a7b4c091
--- /dev/null
+++ b/contracts/test/foundry/KlerosCore_Voting.t.sol
@@ -0,0 +1,553 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.24;
+
+import {KlerosCore_TestBase} from "./KlerosCore_TestBase.sol";
+import {KlerosCore, IArbitratorV2, IArbitrableV2} from "../../src/arbitration/KlerosCore.sol";
+import {DisputeKitClassic, DisputeKitClassicBase} from "../../src/arbitration/dispute-kits/DisputeKitClassic.sol";
+import {IDisputeKit} from "../../src/arbitration/interfaces/IDisputeKit.sol";
+import {UUPSProxy} from "../../src/proxy/UUPSProxy.sol";
+import "../../src/libraries/Constants.sol";
+
+/// @title KlerosCore_VotingTest
+/// @dev Tests for KlerosCore voting system (commit/reveal and direct voting)
+contract KlerosCore_VotingTest is KlerosCore_TestBase {
+ function test_castCommit() public {
+ // Change hidden votes in general court
+ uint256 disputeID = 0;
+ vm.prank(owner);
+ core.changeCourtParameters(
+ GENERAL_COURT,
+ true, // Hidden votes
+ 1000, // min stake
+ 10000, // alpha
+ 0.03 ether, // fee for juror
+ 511, // jurors for jump
+ [uint256(60), uint256(120), uint256(180), uint256(240)] // Times per period
+ );
+
+ vm.prank(staker1);
+ core.setStake(GENERAL_COURT, 10000);
+ vm.prank(disputer);
+ arbitrable.createDispute{value: feeForJuror * DEFAULT_NB_OF_JURORS}("Action");
+ vm.warp(block.timestamp + minStakingTime);
+ sortitionModule.passPhase(); // Generating
+ vm.warp(block.timestamp + rngLookahead);
+ sortitionModule.passPhase(); // Drawing phase
+ core.draw(disputeID, DEFAULT_NB_OF_JURORS);
+
+ uint256 NO = 0;
+ uint256 YES = 1;
+ uint256 salt = 123455678;
+ uint256[] memory voteIDs = new uint256[](1);
+ voteIDs[0] = 0;
+ bytes32 commit;
+ vm.prank(staker1);
+ vm.expectRevert(DisputeKitClassicBase.NotCommitPeriod.selector);
+ disputeKit.castCommit(disputeID, voteIDs, commit);
+
+ vm.expectRevert(KlerosCore.EvidenceNotPassedAndNotAppeal.selector);
+ core.passPeriod(disputeID);
+ vm.warp(block.timestamp + timesPerPeriod[0]);
+
+ vm.expectEmit(true, true, true, true);
+ emit KlerosCore.NewPeriod(disputeID, KlerosCore.Period.commit);
+ core.passPeriod(disputeID);
+
+ (, , KlerosCore.Period period, , uint256 lastPeriodChange) = core.disputes(disputeID);
+
+ assertEq(uint256(period), uint256(KlerosCore.Period.commit), "Wrong period");
+ assertEq(lastPeriodChange, block.timestamp, "Wrong lastPeriodChange");
+
+ vm.prank(staker1);
+ vm.expectRevert(DisputeKitClassicBase.EmptyCommit.selector);
+ disputeKit.castCommit(disputeID, voteIDs, commit);
+
+ commit = keccak256(abi.encodePacked(YES, salt));
+
+ vm.prank(other);
+ vm.expectRevert(DisputeKitClassicBase.JurorHasToOwnTheVote.selector);
+ disputeKit.castCommit(disputeID, voteIDs, commit);
+
+ vm.prank(staker1);
+ vm.expectEmit(true, true, true, true);
+ emit DisputeKitClassicBase.CommitCast(disputeID, staker1, voteIDs, commit);
+ disputeKit.castCommit(disputeID, voteIDs, commit);
+
+ (, , , uint256 totalCommited, uint256 nbVoters, uint256 choiceCount) = disputeKit.getRoundInfo(disputeID, 0, 0);
+ assertEq(totalCommited, 1, "totalCommited should be 1");
+ assertEq(disputeKit.areCommitsAllCast(disputeID), false, "Commits should not all be cast");
+
+ (, bytes32 commitStored, , ) = disputeKit.getVoteInfo(0, 0, 0);
+ assertEq(commitStored, keccak256(abi.encodePacked(YES, salt)), "Incorrect commit");
+
+ // Cast again with the same voteID to check that the count doesn't increase.
+ bytes32 newCommit = keccak256(abi.encodePacked(NO, salt));
+ vm.prank(staker1);
+ disputeKit.castCommit(disputeID, voteIDs, newCommit);
+
+ (, , , totalCommited, , ) = disputeKit.getRoundInfo(disputeID, 0, 0);
+ assertEq(totalCommited, 1, "totalCommited should still be 1");
+ (, commitStored, , ) = disputeKit.getVoteInfo(0, 0, 0);
+ assertEq(commitStored, keccak256(abi.encodePacked(NO, salt)), "Incorrect commit after recommitting");
+
+ voteIDs = new uint256[](2); // Create the leftover votes subset
+ voteIDs[0] = 1;
+ voteIDs[1] = 2;
+
+ vm.prank(staker1);
+ vm.expectEmit(true, true, true, true);
+ emit DisputeKitClassicBase.CommitCast(disputeID, staker1, voteIDs, commit);
+ disputeKit.castCommit(disputeID, voteIDs, commit);
+
+ (, , , totalCommited, nbVoters, choiceCount) = disputeKit.getRoundInfo(disputeID, 0, 0);
+ assertEq(totalCommited, DEFAULT_NB_OF_JURORS, "totalCommited should be 3");
+ assertEq(disputeKit.areCommitsAllCast(disputeID), true, "Commits should all be cast");
+
+ for (uint256 i = 1; i < DEFAULT_NB_OF_JURORS; i++) {
+ (, commitStored, , ) = disputeKit.getVoteInfo(0, 0, i);
+ assertEq(commitStored, keccak256(abi.encodePacked(YES, salt)), "Incorrect commit");
+ }
+
+ // Check reveal in the next period
+ vm.warp(block.timestamp + timesPerPeriod[1]);
+ core.passPeriod(disputeID);
+
+ // Check the require with the wrong choice and then with the wrong salt
+ vm.prank(staker1);
+ vm.expectRevert(DisputeKitClassicBase.ChoiceCommitmentMismatch.selector);
+ disputeKit.castVote(disputeID, voteIDs, 2, salt, "XYZ");
+
+ vm.prank(staker1);
+ vm.expectRevert(DisputeKitClassicBase.ChoiceCommitmentMismatch.selector);
+ disputeKit.castVote(disputeID, voteIDs, YES, salt - 1, "XYZ");
+
+ vm.prank(staker1);
+ disputeKit.castVote(disputeID, voteIDs, YES, salt, "XYZ");
+
+ for (uint256 i = 1; i < DEFAULT_NB_OF_JURORS; i++) {
+ // 0 voteID was skipped when casting a vote
+ (address account, , uint256 choice, bool voted) = disputeKit.getVoteInfo(0, 0, i);
+ assertEq(account, staker1, "Wrong drawn account");
+ assertEq(choice, YES, "Wrong choice");
+ assertEq(voted, true, "Voted should be true");
+ }
+ }
+
+ function test_castCommit_timeoutCheck() public {
+ // Change hidden votes in general court
+ uint256 disputeID = 0;
+ vm.prank(owner);
+ core.changeCourtParameters(
+ GENERAL_COURT,
+ true, // Hidden votes
+ 1000, // min stake
+ 10000, // alpha
+ 0.03 ether, // fee for juror
+ 511, // jurors for jump
+ [uint256(60), uint256(120), uint256(180), uint256(240)] // Times per period
+ );
+
+ vm.prank(staker1);
+ core.setStake(GENERAL_COURT, 10000);
+ vm.prank(disputer);
+ arbitrable.createDispute{value: feeForJuror * DEFAULT_NB_OF_JURORS}("Action");
+ vm.warp(block.timestamp + minStakingTime);
+ sortitionModule.passPhase(); // Generating
+ vm.warp(block.timestamp + rngLookahead);
+ sortitionModule.passPhase(); // Drawing phase
+ core.draw(disputeID, DEFAULT_NB_OF_JURORS);
+
+ vm.warp(block.timestamp + timesPerPeriod[0]);
+ core.passPeriod(disputeID); // Commit
+
+ vm.expectRevert(KlerosCore.CommitPeriodNotPassed.selector);
+ core.passPeriod(disputeID);
+
+ vm.warp(block.timestamp + timesPerPeriod[1]);
+ vm.expectEmit(true, true, true, true);
+ emit KlerosCore.NewPeriod(disputeID, KlerosCore.Period.vote);
+ core.passPeriod(disputeID);
+ }
+
+ function test_castVote() public {
+ uint256 disputeID = 0;
+
+ vm.prank(staker1);
+ core.setStake(GENERAL_COURT, 10000);
+ vm.prank(disputer);
+ arbitrable.createDispute{value: feeForJuror * DEFAULT_NB_OF_JURORS}("Action");
+ vm.warp(block.timestamp + minStakingTime);
+ sortitionModule.passPhase(); // Generating
+ vm.warp(block.timestamp + rngLookahead);
+ sortitionModule.passPhase(); // Drawing phase
+
+ core.draw(disputeID, DEFAULT_NB_OF_JURORS - 1); // Draw less to check the require later
+ vm.warp(block.timestamp + timesPerPeriod[0]);
+
+ uint256[] memory voteIDs = new uint256[](0);
+ vm.prank(staker1);
+ vm.expectRevert(DisputeKitClassicBase.NotVotePeriod.selector);
+ disputeKit.castVote(disputeID, voteIDs, 2, 0, "XYZ"); // Leave salt empty as not needed
+
+ vm.expectRevert(KlerosCore.DisputeStillDrawing.selector);
+ core.passPeriod(disputeID);
+
+ core.draw(disputeID, 1); // Draw the last juror
+
+ vm.expectEmit(true, true, true, true);
+ emit KlerosCore.NewPeriod(disputeID, KlerosCore.Period.vote);
+ core.passPeriod(disputeID); // Vote
+
+ (, , KlerosCore.Period period, , uint256 lastPeriodChange) = core.disputes(disputeID);
+
+ assertEq(uint256(period), uint256(KlerosCore.Period.vote), "Wrong period");
+ assertEq(lastPeriodChange, block.timestamp, "Wrong lastPeriodChange");
+
+ vm.prank(staker1);
+ vm.expectRevert(DisputeKitClassicBase.EmptyVoteIDs.selector);
+ disputeKit.castVote(disputeID, voteIDs, 2, 0, "XYZ");
+
+ voteIDs = new uint256[](1);
+ voteIDs[0] = 0; // Split vote IDs to see how the winner changes
+ vm.prank(staker1);
+ vm.expectRevert(DisputeKitClassicBase.ChoiceOutOfBounds.selector);
+ disputeKit.castVote(disputeID, voteIDs, 2 + 1, 0, "XYZ");
+
+ vm.prank(other);
+ vm.expectRevert(DisputeKitClassicBase.JurorHasToOwnTheVote.selector);
+ disputeKit.castVote(disputeID, voteIDs, 2, 0, "XYZ");
+
+ vm.prank(staker1);
+ vm.expectEmit(true, true, true, true);
+ emit IDisputeKit.VoteCast(disputeID, staker1, voteIDs, 2, "XYZ");
+ disputeKit.castVote(disputeID, voteIDs, 2, 0, "XYZ");
+
+ vm.prank(staker1);
+ vm.expectRevert(DisputeKitClassicBase.VoteAlreadyCast.selector);
+ disputeKit.castVote(disputeID, voteIDs, 2, 0, "XYZ");
+
+ (
+ uint256 winningChoice,
+ bool tied,
+ uint256 totalVoted,
+ uint256 totalCommited,
+ ,
+ uint256 choiceCount
+ ) = disputeKit.getRoundInfo(disputeID, 0, 2);
+ assertEq(winningChoice, 2, "Wrong winning choice");
+ assertEq(tied, false, "tied should be false");
+ assertEq(totalVoted, 1, "totalVoted should be 1");
+ assertEq(totalCommited, 0, "totalCommited should be 0");
+ assertEq(choiceCount, 1, "choiceCount should be 1");
+
+ (address account, bytes32 commit, uint256 choice, bool voted) = disputeKit.getVoteInfo(0, 0, 0); // Dispute - Round - VoteID
+ assertEq(account, staker1, "Wrong drawn account");
+ assertEq(commit, bytes32(0), "Commit should be empty");
+ assertEq(choice, 2, "Choice should be 2");
+ assertEq(voted, true, "Voted should be true");
+
+ assertEq(disputeKit.isVoteActive(0, 0, 0), true, "Vote should be active"); // Dispute - Round - VoteID
+
+ voteIDs = new uint256[](1);
+ voteIDs[0] = 1; // Cast another vote to check the tie.
+
+ vm.prank(staker1);
+ vm.expectEmit(true, true, true, true);
+ emit IDisputeKit.VoteCast(disputeID, staker1, voteIDs, 1, "XYZZ");
+ disputeKit.castVote(disputeID, voteIDs, 1, 0, "XYZZ");
+
+ (, tied, totalVoted, , , choiceCount) = disputeKit.getRoundInfo(disputeID, 0, 1);
+ assertEq(tied, true, "tied should be true");
+ assertEq(totalVoted, 2, "totalVoted should be 2");
+ assertEq(choiceCount, 1, "choiceCount should be 1 for first choice");
+
+ vm.expectRevert(KlerosCore.VotePeriodNotPassed.selector);
+ core.passPeriod(disputeID);
+
+ voteIDs = new uint256[](1);
+ voteIDs[0] = 2; // Cast another vote to declare a new winner.
+
+ vm.prank(staker1);
+ vm.expectEmit(true, true, true, true);
+ emit IDisputeKit.VoteCast(disputeID, staker1, voteIDs, 1, "XYZZ");
+ disputeKit.castVote(disputeID, voteIDs, 1, 0, "XYZZ");
+
+ (winningChoice, tied, totalVoted, , , choiceCount) = disputeKit.getRoundInfo(disputeID, 0, 1);
+ assertEq(winningChoice, 1, "Wrong winning choice");
+ assertEq(tied, false, "tied should be false");
+ assertEq(totalVoted, 3, "totalVoted should be 3");
+ assertEq(choiceCount, 2, "choiceCount should be 2 for first choice");
+ assertEq(disputeKit.areVotesAllCast(disputeID), true, "Votes should all be cast");
+ }
+
+ function test_castVote_timeoutCheck() public {
+ // Change hidden votes in general court
+ uint256 disputeID = 0;
+ vm.prank(staker1);
+ core.setStake(GENERAL_COURT, 10000);
+ vm.prank(disputer);
+ arbitrable.createDispute{value: feeForJuror * DEFAULT_NB_OF_JURORS}("Action");
+ vm.warp(block.timestamp + minStakingTime);
+ sortitionModule.passPhase(); // Generating
+ vm.warp(block.timestamp + rngLookahead);
+ sortitionModule.passPhase(); // Drawing phase
+ core.draw(disputeID, DEFAULT_NB_OF_JURORS);
+
+ vm.warp(block.timestamp + timesPerPeriod[0]);
+ core.passPeriod(disputeID); // Votes
+
+ vm.expectRevert(KlerosCore.VotePeriodNotPassed.selector);
+ core.passPeriod(disputeID);
+
+ vm.warp(block.timestamp + timesPerPeriod[2]);
+ vm.expectEmit(true, true, true, true);
+ emit KlerosCore.AppealPossible(disputeID, arbitrable);
+ vm.expectEmit(true, true, true, true);
+ emit KlerosCore.NewPeriod(disputeID, KlerosCore.Period.appeal);
+ core.passPeriod(disputeID);
+ }
+
+ function test_castVote_rulingCheck() public {
+ // Change hidden votes in general court
+ uint256 disputeID = 0;
+ vm.prank(staker1);
+ core.setStake(GENERAL_COURT, 10000);
+ vm.prank(disputer);
+ arbitrable.createDispute{value: feeForJuror * DEFAULT_NB_OF_JURORS}("Action");
+ vm.warp(block.timestamp + minStakingTime);
+ sortitionModule.passPhase(); // Generating
+ vm.warp(block.timestamp + rngLookahead);
+ sortitionModule.passPhase(); // Drawing phase
+ core.draw(disputeID, DEFAULT_NB_OF_JURORS);
+
+ vm.warp(block.timestamp + timesPerPeriod[0]);
+ core.passPeriod(disputeID); // Votes
+
+ uint256[] memory voteIDs = new uint256[](3);
+ voteIDs[0] = 0;
+ voteIDs[1] = 1;
+ voteIDs[2] = 2;
+
+ vm.prank(staker1);
+ disputeKit.castVote(disputeID, voteIDs, 1, 0, "XYZZ");
+
+ (uint256 ruling, bool tied, bool overridden) = disputeKit.currentRuling(disputeID);
+ assertEq(ruling, 1, "Wrong ruling");
+ assertEq(tied, false, "Not tied");
+ assertEq(overridden, false, "Not overridden");
+ }
+
+ function test_castVote_quickPassPeriod() public {
+ // Change hidden votes in general court
+ uint256 disputeID = 0;
+ vm.prank(owner);
+ core.changeCourtParameters(
+ GENERAL_COURT,
+ true, // Hidden votes
+ 1000, // min stake
+ 10000, // alpha
+ 0.03 ether, // fee for juror
+ 511, // jurors for jump
+ [uint256(60), uint256(120), uint256(180), uint256(240)] // Times per period
+ );
+
+ vm.prank(staker1);
+ core.setStake(GENERAL_COURT, 10000);
+ vm.prank(disputer);
+ arbitrable.createDispute{value: feeForJuror * DEFAULT_NB_OF_JURORS}("Action");
+ vm.warp(block.timestamp + minStakingTime);
+ sortitionModule.passPhase(); // Generating
+ vm.warp(block.timestamp + rngLookahead);
+ sortitionModule.passPhase(); // Drawing phase
+ core.draw(disputeID, DEFAULT_NB_OF_JURORS);
+
+ uint256 YES = 1;
+ uint256 salt = 123455678;
+ uint256[] memory voteIDs = new uint256[](1);
+ voteIDs[0] = 0;
+ bytes32 commit;
+
+ vm.warp(block.timestamp + timesPerPeriod[0]);
+ core.passPeriod(disputeID);
+
+ commit = keccak256(abi.encodePacked(YES, salt));
+
+ vm.prank(staker1);
+ disputeKit.castCommit(disputeID, voteIDs, commit);
+
+ (, , , uint256 totalCommited, uint256 nbVoters, uint256 choiceCount) = disputeKit.getRoundInfo(disputeID, 0, 0);
+ assertEq(totalCommited, 1, "totalCommited should be 1");
+ assertEq(disputeKit.areCommitsAllCast(disputeID), false, "Commits should not all be cast");
+
+ vm.warp(block.timestamp + timesPerPeriod[1]);
+ core.passPeriod(disputeID);
+
+ vm.prank(staker1);
+ disputeKit.castVote(disputeID, voteIDs, YES, salt, "XYZ");
+
+ (, , uint256 totalVoted, , , ) = disputeKit.getRoundInfo(disputeID, 0, 0);
+ assertEq(totalVoted, 1, "totalVoted should be 1");
+ assertEq(disputeKit.areVotesAllCast(disputeID), true, "Every committed vote was cast");
+
+ // Should pass period by counting only committed votes.
+ vm.expectEmit(true, true, true, true);
+ emit KlerosCore.NewPeriod(disputeID, KlerosCore.Period.appeal);
+ core.passPeriod(disputeID);
+ }
+
+ function test_castVote_differentDK() public {
+ DisputeKitClassic dkLogic = new DisputeKitClassic();
+ // Create a new DK to check castVote.
+ bytes memory initDataDk = abi.encodeWithSignature(
+ "initialize(address,address,address,uint256)",
+ owner,
+ address(core),
+ address(wNative),
+ DISPUTE_KIT_CLASSIC
+ );
+
+ UUPSProxy proxyDk = new UUPSProxy(address(dkLogic), initDataDk);
+ DisputeKitClassic newDisputeKit = DisputeKitClassic(address(proxyDk));
+
+ vm.prank(owner);
+ core.addNewDisputeKit(newDisputeKit);
+
+ uint256 newDkID = 2;
+ uint256[] memory supportedDK = new uint256[](1);
+ bytes memory newExtraData = abi.encodePacked(uint256(GENERAL_COURT), DEFAULT_NB_OF_JURORS, newDkID);
+
+ vm.prank(owner);
+ vm.expectEmit(true, true, true, true);
+ emit KlerosCore.DisputeKitEnabled(GENERAL_COURT, newDkID, true);
+ supportedDK[0] = newDkID;
+ core.enableDisputeKits(GENERAL_COURT, supportedDK, true);
+ assertEq(core.isSupported(GENERAL_COURT, newDkID), true, "New DK should be supported by General court");
+
+ vm.prank(staker1);
+ core.setStake(GENERAL_COURT, 20000);
+
+ // Create one dispute for the old DK and two disputes for the new DK.
+ vm.prank(disputer);
+ arbitrable.createDispute{value: feeForJuror * DEFAULT_NB_OF_JURORS}("Action");
+
+ arbitrable.changeArbitratorExtraData(newExtraData);
+
+ vm.prank(disputer);
+ arbitrable.createDispute{value: feeForJuror * DEFAULT_NB_OF_JURORS}("Action");
+
+ vm.prank(disputer);
+ arbitrable.createDispute{value: feeForJuror * DEFAULT_NB_OF_JURORS}("Action");
+
+ uint256 disputeID = 2; // Use the latest dispute for reference. This is the ID in the core contract
+
+ vm.warp(block.timestamp + minStakingTime);
+ sortitionModule.passPhase(); // Generating
+ vm.warp(block.timestamp + rngLookahead);
+ sortitionModule.passPhase(); // Drawing phase
+
+ KlerosCore.Round memory round = core.getRoundInfo(disputeID, 0);
+ assertEq(round.disputeKitID, newDkID, "Wrong DK ID");
+
+ core.draw(disputeID, DEFAULT_NB_OF_JURORS);
+ // Draw jurors for the old DK as well to prepare round.votes array
+ core.draw(0, DEFAULT_NB_OF_JURORS);
+
+ vm.warp(block.timestamp + timesPerPeriod[0]);
+ core.passPeriod(disputeID); // Vote
+
+ // Check that the new DK has the info but not the old one.
+ (bool disputeActive, ) = disputeKit.coreDisputeIDToActive(disputeID);
+ assertEq(disputeActive, false, "Should be false for old DK");
+
+ // This is the DK where dispute was created. Core dispute points to index 1 because new DK has two disputes.
+ (disputeActive, ) = newDisputeKit.coreDisputeIDToActive(disputeID);
+ assertEq(disputeActive, true, "Should be active for new DK");
+ assertEq(newDisputeKit.coreDisputeIDToLocal(disputeID), 1, "Wrong local dispute ID for new DK");
+ (uint256 numberOfChoices, bytes memory extraData) = newDisputeKit.disputes(1);
+ assertEq(numberOfChoices, 2, "Wrong numberOfChoices in new DK");
+ assertEq(extraData, newExtraData, "Wrong extra data");
+
+ uint256[] memory voteIDs = new uint256[](3);
+ voteIDs[0] = 0;
+ voteIDs[1] = 1;
+ voteIDs[2] = 2;
+
+ // Deliberately cast votes using the old DK to see if the exception will be caught.
+ vm.prank(staker1);
+ vm.expectRevert(DisputeKitClassicBase.DisputeUnknownInThisDisputeKit.selector);
+ disputeKit.castVote(disputeID, voteIDs, 2, 0, "XYZ");
+
+ // And check the new DK.
+ vm.prank(staker1);
+ newDisputeKit.castVote(disputeID, voteIDs, 2, 0, "XYZ");
+
+ (
+ uint256 winningChoice,
+ bool tied,
+ uint256 totalVoted,
+ uint256 totalCommited,
+ ,
+ uint256 choiceCount
+ ) = newDisputeKit.getRoundInfo(disputeID, 0, 2);
+ assertEq(winningChoice, 2, "Wrong winning choice");
+ assertEq(tied, false, "tied should be false");
+ assertEq(totalVoted, 3, "totalVoted should be 3");
+ assertEq(totalCommited, 0, "totalCommited should be 0");
+ assertEq(choiceCount, 3, "choiceCount should be 3");
+ }
+
+ function testFuzz_castVote(uint256 numberOfOptions, uint256 choice1, uint256 choice2) public {
+ uint256 disputeID = 0;
+
+ arbitrable.changeNumberOfRulingOptions(numberOfOptions);
+
+ // Have only 2 options for 3 jurors to create a majority
+ vm.assume(choice1 <= numberOfOptions);
+ vm.assume(choice2 <= numberOfOptions);
+
+ vm.prank(staker1);
+ core.setStake(GENERAL_COURT, 2000);
+ vm.prank(disputer);
+ arbitrable.createDispute{value: feeForJuror * DEFAULT_NB_OF_JURORS}("Action");
+ vm.warp(block.timestamp + minStakingTime);
+ sortitionModule.passPhase(); // Generating
+ vm.warp(block.timestamp + rngLookahead);
+ sortitionModule.passPhase(); // Drawing phase
+
+ // Split the stakers' votes. The first staker will get VoteID 0 and the second will take the rest.
+ core.draw(disputeID, 1);
+
+ vm.warp(block.timestamp + maxDrawingTime);
+ sortitionModule.passPhase(); // Staking phase to stake the 2nd voter
+ vm.prank(staker2);
+ core.setStake(GENERAL_COURT, 20000);
+ vm.warp(block.timestamp + minStakingTime);
+ sortitionModule.passPhase(); // Generating
+ vm.warp(block.timestamp + rngLookahead);
+ sortitionModule.passPhase(); // Drawing phase
+
+ core.draw(disputeID, 2); // Assign leftover votes to staker2
+
+ vm.warp(block.timestamp + timesPerPeriod[0]);
+ core.passPeriod(disputeID); // Vote
+
+ uint256[] memory voteIDs = new uint256[](1);
+ voteIDs[0] = 0;
+ vm.prank(staker1);
+ disputeKit.castVote(disputeID, voteIDs, choice1, 0, "XYZ"); // Staker1 only got 1 vote because of low stake
+
+ voteIDs = new uint256[](2);
+ voteIDs[0] = 1;
+ voteIDs[1] = 2;
+ vm.prank(staker2);
+ disputeKit.castVote(disputeID, voteIDs, choice2, 0, "XYZ");
+ core.passPeriod(disputeID); // Appeal
+
+ vm.warp(block.timestamp + timesPerPeriod[3]);
+ core.passPeriod(disputeID); // Execution
+
+ vm.expectEmit(true, true, true, true);
+ emit IArbitrableV2.Ruling(IArbitratorV2(address(core)), disputeID, choice2);
+ core.executeRuling(disputeID);
+ }
+}
diff --git a/contracts/test/integration/getContractsEthers.test.ts b/contracts/test/integration/getContractsEthers.test.ts
index 736717626..40ff2b8f4 100644
--- a/contracts/test/integration/getContractsEthers.test.ts
+++ b/contracts/test/integration/getContractsEthers.test.ts
@@ -4,10 +4,8 @@ import { arbitrum, arbitrumSepolia } from "viem/chains";
import { getContracts } from "../../deployments/contractsEthers";
import {
KlerosCore__factory,
- KlerosCoreNeo__factory,
KlerosCoreUniversity__factory,
SortitionModule__factory,
- SortitionModuleNeo__factory,
SortitionModuleUniversity__factory,
DisputeKitClassic__factory,
DisputeResolver__factory,
@@ -88,7 +86,7 @@ const universityContractMapping: ContractMapping = {
disputeKitGated: { name: "DisputeKitGatedUniversity", optional: true },
disputeKitGatedShutter: { name: "DisputeKitGatedShutterUniversity", optional: true },
disputeResolver: { name: "DisputeResolverUniversity" },
- disputeTemplateRegistry: { name: "DisputeTemplateRegistry" },
+ disputeTemplateRegistry: { name: "DisputeTemplateRegistryUniversity" },
evidence: { name: "EvidenceModule" },
policyRegistry: { name: "PolicyRegistry" },
transactionBatcher: { name: "TransactionBatcher" },
@@ -99,14 +97,14 @@ const universityContractMapping: ContractMapping = {
klerosCoreSnapshotProxy: { name: "KlerosCoreSnapshotProxy" },
};
-const neoContractMapping: ContractMapping = {
- klerosCore: { name: "KlerosCoreNeo" },
- sortition: { name: "SortitionModuleNeo" },
- disputeKitClassic: { name: "DisputeKitClassicNeo" },
- disputeKitShutter: { name: "DisputeKitShutterNeo" },
- disputeKitGated: { name: "DisputeKitGatedNeo" },
- disputeKitGatedShutter: { name: "DisputeKitGatedShutterNeo" },
- disputeResolver: { name: "DisputeResolverNeo" },
+const mainnetContractMapping: ContractMapping = {
+ klerosCore: { name: "KlerosCore" },
+ sortition: { name: "SortitionModule" },
+ disputeKitClassic: { name: "DisputeKitClassic" },
+ disputeKitShutter: { name: "DisputeKitShutter" },
+ disputeKitGated: { name: "DisputeKitGated" },
+ disputeKitGatedShutter: { name: "DisputeKitGatedShutter" },
+ disputeResolver: { name: "DisputeResolver" },
disputeTemplateRegistry: { name: "DisputeTemplateRegistry" },
evidence: { name: "EvidenceModule" },
policyRegistry: { name: "PolicyRegistry" },
@@ -291,16 +289,16 @@ describe("getContractsEthers", async () => {
await verifyDeployedAddresses(contracts, NETWORKS.TESTNET, testnetContractMapping);
});
- it("should return correct contract instances for mainnetNeo", async () => {
- const contracts = await getContracts(arbitrumProvider, "mainnetNeo");
+ it("should return correct contract instances for mainnet", async () => {
+ const contracts = await getContracts(arbitrumProvider, "mainnet");
// Verify chain ID
const network = await arbitrumProvider.getNetwork();
expect(network.chainId).to.equal(arbitrum.id);
// Verify contract instances
- expect(contracts.klerosCore).to.be.instanceOf(getConstructor(KlerosCoreNeo__factory, arbitrumProvider));
- expect(contracts.sortition).to.be.instanceOf(getConstructor(SortitionModuleNeo__factory, arbitrumProvider));
+ expect(contracts.klerosCore).to.be.instanceOf(getConstructor(KlerosCore__factory, arbitrumProvider));
+ expect(contracts.sortition).to.be.instanceOf(getConstructor(SortitionModule__factory, arbitrumProvider));
verifyCommonContractInstances(contracts, arbitrumProvider);
expect(contracts.disputeKitShutter).to.not.be.null;
expect(contracts.disputeKitGated).to.not.be.null;
@@ -310,7 +308,7 @@ describe("getContractsEthers", async () => {
// Verify all contract addresses
await verifyAllContractAddresses(contracts);
- await verifyDeployedAddresses(contracts, NETWORKS.MAINNET, neoContractMapping);
+ await verifyDeployedAddresses(contracts, NETWORKS.MAINNET, mainnetContractMapping);
});
it("should throw error for unsupported deployment", async () => {
diff --git a/contracts/test/integration/getContractsViem.test.ts b/contracts/test/integration/getContractsViem.test.ts
index a32db3c86..b9813a404 100644
--- a/contracts/test/integration/getContractsViem.test.ts
+++ b/contracts/test/integration/getContractsViem.test.ts
@@ -66,7 +66,7 @@ const universityContractMapping: ContractMapping = {
disputeKitGated: { name: "DisputeKitGatedUniversity", optional: true },
disputeKitGatedShutter: { name: "DisputeKitGatedShutterUniversity", optional: true },
disputeResolver: { name: "DisputeResolverUniversity" },
- disputeTemplateRegistry: { name: "DisputeTemplateRegistry" },
+ disputeTemplateRegistry: { name: "DisputeTemplateRegistryUniversity" },
evidence: { name: "EvidenceModule" },
policyRegistry: { name: "PolicyRegistry" },
transactionBatcher: { name: "TransactionBatcher" },
@@ -77,14 +77,14 @@ const universityContractMapping: ContractMapping = {
klerosCoreSnapshotProxy: { name: "KlerosCoreSnapshotProxy" },
};
-const neoContractMapping: ContractMapping = {
- klerosCore: { name: "KlerosCoreNeo" },
- sortition: { name: "SortitionModuleNeo" },
- disputeKitClassic: { name: "DisputeKitClassicNeo" },
- disputeKitShutter: { name: "DisputeKitShutterNeo" },
- disputeKitGated: { name: "DisputeKitGatedNeo" },
- disputeKitGatedShutter: { name: "DisputeKitGatedShutterNeo" },
- disputeResolver: { name: "DisputeResolverNeo" },
+const mainnetContractMapping: ContractMapping = {
+ klerosCore: { name: "KlerosCore" },
+ sortition: { name: "SortitionModule" },
+ disputeKitClassic: { name: "DisputeKitClassic" },
+ disputeKitShutter: { name: "DisputeKitShutter" },
+ disputeKitGated: { name: "DisputeKitGated" },
+ disputeKitGatedShutter: { name: "DisputeKitGatedShutter" },
+ disputeResolver: { name: "DisputeResolver" },
disputeTemplateRegistry: { name: "DisputeTemplateRegistry" },
evidence: { name: "EvidenceModule" },
policyRegistry: { name: "PolicyRegistry" },
@@ -240,10 +240,10 @@ describe("getContractsViem", () => {
await verifyDeployedAddresses(contracts, NETWORKS.TESTNET, testnetContractMapping);
});
- it("should return correct contract instances for mainnetNeo", async () => {
+ it("should return correct contract instances for mainnet", async () => {
const contracts = getContracts({
publicClient: arbitrumClient,
- deployment: "mainnetNeo",
+ deployment: "mainnet",
});
// Verify chain ID
@@ -262,7 +262,7 @@ describe("getContractsViem", () => {
expect(contracts.randomizerRng).to.not.be.undefined;
// Verify deployed addresses
- await verifyDeployedAddresses(contracts, NETWORKS.MAINNET, neoContractMapping);
+ await verifyDeployedAddresses(contracts, NETWORKS.MAINNET, mainnetContractMapping);
});
it("should throw error for unsupported deployment", () => {
diff --git a/contracts/test/integration/index.ts b/contracts/test/integration/index.ts
index 395b9ed8e..897dbff58 100644
--- a/contracts/test/integration/index.ts
+++ b/contracts/test/integration/index.ts
@@ -9,8 +9,6 @@ import {
HomeGateway,
VeaMock,
DisputeKitClassic,
- RandomizerRNG,
- RandomizerMock,
SortitionModule,
ChainlinkRNG,
ChainlinkVRFCoordinatorV2Mock,
@@ -58,16 +56,16 @@ describe("Integration tests", async () => {
fallbackToGlobal: true,
keepExistingDeployments: false,
});
- rng = (await ethers.getContract("ChainlinkRNG")) as ChainlinkRNG;
- vrfCoordinator = (await ethers.getContract("ChainlinkVRFCoordinator")) as ChainlinkVRFCoordinatorV2Mock;
- disputeKit = (await ethers.getContract("DisputeKitClassic")) as DisputeKitClassic;
- pnk = (await ethers.getContract("PNK")) as PNK;
- core = (await ethers.getContract("KlerosCore")) as KlerosCore;
- vea = (await ethers.getContract("VeaMock")) as VeaMock;
- foreignGateway = (await ethers.getContract("ForeignGatewayOnEthereum")) as ForeignGateway;
- arbitrable = (await ethers.getContract("ArbitrableExample")) as ArbitrableExample;
- homeGateway = (await ethers.getContract("HomeGatewayToEthereum")) as HomeGateway;
- sortitionModule = (await ethers.getContract("SortitionModule")) as SortitionModule;
+ rng = await ethers.getContract("ChainlinkRNG");
+ vrfCoordinator = await ethers.getContract("ChainlinkVRFCoordinator");
+ disputeKit = await ethers.getContract("DisputeKitClassic");
+ pnk = await ethers.getContract("PNK");
+ core = await ethers.getContract("KlerosCore");
+ vea = await ethers.getContract("VeaMock");
+ foreignGateway = await ethers.getContract("ForeignGatewayOnEthereum");
+ arbitrable = await ethers.getContract("ArbitrableExample");
+ homeGateway = await ethers.getContract("HomeGatewayToEthereum");
+ sortitionModule = await ethers.getContract("SortitionModule");
});
it("Resolves a dispute on the home chain with no appeal", async () => {
@@ -78,28 +76,28 @@ describe("Integration tests", async () => {
await core.setStake(1, ONE_THOUSAND_PNK);
await sortitionModule.getJurorBalance(deployer, 1).then((result) => {
- expect(result.totalStaked).to.equal(ONE_THOUSAND_PNK);
+ expect(result.totalStakedPnk).to.equal(ONE_THOUSAND_PNK);
expect(result.totalLocked).to.equal(0);
logJurorBalance(result);
});
await core.setStake(1, ONE_HUNDRED_PNK * 5n);
await sortitionModule.getJurorBalance(deployer, 1).then((result) => {
- expect(result.totalStaked).to.equal(ONE_HUNDRED_PNK * 5n);
+ expect(result.totalStakedPnk).to.equal(ONE_HUNDRED_PNK * 5n);
expect(result.totalLocked).to.equal(0);
logJurorBalance(result);
});
await core.setStake(1, 0);
await sortitionModule.getJurorBalance(deployer, 1).then((result) => {
- expect(result.totalStaked).to.equal(0);
+ expect(result.totalStakedPnk).to.equal(0);
expect(result.totalLocked).to.equal(0);
logJurorBalance(result);
});
await core.setStake(1, ONE_THOUSAND_PNK * 4n);
await sortitionModule.getJurorBalance(deployer, 1).then((result) => {
- expect(result.totalStaked).to.equal(ONE_THOUSAND_PNK * 4n);
+ expect(result.totalStakedPnk).to.equal(ONE_THOUSAND_PNK * 4n);
expect(result.totalLocked).to.equal(0);
logJurorBalance(result);
});
@@ -113,15 +111,7 @@ describe("Integration tests", async () => {
await expect(tx)
.to.emit(foreignGateway, "CrossChainDisputeOutgoing")
.withArgs(anyValue, arbitrable.target, 1, 2, "0x00");
- await expect(tx)
- .to.emit(arbitrable, "DisputeRequest")
- .withArgs(
- foreignGateway.target,
- 1,
- 46619385602526556702049273755915206310773794210139929511467397410441395547901n,
- 0,
- ""
- );
+ await expect(tx).to.emit(arbitrable, "DisputeRequest").withArgs(foreignGateway.target, 1, 0);
if (tx.blockNumber === null) throw new Error("tx.blockNumber is null");
const lastBlock = await ethers.provider.getBlock(tx.blockNumber - 1);
if (lastBlock === null) throw new Error("lastBlock is null");
@@ -134,24 +124,20 @@ describe("Integration tests", async () => {
throw new Error("Block hash is null - cannot calculate dispute hash");
}
// Relayer tx
- const tx2 = await homeGateway
- .connect(relayer)
- ["relayCreateDispute((bytes32,uint256,address,uint256,uint256,uint256,string,uint256,bytes))"](
+ await expect(
+ homeGateway.connect(relayer)["relayCreateDispute((bytes32,uint256,address,uint256,uint256,uint256,bytes))"](
{
foreignBlockHash: ethers.toBeHex(lastBlock.hash),
foreignChainID: 31337,
foreignArbitrable: arbitrable.target,
foreignDisputeID: disputeId,
- externalDisputeID: ethers.keccak256(ethers.toUtf8Bytes("future of france")),
templateId: 0,
- templateUri: "",
choices: 2,
extraData: "0x00",
},
{ value: arbitrationCost }
- );
- expect(tx2).to.emit(homeGateway, "DisputeRequest");
- await tx2.wait();
+ )
+ ).to.emit(homeGateway, "DisputeRequest");
await network.provider.send("evm_increaseTime", [2000]); // Wait for minStakingTime
await network.provider.send("evm_mine");
@@ -161,7 +147,6 @@ describe("Integration tests", async () => {
console.log("KC phase: %d", await sortitionModule.phase());
await sortitionModule.passPhase(); // Staking -> Generating
- await mineBlocks(ethers.getNumber(await sortitionModule.rngLookahead())); // Wait for finality
expect(await sortitionModule.phase()).to.equal(Phase.generating);
console.log("KC phase: %d", await sortitionModule.phase());
await vrfCoordinator.fulfillRandomWords(1, rng.target, []);
@@ -191,12 +176,16 @@ describe("Integration tests", async () => {
await core.passPeriod(0);
expect((await core.disputes(0)).period).to.equal(Period.execution);
- expect(await core.execute(0, 0, 1000)).to.emit(core, "TokenAndETHShift");
-
- const tx4 = await core.executeRuling(0, { gasLimit: 10000000, gasPrice: 5000000000 });
+ await expect(core.execute(0, 0, 1000))
+ .to.emit(core, "JurorRewardPenalty")
+ .withArgs(deployer, 0, 0, 10000, 10000, 0, arbitrationCost / 3n, ethers.ZeroAddress);
+
+ await expect(core.executeRuling(0, { gasLimit: 10000000, gasPrice: 5000000000 }))
+ .to.emit(core, "Ruling")
+ .withArgs(homeGateway.target, 0, 0)
+ .and.to.emit(arbitrable, "Ruling")
+ .withArgs(foreignGateway.target, 1, 0); // The ForeignGateway starts counting disputeID from 1.
console.log("Ruling executed on KlerosCore");
- expect(tx4).to.emit(core, "Ruling").withArgs(homeGateway.target, 0, 0);
- expect(tx4).to.emit(arbitrable, "Ruling").withArgs(foreignGateway.target, 1, 0); // The ForeignGateway starts counting disputeID from 1.
});
const mineBlocks = async (n: number) => {
@@ -206,6 +195,10 @@ describe("Integration tests", async () => {
};
});
-const logJurorBalance = async (result) => {
- console.log("staked=%s, locked=%s", ethers.formatUnits(result.totalStaked), ethers.formatUnits(result.totalLocked));
+const logJurorBalance = async (result: { totalStakedPnk: bigint; totalLocked: bigint }) => {
+ console.log(
+ "staked=%s, locked=%s",
+ ethers.formatUnits(result.totalStakedPnk),
+ ethers.formatUnits(result.totalLocked)
+ );
};
diff --git a/contracts/test/proxy/index.ts b/contracts/test/proxy/index.ts
index 6b66a27fb..a58886789 100644
--- a/contracts/test/proxy/index.ts
+++ b/contracts/test/proxy/index.ts
@@ -4,7 +4,7 @@ import { DeployResult } from "hardhat-deploy/types";
import { HardhatEthersSigner } from "@nomicfoundation/hardhat-ethers/signers";
import { deployUpgradable } from "../../deploy/utils/deployUpgradable";
import { UpgradedByInheritanceV1, UpgradedByInheritanceV2 } from "../../typechain-types";
-import { UpgradedByRewrite as UpgradedByRewriteV1 } from "../../typechain-types/src/proxy/mock/by-rewrite";
+import { UpgradedByRewrite as UpgradedByRewriteV1 } from "../../typechain-types/src/proxy/mock/by-rewrite/UpgradedByRewrite.sol";
import { UpgradedByRewrite as UpgradedByRewriteV2 } from "../../typechain-types/src/proxy/mock/by-rewrite/UpgradedByRewriteV2.sol";
let deployer: HardhatEthersSigner;
@@ -46,7 +46,7 @@ describe("Upgradability", async () => {
});
describe("Initialization", async () => {
- it("Governor cannot re-initialize the proxy", async () => {
+ it("Owner cannot re-initialize the proxy", async () => {
await expect(proxy.connect(deployer).initialize(deployer.address)).to.be.revertedWith(
"Contract instance has already been initialized"
);
@@ -79,7 +79,7 @@ describe("Upgradability", async () => {
.withArgs(nonUpgradeableMock.target);
});
it("Should revert if upgrade is performed directly through the implementation", async () => {
- // In the implementation, the `governor` storage slot is not initialized so `governor === address(0)`, which fails _authorizeUpgrade()
+ // In the implementation, the `owner` storage slot is not initialized so `owner === address(0)`, which fails _authorizeUpgrade()
const UUPSUpgradeableMockV2Factory = await ethers.getContractFactory("UUPSUpgradeableMockV2");
const newImplementation = await UUPSUpgradeableMockV2Factory.connect(deployer).deploy();
await expect(
@@ -89,7 +89,7 @@ describe("Upgradability", async () => {
});
describe("Authentication", async () => {
- it("Only the governor (deployer here) can perform upgrades", async () => {
+ it("Only the owner (deployer here) can perform upgrades", async () => {
// Unauthorized user try to upgrade the implementation
const UUPSUpgradeableMockV2Factory = await ethers.getContractFactory("UUPSUpgradeableMockV2");
let upgradable = await UUPSUpgradeableMockV2Factory.connect(user1).deploy();
@@ -97,7 +97,7 @@ describe("Upgradability", async () => {
"No privilege to upgrade"
);
- // Governor updates the implementation
+ // Owner updates the implementation
upgradable = await UUPSUpgradeableMockV2Factory.connect(deployer).deploy();
await expect(proxy.connect(deployer).upgradeToAndCall(upgradable.target, "0x"))
.to.emit(proxy, "Upgraded")
@@ -130,11 +130,11 @@ describe("Upgradability", async () => {
});
it("Initializes v1", async () => {
- proxy = (await ethers.getContract("UpgradedByRewrite")) as UpgradedByRewriteV1;
+ proxy = await ethers.getContract("UpgradedByRewrite");
- implementation = (await ethers.getContract("UpgradedByRewrite_Implementation")) as UpgradedByRewriteV1;
+ implementation = await ethers.getContract("UpgradedByRewrite_Implementation");
- expect(await proxy.governor()).to.equal(deployer.address);
+ expect(await proxy.owner()).to.equal(deployer.address);
expect(await proxy.counter()).to.equal(1);
await proxy.increment();
@@ -156,8 +156,8 @@ describe("Upgradability", async () => {
if (!proxyDeployment.implementation) {
throw new Error("No implementation address");
}
- proxy = (await ethers.getContract("UpgradedByRewrite")) as UpgradedByRewriteV2;
- expect(await proxy.governor()).to.equal(deployer.address);
+ proxy = await ethers.getContract("UpgradedByRewrite");
+ expect(await proxy.owner()).to.equal(deployer.address);
expect(await proxy.counter()).to.equal(3);
await proxy.increment();
@@ -184,11 +184,11 @@ describe("Upgradability", async () => {
});
it("Initializes v1", async () => {
- proxy = (await ethers.getContract("UpgradedByInheritanceV1")) as UpgradedByInheritanceV1;
+ proxy = await ethers.getContract("UpgradedByInheritanceV1");
- implementation = (await ethers.getContract("UpgradedByInheritanceV1_Implementation")) as UpgradedByInheritanceV1;
+ implementation = await ethers.getContract("UpgradedByInheritanceV1_Implementation");
- expect(await proxy.governor()).to.equal(deployer.address);
+ expect(await proxy.owner()).to.equal(deployer.address);
expect(await proxy.counter()).to.equal(1);
await proxy.increment();
@@ -209,9 +209,9 @@ describe("Upgradability", async () => {
log: true,
});
- proxy = (await ethers.getContract("UpgradedByInheritanceV1")) as UpgradedByInheritanceV2;
+ proxy = await ethers.getContract("UpgradedByInheritanceV1");
- expect(await proxy.governor()).to.equal(deployer.address);
+ expect(await proxy.owner()).to.equal(deployer.address);
expect(await proxy.counter()).to.equal(3);
await proxy.increment();
diff --git a/contracts/test/rng/index.ts b/contracts/test/rng/index.ts
index 3d4906721..f61ec9b95 100644
--- a/contracts/test/rng/index.ts
+++ b/contracts/test/rng/index.ts
@@ -1,5 +1,5 @@
import { expect } from "chai";
-import { deployments, ethers, network } from "hardhat";
+import { deployments, ethers, getNamedAccounts, network } from "hardhat";
import {
IncrementalNG,
BlockHashRNG,
@@ -11,6 +11,7 @@ import {
const initialNg = 424242;
const abiCoder = ethers.AbiCoder.defaultAbiCoder();
+let deployer: string;
describe("IncrementalNG", async () => {
let rng: IncrementalNG;
@@ -21,13 +22,13 @@ describe("IncrementalNG", async () => {
});
it("Should return a number incrementing each time", async () => {
- expect(await rng.receiveRandomness.staticCall(689376)).to.equal(initialNg);
- await rng.receiveRandomness(29543).then((tx) => tx.wait());
- expect(await rng.receiveRandomness.staticCall(5894382)).to.equal(initialNg + 1);
- await rng.receiveRandomness(0).then((tx) => tx.wait());
- expect(await rng.receiveRandomness.staticCall(3465)).to.equal(initialNg + 2);
- await rng.receiveRandomness(2n ** 255n).then((tx) => tx.wait());
- expect(await rng.receiveRandomness.staticCall(0)).to.equal(initialNg + 3);
+ expect(await rng.receiveRandomness.staticCall()).to.equal(initialNg);
+ await rng.receiveRandomness().then((tx) => tx.wait());
+ expect(await rng.receiveRandomness.staticCall()).to.equal(initialNg + 1);
+ await rng.receiveRandomness().then((tx) => tx.wait());
+ expect(await rng.receiveRandomness.staticCall()).to.equal(initialNg + 2);
+ await rng.receiveRandomness().then((tx) => tx.wait());
+ expect(await rng.receiveRandomness.staticCall()).to.equal(initialNg + 3);
});
});
@@ -35,26 +36,48 @@ describe("BlockHashRNG", async () => {
let rng: BlockHashRNG;
beforeEach("Setup", async () => {
- const rngFactory = await ethers.getContractFactory("BlockHashRNG");
- rng = (await rngFactory.deploy()) as BlockHashRNG;
+ const [deployer] = await ethers.getSigners();
+ await deployments.delete("BlockHashRNG");
+ await deployments.deploy("BlockHashRNG", {
+ from: deployer.address,
+ args: [deployer.address, deployer.address, 10], // owner, consumer, lookaheadTime (seconds)
+ });
+ rng = await ethers.getContract("BlockHashRNG");
});
- it("Should return a non-zero number for a block number in the past", async () => {
- const tx = await rng.receiveRandomness(5);
- const trace = await network.provider.send("debug_traceTransaction", [tx.hash]);
- await tx.wait();
- const [rn] = abiCoder.decode(["uint"], ethers.getBytes(`${trace.returnValue}`));
- expect(rn).to.not.equal(0);
- await tx.wait();
+ it("Should return a non-zero number after requesting and waiting", async () => {
+ // First request randomness
+ await rng.requestRandomness();
+
+ // Check that it's not ready yet
+ expect(await rng.isRandomnessReady()).to.be.false;
+
+ // Advance time by 10 seconds (the lookahead time)
+ await network.provider.send("evm_increaseTime", [10]);
+ await network.provider.send("evm_mine");
+
+ // Now it should be ready
+ expect(await rng.isRandomnessReady()).to.be.true;
+
+ // Get the random number
+ const randomNumber = await rng.receiveRandomness.staticCall();
+ expect(randomNumber).to.not.equal(0);
});
- it("Should return zero for a block number in the future", async () => {
- const tx = await rng.receiveRandomness(9876543210);
- const trace = await network.provider.send("debug_traceTransaction", [tx.hash]);
- await tx.wait();
- const [rn] = abiCoder.decode(["uint"], ethers.getBytes(`${trace.returnValue}`));
- expect(rn).to.equal(0);
- await tx.wait();
+ it("Should return 0 if randomness not requested", async () => {
+ const randomNumber = await rng.receiveRandomness.staticCall();
+ expect(randomNumber).to.equal(0);
+ });
+
+ it("Should return 0 if not enough time has passed", async () => {
+ await rng.requestRandomness();
+
+ // Don't advance time enough
+ await network.provider.send("evm_increaseTime", [5]); // Only 5 seconds
+ await network.provider.send("evm_mine");
+
+ const randomNumber = await rng.receiveRandomness.staticCall();
+ expect(randomNumber).to.equal(0);
});
});
@@ -63,49 +86,47 @@ describe("ChainlinkRNG", async () => {
let vrfCoordinator: ChainlinkVRFCoordinatorV2Mock;
beforeEach("Setup", async () => {
+ ({ deployer } = await getNamedAccounts());
+
await deployments.fixture(["ChainlinkRNG"], {
fallbackToGlobal: true,
keepExistingDeployments: false,
});
- rng = (await ethers.getContract("ChainlinkRNG")) as ChainlinkRNG;
- vrfCoordinator = (await ethers.getContract("ChainlinkVRFCoordinator")) as ChainlinkVRFCoordinatorV2Mock;
+ rng = await ethers.getContract("ChainlinkRNG");
+ vrfCoordinator = await ethers.getContract("ChainlinkVRFCoordinator");
+
+ await rng.changeConsumer(deployer);
});
it("Should return a non-zero random number", async () => {
const requestId = 1;
- const expectedRn = BigInt(
- ethers.keccak256(ethers.AbiCoder.defaultAbiCoder().encode(["uint256", "uint256"], [requestId, 0]))
- );
+ const expectedRn = BigInt(ethers.keccak256(abiCoder.encode(["uint256", "uint256"], [requestId, 0])));
- let tx = await rng.requestRandomness(0);
+ let tx = await rng.requestRandomness();
await expect(tx).to.emit(rng, "RequestSent").withArgs(requestId);
tx = await vrfCoordinator.fulfillRandomWords(requestId, rng.target, []);
await expect(tx).to.emit(rng, "RequestFulfilled").withArgs(requestId, expectedRn);
- const rn = await rng.receiveRandomness(0);
+ const rn = await rng.receiveRandomness();
expect(rn).to.equal(expectedRn);
await tx.wait();
});
it("Should return only the last random number when multiple requests are made", async () => {
// First request
- let tx = await rng.requestRandomness(0);
+ let tx = await rng.requestRandomness();
const requestId1 = 1;
await expect(tx).to.emit(rng, "RequestSent").withArgs(requestId1);
// Second request
- tx = await rng.requestRandomness(0);
+ tx = await rng.requestRandomness();
const requestId2 = 2;
await expect(tx).to.emit(rng, "RequestSent").withArgs(requestId2);
// Generate expected random numbers
- const expectedRn1 = BigInt(
- ethers.keccak256(ethers.AbiCoder.defaultAbiCoder().encode(["uint256", "uint256"], [requestId1, 0]))
- );
- const expectedRn2 = BigInt(
- ethers.keccak256(ethers.AbiCoder.defaultAbiCoder().encode(["uint256", "uint256"], [requestId2, 0]))
- );
+ const expectedRn1 = BigInt(ethers.keccak256(abiCoder.encode(["uint256", "uint256"], [requestId1, 0])));
+ const expectedRn2 = BigInt(ethers.keccak256(abiCoder.encode(["uint256", "uint256"], [requestId2, 0])));
expect(expectedRn1).to.not.equal(expectedRn2, "Random numbers should be different");
// Fulfill first request
@@ -117,7 +138,7 @@ describe("ChainlinkRNG", async () => {
await expect(tx).to.emit(rng, "RequestFulfilled").withArgs(requestId2, expectedRn2);
// Should return only the last random number
- const rn = await rng.receiveRandomness(0);
+ const rn = await rng.receiveRandomness();
expect(rn).to.equal(expectedRn2);
await tx.wait();
});
@@ -128,12 +149,16 @@ describe("RandomizerRNG", async () => {
let randomizer: RandomizerMock;
beforeEach("Setup", async () => {
+ ({ deployer } = await getNamedAccounts());
+
await deployments.fixture(["RandomizerRNG"], {
fallbackToGlobal: true,
keepExistingDeployments: false,
});
- rng = (await ethers.getContract("RandomizerRNG")) as RandomizerRNG;
- randomizer = (await ethers.getContract("RandomizerOracle")) as RandomizerMock;
+ rng = await ethers.getContract("RandomizerRNG");
+ randomizer = await ethers.getContract("RandomizerOracle");
+
+ await rng.changeConsumer(deployer);
});
it("Should return a non-zero random number", async () => {
@@ -141,25 +166,25 @@ describe("RandomizerRNG", async () => {
const expectedRn = BigInt(ethers.hexlify(randomBytes));
const requestId = 1;
- let tx = await rng.requestRandomness(0);
+ let tx = await rng.requestRandomness();
await expect(tx).to.emit(rng, "RequestSent").withArgs(requestId);
tx = await randomizer.relay(rng.target, requestId, randomBytes);
await expect(tx).to.emit(rng, "RequestFulfilled").withArgs(requestId, expectedRn);
- const rn = await rng.receiveRandomness(0);
+ const rn = await rng.receiveRandomness();
expect(rn).to.equal(expectedRn);
await tx.wait();
});
it("Should return only the last random number when multiple requests are made", async () => {
// First request
- let tx = await rng.requestRandomness(0);
+ let tx = await rng.requestRandomness();
const requestId1 = 1;
await expect(tx).to.emit(rng, "RequestSent").withArgs(requestId1);
// Second request
- tx = await rng.requestRandomness(0);
+ tx = await rng.requestRandomness();
const requestId2 = 2;
await expect(tx).to.emit(rng, "RequestSent").withArgs(requestId2);
@@ -180,7 +205,7 @@ describe("RandomizerRNG", async () => {
await expect(tx).to.emit(rng, "RequestFulfilled").withArgs(requestId2, expectedRn2);
// Should return only the last random number
- const rn = await rng.receiveRandomness(0);
+ const rn = await rng.receiveRandomness();
expect(rn).to.equal(expectedRn2);
await tx.wait();
});
diff --git a/contracts/test/sortition/index.ts b/contracts/test/sortition/index.ts
new file mode 100644
index 000000000..e33d1a0d5
--- /dev/null
+++ b/contracts/test/sortition/index.ts
@@ -0,0 +1,698 @@
+import { expect } from "chai";
+import { ethers } from "hardhat";
+import { SortitionTreesMock } from "../../typechain-types";
+
+describe("SortitionTrees", function () {
+ let sortitionTree: SortitionTreesMock;
+ let accounts: any[];
+
+ beforeEach("Setup", async () => {
+ const factory = await ethers.getContractFactory("SortitionTreesMock");
+ sortitionTree = (await factory.deploy()) as SortitionTreesMock;
+ accounts = await ethers.getSigners();
+ });
+
+ // Helper function to create a test juror address
+ const getTestAddress = (index: number): string => accounts[index % accounts.length].address;
+
+ describe("Stake Path ID Utilities", function () {
+ it("Should convert correctly between stakePathID and account+courtID", async function () {
+ // Test various combinations of addresses and court IDs
+ const testCases = [
+ {
+ address: "0x1234567890123456789012345678901234567890",
+ courtID: 0,
+ },
+ {
+ address: "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF",
+ courtID: 0xffffffffffff, // max uint96
+ },
+ {
+ address: "0x0000000000000000000000000000000000000001",
+ courtID: 1,
+ },
+ {
+ address: "0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF",
+ courtID: 123456789,
+ },
+ ];
+
+ for (const testCase of testCases) {
+ // Test packing
+ const stakePathID = await sortitionTree.testToStakePathID(testCase.address, testCase.courtID);
+
+ // Test unpacking
+ const [unpackedAddress, unpackedCourtID] = await sortitionTree.testToAccountAndCourtID(stakePathID);
+
+ // Verify round-trip equivalence
+ expect(unpackedAddress.toLowerCase()).to.equal(testCase.address.toLowerCase());
+ expect(unpackedCourtID).to.equal(testCase.courtID);
+
+ // Verify the packed format is as expected: [20 bytes address][12 bytes courtID]
+ const expectedPackedValue = ethers.solidityPacked(["address", "uint96"], [testCase.address, testCase.courtID]);
+ expect(stakePathID).to.equal(expectedPackedValue);
+ }
+ });
+
+ it("Should handle TreeKey conversion correctly", async function () {
+ const courtIDs = [
+ 0,
+ 1,
+ 100,
+ 0xffffffffffff, // max uint96
+ ];
+
+ for (const courtID of courtIDs) {
+ const treeKey = await sortitionTree.testToTreeKey(courtID);
+
+ // TreeKey should be the courtID padded to 32 bytes
+ const expectedTreeKey = ethers.zeroPadValue(ethers.toBeHex(courtID), 32);
+ expect(treeKey).to.equal(expectedTreeKey);
+
+ // Court ID 0 will result in zero key, others should not
+ if (courtID === 0) {
+ expect(treeKey).to.equal("0x0000000000000000000000000000000000000000000000000000000000000000");
+ } else {
+ expect(treeKey).to.not.equal("0x0000000000000000000000000000000000000000000000000000000000000000");
+ }
+ }
+ });
+ });
+
+ describe("Tree Creation & Validation", function () {
+ it("Should create trees with valid K values", async function () {
+ const testCases = [
+ { courtID: 0, k: 2 },
+ { courtID: 1, k: 5 },
+ { courtID: 100, k: 10 },
+ { courtID: 999, k: 100 },
+ ];
+
+ for (const testCase of testCases) {
+ await sortitionTree.createTree(testCase.courtID, testCase.k);
+
+ // Verify tree was created
+ expect(await sortitionTree.courtExists(testCase.courtID)).to.be.true;
+ expect(await sortitionTree.getTreeK(testCase.courtID)).to.equal(testCase.k);
+
+ // Verify initial state
+ const nodes = await sortitionTree.getTreeNodes(testCase.courtID);
+ expect(nodes.length).to.equal(1);
+ expect(nodes[0]).to.equal(0); // Root starts at 0
+
+ const stack = await sortitionTree.getTreeStack(testCase.courtID);
+ expect(stack.length).to.equal(0); // Empty stack initially
+ }
+ });
+
+ it("Should reject invalid K values", async function () {
+ // K must be greater than 1
+ await expect(sortitionTree.createTree(0, 0)).to.be.reverted;
+ await expect(sortitionTree.createTree(1, 1)).to.be.reverted;
+ });
+
+ it("Should reject creating duplicate trees", async function () {
+ await sortitionTree.createTree(0, 2);
+ await expect(sortitionTree.createTree(0, 3)).to.be.reverted;
+ });
+
+ it("Should create multiple independent trees", async function () {
+ await sortitionTree.createTree(0, 2);
+ await sortitionTree.createTree(1, 3);
+ await sortitionTree.createTree(2, 5);
+
+ expect(await sortitionTree.getTreeK(0)).to.equal(2);
+ expect(await sortitionTree.getTreeK(1)).to.equal(3);
+ expect(await sortitionTree.getTreeK(2)).to.equal(5);
+ });
+ });
+
+ describe("Single Court Stake Management", function () {
+ beforeEach(async function () {
+ // Create a test tree with K=2 for court 0
+ await sortitionTree.createTree(0, 2);
+ });
+
+ describe("Adding New Stakes", function () {
+ it("Should add first juror to empty tree", async function () {
+ const juror = getTestAddress(0);
+ const stake = 100;
+
+ await sortitionTree.set(0, juror, stake);
+
+ // Verify stake was set
+ expect(await sortitionTree.stakeOf(0, juror)).to.equal(stake);
+ expect(await sortitionTree.getRootSum(0)).to.equal(stake);
+
+ // Verify tree structure
+ const nodes = await sortitionTree.getTreeNodes(0);
+ expect(nodes[0]).to.equal(stake); // Root should equal juror stake
+ expect(nodes[1]).to.equal(stake); // First leaf
+ });
+
+ it("Should add multiple jurors sequentially", async function () {
+ const stakes = [100, 200, 300];
+
+ for (let i = 0; i < stakes.length; i++) {
+ const juror = getTestAddress(i);
+ await sortitionTree.set(0, juror, stakes[i]);
+ expect(await sortitionTree.stakeOf(0, juror)).to.equal(stakes[i]);
+ }
+
+ // Verify total stake
+ const expectedTotal = stakes.reduce((sum, stake) => sum + stake, 0);
+ expect(await sortitionTree.getRootSum(0)).to.equal(expectedTotal);
+ });
+
+ it("Should handle tree restructuring when K threshold is reached", async function () {
+ // Add enough jurors to trigger tree restructuring
+ const stakes = [100, 200, 300, 400]; // More than K=2
+
+ for (let i = 0; i < stakes.length; i++) {
+ const juror = getTestAddress(i);
+ await sortitionTree.set(0, juror, stakes[i]);
+ }
+
+ const nodes = await sortitionTree.getTreeNodes(0);
+ expect(nodes.length).to.be.greaterThan(4); // Should have expanded
+
+ const expectedTotal = stakes.reduce((sum, stake) => sum + stake, 0);
+ expect(await sortitionTree.getRootSum(0)).to.equal(expectedTotal);
+ });
+ });
+
+ describe("Updating Existing Stakes", function () {
+ beforeEach(async function () {
+ // Add initial jurors
+ await sortitionTree.set(0, getTestAddress(0), 100);
+ await sortitionTree.set(0, getTestAddress(1), 200);
+ });
+
+ it("Should increase stake values correctly", async function () {
+ const juror = getTestAddress(0);
+ const oldStake = await sortitionTree.stakeOf(0, juror);
+ const newStake = 250;
+
+ await sortitionTree.set(0, juror, newStake);
+
+ expect(await sortitionTree.stakeOf(0, juror)).to.equal(newStake);
+
+ // Root should reflect the change
+ const rootSum = await sortitionTree.getRootSum(0);
+ expect(rootSum).to.equal(200 + newStake);
+ });
+
+ it("Should decrease stake values correctly", async function () {
+ const juror = getTestAddress(0);
+ const newStake = 50;
+
+ await sortitionTree.set(0, juror, newStake);
+
+ expect(await sortitionTree.stakeOf(0, juror)).to.equal(newStake);
+ expect(await sortitionTree.getRootSum(0)).to.equal(200 + newStake);
+ });
+
+ it("Should be no-op when setting same value", async function () {
+ const juror = getTestAddress(0);
+ const currentStake = await sortitionTree.stakeOf(0, juror);
+ const initialRoot = await sortitionTree.getRootSum(0);
+
+ await sortitionTree.set(0, juror, currentStake);
+
+ expect(await sortitionTree.stakeOf(0, juror)).to.equal(currentStake);
+ expect(await sortitionTree.getRootSum(0)).to.equal(initialRoot);
+ });
+ });
+
+ describe("Removing Stakes", function () {
+ beforeEach(async function () {
+ // Add initial jurors
+ await sortitionTree.set(0, getTestAddress(0), 100);
+ await sortitionTree.set(0, getTestAddress(1), 200);
+ await sortitionTree.set(0, getTestAddress(2), 300);
+ });
+
+ it("Should remove juror by setting stake to 0", async function () {
+ const juror = getTestAddress(1);
+ const initialRoot = await sortitionTree.getRootSum(0);
+
+ await sortitionTree.set(0, juror, 0);
+
+ expect(await sortitionTree.stakeOf(0, juror)).to.equal(0);
+ expect(await sortitionTree.getRootSum(0)).to.equal(initialRoot - 200n);
+ expect(await sortitionTree.getNodeIndex(0, juror)).to.equal(0); // Should be cleared
+ });
+
+ it("Should manage stack for removed positions", async function () {
+ const juror = getTestAddress(1);
+ const initialStackLength = (await sortitionTree.getTreeStack(0)).length;
+
+ await sortitionTree.set(0, juror, 0);
+
+ const newStackLength = (await sortitionTree.getTreeStack(0)).length;
+ expect(newStackLength).to.be.greaterThan(initialStackLength);
+ });
+
+ it("Should reuse vacant positions from stack", async function () {
+ const juror1 = getTestAddress(1);
+ const juror4 = getTestAddress(4);
+
+ // Remove a juror
+ await sortitionTree.set(0, juror1, 0);
+ const stackAfterRemoval = await sortitionTree.getTreeStack(0);
+
+ // Add a new juror (should reuse vacant position)
+ await sortitionTree.set(0, juror4, 150);
+ const stackAfterAdd = await sortitionTree.getTreeStack(0);
+
+ expect(stackAfterAdd.length).to.equal(stackAfterRemoval.length - 1);
+ expect(await sortitionTree.stakeOf(0, juror4)).to.equal(150);
+ });
+ });
+ });
+
+ describe("Drawing Algorithm", function () {
+ beforeEach(async function () {
+ await sortitionTree.createTree(0, 2);
+ });
+
+ it("Should return zero address for empty tree", async function () {
+ const [drawnAddress, courtID] = await sortitionTree.draw(0, 1, 1, 12345);
+ expect(drawnAddress).to.equal(ethers.ZeroAddress);
+ expect(courtID).to.equal(0);
+ });
+
+ it("Should draw single juror from single-juror tree", async function () {
+ const juror = getTestAddress(0);
+ await sortitionTree.set(0, juror, 100);
+
+ // Multiple draws should always return the same juror
+ for (let i = 0; i < 5; i++) {
+ const [drawnAddress, courtID] = await sortitionTree.draw(0, 1, i, 12345 + i);
+ expect(drawnAddress.toLowerCase()).to.equal(juror.toLowerCase());
+ expect(courtID).to.equal(0);
+ }
+ });
+
+ it("Should draw deterministically with same inputs", async function () {
+ // Add multiple jurors
+ await sortitionTree.set(0, getTestAddress(0), 100);
+ await sortitionTree.set(0, getTestAddress(1), 200);
+ await sortitionTree.set(0, getTestAddress(2), 300);
+
+ const disputeID = 1;
+ const nonce = 2;
+ const randomNumber = 12345;
+
+ // Multiple calls with same parameters should return same result
+ const [address1] = await sortitionTree.draw(0, disputeID, nonce, randomNumber);
+ const [address2] = await sortitionTree.draw(0, disputeID, nonce, randomNumber);
+ const [address3] = await sortitionTree.draw(0, disputeID, nonce, randomNumber);
+
+ expect(address1).to.equal(address2);
+ expect(address2).to.equal(address3);
+ });
+
+ it("Should respect weighted probability distribution", async function () {
+ // Add jurors with very different stakes to test weighting
+ await sortitionTree.set(0, getTestAddress(0), 1); // Very low stake
+ await sortitionTree.set(0, getTestAddress(1), 1000); // Very high stake
+
+ let draws = { [getTestAddress(0).toLowerCase()]: 0, [getTestAddress(1).toLowerCase()]: 0 };
+
+ // Perform many draws with different random numbers
+ const numDraws = 100;
+ for (let i = 0; i < numDraws; i++) {
+ const [drawnAddress] = await sortitionTree.draw(0, 1, 1, i);
+ draws[drawnAddress.toLowerCase()]++;
+ }
+
+ // Juror with higher stake should be drawn more frequently
+ // With stakes of 1:1000, we expect roughly 0.1% vs 99.9% distribution
+ expect(draws[getTestAddress(1).toLowerCase()]).to.be.greaterThan(draws[getTestAddress(0).toLowerCase()]);
+ expect(draws[getTestAddress(1).toLowerCase()]).to.be.greaterThan(numDraws * 0.8); // At least 80% for high stake
+ });
+
+ it("Should handle edge case random numbers", async function () {
+ await sortitionTree.set(0, getTestAddress(0), 100);
+ await sortitionTree.set(0, getTestAddress(1), 200);
+
+ // Test with boundary random numbers
+ const testNumbers = [0, 1, ethers.MaxUint256];
+
+ for (const randomNumber of testNumbers) {
+ const [drawnAddress] = await sortitionTree.draw(0, 1, 1, randomNumber);
+ expect(drawnAddress).to.not.equal(ethers.ZeroAddress);
+
+ // Should be one of our jurors
+ const isValidJuror =
+ drawnAddress.toLowerCase() === getTestAddress(0).toLowerCase() ||
+ drawnAddress.toLowerCase() === getTestAddress(1).toLowerCase();
+ expect(isValidJuror).to.be.true;
+ }
+ });
+ });
+
+ describe("Multi-Court Scenarios", function () {
+ beforeEach(async function () {
+ // Create multiple courts with different K values
+ await sortitionTree.createTree(0, 2); // General Court
+ await sortitionTree.createTree(1, 3); // Tech Court
+ await sortitionTree.createTree(2, 2); // Legal Court
+ });
+
+ describe("Independent Court Operations", function () {
+ it("Should handle same juror staking in multiple courts", async function () {
+ const juror = getTestAddress(0);
+ const stakes = [100, 250, 75]; // Different stakes in different courts
+
+ // Set stakes in different courts
+ for (let courtID = 0; courtID < 3; courtID++) {
+ await sortitionTree.set(courtID, juror, stakes[courtID]);
+ }
+
+ // Verify stakes are independent
+ for (let courtID = 0; courtID < 3; courtID++) {
+ expect(await sortitionTree.stakeOf(courtID, juror)).to.equal(stakes[courtID]);
+ expect(await sortitionTree.getRootSum(courtID)).to.equal(stakes[courtID]);
+ }
+ });
+
+ it("Should maintain court isolation", async function () {
+ const juror1 = getTestAddress(0);
+ const juror2 = getTestAddress(1);
+
+ // Add different jurors to different courts
+ await sortitionTree.set(0, juror1, 100);
+ await sortitionTree.set(1, juror2, 200);
+
+ // Court 0 should only have juror1
+ expect(await sortitionTree.stakeOf(0, juror1)).to.equal(100);
+ expect(await sortitionTree.stakeOf(0, juror2)).to.equal(0);
+
+ // Court 1 should only have juror2
+ expect(await sortitionTree.stakeOf(1, juror1)).to.equal(0);
+ expect(await sortitionTree.stakeOf(1, juror2)).to.equal(200);
+ });
+
+ it("Should handle different tree structures independently", async function () {
+ const jurors = [getTestAddress(0), getTestAddress(1), getTestAddress(2), getTestAddress(3)];
+
+ // Add different numbers of jurors to each court
+ await sortitionTree.set(0, jurors[0], 100); // 1 juror in court 0
+
+ await sortitionTree.set(1, jurors[0], 150); // 2 jurors in court 1
+ await sortitionTree.set(1, jurors[1], 250);
+
+ await sortitionTree.set(2, jurors[0], 75); // 3 jurors in court 2
+ await sortitionTree.set(2, jurors[1], 125);
+ await sortitionTree.set(2, jurors[2], 175);
+
+ // Verify independent tree structures
+ expect(await sortitionTree.getRootSum(0)).to.equal(100);
+ expect(await sortitionTree.getRootSum(1)).to.equal(400);
+ expect(await sortitionTree.getRootSum(2)).to.equal(375);
+
+ // Verify each court has correct tree structure
+ const nodes0 = await sortitionTree.getTreeNodes(0);
+ const nodes1 = await sortitionTree.getTreeNodes(1);
+ const nodes2 = await sortitionTree.getTreeNodes(2);
+
+ expect(nodes0.length).to.be.lessThan(nodes2.length); // Fewer jurors = smaller tree
+ expect(nodes1.length).to.be.greaterThan(nodes0.length); // More jurors = larger tree
+ });
+ });
+
+ describe("Cross-Court Stake Updates", function () {
+ it("Should handle simultaneous updates across multiple courts", async function () {
+ const juror = getTestAddress(0);
+ const courtIDs = [0, 1, 2];
+ const initialStakes = [100, 200, 300];
+ const updatedStakes = [150, 250, 350];
+
+ // Set initial stakes
+ for (let i = 0; i < courtIDs.length; i++) {
+ await sortitionTree.set(courtIDs[i], juror, initialStakes[i]);
+ }
+
+ // Update all stakes
+ for (let i = 0; i < courtIDs.length; i++) {
+ await sortitionTree.set(courtIDs[i], juror, updatedStakes[i]);
+ }
+
+ // Verify all updates took effect
+ for (let i = 0; i < courtIDs.length; i++) {
+ expect(await sortitionTree.stakeOf(courtIDs[i], juror)).to.equal(updatedStakes[i]);
+ }
+ });
+
+ it("Should handle partial removals across courts", async function () {
+ const juror = getTestAddress(0);
+
+ // Add juror to all courts
+ await sortitionTree.set(0, juror, 100);
+ await sortitionTree.set(1, juror, 200);
+ await sortitionTree.set(2, juror, 300);
+
+ // Remove from middle court only
+ await sortitionTree.set(1, juror, 0);
+
+ // Verify partial removal
+ expect(await sortitionTree.stakeOf(0, juror)).to.equal(100);
+ expect(await sortitionTree.stakeOf(1, juror)).to.equal(0);
+ expect(await sortitionTree.stakeOf(2, juror)).to.equal(300);
+ });
+
+ it("Should use batch operations correctly", async function () {
+ const juror = getTestAddress(0);
+ const courtIDs = [0, 1, 2];
+ const stake = 500;
+
+ // Use batch operation to set stakes
+ await sortitionTree.setStakeInHierarchy(courtIDs, juror, stake);
+
+ // Verify all stakes were set
+ const stakes = await sortitionTree.getStakesAcrossCourts(juror, courtIDs);
+ for (const retrievedStake of stakes) {
+ expect(retrievedStake).to.equal(stake);
+ }
+ });
+ });
+
+ describe("Multi-Court Drawing", function () {
+ beforeEach(async function () {
+ // Setup jurors in different courts
+ await sortitionTree.set(0, getTestAddress(0), 100); // Court 0: 1 juror
+ await sortitionTree.set(0, getTestAddress(1), 200);
+
+ await sortitionTree.set(1, getTestAddress(1), 300); // Court 1: 2 jurors
+ await sortitionTree.set(1, getTestAddress(2), 400);
+
+ await sortitionTree.set(2, getTestAddress(0), 500); // Court 2: 1 juror only
+ });
+
+ it("Should draw correctly from different courts", async function () {
+ // Draw from each court
+ const [addr0] = await sortitionTree.draw(0, 1, 1, 12345);
+ const [addr1] = await sortitionTree.draw(1, 1, 1, 12345);
+ const [addr2] = await sortitionTree.draw(2, 1, 1, 12345);
+
+ // Should get valid addresses from each court
+ expect(addr0).to.not.equal(ethers.ZeroAddress);
+ expect(addr1).to.not.equal(ethers.ZeroAddress);
+ expect(addr2).to.not.equal(ethers.ZeroAddress);
+
+ // Court 2 should always return getTestAddress(0) since it's the only juror
+ expect(addr2.toLowerCase()).to.equal(getTestAddress(0).toLowerCase());
+ });
+
+ it("Should return correct court ID in draw results", async function () {
+ const [, courtID0] = await sortitionTree.draw(0, 1, 1, 12345);
+ const [, courtID1] = await sortitionTree.draw(1, 1, 1, 12345);
+ const [, courtID2] = await sortitionTree.draw(2, 1, 1, 12345);
+
+ // The returned court IDs should match the stake path IDs
+ // Since we're using the same court for staking and drawing, they should match
+ expect([0, 1]).to.include(Number(courtID0));
+ expect([1, 2]).to.include(Number(courtID1));
+ expect(Number(courtID2)).to.equal(2);
+ });
+
+ it("Should maintain independent probability distributions", async function () {
+ // Test drawing many times from court 0 where juror 1 has 2x stake of juror 0
+ let draws = { [getTestAddress(0).toLowerCase()]: 0, [getTestAddress(1).toLowerCase()]: 0 };
+
+ const numDraws = 50;
+ for (let i = 0; i < numDraws; i++) {
+ const [drawnAddress] = await sortitionTree.draw(0, 1, 1, i);
+ draws[drawnAddress.toLowerCase()]++;
+ }
+
+ // Juror 1 (200 stake) should be drawn more than juror 0 (100 stake)
+ expect(draws[getTestAddress(1).toLowerCase()]).to.be.greaterThan(draws[getTestAddress(0).toLowerCase()]);
+ });
+ });
+
+ describe("Complex Multi-Court Scenarios", function () {
+ it("Should handle realistic court hierarchy simulation", async function () {
+ // Simulate: General Court (0) ← Tech Court (1) ← Blockchain Court (2)
+ const courts = [0, 1, 2];
+ const jurors = [getTestAddress(0), getTestAddress(1), getTestAddress(2), getTestAddress(3)];
+
+ // General lawyers (stake in General Court only)
+ await sortitionTree.set(0, jurors[0], 100);
+ await sortitionTree.set(0, jurors[1], 150);
+
+ // Tech specialists (stake in both General and Tech)
+ await sortitionTree.set(0, jurors[2], 200);
+ await sortitionTree.set(1, jurors[2], 300);
+
+ // Blockchain experts (stake in all three)
+ await sortitionTree.set(0, jurors[3], 250);
+ await sortitionTree.set(1, jurors[3], 350);
+ await sortitionTree.set(2, jurors[3], 450);
+
+ // Verify hierarchy totals
+ expect(await sortitionTree.getRootSum(0)).to.equal(700); // All jurors
+ expect(await sortitionTree.getRootSum(1)).to.equal(650); // Tech specialists + experts
+ expect(await sortitionTree.getRootSum(2)).to.equal(450); // Blockchain experts only
+
+ // Test drawing from most specialized court (should only get experts)
+ const [blockchainExpert] = await sortitionTree.draw(2, 1, 1, 12345);
+ expect(blockchainExpert.toLowerCase()).to.equal(jurors[3].toLowerCase());
+ });
+
+ it("Should handle dynamic court operations", async function () {
+ const juror = getTestAddress(0);
+
+ // Juror starts in general court
+ await sortitionTree.set(0, juror, 100);
+ expect(await sortitionTree.stakeOf(0, juror)).to.equal(100);
+
+ // Juror specializes in tech court
+ await sortitionTree.set(1, juror, 200);
+ expect(await sortitionTree.stakeOf(0, juror)).to.equal(100);
+ expect(await sortitionTree.stakeOf(1, juror)).to.equal(200);
+
+ // Juror reduces general court involvement but increases tech specialization
+ await sortitionTree.set(0, juror, 50);
+ await sortitionTree.set(1, juror, 400);
+ expect(await sortitionTree.stakeOf(0, juror)).to.equal(50);
+ expect(await sortitionTree.stakeOf(1, juror)).to.equal(400);
+
+ // Juror completely leaves general court
+ await sortitionTree.set(0, juror, 0);
+ expect(await sortitionTree.stakeOf(0, juror)).to.equal(0);
+ expect(await sortitionTree.stakeOf(1, juror)).to.equal(400);
+ });
+
+ it("Should handle large multi-court operations efficiently", async function () {
+ const numCourts = 5;
+ const numJurors = 10;
+
+ // Create additional courts
+ for (let courtID = 3; courtID < numCourts; courtID++) {
+ await sortitionTree.createTree(courtID, 2);
+ }
+
+ // Add many jurors across many courts
+ for (let jurorIdx = 0; jurorIdx < numJurors; jurorIdx++) {
+ for (let courtID = 0; courtID < numCourts; courtID++) {
+ const stake = (jurorIdx + 1) * (courtID + 1) * 10; // Varied stakes
+ await sortitionTree.set(courtID, getTestAddress(jurorIdx), stake);
+ }
+ }
+
+ // Verify all operations completed successfully
+ for (let courtID = 0; courtID < numCourts; courtID++) {
+ const rootSum = await sortitionTree.getRootSum(courtID);
+ expect(rootSum).to.be.greaterThan(0);
+
+ // Should be able to draw from each court
+ const [drawnAddress] = await sortitionTree.draw(courtID, 1, 1, 12345 + courtID);
+ expect(drawnAddress).to.not.equal(ethers.ZeroAddress);
+ }
+ });
+ });
+ });
+
+ describe("Edge Cases & Error Conditions", function () {
+ it("Should handle operations on non-existent courts", async function () {
+ const juror = getTestAddress(0);
+
+ // Operations on non-existent court should behave predictably
+ expect(await sortitionTree.courtExists(999)).to.be.false;
+ expect(await sortitionTree.stakeOf(999, juror)).to.equal(0);
+
+ // Drawing from non-existent court should revert (no tree = no nodes array)
+ await expect(sortitionTree.draw(999, 1, 1, 12345)).to.be.reverted;
+ });
+
+ it("Should handle boundary values correctly", async function () {
+ await sortitionTree.createTree(0, 2);
+ const juror = getTestAddress(0);
+
+ // Test with maximum stake value
+ const maxStake = ethers.MaxUint256;
+
+ // This might fail due to gas limits, but should not revert due to overflow
+ // Note: In practice, stakes would be much smaller
+ try {
+ await sortitionTree.set(0, juror, maxStake);
+ expect(await sortitionTree.stakeOf(0, juror)).to.equal(maxStake);
+ } catch (error) {
+ // Expected to fail due to gas limits, not due to overflow
+ expect(error).to.match(/gas/i);
+ }
+ });
+
+ it("Should maintain tree invariants under stress", async function () {
+ await sortitionTree.createTree(0, 3);
+
+ const operations = [];
+ const stakes = [100, 200, 300, 400, 500];
+ const jurors = stakes.map((_, i) => getTestAddress(i));
+
+ // Perform many random operations
+ for (let i = 0; i < 20; i++) {
+ const juror = jurors[i % jurors.length];
+ const stake = stakes[i % stakes.length];
+
+ await sortitionTree.set(0, juror, stake);
+ operations.push({ juror, stake });
+ }
+
+ // Verify tree integrity
+ let expectedTotal = 0;
+ const finalStakes = new Map();
+
+ // Calculate expected final state
+ for (const op of operations) {
+ const prevStake = finalStakes.get(op.juror) || 0;
+ expectedTotal = expectedTotal - prevStake + op.stake;
+ finalStakes.set(op.juror, op.stake);
+ }
+
+ // Verify actual state matches expected
+ expect(await sortitionTree.getRootSum(0)).to.equal(expectedTotal);
+
+ for (const [juror, expectedStake] of finalStakes) {
+ expect(await sortitionTree.stakeOf(0, juror)).to.equal(expectedStake);
+ }
+ });
+
+ it("Should handle rapid stake changes correctly", async function () {
+ await sortitionTree.createTree(0, 2);
+ const juror = getTestAddress(0);
+
+ // Rapid stake changes
+ const stakeSequence = [100, 0, 200, 300, 0, 150, 0, 500];
+
+ for (const stake of stakeSequence) {
+ await sortitionTree.set(0, juror, stake);
+ expect(await sortitionTree.stakeOf(0, juror)).to.equal(stake);
+ expect(await sortitionTree.getRootSum(0)).to.equal(stake);
+ }
+ });
+ });
+});
diff --git a/cspell.json b/cspell.json
index 0ab3e541c..0fa6dc52c 100644
--- a/cspell.json
+++ b/cspell.json
@@ -35,6 +35,7 @@
"IERC",
"Initializable",
"ipfs",
+ "IRNG",
"kleros",
"linguo",
"Numberish",
diff --git a/foundry.toml b/foundry.toml
new file mode 100644
index 000000000..fad3d8b70
--- /dev/null
+++ b/foundry.toml
@@ -0,0 +1,12 @@
+# For `forge doc` only which requires running from the top-level folder
+[profile.default]
+solc = "0.8.30"
+evm_version = "cancun"
+via_ir = true
+optimizer = true
+optimizer_runs = 10000
+
+src = 'contracts/src'
+out = 'contracts/out'
+libs = ['./node_modules', 'contracts/lib']
+
diff --git a/package.json b/package.json
index 6c9deb2d4..6104cc7cc 100644
--- a/package.json
+++ b/package.json
@@ -77,7 +77,8 @@
"elliptic@npm:6.5.4": "npm:6.6.1",
"word-wrap@npm:~1.2.3": "npm:1.2.5",
"@codemirror/state": "npm:6.5.2",
- "undici@npm:7.3.0": "npm:7.5.0"
+ "undici@npm:7.3.0": "npm:7.5.0",
+ "viem@npm:2.x": "npm:^2.23.2"
},
"scripts": {
"check-prerequisites": "scripts/check-prerequisites.sh",
@@ -86,7 +87,9 @@
"postinstall": "yarn check-prerequisites; husky install",
"reinstall": "YARN_CHECKSUM_BEHAVIOR=update yarn install --no-immutable",
"build:web:ci": "yarn workspaces focus @kleros/kleros-v2-web && yarn workspaces foreach -Ap --include kleros-app --include contracts run build && yarn workspace @kleros/kleros-v2-web build-netlify",
- "build:web-devtools:ci": "yarn workspaces focus @kleros/kleros-v2-web-devtools && yarn workspaces foreach -Ap --include contracts run build && yarn workspace @kleros/kleros-v2-web-devtools build-netlify"
+ "build:web-devtools:ci": "yarn workspaces focus @kleros/kleros-v2-web-devtools && yarn workspaces foreach -Ap --include contracts run build && yarn workspace @kleros/kleros-v2-web-devtools build-netlify",
+ "build:contract-docs": "forge doc --build --out contracts/dist",
+ "start:contract-docs": "forge doc --serve"
},
"alias": {
"process": "process/browser.js",
diff --git a/remappings.txt b/remappings.txt
new file mode 100644
index 000000000..c54475ab1
--- /dev/null
+++ b/remappings.txt
@@ -0,0 +1,9 @@
+@ensdomains/=node_modules/@ensdomains/
+@openzeppelin/=node_modules/@openzeppelin/
+@kleros/=node_modules/@kleros/
+ds-test/=contracts/
+forge-std/=contracts/
+eth-gas-reporter/=node_modules/eth-gas-reporter/
+hardhat-deploy/=node_modules/hardhat-deploy/
+hardhat/=node_modules/hardhat/
+solmate/=contracts/lib/solmate/src/
diff --git a/subgraph/core-university/subgraph.template.yaml b/subgraph/core-university/subgraph.template.yaml
index 9e83ab0ee..64d26223d 100644
--- a/subgraph/core-university/subgraph.template.yaml
+++ b/subgraph/core-university/subgraph.template.yaml
@@ -157,6 +157,6 @@ dataSources:
eventHandlers:
- event: StakeLocked(indexed address,uint256,bool)
handler: handleStakeLocked
- - event: StakeSet(indexed address,uint256,uint256,uint256)
+ - event: StakeSet(indexed address,uint256,uint256)
handler: handleStakeSet
file: ./src/SortitionModule.ts
diff --git a/subgraph/core-university/subgraph.yaml b/subgraph/core-university/subgraph.yaml
index d820954c8..38b181ffd 100644
--- a/subgraph/core-university/subgraph.yaml
+++ b/subgraph/core-university/subgraph.yaml
@@ -1,5 +1,7 @@
# THIS FILE IS AUTO-GENERATED BY update.sh FROM subgraph.template.yaml, ANY CHANGES WILL BE LOST.
specVersion: 0.0.5
+description: Kleros v2 Core University
+repository: https://github.com/kleros/kleros-v2/tree/dev/subgraph/core-university
schema:
file: ./schema.graphql
features:
@@ -65,9 +67,9 @@ dataSources:
name: PolicyRegistry
network: arbitrum-sepolia
source:
- address: "0x31d067405184d7FaA64b0834511cBcFAF32CdC4b"
+ address: "0xd8681dBF525ecBda2F799BFddB96840065075e8A"
abi: PolicyRegistry
- startBlock: 141215158
+ startBlock: 175286057
mapping:
kind: ethereum/events
apiVersion: 0.0.7
@@ -120,9 +122,9 @@ dataSources:
name: EvidenceModule
network: arbitrum-sepolia
source:
- address: "0x990f44d19a5F46889801B31bf58e0536fBECf27C"
+ address: "0xA1F72e0445fc395A393247F5B8c958Ec9b7C0B49"
abi: EvidenceModule
- startBlock: 141215177
+ startBlock: 175286065
mapping:
kind: ethereum/events
apiVersion: 0.0.7
@@ -156,6 +158,6 @@ dataSources:
eventHandlers:
- event: StakeLocked(indexed address,uint256,bool)
handler: handleStakeLocked
- - event: StakeSet(indexed address,uint256,uint256,uint256)
+ - event: StakeSet(indexed address,uint256,uint256)
handler: handleStakeSet
file: ./src/SortitionModule.ts
diff --git a/web/netlify.toml b/web/netlify.toml
index 8cf55aefd..3f6682c22 100644
--- a/web/netlify.toml
+++ b/web/netlify.toml
@@ -9,3 +9,8 @@ YARN_ENABLE_GLOBAL_CACHE = "true"
[functions]
directory = "web/netlify/functions/"
+
+[[headers]]
+ for = "/*"
+ [headers.values]
+ X-Robots-Tag = "llms-txt"
\ No newline at end of file
diff --git a/web/package.json b/web/package.json
index 11d688844..d17e27f70 100644
--- a/web/package.json
+++ b/web/package.json
@@ -91,6 +91,7 @@
"@kleros/ui-components-library": "^2.20.0",
"@lifi/wallet-management": "^3.7.1",
"@lifi/widget": "^3.18.1",
+ "@mdxeditor/editor": "^3.45.0",
"@reown/appkit": "^1.7.1",
"@reown/appkit-adapter-wagmi": "^1.7.1",
"@sentry/react": "^7.120.0",
@@ -127,6 +128,9 @@
"react-scripts": "^5.0.1",
"react-toastify": "^9.1.3",
"react-use": "^17.5.1",
+ "rehype-raw": "^7.0.0",
+ "rehype-sanitize": "^6.0.0",
+ "remark-gfm": "^3.0.1",
"styled-components": "^5.3.3",
"subgraph-status": "^1.2.4",
"viem": "^2.24.1",
diff --git a/web/src/components/DisputeFeatures/Features/ClassicVote.tsx b/web/src/components/DisputeFeatures/Features/ClassicVote.tsx
new file mode 100644
index 000000000..44f3bf237
--- /dev/null
+++ b/web/src/components/DisputeFeatures/Features/ClassicVote.tsx
@@ -0,0 +1,33 @@
+import React from "react";
+
+import { Features } from "consts/disputeFeature";
+import { useNewDisputeContext } from "context/NewDisputeContext";
+
+import { useCourtDetails } from "queries/useCourtDetails";
+
+import WithHelpTooltip from "components/WithHelpTooltip";
+
+import { RadioInput, StyledRadio } from ".";
+
+const ClassicVote: React.FC = (props) => {
+ const { disputeData } = useNewDisputeContext();
+ const { data: courtData } = useCourtDetails(disputeData.courtId);
+ const isCommitEnabled = Boolean(courtData?.court?.hiddenVotes);
+ return (
+
+
+
+ );
+};
+
+export default ClassicVote;
diff --git a/web/src/components/DisputeFeatures/Features/GatedErc1155.tsx b/web/src/components/DisputeFeatures/Features/GatedErc1155.tsx
new file mode 100644
index 000000000..3d48228c1
--- /dev/null
+++ b/web/src/components/DisputeFeatures/Features/GatedErc1155.tsx
@@ -0,0 +1,122 @@
+import React, { Fragment, useEffect, useMemo } from "react";
+import styled from "styled-components";
+
+import { Field } from "@kleros/ui-components-library";
+
+import { Features } from "consts/disputeFeature";
+import { IGatedDisputeData, useNewDisputeContext } from "context/NewDisputeContext";
+import { useERC1155Validation } from "hooks/useTokenAddressValidation";
+
+import { isUndefined } from "src/utils";
+
+import WithHelpTooltip from "components/WithHelpTooltip";
+
+import { RadioInput, StyledRadio } from ".";
+
+const FieldContainer = styled.div`
+ width: 100%;
+ padding-left: 32px;
+`;
+
+const StyledField = styled(Field)`
+ width: 100%;
+ margin-top: 8px;
+ margin-bottom: 32px;
+ > small {
+ margin-top: 16px;
+ }
+`;
+
+const GatedErc1155: React.FC = (props) => {
+ const { disputeData, setDisputeData } = useNewDisputeContext();
+
+ const tokenGateAddress = (disputeData.disputeKitData as IGatedDisputeData)?.tokenGate ?? "";
+ const validationEnabled = !isUndefined(tokenGateAddress) && tokenGateAddress.trim() !== "";
+
+ const {
+ isValidating,
+ isValid,
+ error: validationError,
+ } = useERC1155Validation({
+ address: tokenGateAddress,
+ enabled: validationEnabled && props.checked,
+ });
+
+ const [validationMessage, variant] = useMemo(() => {
+ if (isValidating) return [`Validating ERC-1155 token...`, "info"];
+ else if (validationError) return [validationError, "error"];
+ else if (isValid === true) return [`Valid ERC-1155 token`, "success"];
+ else return [undefined, "info"];
+ }, [isValidating, validationError, isValid]);
+
+ // Update validation state in dispute context
+ useEffect(() => {
+ // this can clash with erc20 check
+ if (!props.checked) return;
+ // Only update if isValid has actually changed
+ if (disputeData.disputeKitData) {
+ const currentData = disputeData.disputeKitData as IGatedDisputeData;
+
+ if (currentData.isTokenGateValid !== isValid) {
+ setDisputeData({
+ ...disputeData,
+ disputeKitData: { ...currentData, isTokenGateValid: isValid },
+ });
+ }
+ }
+ }, [isValid, setDisputeData, props.checked]);
+
+ const handleTokenAddressChange = (event: React.ChangeEvent) => {
+ const currentData = disputeData.disputeKitData as IGatedDisputeData;
+
+ setDisputeData({
+ ...disputeData,
+ disputeKitData: {
+ ...currentData,
+ tokenGate: event.target.value,
+ isTokenGateValid: null, // Reset validation state when address changes
+ },
+ });
+ };
+
+ const handleTokenIdChange = (event: React.ChangeEvent) => {
+ const currentData = disputeData.disputeKitData as IGatedDisputeData;
+ // DEV: we only update the tokenGate value here, and the disputeKidID,
+ // and type are still handled in Resolver/Court/FeatureSelection.tsx
+ setDisputeData({
+ ...disputeData,
+ disputeKitData: { ...currentData, tokenId: event.target.value },
+ });
+ };
+
+ return (
+
+
+
+
+ {props.checked ? (
+
+
+
+
+ ) : null}
+
+ );
+};
+
+export default GatedErc1155;
diff --git a/web/src/components/DisputeFeatures/Features/GatedErc20.tsx b/web/src/components/DisputeFeatures/Features/GatedErc20.tsx
new file mode 100644
index 000000000..1ac053b42
--- /dev/null
+++ b/web/src/components/DisputeFeatures/Features/GatedErc20.tsx
@@ -0,0 +1,106 @@
+import React, { Fragment, useEffect, useMemo } from "react";
+import styled from "styled-components";
+
+import { Field } from "@kleros/ui-components-library";
+
+import { Features } from "consts/disputeFeature";
+import { IGatedDisputeData, useNewDisputeContext } from "context/NewDisputeContext";
+import { useERC20ERC721Validation } from "hooks/useTokenAddressValidation";
+
+import { isUndefined } from "src/utils";
+
+import WithHelpTooltip from "components/WithHelpTooltip";
+
+import { RadioInput, StyledRadio } from ".";
+
+const FieldContainer = styled.div`
+ width: 100%;
+ padding-left: 32px;
+`;
+
+const StyledField = styled(Field)`
+ width: 100%;
+ margin-top: 8px;
+ margin-bottom: 32px;
+ > small {
+ margin-top: 16px;
+ }
+`;
+
+const GatedErc20: React.FC = (props) => {
+ const { disputeData, setDisputeData } = useNewDisputeContext();
+
+ const tokenGateAddress = (disputeData.disputeKitData as IGatedDisputeData)?.tokenGate ?? "";
+ const validationEnabled = !isUndefined(tokenGateAddress) && tokenGateAddress.trim() !== "";
+
+ const {
+ isValidating,
+ isValid,
+ error: validationError,
+ } = useERC20ERC721Validation({
+ address: tokenGateAddress,
+ enabled: validationEnabled && props.checked,
+ });
+
+ const [validationMessage, variant] = useMemo(() => {
+ if (isValidating) return [`Validating ERC-20 or ERC-721 token...`, "info"];
+ else if (validationError) return [validationError, "error"];
+ else if (isValid === true) return [`Valid ERC-20 or ERC-721 token`, "success"];
+ else return [undefined, "info"];
+ }, [isValidating, validationError, isValid]);
+
+ // Update validation state in dispute context
+ useEffect(() => {
+ // this can clash with erc1155 check
+ if (!props.checked) return;
+ if (disputeData.disputeKitData) {
+ const currentData = disputeData.disputeKitData as IGatedDisputeData;
+
+ if (currentData.isTokenGateValid !== isValid) {
+ setDisputeData({
+ ...disputeData,
+ disputeKitData: { ...currentData, isTokenGateValid: isValid },
+ });
+ }
+ }
+ }, [isValid, setDisputeData, props.checked]);
+
+ const handleTokenAddressChange = (event: React.ChangeEvent) => {
+ const currentData = disputeData.disputeKitData as IGatedDisputeData;
+ // DEV: we only update the tokenGate value here, and the disputeKidID,
+ // and type are still handled in Resolver/Court/FeatureSelection.tsx
+ setDisputeData({
+ ...disputeData,
+ disputeKitData: {
+ ...currentData,
+ tokenGate: event.target.value,
+ isTokenGateValid: null, // Reset validation state when address changes
+ },
+ });
+ };
+
+ return (
+
+
+
+
+ {props.checked ? (
+
+
+
+ ) : null}
+
+ );
+};
+
+export default GatedErc20;
diff --git a/web/src/components/DisputeFeatures/Features/index.tsx b/web/src/components/DisputeFeatures/Features/index.tsx
new file mode 100644
index 000000000..c98cc77e0
--- /dev/null
+++ b/web/src/components/DisputeFeatures/Features/index.tsx
@@ -0,0 +1,51 @@
+import React from "react";
+import styled from "styled-components";
+
+import { Radio } from "@kleros/ui-components-library";
+
+import { Features } from "consts/disputeFeature";
+
+import WithHelpTooltip from "components/WithHelpTooltip";
+
+import ClassicVote from "./ClassicVote";
+import GatedErc1155 from "./GatedErc1155";
+import GatedErc20 from "./GatedErc20";
+
+export type RadioInput = {
+ name: string;
+ value: Features;
+ checked: boolean;
+ disabled: boolean;
+ onClick: () => void;
+};
+
+export type FeatureUI = React.FC;
+
+export const StyledRadio = styled(Radio)`
+ font-size: 14px;
+ color: ${({ theme, disabled }) => (disabled ? theme.secondaryText : theme.primaryText)};
+ opacity: ${({ disabled }) => (disabled ? "0.7" : 1)};
+`;
+
+export const FeatureUIs: Record = {
+ [Features.ShieldedVote]: (props: RadioInput) => (
+
+
+
+ ),
+
+ [Features.ClassicVote]: (props: RadioInput) => ,
+
+ [Features.ClassicEligibility]: (props: RadioInput) => (
+
+ ),
+
+ [Features.GatedErc20]: (props: RadioInput) => ,
+
+ [Features.GatedErc1155]: (props: RadioInput) => ,
+};
diff --git a/web/src/components/DisputeFeatures/GroupsUI.tsx b/web/src/components/DisputeFeatures/GroupsUI.tsx
new file mode 100644
index 000000000..63b1b2e1b
--- /dev/null
+++ b/web/src/components/DisputeFeatures/GroupsUI.tsx
@@ -0,0 +1,76 @@
+import React from "react";
+import styled from "styled-components";
+
+import { Group } from "consts/disputeFeature";
+
+import LightButton from "../LightButton";
+
+const Container = styled.div`
+ width: 100%;
+ display: flex;
+ flex-direction: column;
+ gap: 16px;
+ align-items: start;
+ padding-bottom: 16px;
+`;
+
+const HeaderContainer = styled.div`
+ width: 100%;
+ padding-top: 16px;
+`;
+
+const Header = styled.h2`
+ display: flex;
+ font-size: 16px;
+ font-weight: 600;
+ margin: 0;
+ align-items: center;
+ gap: 8px;
+`;
+
+const SubTitle = styled.p`
+ font-size: 14px;
+ color: ${({ theme }) => theme.secondaryText};
+ padding: 0;
+ margin: 0;
+`;
+
+const StyledLightButton = styled(LightButton)`
+ padding: 0 !important;
+ .button-text {
+ color: ${({ theme }) => theme.primaryBlue};
+ font-size: 14px;
+ }
+ :hover {
+ background-color: transparent !important;
+ .button-text {
+ color: ${({ theme }) => theme.secondaryBlue};
+ }
+ }
+`;
+
+export type GroupUI = (props: { children: JSX.Element; clearAll: () => void }) => JSX.Element;
+export const GroupsUI: Record = {
+ [Group.Voting]: ({ children, clearAll }) => (
+
+
+
+ This feature hides the jurors votes until the end of the voting period.
+
+ {children}
+
+ ),
+ [Group.Eligibility]: ({ children, clearAll }) => (
+
+
+
+ This feature determines who can be selected as a juror.
+
+ {children}
+
+ ),
+};
diff --git a/web/src/components/DisputePreview/DisputeContext.tsx b/web/src/components/DisputePreview/DisputeContext.tsx
index 435bc47a8..70111de69 100644
--- a/web/src/components/DisputePreview/DisputeContext.tsx
+++ b/web/src/components/DisputePreview/DisputeContext.tsx
@@ -1,26 +1,27 @@
import React, { useMemo } from "react";
import styled from "styled-components";
-import { DisputeDetails } from "@kleros/kleros-sdk/src/dataMappings/utils/disputeDetailsTypes";
import { useAccount } from "wagmi";
+import { DisputeDetails } from "@kleros/kleros-sdk/src/dataMappings/utils/disputeDetailsTypes";
+
import { INVALID_DISPUTE_DATA_ERROR, RPC_ERROR } from "consts/index";
import { Answer as IAnswer } from "context/NewDisputeContext";
import { isUndefined } from "utils/index";
-import { responsiveSize } from "styles/responsiveSize";
-
import { DisputeDetailsQuery, VotingHistoryQuery } from "src/graphql/graphql";
-import ReactMarkdown from "components/ReactMarkdown";
+import { responsiveSize } from "styles/responsiveSize";
+
+import MarkdownRenderer from "components/MarkdownRenderer";
import { StyledSkeleton } from "components/StyledSkeleton";
+import CardLabel from "../DisputeView/CardLabels";
import { Divider } from "../Divider";
import { ExternalLink } from "../ExternalLink";
+import RulingAndRewardsIndicators from "../Verdict/RulingAndRewardsIndicators";
import AliasDisplay from "./Alias";
-import RulingAndRewardsIndicators from "../Verdict/RulingAndRewardsIndicators";
-import CardLabel from "../DisputeView/CardLabels";
const StyledH1 = styled.h1`
margin: 0;
@@ -134,12 +135,12 @@ export const DisputeContext: React.FC = ({
{disputeDetails?.question?.trim() ? (
- {disputeDetails.question}
+
) : null}
{disputeDetails?.description?.trim() ? (
- {disputeDetails.description}
+
) : null}
diff --git a/web/src/components/DisputeView/CardLabels/index.tsx b/web/src/components/DisputeView/CardLabels/index.tsx
index d6ca94a56..6a37e8a8e 100644
--- a/web/src/components/DisputeView/CardLabels/index.tsx
+++ b/web/src/components/DisputeView/CardLabels/index.tsx
@@ -61,13 +61,13 @@ interface ICardLabels {
}
const LabelArgs: Record>; color: IColors }> = {
- EvidenceTime: { text: "Evidence Time", icon: EvidenceIcon, color: "blue" },
- NotDrawn: { text: "Not Drawn", icon: NotDrawnIcon, color: "grey" },
- CanVote: { text: "Time to vote", icon: CanVoteIcon, color: "blue" },
- Voted: { text: "I voted", icon: VotedIcon, color: "purple" },
- DidNotVote: { text: "Didn't cast a vote", icon: ForgotToVoteIcon, color: "purple" },
+ EvidenceTime: { text: "Evidence time", icon: EvidenceIcon, color: "blue" },
+ NotDrawn: { text: "You were not drawn", icon: NotDrawnIcon, color: "grey" },
+ CanVote: { text: "You can vote now", icon: CanVoteIcon, color: "blue" },
+ Voted: { text: "You voted", icon: VotedIcon, color: "purple" },
+ DidNotVote: { text: "You did not vote", icon: ForgotToVoteIcon, color: "purple" },
CanFund: { text: "Appeal possible", icon: AppealIcon, color: "lightPurple" },
- Funded: { text: "I funded", icon: FundedIcon, color: "lightPurple" },
+ Funded: { text: "You funded an appeal", icon: FundedIcon, color: "lightPurple" },
};
const getFundingRewards = (contributions: ClassicContribution[], closed: boolean) => {
diff --git a/web/src/components/EvidenceCard.tsx b/web/src/components/EvidenceCard.tsx
index f17d97e26..90ea42f00 100644
--- a/web/src/components/EvidenceCard.tsx
+++ b/web/src/components/EvidenceCard.tsx
@@ -1,7 +1,6 @@
import React, { useMemo } from "react";
import styled, { css } from "styled-components";
-import ReactMarkdown from "react-markdown";
import { useParams } from "react-router-dom";
import { Card } from "@kleros/ui-components-library";
@@ -18,9 +17,11 @@ import { hoverShortTransitionTiming } from "styles/commonStyles";
import { landscapeStyle } from "styles/landscapeStyle";
import { responsiveSize } from "styles/responsiveSize";
+import JurorTitle from "pages/Home/TopJurors/JurorCard/JurorTitle";
+
import { ExternalLink } from "./ExternalLink";
import { InternalLink } from "./InternalLink";
-import JurorTitle from "pages/Home/TopJurors/JurorCard/JurorTitle";
+import MarkdownRenderer from "./MarkdownRenderer";
const StyledCard = styled(Card)`
width: 100%;
@@ -66,17 +67,6 @@ const Index = styled.p`
`;
const ReactMarkdownWrapper = styled.div``;
-const StyledReactMarkdown = styled(ReactMarkdown)`
- a {
- font-size: 16px;
- }
- code {
- color: ${({ theme }) => theme.secondaryText};
- }
- p {
- margin: 0;
- }
-`;
const BottomShade = styled.div`
background-color: ${({ theme }) => theme.lightBlue};
@@ -227,10 +217,12 @@ const EvidenceCard: React.FC = ({
{name && description ? (
- {description}
+
) : (
- {evidence}
+
+
+
)}
diff --git a/web/src/components/ExternalLinkWarning.tsx b/web/src/components/ExternalLinkWarning.tsx
new file mode 100644
index 000000000..ce2373dab
--- /dev/null
+++ b/web/src/components/ExternalLinkWarning.tsx
@@ -0,0 +1,170 @@
+import React from "react";
+import styled, { css } from "styled-components";
+
+import Modal from "react-modal";
+
+import { Button } from "@kleros/ui-components-library";
+
+import WarningIcon from "svgs/icons/warning-outline.svg";
+
+import { landscapeStyle } from "styles/landscapeStyle";
+
+const StyledModal = styled(Modal)`
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ right: auto;
+ bottom: auto;
+ margin-right: -50%;
+ transform: translate(-50%, -50%);
+ height: auto;
+ max-height: 90vh;
+ width: min(90%, 480px);
+ border: 1px solid ${({ theme }) => theme.stroke};
+ border-radius: 8px;
+ background-color: ${({ theme }) => theme.whiteBackground};
+ padding: 32px;
+ box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
+ z-index: 10002;
+ overflow-y: auto;
+`;
+
+const Overlay = styled.div`
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background-color: rgba(0, 0, 0, 0.5);
+ z-index: 10001;
+`;
+
+const Header = styled.div`
+ display: flex;
+ align-items: center;
+ gap: 12px;
+ margin-bottom: 16px;
+`;
+
+const StyledWarningIcon = styled(WarningIcon)`
+ width: 24px;
+ height: 24px;
+ fill: ${({ theme }) => theme.warning};
+`;
+
+const Title = styled.h3`
+ color: ${({ theme }) => theme.primaryText};
+ font-size: 18px;
+ font-weight: 600;
+ margin: 0;
+`;
+
+const Message = styled.p`
+ color: ${({ theme }) => theme.primaryText};
+ font-size: 14px;
+ line-height: 1.5;
+ margin: 0 0 16px 0;
+`;
+
+const UrlContainer = styled.div`
+ background-color: ${({ theme }) => theme.lightGrey};
+ border: 1px solid ${({ theme }) => theme.stroke};
+ border-radius: 4px;
+ padding: 12px;
+ margin: 16px 0;
+ word-break: break-all;
+`;
+
+const Url = styled.code`
+ color: ${({ theme }) => theme.secondaryText};
+ font-size: 13px;
+ font-family: monospace;
+`;
+
+const ButtonContainer = styled.div`
+ display: flex;
+ gap: 12px;
+ justify-content: center;
+ flex-wrap: wrap;
+ margin-top: 24px;
+
+ ${landscapeStyle(
+ () => css`
+ justify-content: flex-end;
+ `
+ )}
+`;
+
+const CancelButton = styled(Button)`
+ background-color: ${({ theme }) => theme.whiteBackground};
+ border: 1px solid ${({ theme }) => theme.stroke};
+
+ p {
+ color: ${({ theme }) => theme.primaryText} !important;
+ }
+
+ &:hover {
+ background-color: ${({ theme }) => theme.mediumBlue};
+ }
+`;
+
+const ConfirmButton = styled(Button)`
+ background-color: ${({ theme }) => theme.warning};
+ color: ${({ theme }) => theme.whiteBackground};
+ border: 1px solid ${({ theme }) => theme.warning};
+
+ &:hover {
+ background-color: ${({ theme }) => theme.warning}BB;
+ }
+`;
+
+interface IExternalLinkWarning {
+ isOpen: boolean;
+ url: string;
+ onConfirm: () => void;
+ onCancel: () => void;
+}
+
+const ExternalLinkWarning: React.FC = ({ isOpen, url, onConfirm, onCancel }) => {
+ return (
+ {contentElement} }
+ ariaHideApp={false}
+ role="dialog"
+ aria-labelledby="external-link-title"
+ aria-describedby="external-link-description"
+ >
+
+
+ External Link Warning
+
+
+
+ You are about to navigate to an external website. Please verify the URL before proceeding to ensure it's
+ safe and legitimate.
+
+
+
+ {url}
+
+
+
+ Safety Tips:
+
+ • Verify the domain name is correct
+
+ • Check for suspicious characters or typos
+ • Only proceed if you trust this destination
+
+
+
+
+
+
+
+ );
+};
+
+export default ExternalLinkWarning;
diff --git a/web/src/components/FileViewer/Viewers/MarkdownViewer.tsx b/web/src/components/FileViewer/Viewers/MarkdownViewer.tsx
index 0ee77ac37..e7cc14079 100644
--- a/web/src/components/FileViewer/Viewers/MarkdownViewer.tsx
+++ b/web/src/components/FileViewer/Viewers/MarkdownViewer.tsx
@@ -2,23 +2,14 @@ import React from "react";
import styled from "styled-components";
import { type DocRenderer } from "@cyntler/react-doc-viewer";
-import ReactMarkdown from "react-markdown";
+
+import MarkdownRenderer from "../../MarkdownRenderer";
const Container = styled.div`
padding: 16px;
`;
-const StyledMarkdown = styled(ReactMarkdown)`
- background-color: ${({ theme }) => theme.whiteBackground};
- a {
- font-size: 16px;
- }
- code {
- color: ${({ theme }) => theme.secondaryText};
- }
-`;
-
-const MarkdownRenderer: DocRenderer = ({ mainState: { currentDocument } }) => {
+const MarkdownDocRenderer: DocRenderer = ({ mainState: { currentDocument } }) => {
if (!currentDocument) return null;
const base64String = (currentDocument.fileData as string).split(",")[1];
@@ -27,12 +18,12 @@ const MarkdownRenderer: DocRenderer = ({ mainState: { currentDocument } }) => {
return (
- {decodedData}
+
);
};
-MarkdownRenderer.fileTypes = ["md", "text/plain"];
-MarkdownRenderer.weight = 1;
+MarkdownDocRenderer.fileTypes = ["md", "text/plain"];
+MarkdownDocRenderer.weight = 1;
-export default MarkdownRenderer;
+export default MarkdownDocRenderer;
diff --git a/web/src/components/MarkdownEditor.tsx b/web/src/components/MarkdownEditor.tsx
new file mode 100644
index 000000000..e49c4ffa2
--- /dev/null
+++ b/web/src/components/MarkdownEditor.tsx
@@ -0,0 +1,170 @@
+import React, { useRef } from "react";
+import styled from "styled-components";
+
+import {
+ MDXEditor,
+ type MDXEditorMethods,
+ type MDXEditorProps,
+ headingsPlugin,
+ listsPlugin,
+ quotePlugin,
+ thematicBreakPlugin,
+ markdownShortcutPlugin,
+ linkPlugin,
+ linkDialogPlugin,
+ tablePlugin,
+ codeBlockPlugin,
+ codeMirrorPlugin,
+ toolbarPlugin,
+ UndoRedo,
+ BoldItalicUnderlineToggles,
+ ListsToggle,
+ CreateLink,
+ InsertTable,
+ InsertCodeBlock,
+ BlockTypeSelect,
+ Separator,
+} from "@mdxeditor/editor";
+
+import InfoIcon from "svgs/icons/info-circle.svg";
+
+import { isValidUrl } from "utils/urlValidation";
+
+import { MDXEditorContainer, MDXEditorGlobalStyles } from "styles/mdxEditorTheme";
+
+import "@mdxeditor/editor/style.css";
+
+const Container = styled(MDXEditorContainer)<{ isEmpty: boolean }>``;
+
+const MessageContainer = styled.div`
+ display: flex;
+ align-items: flex-start;
+ gap: 8px;
+ margin-top: 8px;
+`;
+
+const MessageText = styled.small`
+ font-size: 14px;
+ font-weight: 400;
+ color: ${({ theme }) => theme.secondaryText};
+ hyphens: auto;
+ line-height: 1.4;
+`;
+
+const StyledInfoIcon = styled(InfoIcon)`
+ width: 16px;
+ height: 16px;
+ fill: ${({ theme }) => theme.secondaryText} !important;
+ flex-shrink: 0;
+ margin-top: 2px;
+
+ path {
+ fill: ${({ theme }) => theme.secondaryText} !important;
+ }
+
+ * {
+ fill: ${({ theme }) => theme.secondaryText} !important;
+ }
+`;
+
+interface IMarkdownEditor {
+ value: string;
+ onChange: (value: string) => void;
+ placeholder?: string;
+ showMessage?: boolean;
+}
+
+const MarkdownEditor: React.FC = ({
+ value,
+ onChange,
+ placeholder = "Justify your vote...",
+ showMessage = true,
+}) => {
+ const editorRef = useRef(null);
+
+ const handleChange = (markdown: string) => {
+ let cleanedMarkdown = markdown === "\u200B" ? "" : markdown.replace(/^\u200B/, "");
+ // Remove ALL escape characters - no exceptions
+ cleanedMarkdown = cleanedMarkdown.replace(/\\([`[]*_#|>-+=~^{}()!&<$%\\])/g, "$1");
+ // Also handle multiple consecutive backslashes that might accumulate
+ cleanedMarkdown = cleanedMarkdown.replace(/\\+/g, "");
+
+ onChange(cleanedMarkdown);
+ };
+
+ const handleContainerClick = () => {
+ if (isEmpty && editorRef.current) {
+ editorRef.current.setMarkdown("\u200B");
+ setTimeout(() => {
+ if (editorRef.current) {
+ editorRef.current.focus();
+ }
+ }, 0);
+ }
+ };
+
+ const isEmpty = !value || value.trim() === "";
+
+ const editorProps: MDXEditorProps = {
+ markdown: value,
+ onChange: handleChange,
+ placeholder,
+ suppressHtmlProcessing: true,
+ plugins: [
+ headingsPlugin(),
+ listsPlugin(),
+ quotePlugin(),
+ thematicBreakPlugin(),
+ markdownShortcutPlugin(),
+ linkPlugin({
+ validateUrl: (url) => isValidUrl(url),
+ }),
+ linkDialogPlugin(),
+ tablePlugin(),
+ codeBlockPlugin({ defaultCodeBlockLanguage: "text" }),
+ codeMirrorPlugin({
+ codeBlockLanguages: {
+ text: "Code",
+ },
+ }),
+ toolbarPlugin({
+ toolbarContents: () => (
+ <>
+
+
+
+
+
+
+
+
+
+
+
+ >
+ ),
+ }),
+ ],
+ };
+
+ return (
+ <>
+
+
+
+ {showMessage && (
+
+
+
+ Please provide a comprehensive justification for your decision. Quality explanations are essential for the
+ parties involved and may be eligible for additional compensation in accordance with our justification
+ policy.
+
+
+ )}
+
+ >
+ );
+};
+
+export default MarkdownEditor;
diff --git a/web/src/components/MarkdownRenderer.tsx b/web/src/components/MarkdownRenderer.tsx
new file mode 100644
index 000000000..4c6c47acf
--- /dev/null
+++ b/web/src/components/MarkdownRenderer.tsx
@@ -0,0 +1,404 @@
+import React, { useCallback, useEffect, useRef, useState } from "react";
+import styled from "styled-components";
+
+import ReactMarkdown from "react-markdown";
+import rehypeRaw from "rehype-raw";
+import rehypeSanitize from "rehype-sanitize";
+import remarkGfm from "remark-gfm";
+
+import { isExternalLink } from "utils/linkUtils";
+import { isValidUrl } from "utils/urlValidation";
+
+import ExternalLinkWarning from "components/ExternalLinkWarning";
+
+const MarkdownContainer = styled.div`
+ font-size: 16px;
+ line-height: 1.6;
+
+ *,
+ ** {
+ font-size: 16px;
+ }
+
+ a {
+ pointer-events: none;
+ cursor: pointer;
+ position: relative;
+
+ &::after {
+ content: "";
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ pointer-events: auto;
+ cursor: pointer;
+ }
+ }
+
+ pre {
+ background-color: ${({ theme }) => theme.lightBackground};
+ border-radius: 8px;
+ padding: 16px;
+ overflow-x: auto;
+ }
+
+ code {
+ background-color: ${({ theme }) => theme.lightBackground};
+ padding: 2px 4px;
+ border-radius: 4px;
+ font-family: "Fira Code", monospace;
+ }
+
+ pre code {
+ background-color: transparent;
+ padding: 0;
+ }
+
+ blockquote {
+ border-left: 4px solid ${({ theme }) => theme.primaryBlue};
+ margin: 16px 0;
+ padding-left: 16px;
+ color: ${({ theme }) => theme.secondaryText};
+ }
+
+ ul,
+ ol {
+ padding-left: 20px;
+ }
+
+ input[type="checkbox"] {
+ margin-right: 8px;
+ margin-top: 4px;
+ accent-color: ${({ theme }) => theme.primaryBlue};
+ cursor: default;
+ vertical-align: top;
+ }
+
+ h1,
+ h2,
+ h3,
+ h4,
+ h5,
+ h6 {
+ color: ${({ theme }) => theme.primaryText};
+ margin: 16px 0 8px 0;
+ line-height: 1.3;
+ }
+
+ h1 {
+ font-size: 2em;
+ font-weight: 700;
+ }
+
+ h2 {
+ font-size: 1.5em;
+ font-weight: 600;
+ }
+
+ h3 {
+ font-size: 1.25em;
+ font-weight: 600;
+ }
+
+ h4 {
+ font-size: 1.125em;
+ font-weight: 600;
+ }
+
+ h5 {
+ font-size: 1em;
+ font-weight: 600;
+ }
+
+ h6 {
+ font-size: 0.875em;
+ font-weight: 600;
+ }
+
+ pre {
+ color: ${({ theme }) => theme.primaryText};
+ }
+
+ pre code {
+ color: inherit;
+ }
+
+ code {
+ color: ${({ theme }) => theme.primaryText};
+ }
+
+ table {
+ border-collapse: collapse;
+ width: 100%;
+ margin: 16px 0;
+ border: 1px solid ${({ theme }) => theme.stroke};
+ }
+
+ th,
+ td {
+ border: 1px solid ${({ theme }) => theme.stroke};
+ padding: 8px 12px;
+ text-align: left;
+ }
+
+ th {
+ background-color: ${({ theme }) => theme.lightBackground};
+ color: ${({ theme }) => theme.primaryText};
+ font-weight: 600;
+ }
+
+ td {
+ color: ${({ theme }) => theme.primaryText};
+ }
+
+ tbody tr:nth-child(even) {
+ background-color: ${({ theme }) => theme.lightGrey};
+ }
+
+ details {
+ border: 1px solid ${({ theme }) => theme.stroke};
+ border-radius: 8px;
+ padding: 8px 12px;
+ margin: 16px 0;
+ background-color: ${({ theme }) => theme.lightBackground};
+ }
+
+ summary {
+ font-weight: 600;
+ cursor: pointer;
+ color: ${({ theme }) => theme.primaryText};
+ padding: 4px 0;
+ outline: none;
+ }
+
+ summary:hover {
+ color: ${({ theme }) => theme.primaryBlue};
+ }
+
+ details[open] summary {
+ margin-bottom: 8px;
+ border-bottom: 1px solid ${({ theme }) => theme.stroke};
+ padding-bottom: 8px;
+ }
+
+ u {
+ text-decoration: underline;
+ text-decoration-color: ${({ theme }) => theme.primaryText};
+ }
+
+ del,
+ s {
+ text-decoration: line-through;
+ text-decoration-color: ${({ theme }) => theme.secondaryText};
+ }
+
+ mark {
+ background-color: ${({ theme }) => theme.warning};
+ color: ${({ theme }) => theme.primaryText};
+ padding: 2px 4px;
+ border-radius: 2px;
+ }
+
+ sub,
+ sup {
+ font-size: 0.75em;
+ line-height: 0;
+ position: relative;
+ vertical-align: baseline;
+ }
+
+ sup {
+ top: -0.5em;
+ }
+
+ sub {
+ bottom: -0.25em;
+ }
+
+ kbd {
+ background-color: ${({ theme }) => theme.lightBackground};
+ border: 1px solid ${({ theme }) => theme.stroke};
+ border-radius: 4px;
+ box-shadow: 0 1px 1px ${({ theme }) => theme.stroke};
+ color: ${({ theme }) => theme.primaryText};
+ font-family: "Fira Code", monospace;
+ font-size: 0.875em;
+ padding: 2px 6px;
+ }
+
+ abbr {
+ text-decoration: underline dotted;
+ cursor: help;
+ }
+`;
+
+interface IMarkdownRenderer {
+ content: string;
+ className?: string;
+}
+
+const MarkdownRenderer: React.FC = ({ content, className }) => {
+ const [isWarningOpen, setIsWarningOpen] = useState(false);
+ const [pendingUrl, setPendingUrl] = useState("");
+ const containerRef = useRef(null);
+
+ const handleExternalLink = useCallback((url: string) => {
+ setPendingUrl(url);
+ setIsWarningOpen(true);
+ }, []);
+
+ const handleConfirmNavigation = useCallback(() => {
+ if (pendingUrl) {
+ window.open(pendingUrl, "_blank", "noopener,noreferrer");
+ }
+ setIsWarningOpen(false);
+ setPendingUrl("");
+ }, [pendingUrl]);
+
+ const handleCancelNavigation = useCallback(() => {
+ setIsWarningOpen(false);
+ setPendingUrl("");
+ }, []);
+
+ useEffect(() => {
+ const container = containerRef.current;
+ if (!container) return;
+
+ const handleClick = (event: Event) => {
+ const target = event.target as HTMLElement;
+
+ if (!container.contains(target)) {
+ return;
+ }
+
+ const linkElement = target.closest("a") as HTMLAnchorElement | null;
+
+ if (linkElement) {
+ const href = linkElement.getAttribute("href") || linkElement.href;
+ if (href && isValidUrl(href) && isExternalLink(href)) {
+ event.preventDefault();
+ event.stopImmediatePropagation();
+ handleExternalLink(href);
+ }
+ }
+ };
+
+ container.addEventListener("click", handleClick, true);
+
+ return () => {
+ container.removeEventListener("click", handleClick, true);
+ };
+ }, [handleExternalLink]);
+
+ if (!content || content.trim() === "") {
+ return null;
+ }
+
+ return (
+ <>
+
+ {
+ return (
+
+ {children}
+
+ );
+ },
+ }}
+ >
+ {content}
+
+
+
+ >
+ );
+};
+
+export default MarkdownRenderer;
diff --git a/web/src/components/NumberDisplay.tsx b/web/src/components/NumberDisplay.tsx
index fa0951825..d32a0ea23 100644
--- a/web/src/components/NumberDisplay.tsx
+++ b/web/src/components/NumberDisplay.tsx
@@ -35,7 +35,7 @@ const NumberDisplay: React.FC = ({
}) => {
const parsedValue = Number(value);
const formattedValue = commify(getFormattedValue(parsedValue, decimals));
- const tooltipValue = isCurrency ? `${unit} ${value}` : `${value} ${unit}`;
+ const tooltipValue = isCurrency ? `${unit} ${commify(value)}` : `${commify(value)} ${unit}`;
const displayUnit = showUnitInDisplay ? unit : "";
const displayValue = isCurrency ? `${displayUnit} ${formattedValue}` : `${formattedValue} ${displayUnit}`;
diff --git a/web/src/components/ReactMarkdown.tsx b/web/src/components/ReactMarkdown.tsx
deleted file mode 100644
index f7b52bb90..000000000
--- a/web/src/components/ReactMarkdown.tsx
+++ /dev/null
@@ -1,16 +0,0 @@
-import React from "react";
-import styled from "styled-components";
-
-import Reactmkdwn from "react-markdown";
-
-const StyledMarkdown = styled(Reactmkdwn)`
- font-size: 16px;
- *,
- ** {
- font-size: 16px;
- }
-`;
-
-const ReactMarkdown: React.FC<{ children: string }> = ({ children }) => {children} ;
-
-export default ReactMarkdown;
diff --git a/web/src/consts/disputeFeature.ts b/web/src/consts/disputeFeature.ts
new file mode 100644
index 000000000..f852047ac
--- /dev/null
+++ b/web/src/consts/disputeFeature.ts
@@ -0,0 +1,226 @@
+export enum Group {
+ Voting = "Voting",
+ Eligibility = "Eligibility",
+}
+
+/** A single feature, grouped into categories. has to be atomic.
+ * For gated, we split them into atomic erc20 and erc1155 */
+export enum Features {
+ ShieldedVote = "shieldedVote",
+ ClassicVote = "classicVote",
+ ClassicEligibility = "classicEligibility",
+ GatedErc20 = "gatedErc20",
+ GatedErc1155 = "gatedErc1155",
+}
+
+/** Group of features (like radio buttons per category) */
+export type FeatureGroups = Record;
+
+/** Definition of a dispute kit */
+export interface DisputeKit {
+ id: number;
+ /**
+ * The feature sets this kit supports.
+ * Each array represents a valid configuration, and has to be 1:1,
+ * if either subset matches the selected feature array this dispute kit is selected
+ */
+ featureSets: Features[][];
+
+ type: "general" | "gated";
+}
+
+export type DisputeKits = DisputeKit[];
+
+// groups
+// withing a group only one feature can be selected, we deselect the other one when a new one is selected
+// we don't use these directly in here for utils because these need to be filtered based on court selection.
+// NOTE: a feature cannot appear in more than one Group
+// DEV: the order of features in array , determine the order the radios appear on UI
+export const featureGroups: FeatureGroups = {
+ [Group.Voting]: [Features.ClassicVote, Features.ShieldedVote],
+ [Group.Eligibility]: [Features.ClassicEligibility, Features.GatedErc20, Features.GatedErc1155],
+};
+
+// dispute kits
+// each array is a unique match, for multiple combinations, add more arrays.
+export const disputeKits: DisputeKits = [
+ {
+ id: 1,
+ featureSets: [[Features.ClassicVote, Features.ClassicEligibility]],
+ type: "general",
+ }, // strict
+ { id: 2, featureSets: [[Features.ShieldedVote, Features.ClassicEligibility]], type: "general" }, // strict
+ {
+ id: 3,
+ // strictly keep the common feature in front and in order.
+ featureSets: [
+ [Features.ClassicVote, Features.GatedErc20],
+ [Features.ClassicVote, Features.GatedErc1155],
+ ],
+ type: "gated",
+ },
+ {
+ id: 4,
+ featureSets: [
+ [Features.ShieldedVote, Features.GatedErc20],
+ [Features.ShieldedVote, Features.GatedErc1155],
+ ],
+ type: "gated",
+ },
+];
+
+/** Canonical string for a feature set (order-independent) */
+function normalize(features: Features[]): string {
+ return [...features].sort().join("|");
+}
+
+/** Check if `a` is exactly the same as `b` (order-insensitive) */
+function arraysEqual(a: Features[], b: Features[]): boolean {
+ return normalize(a) === normalize(b);
+}
+
+/**
+ * Toggle a feature, ensuring radio behavior per group
+ * @returns the updated selected features array
+ */
+export function toggleFeature(selected: Features[], feature: Features, groups: FeatureGroups): Features[] {
+ const group = Object.entries(groups).find(([_, feats]) => feats.includes(feature));
+ if (!group) return selected; // not found in any group
+ const [_, features] = group; // <= this is the group we are making selection in currently
+
+ // Remove any feature from this group
+ const withoutGroup = selected.filter((f) => !features.includes(f));
+
+ // If it was already selected => deselect
+ if (selected.includes(feature)) {
+ return withoutGroup;
+ }
+
+ // Otherwise => select this one
+ return [...withoutGroup, feature];
+}
+
+/**
+ * Find dispute kits that match the given selection
+ */
+export function findMatchingKits(selected: Features[], kits: DisputeKits): DisputeKit[] {
+ return kits.filter((kit) =>
+ kit.featureSets.some(
+ (set) => arraysEqual(set, selected) // strict exact match
+ )
+ );
+}
+
+/**
+ * Ensures that the current selection of features is always in a valid state.
+ * We use this just to make sure we don't accidently allow user to select an invalid state in handleToggle
+ *
+ * "Valid" means:
+ * - Either matches at least one dispute kit fully, OR
+ * - Could still be completed into a valid kit (prefix of a valid set).
+ *
+ * If the selection is invalid:
+ * 1. Try removing one conflicting group to recover validity.
+ * 2. If nothing works, fallback to keeping only the last clicked feature.
+ *
+ * @returns A corrected selection that is guaranteed to be valid.
+ */
+export function ensureValidSmart(selected: Features[], groups: FeatureGroups, kits: DisputeKits): Features[] {
+ // --- Helper: checks if a candidate is valid or could still become valid ---
+ function isValidOrPrefix(candidate: Features[]): boolean {
+ return (
+ findMatchingKits(candidate, kits).length > 0 ||
+ kits.some((kit) =>
+ kit.featureSets.some(
+ (set) => candidate.every((f) => set.includes(f)) // prefix check
+ )
+ )
+ );
+ }
+
+ // --- Case 1: Current selection is already valid ---
+ if (isValidOrPrefix(selected)) {
+ return selected;
+ }
+
+ // --- Case 2: Try fixing by removing one group at a time ---
+ for (const [_, features] of Object.entries(groups)) {
+ const withoutGroup = selected.filter((f) => !features.includes(f));
+ if (isValidOrPrefix(withoutGroup)) {
+ return withoutGroup;
+ }
+ }
+
+ // --- Case 3: Fallback to only the last picked feature ---
+ return selected.length > 0 ? [selected[selected.length - 1]] : [];
+}
+
+// Checks if the candidate if selected, can still lead to a match
+function canStillLeadToMatch(candidate: Features[], kits: DisputeKits): boolean {
+ return kits.some((kit) =>
+ kit.featureSets.some((set) =>
+ // candidate must be subset of this set
+ candidate.every((f) => set.includes(f))
+ )
+ );
+}
+
+/**
+ * Compute which features should be disabled,
+ * given the current selection.
+ */
+export function getDisabledOptions(selected: Features[], groups: FeatureGroups, kits: DisputeKits): Set {
+ const disabled = new Set();
+
+ // If nothing is selected => allow all
+ if (selected.length === 0) {
+ return disabled;
+ }
+
+ for (const [_, features] of Object.entries(groups)) {
+ for (const feature of features) {
+ const candidate = toggleFeature(selected, feature, groups);
+
+ // Instead of only checking full matches:
+ const valid = findMatchingKits(candidate, kits).length > 0 || canStillLeadToMatch(candidate, kits);
+
+ if (!valid) {
+ disabled.add(feature);
+ }
+ }
+ }
+
+ return disabled;
+}
+
+/**
+ * Features that are visible for a given court,
+ * based only on the kits that court supports.
+ */
+export function getVisibleFeaturesForCourt(
+ supportedKits: number[],
+ allKits: DisputeKits,
+ groups: FeatureGroups
+): FeatureGroups {
+ // Get supported kits for this court
+ const filteredKits = allKits.filter((kit) => supportedKits.includes(kit.id));
+
+ // Gather all features that appear in these kits
+ const visible = new Set();
+ for (const kit of filteredKits) {
+ for (const set of kit.featureSets) {
+ set.forEach((f) => visible.add(f));
+ }
+ }
+
+ // Filter groups => only keep features that are visible
+ const filteredGroups: FeatureGroups = {};
+ for (const [groupName, features] of Object.entries(groups)) {
+ const visibleFeatures = features.filter((f) => visible.has(f));
+ if (visibleFeatures.length > 0) {
+ filteredGroups[groupName] = visibleFeatures;
+ }
+ }
+
+ return filteredGroups;
+}
diff --git a/web/src/context/NewDisputeContext.tsx b/web/src/context/NewDisputeContext.tsx
index 52abb696d..25fdb1ccd 100644
--- a/web/src/context/NewDisputeContext.tsx
+++ b/web/src/context/NewDisputeContext.tsx
@@ -4,10 +4,13 @@ import { useLocation } from "react-router-dom";
import { Address } from "viem";
import { DEFAULT_CHAIN } from "consts/chains";
+import { Features } from "consts/disputeFeature";
import { klerosCoreAddress } from "hooks/contracts/generated";
import { useLocalStorage } from "hooks/useLocalStorage";
import { isEmpty, isUndefined } from "utils/index";
+import { DisputeKits } from "src/consts";
+
export const MIN_DISPUTE_BATCH_SIZE = 2;
export type Answer = {
@@ -24,6 +27,12 @@ export type AliasArray = {
isValid?: boolean;
};
+export type DisputeKitOption = {
+ text: DisputeKits;
+ value: number;
+ gated: boolean;
+};
+
export type Alias = Record;
export interface IDisputeTemplate {
answers: Answer[];
@@ -61,6 +70,7 @@ export interface IGatedDisputeData {
isERC1155: boolean;
tokenGate: string;
tokenId: string;
+ isTokenGateValid?: boolean | null; // null = not validated, false = invalid, true = valid
}
// Placeholder
@@ -82,6 +92,8 @@ interface INewDisputeContext {
setIsBatchCreation: (isBatchCreation: boolean) => void;
batchSize: number;
setBatchSize: (batchSize?: number) => void;
+ selectedFeatures: Features[];
+ setSelectedFeatures: React.Dispatch>;
}
const getInitialDisputeData = (): IDisputeData => ({
@@ -117,6 +129,7 @@ export const NewDisputeProvider: React.FC<{ children: React.ReactNode }> = ({ ch
const [isPolicyUploading, setIsPolicyUploading] = useState(false);
const [isBatchCreation, setIsBatchCreation] = useState(false);
const [batchSize, setBatchSize] = useLocalStorage("disputeBatchSize", MIN_DISPUTE_BATCH_SIZE);
+ const [selectedFeatures, setSelectedFeatures] = useState([]);
const disputeTemplate = useMemo(() => constructDisputeTemplate(disputeData), [disputeData]);
const location = useLocation();
@@ -150,6 +163,8 @@ export const NewDisputeProvider: React.FC<{ children: React.ReactNode }> = ({ ch
setIsBatchCreation,
batchSize,
setBatchSize,
+ selectedFeatures,
+ setSelectedFeatures,
}),
[
disputeData,
@@ -162,6 +177,8 @@ export const NewDisputeProvider: React.FC<{ children: React.ReactNode }> = ({ ch
setIsBatchCreation,
batchSize,
setBatchSize,
+ selectedFeatures,
+ setSelectedFeatures,
]
);
diff --git a/web/src/hooks/queries/useCourtDetails.ts b/web/src/hooks/queries/useCourtDetails.ts
index 46795d763..5cfa7a2e9 100644
--- a/web/src/hooks/queries/useCourtDetails.ts
+++ b/web/src/hooks/queries/useCourtDetails.ts
@@ -26,6 +26,7 @@ const courtDetailsQuery = graphql(`
timesPerPeriod
feeForJuror
name
+ hiddenVotes
}
}
`);
diff --git a/web/src/hooks/useTokenAddressValidation.ts b/web/src/hooks/useTokenAddressValidation.ts
new file mode 100644
index 000000000..bb18addf0
--- /dev/null
+++ b/web/src/hooks/useTokenAddressValidation.ts
@@ -0,0 +1,217 @@
+import { useEffect, useState, useMemo } from "react";
+
+import { useQuery } from "@tanstack/react-query";
+import { getContract, isAddress } from "viem";
+import { usePublicClient, useChainId } from "wagmi";
+
+import { isUndefined } from "utils/index";
+
+const ERC1155_ABI = [
+ {
+ inputs: [
+ {
+ internalType: "address",
+ name: "account",
+ type: "address",
+ },
+ {
+ internalType: "uint256",
+ name: "id",
+ type: "uint256",
+ },
+ ],
+ name: "balanceOf",
+ outputs: [
+ {
+ internalType: "uint256",
+ name: "",
+ type: "uint256",
+ },
+ ],
+ stateMutability: "view",
+ type: "function",
+ },
+] as const;
+
+const ERC20_ERC721_ABI = [
+ {
+ inputs: [
+ {
+ internalType: "address",
+ name: "account",
+ type: "address",
+ },
+ ],
+ name: "balanceOf",
+ outputs: [
+ {
+ internalType: "uint256",
+ name: "",
+ type: "uint256",
+ },
+ ],
+ stateMutability: "view",
+ type: "function",
+ },
+] as const;
+
+interface UseTokenValidationParams {
+ address?: string;
+ enabled?: boolean;
+}
+
+interface TokenValidationResult {
+ isValidating: boolean;
+ isValid: boolean | null;
+ error: string | null;
+}
+
+/**
+ * Hook to validate if an address is a valid ERC20 or ERC721 token by attempting to call balanceOf(address)
+ * @param address The address to validate
+ * @param enabled Whether validation should be enabled
+ * @returns Validation state including loading, result, and error
+ */
+export const useERC20ERC721Validation = ({
+ address,
+ enabled = true,
+}: UseTokenValidationParams): TokenValidationResult => {
+ // We query the balance for a random non-zero address because many implementations revert on it
+ return useTokenValidation({
+ address,
+ enabled,
+ abi: ERC20_ERC721_ABI,
+ contractCall: (contract) => contract.read.balanceOf(["0x0000000000000000000000000000000000001234"]),
+ tokenType: "ERC-20 or ERC-721",
+ });
+};
+
+/**
+ * Hook to validate if an address is a valid ERC1155 token by attempting to call balanceOf(address, tokenId)
+ * @param address The address to validate
+ * @param enabled Whether validation should be enabled
+ * @returns Validation state including loading, result, and error
+ */
+export const useERC1155Validation = ({ address, enabled = true }: UseTokenValidationParams): TokenValidationResult => {
+ // We query the balance for a random non-zero address because many implementations revert on it
+ return useTokenValidation({
+ address,
+ enabled,
+ abi: ERC1155_ABI,
+ contractCall: (contract) => contract.read.balanceOf(["0x0000000000000000000000000000000000001234", 0]),
+ tokenType: "ERC-1155",
+ });
+};
+
+/**
+ * Generic hook for token contract validation
+ */
+const useTokenValidation = ({
+ address,
+ enabled = true,
+ abi,
+ contractCall,
+ tokenType,
+}: UseTokenValidationParams & {
+ abi: readonly any[];
+ contractCall: (contract: any) => Promise;
+ tokenType: string;
+}): TokenValidationResult => {
+ const publicClient = usePublicClient();
+ const chainId = useChainId();
+ const [debouncedAddress, setDebouncedAddress] = useState();
+
+ // Debounce address changes to avoid excessive network calls
+ useEffect(() => {
+ const timer = setTimeout(() => {
+ setDebouncedAddress(address);
+ }, 500);
+
+ return () => clearTimeout(timer);
+ }, [address]);
+
+ // Early validation - check format
+ const isValidFormat = useMemo(() => {
+ if (!debouncedAddress || debouncedAddress.trim() === "") return null;
+ return isAddress(debouncedAddress);
+ }, [debouncedAddress]);
+
+ // Contract validation query
+ const {
+ data: isValidContract,
+ isLoading,
+ error,
+ } = useQuery({
+ queryKey: [`${tokenType}-validation`, chainId, debouncedAddress],
+ enabled: enabled && !isUndefined(publicClient) && Boolean(isValidFormat),
+ staleTime: 300000, // Cache for 5 minutes
+ retry: 1, // Only retry once to fail faster
+ retryDelay: 1000, // Short retry delay
+ queryFn: async () => {
+ if (!publicClient || !debouncedAddress) {
+ throw new Error("Missing required dependencies");
+ }
+
+ try {
+ const contract = getContract({
+ address: debouncedAddress as `0x${string}`,
+ abi,
+ client: publicClient,
+ });
+
+ // Execute the contract call specific to the token type
+ await contractCall(contract);
+
+ return true;
+ } catch {
+ throw new Error(`Address does not implement ${tokenType} interface`);
+ }
+ },
+ });
+
+ // Determine final validation state
+ const isValid = useMemo(() => {
+ if (!debouncedAddress || debouncedAddress.trim() === "") {
+ return null;
+ }
+
+ if (isValidFormat === false) {
+ return false;
+ }
+
+ if (isLoading) {
+ return null; // Still validating
+ }
+
+ return isValidContract === true;
+ }, [debouncedAddress, isValidFormat, isLoading, isValidContract]);
+
+ const validationError = useMemo(() => {
+ if (!debouncedAddress || debouncedAddress.trim() === "") {
+ return null;
+ }
+
+ if (isValidFormat === false) {
+ return "Invalid Ethereum address format";
+ }
+
+ if (error) {
+ const errorMessage = error instanceof Error ? error.message : "Unknown error";
+ if (errorMessage.includes("not a contract")) {
+ return "Address is not a contract";
+ }
+ if (errorMessage.includes(`does not implement ${tokenType}`)) {
+ return `Not a valid ${tokenType} token address`;
+ }
+ return "Network error - please try again";
+ }
+
+ return null;
+ }, [debouncedAddress, isValidFormat, error, tokenType]);
+
+ return {
+ isValidating: isLoading && enabled && !!debouncedAddress,
+ isValid,
+ error: validationError,
+ };
+};
diff --git a/web/src/hooks/useVotingContext.tsx b/web/src/hooks/useVotingContext.tsx
index fa92bf09c..59abeb2f7 100644
--- a/web/src/hooks/useVotingContext.tsx
+++ b/web/src/hooks/useVotingContext.tsx
@@ -3,10 +3,16 @@ import React, { useContext, createContext, useMemo } from "react";
import { useParams } from "react-router-dom";
import { useAccount } from "wagmi";
-import { REFETCH_INTERVAL } from "consts/index";
-import { useReadDisputeKitClassicIsVoteActive } from "hooks/contracts/generated";
+import { REFETCH_INTERVAL, DisputeKits } from "consts/index";
+import {
+ useReadDisputeKitClassicIsVoteActive,
+ useReadDisputeKitShutterIsVoteActive,
+ useReadDisputeKitGatedIsVoteActive,
+ useReadDisputeKitGatedShutterIsVoteActive,
+} from "hooks/contracts/generated";
import { useDisputeDetailsQuery } from "hooks/queries/useDisputeDetailsQuery";
import { useDrawQuery } from "hooks/queries/useDrawQuery";
+import { useDisputeKitAddresses } from "hooks/useDisputeKitAddresses";
import { isUndefined } from "utils/index";
interface IVotingContext {
@@ -35,16 +41,70 @@ export const VotingContextProvider: React.FC<{ children: React.ReactNode }> = ({
const { data: drawData, isLoading } = useDrawQuery(address?.toLowerCase(), id, disputeData?.dispute?.currentRound.id);
const roundId = disputeData?.dispute?.currentRoundIndex;
const voteId = drawData?.draws?.[0]?.voteIDNum;
- const { data: hasVoted } = useReadDisputeKitClassicIsVoteActive({
+
+ const disputeKitAddress = disputeData?.dispute?.currentRound?.disputeKit?.address;
+ const { disputeKitName } = useDisputeKitAddresses({ disputeKitAddress });
+
+ const hookArgs = [BigInt(id ?? 0), roundId, voteId] as const;
+ const isEnabled = !isUndefined(roundId) && !isUndefined(voteId);
+
+ // Add a hook call for each DisputeKit
+ const classicVoteResult = useReadDisputeKitClassicIsVoteActive({
+ query: {
+ enabled: isEnabled && disputeKitName === DisputeKits.Classic,
+ refetchInterval: REFETCH_INTERVAL,
+ },
+ args: hookArgs,
+ });
+
+ const shutterVoteResult = useReadDisputeKitShutterIsVoteActive({
query: {
- enabled: !isUndefined(roundId) && !isUndefined(voteId),
+ enabled: isEnabled && disputeKitName === DisputeKits.Shutter,
refetchInterval: REFETCH_INTERVAL,
},
- args: [BigInt(id ?? 0), roundId, voteId],
+ args: hookArgs,
});
+ const gatedVoteResult = useReadDisputeKitGatedIsVoteActive({
+ query: {
+ enabled: isEnabled && disputeKitName === DisputeKits.Gated,
+ refetchInterval: REFETCH_INTERVAL,
+ },
+ args: hookArgs,
+ });
+
+ const gatedShutterVoteResult = useReadDisputeKitGatedShutterIsVoteActive({
+ query: {
+ enabled: isEnabled && disputeKitName === DisputeKits.GatedShutter,
+ refetchInterval: REFETCH_INTERVAL,
+ },
+ args: hookArgs,
+ });
+
+ // Add a return for each DisputeKit
+ const hasVoted = useMemo(() => {
+ switch (disputeKitName) {
+ case DisputeKits.Classic:
+ return classicVoteResult.data;
+ case DisputeKits.Shutter:
+ return shutterVoteResult.data;
+ case DisputeKits.Gated:
+ return gatedVoteResult.data;
+ case DisputeKits.GatedShutter:
+ return gatedShutterVoteResult.data;
+ default:
+ return undefined;
+ }
+ }, [
+ disputeKitName,
+ classicVoteResult.data,
+ shutterVoteResult.data,
+ gatedVoteResult.data,
+ gatedShutterVoteResult.data,
+ ]);
+
const wasDrawn = useMemo(() => !isUndefined(drawData) && drawData.draws.length > 0, [drawData]);
- const isHiddenVotes = useMemo(() => disputeData?.dispute?.court.hiddenVotes, [disputeData]);
+ const isHiddenVotes = useMemo(() => disputeData?.dispute?.court.hiddenVotes ?? false, [disputeData]);
const isCommitPeriod = useMemo(() => disputeData?.dispute?.period === "commit", [disputeData]);
const isVotingPeriod = useMemo(() => disputeData?.dispute?.period === "vote", [disputeData]);
diff --git a/web/src/pages/Cases/CaseDetails/Evidence/SubmitEvidenceModal.tsx b/web/src/pages/Cases/CaseDetails/Evidence/SubmitEvidenceModal.tsx
index 12916f302..e163d77a9 100644
--- a/web/src/pages/Cases/CaseDetails/Evidence/SubmitEvidenceModal.tsx
+++ b/web/src/pages/Cases/CaseDetails/Evidence/SubmitEvidenceModal.tsx
@@ -5,7 +5,7 @@ import Modal from "react-modal";
import { useWalletClient, usePublicClient, useConfig } from "wagmi";
import { Roles, useAtlasProvider } from "@kleros/kleros-app";
-import { Textarea, Button, FileUploader } from "@kleros/ui-components-library";
+import { Button, FileUploader } from "@kleros/ui-components-library";
import { simulateEvidenceModuleSubmitEvidence } from "hooks/contracts/generated";
import { wrapWithToast, errorToast, infoToast, successToast } from "utils/wrapWithToast";
@@ -14,6 +14,7 @@ import { getFileUploaderMsg, isEmpty } from "src/utils";
import EnsureAuth from "components/EnsureAuth";
import { EnsureChain } from "components/EnsureChain";
+import MarkdownEditor from "components/MarkdownEditor";
const StyledModal = styled(Modal)`
position: absolute;
@@ -36,9 +37,12 @@ const StyledModal = styled(Modal)`
gap: 16px;
`;
-const StyledTextArea = styled(Textarea)`
+const EditorContainer = styled.div`
width: 100%;
- height: 200px;
+
+ [class*="contentEditable"] {
+ min-height: 200px;
+ }
`;
const StyledFileUploader = styled(FileUploader)`
@@ -93,12 +97,14 @@ const SubmitEvidenceModal: React.FC<{
return (
Submit New Evidence
- setMessage(e.target.value)}
- placeholder="Your Arguments"
- />
+
+
+
setFile(file)}
msg={getFileUploaderMsg(Roles.Evidence, roleRestrictions)}
diff --git a/web/src/pages/Cases/CaseDetails/Timeline.tsx b/web/src/pages/Cases/CaseDetails/Timeline.tsx
index 0dbf8fdfd..3d8af7464 100644
--- a/web/src/pages/Cases/CaseDetails/Timeline.tsx
+++ b/web/src/pages/Cases/CaseDetails/Timeline.tsx
@@ -68,7 +68,7 @@ const Timeline: React.FC<{
currentPeriodIndex: number;
}> = ({ currentPeriodIndex, dispute }) => {
const currentItemIndex = currentPeriodToCurrentItem(currentPeriodIndex, dispute?.court.hiddenVotes);
- const items = useTimeline(dispute, currentItemIndex, currentItemIndex);
+ const items = useTimeline(dispute, currentPeriodIndex);
return (
@@ -103,30 +103,26 @@ const currentPeriodToCurrentItem = (currentPeriodIndex: number, hiddenVotes?: bo
else return currentPeriodIndex - 1;
};
-const useTimeline = (dispute: DisputeDetailsQuery["dispute"], currentItemIndex: number, currentPeriodIndex: number) => {
+const useTimeline = (dispute: DisputeDetailsQuery["dispute"], currentPeriodIndex: number) => {
const isDesktop = useIsDesktop();
- const titles = useMemo(() => {
- const titles = ["Evidence", "Voting", "Appeal", "Executed"];
- if (dispute?.court.hiddenVotes) {
- titles.splice(1, 0, "Commit");
- }
- return titles;
- }, [dispute]);
+ const titles = ["Evidence", "Commit", "Voting", "Appeal", "Executed"];
+
const deadlineCurrentPeriod = getDeadline(
currentPeriodIndex,
dispute?.lastPeriodChange,
dispute?.court.timesPerPeriod
);
+
const countdown = useCountdown(deadlineCurrentPeriod);
const getSubitems = (index: number): string[] | React.ReactNode[] => {
if (typeof countdown !== "undefined" && dispute) {
if (index === titles.length - 1) {
return [];
- } else if (index === currentItemIndex && countdown === 0) {
+ } else if (index === currentPeriodIndex && countdown === 0) {
return ["Time's up!"];
- } else if (index < currentItemIndex) {
+ } else if (index < currentPeriodIndex) {
return [];
- } else if (index === currentItemIndex) {
+ } else if (index === currentPeriodIndex) {
return [secondsToDayHourMinute(countdown)];
} else {
return [secondsToDayHourMinute(dispute?.court.timesPerPeriod[index])];
@@ -134,10 +130,16 @@ const useTimeline = (dispute: DisputeDetailsQuery["dispute"], currentItemIndex:
}
return [ ];
};
- return titles.map((title, i) => ({
- title: i + 1 < titles.length && isDesktop ? `${title} Period` : title,
- subitems: getSubitems(i),
- }));
+ return titles.flatMap((title, i) => {
+ // if not hidden votes, skip commit index
+ if (!dispute?.court.hiddenVotes && i === Periods.commit) return [];
+ return [
+ {
+ title: i + 1 < titles.length && isDesktop ? `${title} Period` : title,
+ subitems: getSubitems(i),
+ },
+ ];
+ });
};
export const getDeadline = (
diff --git a/web/src/pages/Cases/CaseDetails/Voting/Classic/Reveal.tsx b/web/src/pages/Cases/CaseDetails/Voting/Classic/Reveal.tsx
index 432f07e2a..f4ce45368 100644
--- a/web/src/pages/Cases/CaseDetails/Voting/Classic/Reveal.tsx
+++ b/web/src/pages/Cases/CaseDetails/Voting/Classic/Reveal.tsx
@@ -1,7 +1,6 @@
import React, { useCallback, useMemo, useState } from "react";
import styled from "styled-components";
-import ReactMarkdown from "react-markdown";
import { useParams } from "react-router-dom";
import { useLocalStorage } from "react-use";
import { encodePacked, keccak256, PrivateKeyAccount } from "viem";
@@ -20,8 +19,8 @@ import { useDisputeDetailsQuery } from "queries/useDisputeDetailsQuery";
import { EnsureChain } from "components/EnsureChain";
import InfoCard from "components/InfoCard";
-
-import JustificationArea from "../JustificationArea";
+import MarkdownEditor from "components/MarkdownEditor";
+import MarkdownRenderer from "components/MarkdownRenderer";
const Container = styled.div`
width: 100%;
@@ -40,7 +39,7 @@ const StyledEnsureChain = styled(EnsureChain)`
margin: 8px auto;
`;
-const ReactMarkdownWrapper = styled.div``;
+const MarkdownWrapper = styled.div``;
interface IReveal {
arbitrable?: `0x${string}`;
voteIDs: string[];
@@ -111,10 +110,10 @@ const Reveal: React.FC = ({ arbitrable, voteIDs, setIsOpen, commit, isR
) : isRevealPeriod ? (
<>
-
- {disputeDetails?.question ?? ""}
-
-
+
+
+
+
(
+ // when dispute is invalid, just add RFA to the answers array
+ const candidates =
+ answers?.length > 0
+ ? answers
+ : [{ id: "0x0", title: "Refuse To Arbitrate", description: "Refuse To Arbitrate" } as Answer];
+
+ const { choice } = candidates.reduce<{ found: boolean; choice: bigint }>(
(acc, answer) => {
if (acc.found) return acc;
const innerCommit = keccak256(encodePacked(["uint256", "uint256"], [BigInt(answer.id), BigInt(salt)]));
diff --git a/web/src/pages/Cases/CaseDetails/Voting/JustificationArea.tsx b/web/src/pages/Cases/CaseDetails/Voting/JustificationArea.tsx
deleted file mode 100644
index d92b036a1..000000000
--- a/web/src/pages/Cases/CaseDetails/Voting/JustificationArea.tsx
+++ /dev/null
@@ -1,37 +0,0 @@
-import React from "react";
-import styled from "styled-components";
-
-import { Textarea } from "@kleros/ui-components-library";
-
-const StyledTextarea = styled(Textarea)`
- width: 100%;
- height: auto;
- textarea {
- height: 200px;
- border-color: ${({ theme }) => theme.stroke};
- }
- small {
- font-weight: 400;
- hyphens: auto;
- }
-`;
-
-interface IJustificationArea {
- justification: string;
- setJustification: (arg0: string) => void;
-}
-
-const JustificationArea: React.FC = ({ justification, setJustification }) => (
- setJustification(e.target.value)}
- placeholder="Justify your vote..."
- message={
- "A good justification contributes to case comprehension. " + "Low quality justifications can be challenged."
- }
- variant="info"
- />
-);
-
-export default JustificationArea;
diff --git a/web/src/pages/Cases/CaseDetails/Voting/OptionsContainer.tsx b/web/src/pages/Cases/CaseDetails/Voting/OptionsContainer.tsx
index f58d132b0..9f4d5d6be 100644
--- a/web/src/pages/Cases/CaseDetails/Voting/OptionsContainer.tsx
+++ b/web/src/pages/Cases/CaseDetails/Voting/OptionsContainer.tsx
@@ -1,19 +1,18 @@
import React, { useCallback, useMemo, useState } from "react";
import styled from "styled-components";
-import ReactMarkdown from "react-markdown";
import { useParams } from "react-router-dom";
+import { Answer } from "@kleros/kleros-sdk";
+import { RefuseToArbitrateAnswer } from "@kleros/kleros-sdk/src/dataMappings/utils/disputeDetailsSchema";
import { Button, Tooltip } from "@kleros/ui-components-library";
import { usePopulatedDisputeData } from "hooks/queries/usePopulatedDisputeData";
import { isUndefined } from "utils/index";
import { EnsureChain } from "components/EnsureChain";
-
-import JustificationArea from "./JustificationArea";
-import { Answer } from "@kleros/kleros-sdk";
-import { RefuseToArbitrateAnswer } from "@kleros/kleros-sdk/src/dataMappings/utils/disputeDetailsSchema";
+import MarkdownEditor from "components/MarkdownEditor";
+import MarkdownRenderer from "components/MarkdownRenderer";
const MainContainer = styled.div`
width: 100%;
@@ -85,9 +84,9 @@ const Options: React.FC = ({ arbitrable, handleSelection, justificatio
return id ? (
<>
- {disputeDetails?.question ?? ""}
+
{!isUndefined(justification) && !isUndefined(setJustification) ? (
-
+
) : null}
{isUndefined(disputeDetails?.answers) ? null : (
diff --git a/web/src/pages/Cases/CaseDetails/Voting/Shutter/Commit.tsx b/web/src/pages/Cases/CaseDetails/Voting/Shutter/Commit.tsx
index db7172f74..28363514f 100644
--- a/web/src/pages/Cases/CaseDetails/Voting/Shutter/Commit.tsx
+++ b/web/src/pages/Cases/CaseDetails/Voting/Shutter/Commit.tsx
@@ -85,6 +85,10 @@ const Commit: React.FC = ({
const handleCommit = useCallback(
async (choice: bigint) => {
+ if (!import.meta.env.REACT_APP_SHUTTER_API || import.meta.env.REACT_APP_SHUTTER_API.trim() === "") {
+ console.error("REACT_APP_SHUTTER_API environment variable is not set or is empty");
+ throw new Error("Cannot commit vote: REACT_APP_SHUTTER_API environment variable is required but not set");
+ }
const message = { message: saltKey };
const rawSalt = !isUndefined(signingAccount)
? await signingAccount.signMessage(message)
diff --git a/web/src/pages/Cases/CaseDetails/Voting/Shutter/index.tsx b/web/src/pages/Cases/CaseDetails/Voting/Shutter/index.tsx
index d2821108e..3000b2872 100644
--- a/web/src/pages/Cases/CaseDetails/Voting/Shutter/index.tsx
+++ b/web/src/pages/Cases/CaseDetails/Voting/Shutter/index.tsx
@@ -26,11 +26,17 @@ const Shutter: React.FC = ({ arbitrable, setIsOpen, dispute, currentPe
const { isCommitPeriod, isVotingPeriod, commited } = useVotingContext();
const voteIDs = useMemo(() => drawData?.draws?.map((draw) => draw.voteIDNum) as string[], [drawData]);
- return id && isCommitPeriod && !commited ? (
-
- ) : id && isVotingPeriod ? (
-
- ) : null;
+ const shouldShowCommit = id && isCommitPeriod && !commited;
+ const shouldShowReveal = id && isVotingPeriod;
+
+ return (
+ <>
+ {shouldShowCommit && (
+
+ )}
+ {shouldShowReveal && }
+ >
+ );
};
export default Shutter;
diff --git a/web/src/pages/Cases/CaseDetails/Voting/VotesDetails/index.tsx b/web/src/pages/Cases/CaseDetails/Voting/VotesDetails/index.tsx
index 7396d610e..d380be531 100644
--- a/web/src/pages/Cases/CaseDetails/Voting/VotesDetails/index.tsx
+++ b/web/src/pages/Cases/CaseDetails/Voting/VotesDetails/index.tsx
@@ -14,6 +14,7 @@ import { landscapeStyle } from "styles/landscapeStyle";
import { ExternalLink } from "components/ExternalLink";
import InfoCard from "components/InfoCard";
+import MarkdownRenderer from "components/MarkdownRenderer";
import AccordionTitle from "./AccordionTitle";
@@ -84,10 +85,13 @@ const VotedText = styled.label`
}
`;
-const JustificationText = styled(VotedText)`
+const JustificationContainer = styled.div`
line-height: 1.25;
- ::before {
+
+ &::before {
content: "Justification: ";
+ color: ${({ theme }) => theme.primaryText};
+ font-size: 16px;
}
`;
@@ -117,7 +121,9 @@ const AccordionContent: React.FC<{
{!isUndefined(choice) && {getVoteChoice(choice, answers)} }
{justification ? (
- {justification}
+
+
+
) : (
No justification provided
)}
diff --git a/web/src/pages/Cases/CaseDetails/Voting/VotingHistory.tsx b/web/src/pages/Cases/CaseDetails/Voting/VotingHistory.tsx
index da02108bf..e6421b1c4 100644
--- a/web/src/pages/Cases/CaseDetails/Voting/VotingHistory.tsx
+++ b/web/src/pages/Cases/CaseDetails/Voting/VotingHistory.tsx
@@ -2,7 +2,6 @@ import React, { useEffect, useMemo, useState } from "react";
import styled from "styled-components";
import Skeleton from "react-loading-skeleton";
-import ReactMarkdown from "react-markdown";
import { useParams } from "react-router-dom";
import { useToggle } from "react-use";
@@ -19,6 +18,7 @@ import { useVotingHistory } from "queries/useVotingHistory";
import { responsiveSize } from "styles/responsiveSize";
import HowItWorks from "components/HowItWorks";
+import MarkdownRenderer from "components/MarkdownRenderer";
import BinaryVoting from "components/Popup/MiniGuides/BinaryVoting";
import PendingVotesBox from "./PendingVotesBox";
@@ -47,8 +47,8 @@ const StyledTitle = styled.h1`
margin-bottom: 0;
font-size: ${responsiveSize(18, 24)};
`;
-const ReactMarkdownWrapper = styled.div``;
-const StyledReactMarkDown = styled(ReactMarkdown)`
+const MarkdownWrapper = styled.div``;
+const StyledMarkdownRenderer = styled(MarkdownRenderer)`
max-width: inherit;
word-wrap: break-word;
p {
@@ -95,11 +95,11 @@ const VotingHistory: React.FC<{ arbitrable?: `0x${string}`; isQuestion: boolean
{isQuestion && (
<>
{disputeDetails.question ? (
-
- {disputeDetails.question}
-
+
+
+
) : (
- {isError ? RPC_ERROR : INVALID_DISPUTE_DATA_ERROR}
+
)}
>
)}
diff --git a/web/src/pages/Courts/CourtDetails/Description.tsx b/web/src/pages/Courts/CourtDetails/Description.tsx
index b8ff78dbb..c860cdd0e 100644
--- a/web/src/pages/Courts/CourtDetails/Description.tsx
+++ b/web/src/pages/Courts/CourtDetails/Description.tsx
@@ -1,12 +1,13 @@
import React, { useEffect } from "react";
import styled from "styled-components";
-import ReactMarkdown from "react-markdown";
import { Routes, Route, Navigate, useParams, useNavigate, useLocation, useSearchParams } from "react-router-dom";
+
import { Tabs } from "@kleros/ui-components-library";
import { useCourtPolicy } from "queries/useCourtPolicy";
+import MarkdownRenderer from "components/MarkdownRenderer";
import { StyledSkeleton } from "components/StyledSkeleton";
const Container = styled.div`
@@ -18,7 +19,7 @@ const TextContainer = styled.div`
padding: 12px 0;
`;
-const StyledReactMarkdown = styled(ReactMarkdown)`
+const StyledMarkdownRenderer = styled(MarkdownRenderer)`
p {
word-break: break-word;
}
@@ -127,6 +128,6 @@ const Description: React.FC = () => {
};
const formatMarkdown = (markdown?: string) =>
- markdown ? {markdown.replace(/\n/g, " \n")} : ;
+ markdown ? : ;
export default Description;
diff --git a/web/src/pages/Profile/Courts/Header.tsx b/web/src/pages/Profile/Courts/Header.tsx
deleted file mode 100644
index 07f61e11c..000000000
--- a/web/src/pages/Profile/Courts/Header.tsx
+++ /dev/null
@@ -1,79 +0,0 @@
-import React from "react";
-import styled, { css } from "styled-components";
-
-import { formatUnits } from "viem";
-import { useSearchParams } from "react-router-dom";
-
-import LockerIcon from "svgs/icons/locker.svg";
-
-import { isUndefined } from "utils/index";
-
-import { landscapeStyle } from "styles/landscapeStyle";
-import { responsiveSize } from "styles/responsiveSize";
-
-import NumberDisplay from "components/NumberDisplay";
-
-const Container = styled.div`
- display: flex;
- flex-direction: row;
- flex-wrap: wrap;
- width: 100%;
- gap: 4px 16px;
- align-items: center;
- margin-bottom: ${responsiveSize(16, 24)};
-
- ${landscapeStyle(
- () => css`
- justify-content: space-between;
- `
- )}
-`;
-
-const LockedPnk = styled.div`
- display: flex;
- flex-wrap: nowrap;
- gap: 8px;
- justify-content: flex-start;
-
- ${landscapeStyle(
- () => css`
- align-self: center;
- `
- )}
-`;
-
-const StyledTitle = styled.h1`
- margin-bottom: 0;
- font-size: ${responsiveSize(20, 24)};
-`;
-
-const StyledLockerIcon = styled(LockerIcon)`
- fill: ${({ theme }) => theme.secondaryPurple};
- width: 14px;
-`;
-
-interface IHeader {
- lockedStake: bigint;
-}
-
-const Header: React.FC = ({ lockedStake }) => {
- const formattedLockedStake = !isUndefined(lockedStake) && formatUnits(lockedStake, 18);
- const [searchParams] = useSearchParams();
- const searchParamAddress = searchParams.get("address")?.toLowerCase();
-
- return (
-
- {searchParamAddress ? "Their" : "My"} Courts
- {!isUndefined(lockedStake) ? (
-
-
- Locked Stake:
-
-
-
-
- ) : null}
-
- );
-};
-export default Header;
diff --git a/web/src/pages/Profile/Courts/CourtCard/CourtName.tsx b/web/src/pages/Profile/Stakes/CourtCard/CourtName.tsx
similarity index 100%
rename from web/src/pages/Profile/Courts/CourtCard/CourtName.tsx
rename to web/src/pages/Profile/Stakes/CourtCard/CourtName.tsx
diff --git a/web/src/pages/Profile/Courts/CourtCard/Stake.tsx b/web/src/pages/Profile/Stakes/CourtCard/Stake.tsx
similarity index 100%
rename from web/src/pages/Profile/Courts/CourtCard/Stake.tsx
rename to web/src/pages/Profile/Stakes/CourtCard/Stake.tsx
diff --git a/web/src/pages/Profile/Courts/CourtCard/index.tsx b/web/src/pages/Profile/Stakes/CourtCard/index.tsx
similarity index 100%
rename from web/src/pages/Profile/Courts/CourtCard/index.tsx
rename to web/src/pages/Profile/Stakes/CourtCard/index.tsx
diff --git a/web/src/pages/Profile/Stakes/Header.tsx b/web/src/pages/Profile/Stakes/Header.tsx
new file mode 100644
index 000000000..811ab0e1f
--- /dev/null
+++ b/web/src/pages/Profile/Stakes/Header.tsx
@@ -0,0 +1,139 @@
+import React from "react";
+import styled, { css } from "styled-components";
+
+import { useSearchParams } from "react-router-dom";
+import { formatUnits } from "viem";
+
+import LockerIcon from "svgs/icons/locker.svg";
+import PnkIcon from "svgs/icons/pnk.svg";
+
+import { isUndefined } from "utils/index";
+
+import { landscapeStyle } from "styles/landscapeStyle";
+import { responsiveSize } from "styles/responsiveSize";
+
+import NumberDisplay from "components/NumberDisplay";
+
+const Container = styled.div`
+ display: flex;
+ flex-direction: row;
+ flex-wrap: wrap;
+ width: 100%;
+ gap: 4px 16px;
+ align-items: center;
+ margin-bottom: ${responsiveSize(16, 24)};
+
+ ${landscapeStyle(
+ () => css`
+ justify-content: space-between;
+ `
+ )}
+`;
+
+const LockedPnk = styled.div`
+ display: flex;
+ flex-wrap: nowrap;
+ gap: 8px;
+ align-items: center;
+ justify-content: center;
+`;
+
+const StakesGroup = styled.div`
+ display: flex;
+ gap: 12px 24px;
+ align-items: center;
+ flex-wrap: wrap;
+`;
+
+const AvailablePnk = styled.div`
+ display: flex;
+ flex-wrap: nowrap;
+ gap: 8px;
+ align-items: center;
+ justify-content: center;
+`;
+
+const EffectivePnk = styled.div`
+ display: flex;
+ flex-wrap: nowrap;
+ gap: 8px;
+ align-items: center;
+ justify-content: center;
+`;
+
+const StyledTitle = styled.h1`
+ margin-bottom: 0;
+ font-size: ${responsiveSize(20, 24)};
+`;
+
+const StyledLockerIcon = styled(LockerIcon)`
+ fill: ${({ theme }) => theme.secondaryPurple};
+ width: 14px;
+ height: 14px;
+ margin-bottom: 1px;
+`;
+
+const StyledPnkIcon = styled(PnkIcon)`
+ fill: ${({ theme }) => theme.secondaryPurple};
+ width: 14px;
+ height: 14px;
+ margin-bottom: 1px;
+`;
+
+const StyledEffectivePnkIcon = styled(PnkIcon)`
+ fill: ${({ theme }) => theme.secondaryPurple};
+ width: 14px;
+ height: 14px;
+ margin-bottom: 1px;
+`;
+
+interface IHeader {
+ availableStake?: bigint;
+ lockedStake?: bigint;
+ effectiveStake?: bigint;
+}
+
+const Header: React.FC = ({ availableStake, lockedStake, effectiveStake }) => {
+ const formattedAvailableStake = !isUndefined(availableStake) && formatUnits(availableStake, 18);
+ const formattedLockedStake = !isUndefined(lockedStake) && formatUnits(lockedStake, 18);
+ const formattedEffectiveStake = !isUndefined(effectiveStake) && formatUnits(effectiveStake, 18);
+ const [searchParams] = useSearchParams();
+ const searchParamAddress = searchParams.get("address")?.toLowerCase();
+
+ return (
+
+ {searchParamAddress ? "Their" : "My"} Stakes
+
+ {!isUndefined(availableStake) ? (
+
+
+ Available:
+
+
+
+
+ ) : null}
+ {!isUndefined(effectiveStake) ? (
+
+
+ Staked:
+
+
+
+
+ ) : null}
+ {!isUndefined(lockedStake) ? (
+
+
+ Locked:
+
+
+
+
+ ) : null}
+
+
+ );
+};
+
+export default Header;
diff --git a/web/src/pages/Profile/Courts/index.tsx b/web/src/pages/Profile/Stakes/index.tsx
similarity index 84%
rename from web/src/pages/Profile/Courts/index.tsx
rename to web/src/pages/Profile/Stakes/index.tsx
index 512478b1d..8df01bb0b 100644
--- a/web/src/pages/Profile/Courts/index.tsx
+++ b/web/src/pages/Profile/Stakes/index.tsx
@@ -35,11 +35,11 @@ const StyledLabel = styled.label`
font-size: ${responsiveSize(14, 16)};
`;
-interface ICourts {
+interface IStakes {
addressToQuery: `0x${string}`;
}
-const Courts: React.FC = ({ addressToQuery }) => {
+const Stakes: React.FC = ({ addressToQuery }) => {
const { data: stakeData, isLoading } = useJurorStakeDetailsQuery(addressToQuery);
const { data: jurorBalance } = useReadSortitionModuleGetJurorBalance({
args: [addressToQuery, BigInt(1)],
@@ -48,11 +48,15 @@ const Courts: React.FC = ({ addressToQuery }) => {
const searchParamAddress = searchParams.get("address")?.toLowerCase();
const stakedCourts = stakeData?.jurorTokensPerCourts?.filter(({ staked }) => staked > 0);
const isStaked = stakedCourts && stakedCourts.length > 0;
+ const availableStake = jurorBalance?.[0];
const lockedStake = jurorBalance?.[1];
+ const effectiveStake = stakeData?.jurorTokensPerCourts?.[0]?.effectiveStake
+ ? BigInt(stakeData.jurorTokensPerCourts[0].effectiveStake)
+ : undefined;
return (
-
+
{isLoading ? : null}
{!isStaked && !isLoading ? (
{searchParamAddress ? "They" : "You"} are not staked in any court
@@ -70,4 +74,4 @@ const Courts: React.FC = ({ addressToQuery }) => {
);
};
-export default Courts;
+export default Stakes;
diff --git a/web/src/pages/Profile/index.tsx b/web/src/pages/Profile/index.tsx
index 109046748..b52327eda 100644
--- a/web/src/pages/Profile/index.tsx
+++ b/web/src/pages/Profile/index.tsx
@@ -1,24 +1,27 @@
import React, { useMemo } from "react";
-
import styled, { css } from "styled-components";
-import { MAX_WIDTH_LANDSCAPE, landscapeStyle } from "styles/landscapeStyle";
-import { responsiveSize } from "styles/responsiveSize";
import { useNavigate, useParams, useSearchParams } from "react-router-dom";
import { useAccount } from "wagmi";
import { isUndefined } from "utils/index";
import { decodeURIFilter, useRootPath } from "utils/uri";
+
import { DisputeDetailsFragment, useMyCasesQuery } from "queries/useCasesQuery";
import { useUserQuery } from "queries/useUser";
+
import { Dispute_Filter, OrderDirection, UserDetailsFragment } from "src/graphql/graphql";
+import { MAX_WIDTH_LANDSCAPE, landscapeStyle } from "styles/landscapeStyle";
+import { responsiveSize } from "styles/responsiveSize";
+
import CasesDisplay from "components/CasesDisplay";
import ConnectWallet from "components/ConnectWallet";
import FavoriteCases from "components/FavoriteCases";
import ScrollTop from "components/ScrollTop";
-import Courts from "./Courts";
+
import JurorInfo from "./JurorInfo";
+import Stakes from "./Stakes";
const Container = styled.div`
width: 100%;
@@ -110,7 +113,7 @@ const Profile: React.FC = () => {
{isConnected || searchParamAddress ? (
<>
-
+
css`
width: ${responsiveSize(442, 700, 900)};
@@ -32,15 +29,18 @@ const Description: React.FC = () => {
const { disputeData, setDisputeData } = useNewDisputeContext();
const containerRef = useRef(null);
- const handleWrite = (event: React.ChangeEvent) => {
- setDisputeData({ ...disputeData, description: event.target.value });
+ const handleWrite = (value: string) => {
+ setDisputeData({ ...disputeData, description: value });
};
useEffect(() => {
if (containerRef.current) {
- const textareaElement = containerRef.current.querySelector("textarea");
- if (textareaElement) {
- textareaElement.focus();
+ const editorElement = containerRef.current.querySelector('[role="region"]');
+ if (editorElement) {
+ const contentEditable = editorElement.querySelector('[contenteditable="true"]');
+ if (contentEditable) {
+ (contentEditable as HTMLElement).focus();
+ }
}
}
}, []);
@@ -48,12 +48,14 @@ const Description: React.FC = () => {
return (
-
+
+
+
);
diff --git a/web/src/pages/Resolver/NavigationButtons/NextButton.tsx b/web/src/pages/Resolver/NavigationButtons/NextButton.tsx
index e6d51f8bf..e54082f44 100644
--- a/web/src/pages/Resolver/NavigationButtons/NextButton.tsx
+++ b/web/src/pages/Resolver/NavigationButtons/NextButton.tsx
@@ -4,7 +4,8 @@ import { useLocation, useNavigate } from "react-router-dom";
import { Button } from "@kleros/ui-components-library";
-import { useNewDisputeContext } from "context/NewDisputeContext";
+import { IGatedDisputeData, useNewDisputeContext } from "context/NewDisputeContext";
+
import { isEmpty } from "src/utils";
interface INextButton {
@@ -16,6 +17,17 @@ const NextButton: React.FC = ({ nextRoute }) => {
const { disputeData, isPolicyUploading } = useNewDisputeContext();
const location = useLocation();
+ // Check gated dispute kit validation status
+ const isGatedTokenValid = React.useMemo(() => {
+ if (!disputeData.disputeKitData || disputeData.disputeKitData.type !== "gated") return true;
+
+ const gatedData = disputeData.disputeKitData as IGatedDisputeData;
+ if (!gatedData?.tokenGate?.trim()) return false; // No token address provided, so invalid
+
+ // If token address is provided, it must be validated as valid ERC20
+ return gatedData.isTokenGateValid === true;
+ }, [disputeData.disputeKitData]);
+
//checks if each answer is filled in
const areVotingOptionsFilled =
disputeData.question !== "" &&
@@ -29,7 +41,8 @@ const NextButton: React.FC = ({ nextRoute }) => {
const isButtonDisabled =
(location.pathname.includes("/resolver/title") && !disputeData.title) ||
(location.pathname.includes("/resolver/description") && !disputeData.description) ||
- (location.pathname.includes("/resolver/court") && !disputeData.courtId) ||
+ (location.pathname.includes("/resolver/court") &&
+ (!disputeData.courtId || !isGatedTokenValid || !disputeData.disputeKitId)) ||
(location.pathname.includes("/resolver/jurors") && !disputeData.arbitrationCost) ||
(location.pathname.includes("/resolver/voting-options") && !areVotingOptionsFilled) ||
(location.pathname.includes("/resolver/notable-persons") && !areAliasesValidOrEmpty) ||
diff --git a/web/src/pages/Resolver/Parameters/Court.tsx b/web/src/pages/Resolver/Parameters/Court.tsx
deleted file mode 100644
index b82fbb133..000000000
--- a/web/src/pages/Resolver/Parameters/Court.tsx
+++ /dev/null
@@ -1,224 +0,0 @@
-import React, { useMemo } from "react";
-import styled, { css } from "styled-components";
-
-import { AlertMessage, Checkbox, DropdownCascader, DropdownSelect, Field } from "@kleros/ui-components-library";
-
-import { DisputeKits } from "consts/index";
-import { IGatedDisputeData, useNewDisputeContext } from "context/NewDisputeContext";
-import { rootCourtToItems, useCourtTree } from "hooks/queries/useCourtTree";
-import { useDisputeKitAddressesAll } from "hooks/useDisputeKitAddresses";
-import { isUndefined } from "utils/index";
-
-import { useSupportedDisputeKits } from "queries/useSupportedDisputeKits";
-
-import { landscapeStyle } from "styles/landscapeStyle";
-import { responsiveSize } from "styles/responsiveSize";
-
-import { StyledSkeleton } from "components/StyledSkeleton";
-import Header from "pages/Resolver/Header";
-
-import NavigationButtons from "../NavigationButtons";
-
-const Container = styled.div`
- display: flex;
- flex-direction: column;
- align-items: center;
-
- ${landscapeStyle(
- () => css`
- padding-bottom: 115px;
- `
- )}
-`;
-
-const StyledDropdownCascader = styled(DropdownCascader)`
- width: 84vw;
- ${landscapeStyle(
- () => css`
- width: ${responsiveSize(442, 700, 900)};
- `
- )}
- > button {
- width: 100%;
- }
-`;
-
-const AlertMessageContainer = styled.div`
- width: 84vw;
- ${landscapeStyle(
- () => css`
- width: ${responsiveSize(442, 700, 900)};
- `
- )}
- margin-top: 24px;
-`;
-
-const StyledDropdownSelect = styled(DropdownSelect)`
- width: 84vw;
- margin-top: 24px;
- ${landscapeStyle(
- () => css`
- width: ${responsiveSize(442, 700, 900)};
- `
- )}
-`;
-
-const StyledField = styled(Field)`
- width: 84vw;
- margin-top: 24px;
- ${landscapeStyle(
- () => css`
- width: ${responsiveSize(442, 700, 900)};
- `
- )}
- > small {
- margin-top: 16px;
- }
-`;
-
-const StyledCheckbox = styled(Checkbox)`
- width: 84vw;
- margin-top: 24px;
- ${landscapeStyle(
- () => css`
- width: ${responsiveSize(442, 700, 900)};
- `
- )}
-`;
-
-const Court: React.FC = () => {
- const { disputeData, setDisputeData } = useNewDisputeContext();
- const { data: courtTree } = useCourtTree();
- const { data: supportedDisputeKits } = useSupportedDisputeKits(disputeData.courtId);
- const items = useMemo(() => !isUndefined(courtTree?.court) && [rootCourtToItems(courtTree.court)], [courtTree]);
- const { availableDisputeKits } = useDisputeKitAddressesAll();
-
- const disputeKitOptions = useMemo(() => {
- return (
- supportedDisputeKits?.court?.supportedDisputeKits.map((dk) => {
- const text = availableDisputeKits[dk.address.toLowerCase()] ?? "";
- return {
- text,
- value: Number(dk.id),
- gated: text === DisputeKits.Gated || text === DisputeKits.GatedShutter,
- };
- }) || []
- );
- }, [supportedDisputeKits, availableDisputeKits]);
-
- const selectedDisputeKitId = useMemo(() => {
- // If there's only 1 supported dispute kit, select it by default
- if (disputeKitOptions.length === 1) {
- return disputeKitOptions[0].value;
- }
- // If there's no saved selection, select nothing
- return disputeData.disputeKitId ?? -1;
- }, [disputeKitOptions, disputeData.disputeKitId]);
-
- const isGatedDisputeKit = useMemo(() => {
- const options = disputeKitOptions.find((dk) => String(dk.value) === String(selectedDisputeKitId));
- return options?.gated ?? false;
- }, [disputeKitOptions, selectedDisputeKitId]);
-
- const handleCourtChange = (courtId: string) => {
- if (disputeData.courtId !== courtId) {
- setDisputeData({ ...disputeData, courtId, disputeKitId: undefined });
- }
- };
-
- const handleDisputeKitChange = (newValue: string | number) => {
- const options = disputeKitOptions.find((dk) => String(dk.value) === String(newValue));
- const gatedDisputeKitData: IGatedDisputeData | undefined =
- (options?.gated ?? false)
- ? {
- type: "gated",
- tokenGate: "",
- isERC1155: false,
- tokenId: "0",
- }
- : undefined;
- setDisputeData({ ...disputeData, disputeKitId: Number(newValue), disputeKitData: gatedDisputeKitData });
- };
-
- const handleTokenAddressChange = (event: React.ChangeEvent) => {
- const currentData = disputeData.disputeKitData as IGatedDisputeData;
- setDisputeData({
- ...disputeData,
- disputeKitData: { ...currentData, tokenGate: event.target.value },
- });
- };
-
- const handleERC1155TokenChange = (event: React.ChangeEvent) => {
- const currentData = disputeData.disputeKitData as IGatedDisputeData;
- setDisputeData({
- ...disputeData,
- disputeKitData: { ...currentData, isERC1155: event.target.checked },
- });
- };
-
- const handleTokenIdChange = (event: React.ChangeEvent) => {
- const currentData = disputeData.disputeKitData as IGatedDisputeData;
- setDisputeData({
- ...disputeData,
- disputeKitData: { ...currentData, tokenId: event.target.value },
- });
- };
-
- return (
-
-
- {items ? (
- typeof path === "string" && handleCourtChange(path.split("/").pop()!)}
- placeholder="Select Court"
- value={`/courts/${disputeData.courtId}`}
- />
- ) : (
-
- )}
- {disputeData?.courtId && disputeKitOptions.length > 0 && (
-
- )}
- {isGatedDisputeKit && (
- <>
-
-
- {(disputeData.disputeKitData as IGatedDisputeData)?.isERC1155 && (
-
- )}
- >
- )}
-
-
-
-
-
- );
-};
-
-export default Court;
diff --git a/web/src/pages/Resolver/Parameters/Court/FeatureSelection/FeatureSkeleton.tsx b/web/src/pages/Resolver/Parameters/Court/FeatureSelection/FeatureSkeleton.tsx
new file mode 100644
index 000000000..3e38e8716
--- /dev/null
+++ b/web/src/pages/Resolver/Parameters/Court/FeatureSelection/FeatureSkeleton.tsx
@@ -0,0 +1,47 @@
+import React from "react";
+import styled from "styled-components";
+
+import Skeleton from "react-loading-skeleton";
+
+const Container = styled.div`
+ width: 100%;
+ display: flex;
+ flex-direction: column;
+ gap: 16px;
+ margin-top: 16px;
+`;
+
+const HeaderContainer = styled.div`
+ display: flex;
+ flex-direction: column;
+ gap: 8px;
+`;
+
+const HeaderSkeleton = styled(Skeleton)`
+ width: 25%;
+ height: 22px;
+`;
+
+const SubHeaderSkeleton = styled(Skeleton)`
+ width: 75%;
+ height: 19px;
+`;
+
+const RadioSkeleton = styled(Skeleton)`
+ width: 20%;
+ height: 19px;
+`;
+
+const FeatureSkeleton: React.FC = () => {
+ return (
+
+
+
+
+
+
+
+ );
+};
+
+export default FeatureSkeleton;
diff --git a/web/src/pages/Resolver/Parameters/Court/FeatureSelection/index.tsx b/web/src/pages/Resolver/Parameters/Court/FeatureSelection/index.tsx
new file mode 100644
index 000000000..8c0d342ae
--- /dev/null
+++ b/web/src/pages/Resolver/Parameters/Court/FeatureSelection/index.tsx
@@ -0,0 +1,180 @@
+import React, { Fragment, useEffect, useMemo } from "react";
+import styled from "styled-components";
+
+import { Card } from "@kleros/ui-components-library";
+
+import {
+ disputeKits,
+ ensureValidSmart,
+ featureGroups,
+ Features,
+ findMatchingKits,
+ getDisabledOptions,
+ getVisibleFeaturesForCourt,
+ Group,
+ toggleFeature,
+} from "consts/disputeFeature";
+import { IGatedDisputeData, useNewDisputeContext } from "context/NewDisputeContext";
+
+import { useSupportedDisputeKits } from "queries/useSupportedDisputeKits";
+
+import { isUndefined } from "src/utils";
+
+import { FeatureUIs } from "components/DisputeFeatures/Features";
+import { GroupsUI } from "components/DisputeFeatures/GroupsUI";
+
+import FeatureSkeleton from "./FeatureSkeleton";
+
+const Container = styled(Card)`
+ width: 100%;
+ height: auto;
+ padding: 32px;
+ display: flex;
+ flex-direction: column;
+ margin-top: 16px;
+`;
+
+const SubTitle = styled.p`
+ font-size: 18px;
+ color: ${({ theme }) => theme.secondaryBlue};
+ padding: 0;
+ margin: 0;
+`;
+
+const Separator = styled.hr`
+ width: 100%;
+`;
+const FeatureSelection: React.FC = () => {
+ const {
+ disputeData,
+ setDisputeData,
+ selectedFeatures: selected,
+ setSelectedFeatures: setSelected,
+ } = useNewDisputeContext();
+ const { data: supportedDisputeKits } = useSupportedDisputeKits(disputeData.courtId);
+
+ // DEV: initial feature selection logic, included hardcoded logic
+ useEffect(() => {
+ if (!isUndefined(disputeData?.disputeKitId)) {
+ const defaultKit = disputeKits.find((dk) => dk.id === disputeData.disputeKitId);
+ if (!defaultKit) return;
+
+ // some kits like gated can have two feature sets, one for gatedERC20 and other for ERC1155
+ if (defaultKit?.featureSets.length > 1) {
+ if ((disputeData?.disputeKitData as IGatedDisputeData)?.isERC1155) {
+ // defaultKit.featureSets[0][0] - is either Classic or Shutter
+ setSelected([defaultKit.featureSets[0][0], Features.GatedErc1155]);
+ } else {
+ setSelected([defaultKit.featureSets[0][0], Features.GatedErc20]);
+ }
+ } else if (defaultKit.featureSets.length === 1) {
+ setSelected(defaultKit.featureSets[0]);
+ }
+ }
+ }, []);
+
+ const allowedDisputeKits = useMemo(() => {
+ if (!supportedDisputeKits?.court?.supportedDisputeKits) return [];
+ const allowedIds = supportedDisputeKits.court.supportedDisputeKits.map((dk) => Number(dk.id));
+ return disputeKits.filter((kit) => allowedIds.includes(kit.id));
+ }, [supportedDisputeKits]);
+
+ // Court specific groups
+ const courtGroups = useMemo(() => {
+ const courtKits = supportedDisputeKits?.court?.supportedDisputeKits.map((dk) => Number(dk.id));
+ if (isUndefined(courtKits) || allowedDisputeKits.length === 0) return {};
+ return getVisibleFeaturesForCourt(courtKits, allowedDisputeKits, featureGroups);
+ }, [supportedDisputeKits, allowedDisputeKits]);
+
+ const disabled = useMemo(
+ () => getDisabledOptions(selected, courtGroups, allowedDisputeKits),
+ [selected, courtGroups, allowedDisputeKits]
+ );
+
+ const matchingKits = useMemo(() => findMatchingKits(selected, allowedDisputeKits), [selected, allowedDisputeKits]);
+
+ const handleToggle = (feature: Features) => {
+ setSelected((prev) => {
+ const toggled = toggleFeature(prev, feature, courtGroups);
+ // we don't necessarily need ensureValidSmart here,
+ // but in case a bug allows picking a disabled option, this will correct that
+ return ensureValidSmart(toggled, courtGroups, allowedDisputeKits);
+ });
+ };
+
+ const handleGroupDisable = (group: Group) => {
+ const groupFeatures = courtGroups[group];
+ // we have a feature selected from this group
+ for (const feature of groupFeatures) {
+ if (selected.includes(feature)) {
+ // turn off this feature
+ handleToggle(feature);
+ }
+ }
+ };
+
+ // if each group only has one feature, select them by default
+ // This should not clash with the initial selection logic,
+ // as it only runs when there's one disputeKit and featureSet to pick
+ useEffect(() => {
+ // if only one disputeKit is found, and that dk has only one featureSEt to pick, then select by default
+ if (allowedDisputeKits.length === 1 && allowedDisputeKits[0].featureSets.length === 1) {
+ setSelected(allowedDisputeKits[0].featureSets[0]);
+ }
+ }, [allowedDisputeKits, setSelected]);
+
+ useEffect(() => {
+ // work of feature selection ends here by giving us the disputeKitId,
+ // any further checks we do separately, like for NextButton
+ // right now we don't have kits that can have same features, so we assume it will be 1 length array
+ if (matchingKits.length === 1) {
+ const selectedKit = matchingKits[0];
+
+ setDisputeData({
+ ...disputeData,
+ disputeKitId: selectedKit.id,
+ disputeKitData:
+ selectedKit.type === "general"
+ ? undefined
+ : ({ ...disputeData.disputeKitData, type: selectedKit.type } as IGatedDisputeData),
+ });
+ } else if (matchingKits.length === 0) {
+ setDisputeData({ ...disputeData, disputeKitId: undefined });
+ }
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [matchingKits]);
+
+ return (
+
+ Features in this Court
+
+ {Object.entries(courtGroups).length > 0 ? (
+ Object.entries(courtGroups).map(([groupName, features], index) => (
+ <>
+ {GroupsUI[groupName]({
+ clearAll: () => handleGroupDisable(groupName as Group),
+ children: (
+
+ {features.map((feature) =>
+ FeatureUIs[feature]({
+ name: groupName,
+ checked: selected.includes(feature),
+ disabled: disabled.has(feature),
+ onClick: () => handleToggle(feature),
+ value: feature,
+ })
+ )}
+
+ ),
+ })}
+ {index !== Object.entries(courtGroups).length - 1 ? : null}
+ >
+ ))
+ ) : (
+
+ )}
+
+ );
+};
+
+export default FeatureSelection;
diff --git a/web/src/pages/Resolver/Parameters/Court/index.tsx b/web/src/pages/Resolver/Parameters/Court/index.tsx
new file mode 100644
index 000000000..758f167bc
--- /dev/null
+++ b/web/src/pages/Resolver/Parameters/Court/index.tsx
@@ -0,0 +1,93 @@
+import React, { useMemo } from "react";
+import styled, { css } from "styled-components";
+
+import { AlertMessage, DropdownCascader } from "@kleros/ui-components-library";
+
+import { useNewDisputeContext } from "context/NewDisputeContext";
+import { rootCourtToItems, useCourtTree } from "hooks/queries/useCourtTree";
+import { isUndefined } from "utils/index";
+
+import { landscapeStyle } from "styles/landscapeStyle";
+import { responsiveSize } from "styles/responsiveSize";
+
+import { StyledSkeleton } from "components/StyledSkeleton";
+import Header from "pages/Resolver/Header";
+
+import NavigationButtons from "../../NavigationButtons";
+
+import FeatureSelection from "./FeatureSelection";
+
+const Container = styled.div`
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+
+ ${landscapeStyle(
+ () => css`
+ padding-bottom: 115px;
+ `
+ )}
+`;
+
+const StyledDropdownCascader = styled(DropdownCascader)`
+ width: 84vw;
+ ${landscapeStyle(
+ () => css`
+ width: ${responsiveSize(442, 700, 900)};
+ `
+ )}
+ > button {
+ width: 100%;
+ }
+`;
+
+const AlertMessageContainer = styled.div`
+ width: 84vw;
+ ${landscapeStyle(
+ () => css`
+ width: ${responsiveSize(442, 700, 900)};
+ `
+ )}
+ margin-top: 24px;
+`;
+
+const Court: React.FC = () => {
+ const { disputeData, setDisputeData, setSelectedFeatures } = useNewDisputeContext();
+ const { data: courtTree } = useCourtTree();
+ const items = useMemo(() => !isUndefined(courtTree?.court) && [rootCourtToItems(courtTree.court)], [courtTree]);
+
+ const handleCourtChange = (courtId: string) => {
+ if (disputeData.courtId !== courtId) {
+ setDisputeData({ ...disputeData, courtId, disputeKitId: undefined, disputeKitData: undefined });
+ setSelectedFeatures([]);
+ }
+ };
+
+ return (
+
+
+ {items ? (
+ typeof path === "string" && handleCourtChange(path.split("/").pop()!)}
+ placeholder="Select Court"
+ value={`/courts/${disputeData.courtId}`}
+ />
+ ) : (
+
+ )}
+
+
+
+
+ {isUndefined(disputeData.courtId) ? null : }
+
+
+ );
+};
+
+export default Court;
diff --git a/web/src/public/llms.txt b/web/src/public/llms.txt
new file mode 100644
index 000000000..00c5825f0
--- /dev/null
+++ b/web/src/public/llms.txt
@@ -0,0 +1,9 @@
+# v2.kleros.builders llms.txt
+
+> Facilitates decentralized arbitration by allowing users to create, manage, and resolve dispute cases through crowdsourced juror consensus, rewarding jurors with cryptocurrency for coherent votes on disputes on the blockchain-based Kleros platform.
+
+- [Kleros Dispute Dashboard](https://v2.kleros.builders): Dashboard for managing and viewing decentralized dispute cases, jurors, and court statistics on Kleros platform.
+- [Kleros Dispute Cases](https://v2.kleros.builders/#/cases/display/1/desc/all): Provide a platform for viewing and managing decentralized dispute resolution cases.
+- [Kleros Decentralized Courts](https://v2.kleros.builders/#/courts): Facilitate decentralized dispute resolution by allowing users to stake tokens, participate as jurors, and view court cases.
+- [Kleros Jurors Leaderboard](https://v2.kleros.builders/#/jurors/1/desc/all): Display ranking and statistics of jurors based on coherent voting and rewards in the Kleros decentralized arbitration system.
+- [Get PNK Token](https://v2.kleros.builders/#/get-pnk): Facilitates cross-chain swaps of PNK tokens typically between the Ethereum and Arbitrum networks.
diff --git a/web/src/styles/mdxEditorTheme.ts b/web/src/styles/mdxEditorTheme.ts
new file mode 100644
index 000000000..0ef1d8b21
--- /dev/null
+++ b/web/src/styles/mdxEditorTheme.ts
@@ -0,0 +1,256 @@
+import styled, { createGlobalStyle, css } from "styled-components";
+
+const sharedContentStyles = css`
+ .mdxeditor-root-contenteditable {
+ transition: background-color 0.1s ease !important;
+ :hover {
+ background-color: ${({ theme }) => theme.lightGrey}60 !important;
+ }
+ }
+
+ .mdxeditor-root-contenteditable p {
+ color: ${({ theme }) => theme.primaryText} !important;
+ margin: 0 0 12px 0;
+ }
+
+ .mdxeditor-root-contenteditable h1,
+ .mdxeditor-root-contenteditable h2,
+ .mdxeditor-root-contenteditable h3,
+ .mdxeditor-root-contenteditable h4,
+ .mdxeditor-root-contenteditable h5,
+ .mdxeditor-root-contenteditable h6 {
+ color: ${({ theme }) => theme.primaryText} !important;
+ font-weight: 600;
+ margin: 16px 0 8px 0;
+ }
+
+ .mdxeditor-root-contenteditable blockquote {
+ color: ${({ theme }) => theme.primaryText} !important;
+ border-left: 3px solid ${({ theme }) => theme.mediumBlue} !important;
+ font-style: italic;
+ margin: 16px 0;
+ padding-left: 12px;
+ }
+
+ .mdxeditor-root-contenteditable pre {
+ background-color: ${({ theme }) => theme.lightBackground} !important;
+ color: ${({ theme }) => theme.primaryText} !important;
+ border: 1px solid ${({ theme }) => theme.stroke} !important;
+ border-radius: 6px !important;
+ padding: 12px !important;
+ margin: 12px 0 !important;
+ font-family: "Fira Code", monospace !important;
+ font-size: 14px !important;
+ }
+
+ .mdxeditor-root-contenteditable a {
+ color: ${({ theme }) => theme.primaryBlue} !important;
+ }
+
+ .mdxeditor-root-contenteditable span[class*="_code_"],
+ .mdxeditor-root-contenteditable code {
+ background-color: ${({ theme }) => theme.lightBackground} !important;
+ color: ${({ theme }) => theme.primaryText} !important;
+ padding: 2px 6px !important;
+ border-radius: 4px !important;
+ font-size: 14px !important;
+ font-family: "Fira Code", monospace !important;
+ border: 1px solid ${({ theme }) => theme.stroke} !important;
+ }
+
+ .mdxeditor-root-contenteditable th {
+ background-color: ${({ theme }) => theme.lightGrey} !important;
+ color: ${({ theme }) => theme.primaryText} !important;
+ }
+
+ .mdxeditor-root-contenteditable td {
+ color: ${({ theme }) => theme.primaryText} !important;
+ }
+`;
+
+export const MDXEditorContainer = styled.div`
+ width: 100%;
+
+ .mdxeditor-toolbar {
+ display: flex;
+ flex-wrap: wrap;
+ background-color: ${({ theme }) => theme.lightGrey} !important;
+ border: 1px solid ${({ theme }) => theme.stroke} !important;
+ border-radius: 3px;
+ font-family: "Open Sans", sans-serif;
+ }
+
+ .mdxeditor-toolbar button {
+ color: ${({ theme }) => theme.primaryText} !important;
+ }
+
+ .mdxeditor-toolbar button:hover {
+ background-color: ${({ theme }) => theme.whiteBackground} !important;
+ cursor: pointer !important;
+ }
+
+ .mdxeditor-toolbar button[data-state="on"],
+ .mdxeditor-toolbar button[aria-pressed="true"] {
+ background-color: ${({ theme }) => theme.whiteBackground} !important;
+ }
+
+ .mdxeditor-toolbar button:disabled,
+ .mdxeditor-toolbar button[data-disabled="true"] {
+ opacity: 0.4 !important;
+ cursor: not-allowed !important;
+ }
+
+ .mdxeditor-toolbar button svg {
+ color: ${({ theme }) => theme.primaryText} !important;
+ }
+
+ .mdxeditor-toolbar button:disabled svg,
+ .mdxeditor-toolbar button[data-disabled="true"] svg {
+ color: ${({ theme }) => theme.secondaryText} !important;
+ }
+
+ .mdxeditor-root-contenteditable {
+ background-color: ${({ theme }) => theme.whiteBackground} !important;
+ border: 1px solid ${({ theme }) => theme.stroke} !important;
+ border-radius: 3px;
+ color: ${({ theme }) => theme.primaryText} !important;
+ height: 220px;
+ overflow-y: auto;
+ overflow-x: hidden;
+ padding: 16px;
+ font-size: 16px;
+ line-height: 1.5;
+ }
+
+ [class*="placeholder"] {
+ color: ${({ theme }) => theme.secondaryText} !important;
+ opacity: 0.6 !important;
+ margin-top: 16px;
+ }
+
+ ${sharedContentStyles}
+
+ [class*="tableColumnEditorPopoverContent"],
+ [class*="addRowButton"],
+ [class*="addColumnButton"],
+ [class*="deleteRowButton"],
+ [class*="deleteColumnButton"],
+ [class*="tableEditor"],
+ [class*="tableToolbar"],
+ [class*="tablePopover"] {
+ background-color: ${({ theme }) => theme.whiteBackground} !important;
+
+ svg,
+ path {
+ color: ${({ theme }) => theme.primaryText} !important;
+ }
+ }
+`;
+
+export const MDXEditorGlobalStyles = createGlobalStyle`
+ .cm-editor {
+ background-color: ${({ theme }) => theme.lightBackground} !important;
+ border: 1px solid ${({ theme }) => theme.stroke} !important;
+ border-radius: 6px !important;
+ }
+
+ .cm-content {
+ color: ${({ theme }) => theme.primaryText} !important;
+ font-family: "Fira Code", monospace !important;
+ font-size: 14px !important;
+ padding: 12px !important;
+ }
+
+ .cm-focused {
+ outline: none !important;
+ }
+
+ [class*="codeMirrorToolbar"] {
+ background-color: transparent !important;
+ }
+
+ [class*="cm-gutterElement"] {
+ color: ${({ theme }) => theme.secondaryText} !important;
+ }
+
+ [class*="codeMirrorWrapper"] {
+ border: 1px solid ${({ theme }) => theme.stroke} !important;
+ padding: 0 !important;
+ }
+
+ [class*="activeLineGutter"] {
+ background-color: transparent !important;
+ }
+
+ /* Global styles for all MDXEditor popups and overlays */
+ [class*="linkDialogPopoverContent"],
+ [class*="selectTrigger"],
+ [class*="selectContent"],
+ [class*="tableColumnEditorPopoverContent"],
+ [class*="tablePopover"],
+ [data-radix-popper-content-wrapper] [class*="linkDialog"],
+ [data-radix-popper-content-wrapper] [class*="select"],
+ [data-radix-popper-content-wrapper] [class*="table"],
+ [data-radix-portal] [class*="linkDialog"],
+ [data-radix-portal] [class*="select"],
+ [data-radix-portal] [class*="table"],
+ [data-radix-portal] div[class*="mdx"],
+ [data-radix-popper-content-wrapper] div[class*="mdx"] {
+ background-color: ${({ theme }) => theme.whiteBackground} !important;
+ border: 1px solid ${({ theme }) => theme.stroke} !important;
+ color: ${({ theme }) => theme.primaryText} !important;
+
+ input,
+ select {
+ background-color: ${({ theme }) => theme.whiteBackground} !important;
+ border: 1px solid ${({ theme }) => theme.stroke} !important;
+ color: ${({ theme }) => theme.primaryText} !important;
+
+ &:hover {
+ background-color: ${({ theme }) => theme.lightGrey} !important;
+ }
+ }
+
+ button {
+ background-color: ${({ theme }) => theme.lightGrey} !important;
+ color: ${({ theme }) => theme.primaryText} !important;
+ border: 1px solid ${({ theme }) => theme.stroke} !important;
+ cursor: pointer !important;
+ transition: background-color 0.2s ease !important;
+
+ &:hover {
+ background-color: ${({ theme }) => theme.lightBackground} !important;
+ }
+
+ &:active {
+ background-color: ${({ theme }) => theme.stroke} !important;
+ }
+ }
+
+ label,
+ span,
+ div {
+ color: ${({ theme }) => theme.primaryText} !important;
+ }
+
+ svg,
+ path {
+ color: ${({ theme }) => theme.primaryText} !important;
+ }
+ }
+
+ [class*="mdx"] button,
+ [class*="select"] button,
+ [class*="trigger"],
+ [role="button"],
+ [data-radix-portal] [role="button"],
+ [data-radix-popper-content-wrapper] [role="button"],
+ [data-radix-portal] [data-state],
+ [data-radix-popper-content-wrapper] [data-state] {
+ cursor: pointer !important;
+ transition: all 0.1s ease !important;
+ &:hover {
+ background-color: ${({ theme }) => theme.lightGrey} !important;
+ }
+ }
+`;
diff --git a/web/src/utils/extradataToTokenInfo.ts b/web/src/utils/extradataToTokenInfo.ts
index 7feca7137..f4d3180b0 100644
--- a/web/src/utils/extradataToTokenInfo.ts
+++ b/web/src/utils/extradataToTokenInfo.ts
@@ -10,16 +10,13 @@ type GatedTokenInfo = {
* @dev Decodes token information from encoded extra data.
* @param extraData The extraData
* @returns GatedTokenInfo object with tokenGate address, isERC1155 flag, and tokenId.
+ * `undefined` if it's not a gated disputeKit
*/
-export function extraDataToTokenInfo(extraDataHex: `0x${string}`): GatedTokenInfo {
+export function extraDataToTokenInfo(extraDataHex: `0x${string}`): GatedTokenInfo | undefined {
const extraDataBytes = hexToBytes(extraDataHex);
if (extraDataBytes.length < 160) {
- return {
- tokenGate: "0x0000000000000000000000000000000000000000",
- isERC1155: false,
- tokenId: "0",
- };
+ return;
}
// Slot 4 (bytes 96–127): packedTokenGateAndFlag
diff --git a/web/src/utils/linkUtils.ts b/web/src/utils/linkUtils.ts
new file mode 100644
index 000000000..e926d70f0
--- /dev/null
+++ b/web/src/utils/linkUtils.ts
@@ -0,0 +1,28 @@
+export const isExternalLink = (url: string): boolean => {
+ if (!url || typeof url !== "string") {
+ return false;
+ }
+
+ const trimmedUrl = url.trim();
+
+ if (trimmedUrl.startsWith("/") || trimmedUrl.startsWith("./") || trimmedUrl.startsWith("../")) {
+ return false;
+ }
+
+ if (trimmedUrl.startsWith("#")) {
+ return false;
+ }
+
+ if (trimmedUrl.startsWith("mailto:") || trimmedUrl.startsWith("tel:")) {
+ return true;
+ }
+
+ try {
+ const currentOrigin = window.location.origin;
+ const linkUrl = new URL(trimmedUrl, currentOrigin);
+
+ return linkUrl.origin !== currentOrigin;
+ } catch {
+ return true;
+ }
+};
diff --git a/web/src/utils/urlValidation.ts b/web/src/utils/urlValidation.ts
new file mode 100644
index 000000000..ba4cc7b36
--- /dev/null
+++ b/web/src/utils/urlValidation.ts
@@ -0,0 +1,46 @@
+const DANGEROUS_PROTOCOLS = ["javascript:", "vbscript:", "file:", "about:", "blob:", "filesystem:"];
+
+const ALLOWED_PROTOCOLS = ["http:", "https:", "mailto:", "tel:", "ftp:"];
+
+const ALLOWED_DATA_TYPES = ["image/jpeg", "image/png", "image/gif", "image/webp", "image/svg+xml"];
+
+const isValidDataUri = (url: string): boolean => {
+ const dataUriRegex = /^data:([^;,]+)(;base64)?,/i;
+ const match = url.match(dataUriRegex);
+
+ if (!match) {
+ return false;
+ }
+
+ const mimeType = match[1].toLowerCase();
+ return ALLOWED_DATA_TYPES.includes(mimeType);
+};
+
+export const isValidUrl = (url: string): boolean => {
+ if (!url || typeof url !== "string") {
+ return false;
+ }
+
+ const trimmedUrl = url.trim().toLowerCase();
+
+ if (trimmedUrl.length === 0) {
+ return false;
+ }
+
+ if (trimmedUrl.startsWith("data:")) {
+ return isValidDataUri(trimmedUrl);
+ }
+
+ for (const protocol of DANGEROUS_PROTOCOLS) {
+ if (trimmedUrl.startsWith(protocol)) {
+ return false;
+ }
+ }
+
+ try {
+ const urlObj = new URL(url);
+ return ALLOWED_PROTOCOLS.includes(urlObj.protocol);
+ } catch {
+ return false;
+ }
+};
diff --git a/web/wagmi.config.ts b/web/wagmi.config.ts
index 893df2554..f3b21dd0d 100644
--- a/web/wagmi.config.ts
+++ b/web/wagmi.config.ts
@@ -18,7 +18,7 @@ dotenv.config();
const readArtifacts = async (type: ArbitratorTypes, viemChainName: string, hardhatChainName?: string) => {
const artifactSuffix =
- type === ArbitratorTypes.vanilla
+ type === ArbitratorTypes.vanilla || type === ArbitratorTypes.neo
? ""
: ArbitratorTypes[type].toString().charAt(0).toUpperCase() + ArbitratorTypes[type].toString().slice(1);
const vanillaArtifacts = [
@@ -59,7 +59,7 @@ const readArtifacts = async (type: ArbitratorTypes, viemChainName: string, hardh
// console.debug(`Skipping ${name} for deployment type ${ArbitratorTypes[type]}`);
continue;
}
- if (type !== ArbitratorTypes.vanilla) {
+ if (type === ArbitratorTypes.university) {
nameWithoutSuffix = name.slice(0, -artifactSuffix.length);
// console.debug(`Using ${nameWithoutSuffix} instead of ${name}`);
}
diff --git a/yarn.lock b/yarn.lock
index 166200247..8b05f14c9 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1811,6 +1811,13 @@ __metadata:
languageName: node
linkType: hard
+"@babel/runtime@npm:^7.14.8":
+ version: 7.28.4
+ resolution: "@babel/runtime@npm:7.28.4"
+ checksum: 10/6c9a70452322ea80b3c9b2a412bcf60771819213a67576c8cec41e88a95bb7bf01fc983754cda35dc19603eef52df22203ccbf7777b9d6316932f9fb77c25163
+ languageName: node
+ linkType: hard
+
"@babel/runtime@npm:^7.26.10":
version: 7.27.0
resolution: "@babel/runtime@npm:7.27.0"
@@ -2271,6 +2278,18 @@ __metadata:
languageName: node
linkType: hard
+"@codemirror/autocomplete@npm:^6.0.0, @codemirror/autocomplete@npm:^6.3.2, @codemirror/autocomplete@npm:^6.4.0, @codemirror/autocomplete@npm:^6.7.1":
+ version: 6.18.7
+ resolution: "@codemirror/autocomplete@npm:6.18.7"
+ dependencies:
+ "@codemirror/language": "npm:^6.0.0"
+ "@codemirror/state": "npm:^6.0.0"
+ "@codemirror/view": "npm:^6.17.0"
+ "@lezer/common": "npm:^1.0.0"
+ checksum: 10/e50e3345d7d33e762d9abd2e6b1ea4ff54afe1630310464a5ddb42cab52fd5bac783ec0dc8a328cb746be6a7f9f711b6fcd8ef311af123511e8307b4c056cb9d
+ languageName: node
+ linkType: hard
+
"@codemirror/autocomplete@npm:^6.18.1":
version: 6.18.6
resolution: "@codemirror/autocomplete@npm:6.18.6"
@@ -2283,7 +2302,7 @@ __metadata:
languageName: node
linkType: hard
-"@codemirror/commands@npm:^6.7.1":
+"@codemirror/commands@npm:^6.0.0, @codemirror/commands@npm:^6.1.3, @codemirror/commands@npm:^6.2.4, @codemirror/commands@npm:^6.7.1":
version: 6.8.1
resolution: "@codemirror/commands@npm:6.8.1"
dependencies:
@@ -2295,6 +2314,108 @@ __metadata:
languageName: node
linkType: hard
+"@codemirror/lang-angular@npm:^0.1.0":
+ version: 0.1.4
+ resolution: "@codemirror/lang-angular@npm:0.1.4"
+ dependencies:
+ "@codemirror/lang-html": "npm:^6.0.0"
+ "@codemirror/lang-javascript": "npm:^6.1.2"
+ "@codemirror/language": "npm:^6.0.0"
+ "@lezer/common": "npm:^1.2.0"
+ "@lezer/highlight": "npm:^1.0.0"
+ "@lezer/lr": "npm:^1.3.3"
+ checksum: 10/94f8e03a7636918a74cb18cb695538b8609732c0c39ac255b822dfd06cc55238bc488146e16b9f051e88949208e032045882f1feabac78e2968d2890056b08c7
+ languageName: node
+ linkType: hard
+
+"@codemirror/lang-cpp@npm:^6.0.0":
+ version: 6.0.3
+ resolution: "@codemirror/lang-cpp@npm:6.0.3"
+ dependencies:
+ "@codemirror/language": "npm:^6.0.0"
+ "@lezer/cpp": "npm:^1.0.0"
+ checksum: 10/982b9a9624367a0086520e1d499b7ad2fba2a14bdd57df88520bac279bd980e12154fd281659226fbcfa530edb5dd72edd114481365e6224bf53e97bc972f3b8
+ languageName: node
+ linkType: hard
+
+"@codemirror/lang-css@npm:^6.0.0, @codemirror/lang-css@npm:^6.0.1, @codemirror/lang-css@npm:^6.2.0":
+ version: 6.3.1
+ resolution: "@codemirror/lang-css@npm:6.3.1"
+ dependencies:
+ "@codemirror/autocomplete": "npm:^6.0.0"
+ "@codemirror/language": "npm:^6.0.0"
+ "@codemirror/state": "npm:^6.0.0"
+ "@lezer/common": "npm:^1.0.2"
+ "@lezer/css": "npm:^1.1.7"
+ checksum: 10/709994b0a787fe06ebac7a47c6a6a92c9680fe2b4479bbe2a72b27ad4d863953ad64a61b36f15098d00bd9a655bc9b3a3ecf2877354351ff873a01186fb38386
+ languageName: node
+ linkType: hard
+
+"@codemirror/lang-go@npm:^6.0.0":
+ version: 6.0.1
+ resolution: "@codemirror/lang-go@npm:6.0.1"
+ dependencies:
+ "@codemirror/autocomplete": "npm:^6.0.0"
+ "@codemirror/language": "npm:^6.6.0"
+ "@codemirror/state": "npm:^6.0.0"
+ "@lezer/common": "npm:^1.0.0"
+ "@lezer/go": "npm:^1.0.0"
+ checksum: 10/6e361bddb35683b225e1367807f598044b861c6858c9a011227fb73a872735985141746b3c410dcd8ef11b4c0e54819e720c5e663201a6a5e69ba8a9519fa287
+ languageName: node
+ linkType: hard
+
+"@codemirror/lang-html@npm:^6.0.0, @codemirror/lang-html@npm:^6.4.0":
+ version: 6.4.10
+ resolution: "@codemirror/lang-html@npm:6.4.10"
+ dependencies:
+ "@codemirror/autocomplete": "npm:^6.0.0"
+ "@codemirror/lang-css": "npm:^6.0.0"
+ "@codemirror/lang-javascript": "npm:^6.0.0"
+ "@codemirror/language": "npm:^6.4.0"
+ "@codemirror/state": "npm:^6.0.0"
+ "@codemirror/view": "npm:^6.17.0"
+ "@lezer/common": "npm:^1.0.0"
+ "@lezer/css": "npm:^1.1.0"
+ "@lezer/html": "npm:^1.3.0"
+ checksum: 10/258ba6f90dee9fb7cefe32926b59cc4a9223b8c7bac8fea14518daa5195cffb8383efac2102f7769c50c45d0d93c17c67cdcebaea43c81511b61447f743ffc2d
+ languageName: node
+ linkType: hard
+
+"@codemirror/lang-java@npm:^6.0.0":
+ version: 6.0.2
+ resolution: "@codemirror/lang-java@npm:6.0.2"
+ dependencies:
+ "@codemirror/language": "npm:^6.0.0"
+ "@lezer/java": "npm:^1.0.0"
+ checksum: 10/ed884f5e1a90c0d487bc4e5073c6154f3abf51b0b652c3d015e8cb322e171a38307427a85ecc16d5be82bd3243577e77e202325d84394a9c5ac356ee358c56c9
+ languageName: node
+ linkType: hard
+
+"@codemirror/lang-javascript@npm:^6.0.0, @codemirror/lang-javascript@npm:^6.1.2":
+ version: 6.2.4
+ resolution: "@codemirror/lang-javascript@npm:6.2.4"
+ dependencies:
+ "@codemirror/autocomplete": "npm:^6.0.0"
+ "@codemirror/language": "npm:^6.6.0"
+ "@codemirror/lint": "npm:^6.0.0"
+ "@codemirror/state": "npm:^6.0.0"
+ "@codemirror/view": "npm:^6.17.0"
+ "@lezer/common": "npm:^1.0.0"
+ "@lezer/javascript": "npm:^1.0.0"
+ checksum: 10/7d0b7fdacc90f89d1a5f2b9c575c61b6ee7813005cde32c1f35aedb0da71ad298998e116126ba19ca0bb02cdb14064945c31e24c57ef60bcbd5c19dae955ccb6
+ languageName: node
+ linkType: hard
+
+"@codemirror/lang-json@npm:^6.0.0":
+ version: 6.0.2
+ resolution: "@codemirror/lang-json@npm:6.0.2"
+ dependencies:
+ "@codemirror/language": "npm:^6.0.0"
+ "@lezer/json": "npm:^1.0.0"
+ checksum: 10/a8e57ad5c6cc53edd0d8bce4c26fa189dd5a95c371e72d32957d4a5c857f814761d9dfab81361f8e8ae9da7bcf657e7e1343f39694f9cffb1c144dd3ef7092a0
+ languageName: node
+ linkType: hard
+
"@codemirror/lang-json@npm:^6.0.1":
version: 6.0.1
resolution: "@codemirror/lang-json@npm:6.0.1"
@@ -2305,6 +2426,198 @@ __metadata:
languageName: node
linkType: hard
+"@codemirror/lang-less@npm:^6.0.0":
+ version: 6.0.2
+ resolution: "@codemirror/lang-less@npm:6.0.2"
+ dependencies:
+ "@codemirror/lang-css": "npm:^6.2.0"
+ "@codemirror/language": "npm:^6.0.0"
+ "@lezer/common": "npm:^1.2.0"
+ "@lezer/highlight": "npm:^1.0.0"
+ "@lezer/lr": "npm:^1.0.0"
+ checksum: 10/233aa03e0bfb57e4f23fdb2a8d52ad3143a52553895b97cb2901f66d59fc40246b525a21b7be72d873efa98783f6da5f4e8e042da442b092fab9eb63c69524c8
+ languageName: node
+ linkType: hard
+
+"@codemirror/lang-liquid@npm:^6.0.0":
+ version: 6.3.0
+ resolution: "@codemirror/lang-liquid@npm:6.3.0"
+ dependencies:
+ "@codemirror/autocomplete": "npm:^6.0.0"
+ "@codemirror/lang-html": "npm:^6.0.0"
+ "@codemirror/language": "npm:^6.0.0"
+ "@codemirror/state": "npm:^6.0.0"
+ "@codemirror/view": "npm:^6.0.0"
+ "@lezer/common": "npm:^1.0.0"
+ "@lezer/highlight": "npm:^1.0.0"
+ "@lezer/lr": "npm:^1.3.1"
+ checksum: 10/da6bd8108598db397bb11fe13e81b0517cf63181d8e3f10d7e7c7775cbe0c32e3babd1d0c96e96640952c94e9dc4c0d0242dce1acc445b837044c7d5dcf17729
+ languageName: node
+ linkType: hard
+
+"@codemirror/lang-markdown@npm:^6.0.0, @codemirror/lang-markdown@npm:^6.2.3":
+ version: 6.3.4
+ resolution: "@codemirror/lang-markdown@npm:6.3.4"
+ dependencies:
+ "@codemirror/autocomplete": "npm:^6.7.1"
+ "@codemirror/lang-html": "npm:^6.0.0"
+ "@codemirror/language": "npm:^6.3.0"
+ "@codemirror/state": "npm:^6.0.0"
+ "@codemirror/view": "npm:^6.0.0"
+ "@lezer/common": "npm:^1.2.1"
+ "@lezer/markdown": "npm:^1.0.0"
+ checksum: 10/8e23721a6c113cd56eca183a1089a01b19ad8cfe16b0604c0d9d825f285e2a3dc8de18a763c6a1aaf37947a890fc3ddd3cac3d25e912a506d310e4a01ceb8ab0
+ languageName: node
+ linkType: hard
+
+"@codemirror/lang-php@npm:^6.0.0":
+ version: 6.0.2
+ resolution: "@codemirror/lang-php@npm:6.0.2"
+ dependencies:
+ "@codemirror/lang-html": "npm:^6.0.0"
+ "@codemirror/language": "npm:^6.0.0"
+ "@codemirror/state": "npm:^6.0.0"
+ "@lezer/common": "npm:^1.0.0"
+ "@lezer/php": "npm:^1.0.0"
+ checksum: 10/ae697fa8101f034244467ffc812a0de9c944bab1b141da2c55a4a80e5cedfd2fcbe9d1dcd36d4d3593ff9fb8e1963d7c3fb4fa307d652a73aa7607322aec1ce7
+ languageName: node
+ linkType: hard
+
+"@codemirror/lang-python@npm:^6.0.0":
+ version: 6.2.1
+ resolution: "@codemirror/lang-python@npm:6.2.1"
+ dependencies:
+ "@codemirror/autocomplete": "npm:^6.3.2"
+ "@codemirror/language": "npm:^6.8.0"
+ "@codemirror/state": "npm:^6.0.0"
+ "@lezer/common": "npm:^1.2.1"
+ "@lezer/python": "npm:^1.1.4"
+ checksum: 10/8651972fcfc194c0da028bea0162eb070f8f9b6241a9ec7771b3061bd7f3c4122ca0eed2e5fcf4c46e731cb31d4af1fb7f1d2949387ba9133826aa0253a9dddb
+ languageName: node
+ linkType: hard
+
+"@codemirror/lang-rust@npm:^6.0.0":
+ version: 6.0.2
+ resolution: "@codemirror/lang-rust@npm:6.0.2"
+ dependencies:
+ "@codemirror/language": "npm:^6.0.0"
+ "@lezer/rust": "npm:^1.0.0"
+ checksum: 10/4cb7528c723ec3f421bd82a5324c56d836f3675e3b28e2b2d3c9d251e8f206bf9d932d52696c310dca51d71644063441fb8330d5ad1278c68002f8598b4bc067
+ languageName: node
+ linkType: hard
+
+"@codemirror/lang-sass@npm:^6.0.0":
+ version: 6.0.2
+ resolution: "@codemirror/lang-sass@npm:6.0.2"
+ dependencies:
+ "@codemirror/lang-css": "npm:^6.2.0"
+ "@codemirror/language": "npm:^6.0.0"
+ "@codemirror/state": "npm:^6.0.0"
+ "@lezer/common": "npm:^1.0.2"
+ "@lezer/sass": "npm:^1.0.0"
+ checksum: 10/de5c72f62714960961b616c8fe25b4f127906b0c05ec2e8e633d0b896fb2da979732cad0f51b1c0bc058494db5447664234b7910a3345fb5080d8222d4011818
+ languageName: node
+ linkType: hard
+
+"@codemirror/lang-sql@npm:^6.0.0":
+ version: 6.10.0
+ resolution: "@codemirror/lang-sql@npm:6.10.0"
+ dependencies:
+ "@codemirror/autocomplete": "npm:^6.0.0"
+ "@codemirror/language": "npm:^6.0.0"
+ "@codemirror/state": "npm:^6.0.0"
+ "@lezer/common": "npm:^1.2.0"
+ "@lezer/highlight": "npm:^1.0.0"
+ "@lezer/lr": "npm:^1.0.0"
+ checksum: 10/23b9f4f1283bf63a41e7e8455f33fb528769bcc277ab0981b1bf7b8a589041883f9e2dcb0d64e0de0964577a7a6a30921ed3109c7fa0d85405716236ddc97d45
+ languageName: node
+ linkType: hard
+
+"@codemirror/lang-vue@npm:^0.1.1":
+ version: 0.1.3
+ resolution: "@codemirror/lang-vue@npm:0.1.3"
+ dependencies:
+ "@codemirror/lang-html": "npm:^6.0.0"
+ "@codemirror/lang-javascript": "npm:^6.1.2"
+ "@codemirror/language": "npm:^6.0.0"
+ "@lezer/common": "npm:^1.2.0"
+ "@lezer/highlight": "npm:^1.0.0"
+ "@lezer/lr": "npm:^1.3.1"
+ checksum: 10/f08c04c47671de0b65568cbc0f9e517c7c443bd097eb0ca63ecdc1b81f842dbfd0b81b208ee5c31e3293ebc377b4b271c89cf18bf04bb898ecac538df22aff3a
+ languageName: node
+ linkType: hard
+
+"@codemirror/lang-wast@npm:^6.0.0":
+ version: 6.0.2
+ resolution: "@codemirror/lang-wast@npm:6.0.2"
+ dependencies:
+ "@codemirror/language": "npm:^6.0.0"
+ "@lezer/common": "npm:^1.2.0"
+ "@lezer/highlight": "npm:^1.0.0"
+ "@lezer/lr": "npm:^1.0.0"
+ checksum: 10/c7f9820191ca8d8877b38a6205f7e46721c0deeb552c3f234a7166bfd4581e071718cbf395749f271bd5c0da879285a7829a5843c052dd52e8a4e41509777e35
+ languageName: node
+ linkType: hard
+
+"@codemirror/lang-xml@npm:^6.0.0":
+ version: 6.1.0
+ resolution: "@codemirror/lang-xml@npm:6.1.0"
+ dependencies:
+ "@codemirror/autocomplete": "npm:^6.0.0"
+ "@codemirror/language": "npm:^6.4.0"
+ "@codemirror/state": "npm:^6.0.0"
+ "@codemirror/view": "npm:^6.0.0"
+ "@lezer/common": "npm:^1.0.0"
+ "@lezer/xml": "npm:^1.0.0"
+ checksum: 10/f5e54668c30efbb8a78a51e49ccec92a06931f2b98dce35c90be94ded30da02dac525124ce3c40f65c7b071f8db72d16b10a5a1795ccbf10e69939c0a9c1cac8
+ languageName: node
+ linkType: hard
+
+"@codemirror/lang-yaml@npm:^6.0.0":
+ version: 6.1.2
+ resolution: "@codemirror/lang-yaml@npm:6.1.2"
+ dependencies:
+ "@codemirror/autocomplete": "npm:^6.0.0"
+ "@codemirror/language": "npm:^6.0.0"
+ "@codemirror/state": "npm:^6.0.0"
+ "@lezer/common": "npm:^1.2.0"
+ "@lezer/highlight": "npm:^1.2.0"
+ "@lezer/lr": "npm:^1.0.0"
+ "@lezer/yaml": "npm:^1.0.0"
+ checksum: 10/1a1ad16554b27d9f66ad2a342170e7c7e51781876280727790e763e9a770163772d4880a9c344705ca65acc2b5fb228962dc3281ba05a71d2c071515541258ae
+ languageName: node
+ linkType: hard
+
+"@codemirror/language-data@npm:^6.5.1":
+ version: 6.5.1
+ resolution: "@codemirror/language-data@npm:6.5.1"
+ dependencies:
+ "@codemirror/lang-angular": "npm:^0.1.0"
+ "@codemirror/lang-cpp": "npm:^6.0.0"
+ "@codemirror/lang-css": "npm:^6.0.0"
+ "@codemirror/lang-go": "npm:^6.0.0"
+ "@codemirror/lang-html": "npm:^6.0.0"
+ "@codemirror/lang-java": "npm:^6.0.0"
+ "@codemirror/lang-javascript": "npm:^6.0.0"
+ "@codemirror/lang-json": "npm:^6.0.0"
+ "@codemirror/lang-less": "npm:^6.0.0"
+ "@codemirror/lang-liquid": "npm:^6.0.0"
+ "@codemirror/lang-markdown": "npm:^6.0.0"
+ "@codemirror/lang-php": "npm:^6.0.0"
+ "@codemirror/lang-python": "npm:^6.0.0"
+ "@codemirror/lang-rust": "npm:^6.0.0"
+ "@codemirror/lang-sass": "npm:^6.0.0"
+ "@codemirror/lang-sql": "npm:^6.0.0"
+ "@codemirror/lang-vue": "npm:^0.1.1"
+ "@codemirror/lang-wast": "npm:^6.0.0"
+ "@codemirror/lang-xml": "npm:^6.0.0"
+ "@codemirror/lang-yaml": "npm:^6.0.0"
+ "@codemirror/language": "npm:^6.0.0"
+ "@codemirror/legacy-modes": "npm:^6.4.0"
+ checksum: 10/a46f4015da2c213ebe7cc685b5c657b92a340e3f12ed26a9f8c3a04cf3e46063c86141c6f9dca4faeaaf6de068b4e797d40c9a572ca317a122f84ad7ceb5e684
+ languageName: node
+ linkType: hard
+
"@codemirror/language@npm:^6.0.0":
version: 6.10.3
resolution: "@codemirror/language@npm:6.10.3"
@@ -2333,7 +2646,30 @@ __metadata:
languageName: node
linkType: hard
-"@codemirror/lint@npm:^6.8.2":
+"@codemirror/language@npm:^6.3.0, @codemirror/language@npm:^6.3.2, @codemirror/language@npm:^6.4.0, @codemirror/language@npm:^6.6.0, @codemirror/language@npm:^6.8.0":
+ version: 6.11.3
+ resolution: "@codemirror/language@npm:6.11.3"
+ dependencies:
+ "@codemirror/state": "npm:^6.0.0"
+ "@codemirror/view": "npm:^6.23.0"
+ "@lezer/common": "npm:^1.1.0"
+ "@lezer/highlight": "npm:^1.0.0"
+ "@lezer/lr": "npm:^1.0.0"
+ style-mod: "npm:^4.0.0"
+ checksum: 10/8538a2835c1de6ca2d520ff66449185f2ea3a93e7d69382d9db3b4db6460f4c46b44f19724458c50230abfa87cf2c225834d39c3fe3119c48370db6b3de0b772
+ languageName: node
+ linkType: hard
+
+"@codemirror/legacy-modes@npm:^6.4.0":
+ version: 6.5.1
+ resolution: "@codemirror/legacy-modes@npm:6.5.1"
+ dependencies:
+ "@codemirror/language": "npm:^6.0.0"
+ checksum: 10/585de2a47a4ac10b3f96ef1616c849167cc6bae2a337a58a9a85c094cb95c4c27b8429c6bf2edf6a072946eb65b8169d090333003592c0b1ad0a51bc5a438c2a
+ languageName: node
+ linkType: hard
+
+"@codemirror/lint@npm:^6.0.0, @codemirror/lint@npm:^6.8.2":
version: 6.8.5
resolution: "@codemirror/lint@npm:6.8.5"
dependencies:
@@ -2344,6 +2680,30 @@ __metadata:
languageName: node
linkType: hard
+"@codemirror/merge@npm:^6.4.0":
+ version: 6.10.2
+ resolution: "@codemirror/merge@npm:6.10.2"
+ dependencies:
+ "@codemirror/language": "npm:^6.0.0"
+ "@codemirror/state": "npm:^6.0.0"
+ "@codemirror/view": "npm:^6.17.0"
+ "@lezer/highlight": "npm:^1.0.0"
+ style-mod: "npm:^4.1.0"
+ checksum: 10/b19b9fb4ae7dca94d87d7884c1ec7c33835b0a87081aa733deeb37c2930589222eb431f5a2e2c61f7d791ba2e73e002076480342790d0f64ab76033acb8ff98b
+ languageName: node
+ linkType: hard
+
+"@codemirror/search@npm:^6.0.0":
+ version: 6.5.11
+ resolution: "@codemirror/search@npm:6.5.11"
+ dependencies:
+ "@codemirror/state": "npm:^6.0.0"
+ "@codemirror/view": "npm:^6.0.0"
+ crelt: "npm:^1.0.5"
+ checksum: 10/d057f37cb369460b25625d7eb72f40636bf78ecd140608da53010cf3660f982a9e613826e38d85d87c9c2ff11e45c9482429987bfd4f29cbbd192f1ee3fd2695
+ languageName: node
+ linkType: hard
+
"@codemirror/search@npm:^6.5.6":
version: 6.5.7
resolution: "@codemirror/search@npm:6.5.7"
@@ -2397,6 +2757,72 @@ __metadata:
languageName: node
linkType: hard
+"@codemirror/view@npm:^6.7.1":
+ version: 6.38.3
+ resolution: "@codemirror/view@npm:6.38.3"
+ dependencies:
+ "@codemirror/state": "npm:^6.5.0"
+ crelt: "npm:^1.0.6"
+ style-mod: "npm:^4.1.0"
+ w3c-keyname: "npm:^2.2.4"
+ checksum: 10/2df41450399cbac0eaf06dba822418dd6926e48344b9255902248075ef040c957dfe97fe842a755e284a2fd4a66dc17b9638385f46ad74e926baac2e797335a2
+ languageName: node
+ linkType: hard
+
+"@codesandbox/nodebox@npm:0.1.8":
+ version: 0.1.8
+ resolution: "@codesandbox/nodebox@npm:0.1.8"
+ dependencies:
+ outvariant: "npm:^1.4.0"
+ strict-event-emitter: "npm:^0.4.3"
+ checksum: 10/3de00d306ae0236524c436b8640c442a4541f0eb696820aa5f6fc66018dc66431d8d78edd9305986aa2877befca292a3906bb4c6af2ecba5f15dbd587d1c916d
+ languageName: node
+ linkType: hard
+
+"@codesandbox/sandpack-client@npm:^2.19.8":
+ version: 2.19.8
+ resolution: "@codesandbox/sandpack-client@npm:2.19.8"
+ dependencies:
+ "@codesandbox/nodebox": "npm:0.1.8"
+ buffer: "npm:^6.0.3"
+ dequal: "npm:^2.0.2"
+ mime-db: "npm:^1.52.0"
+ outvariant: "npm:1.4.0"
+ static-browser-server: "npm:1.0.3"
+ checksum: 10/7913fa4a7bbaf925f4ab0ad1969a4da1f52c093b1b71229dd8ecf3f50462bd004fcf3fddccdb15225b55737305d3f6727a187353f12cb39a75336fa7229eb4dd
+ languageName: node
+ linkType: hard
+
+"@codesandbox/sandpack-react@npm:^2.20.0":
+ version: 2.20.0
+ resolution: "@codesandbox/sandpack-react@npm:2.20.0"
+ dependencies:
+ "@codemirror/autocomplete": "npm:^6.4.0"
+ "@codemirror/commands": "npm:^6.1.3"
+ "@codemirror/lang-css": "npm:^6.0.1"
+ "@codemirror/lang-html": "npm:^6.4.0"
+ "@codemirror/lang-javascript": "npm:^6.1.2"
+ "@codemirror/language": "npm:^6.3.2"
+ "@codemirror/state": "npm:^6.2.0"
+ "@codemirror/view": "npm:^6.7.1"
+ "@codesandbox/sandpack-client": "npm:^2.19.8"
+ "@lezer/highlight": "npm:^1.1.3"
+ "@react-hook/intersection-observer": "npm:^3.1.1"
+ "@stitches/core": "npm:^1.2.6"
+ anser: "npm:^2.1.1"
+ clean-set: "npm:^1.1.2"
+ dequal: "npm:^2.0.2"
+ escape-carriage: "npm:^1.3.1"
+ lz-string: "npm:^1.4.4"
+ react-devtools-inline: "npm:4.4.0"
+ react-is: "npm:^17.0.2"
+ peerDependencies:
+ react: ^16.8.0 || ^17 || ^18 || ^19
+ react-dom: ^16.8.0 || ^17 || ^18 || ^19
+ checksum: 10/313c937dacaafcc18622f54a274835aa3a444ff697e9e511c52d548d7ba4e233d19ef8bb1da081668251020bd9afd480641194032504b4b3d20ac3cb0cbcd03b
+ languageName: node
+ linkType: hard
+
"@coinbase/wallet-sdk@npm:4.3.0":
version: 4.3.0
resolution: "@coinbase/wallet-sdk@npm:4.3.0"
@@ -3065,6 +3491,13 @@ __metadata:
languageName: node
linkType: hard
+"@esbuild/aix-ppc64@npm:0.25.8":
+ version: 0.25.8
+ resolution: "@esbuild/aix-ppc64@npm:0.25.8"
+ conditions: os=aix & cpu=ppc64
+ languageName: node
+ linkType: hard
+
"@esbuild/android-arm64@npm:0.19.12":
version: 0.19.12
resolution: "@esbuild/android-arm64@npm:0.19.12"
@@ -3079,6 +3512,13 @@ __metadata:
languageName: node
linkType: hard
+"@esbuild/android-arm64@npm:0.25.8":
+ version: 0.25.8
+ resolution: "@esbuild/android-arm64@npm:0.25.8"
+ conditions: os=android & cpu=arm64
+ languageName: node
+ linkType: hard
+
"@esbuild/android-arm@npm:0.19.12":
version: 0.19.12
resolution: "@esbuild/android-arm@npm:0.19.12"
@@ -3093,6 +3533,13 @@ __metadata:
languageName: node
linkType: hard
+"@esbuild/android-arm@npm:0.25.8":
+ version: 0.25.8
+ resolution: "@esbuild/android-arm@npm:0.25.8"
+ conditions: os=android & cpu=arm
+ languageName: node
+ linkType: hard
+
"@esbuild/android-x64@npm:0.19.12":
version: 0.19.12
resolution: "@esbuild/android-x64@npm:0.19.12"
@@ -3107,6 +3554,13 @@ __metadata:
languageName: node
linkType: hard
+"@esbuild/android-x64@npm:0.25.8":
+ version: 0.25.8
+ resolution: "@esbuild/android-x64@npm:0.25.8"
+ conditions: os=android & cpu=x64
+ languageName: node
+ linkType: hard
+
"@esbuild/darwin-arm64@npm:0.19.12":
version: 0.19.12
resolution: "@esbuild/darwin-arm64@npm:0.19.12"
@@ -3121,6 +3575,13 @@ __metadata:
languageName: node
linkType: hard
+"@esbuild/darwin-arm64@npm:0.25.8":
+ version: 0.25.8
+ resolution: "@esbuild/darwin-arm64@npm:0.25.8"
+ conditions: os=darwin & cpu=arm64
+ languageName: node
+ linkType: hard
+
"@esbuild/darwin-x64@npm:0.19.12":
version: 0.19.12
resolution: "@esbuild/darwin-x64@npm:0.19.12"
@@ -3135,6 +3596,13 @@ __metadata:
languageName: node
linkType: hard
+"@esbuild/darwin-x64@npm:0.25.8":
+ version: 0.25.8
+ resolution: "@esbuild/darwin-x64@npm:0.25.8"
+ conditions: os=darwin & cpu=x64
+ languageName: node
+ linkType: hard
+
"@esbuild/freebsd-arm64@npm:0.19.12":
version: 0.19.12
resolution: "@esbuild/freebsd-arm64@npm:0.19.12"
@@ -3149,6 +3617,13 @@ __metadata:
languageName: node
linkType: hard
+"@esbuild/freebsd-arm64@npm:0.25.8":
+ version: 0.25.8
+ resolution: "@esbuild/freebsd-arm64@npm:0.25.8"
+ conditions: os=freebsd & cpu=arm64
+ languageName: node
+ linkType: hard
+
"@esbuild/freebsd-x64@npm:0.19.12":
version: 0.19.12
resolution: "@esbuild/freebsd-x64@npm:0.19.12"
@@ -3163,6 +3638,13 @@ __metadata:
languageName: node
linkType: hard
+"@esbuild/freebsd-x64@npm:0.25.8":
+ version: 0.25.8
+ resolution: "@esbuild/freebsd-x64@npm:0.25.8"
+ conditions: os=freebsd & cpu=x64
+ languageName: node
+ linkType: hard
+
"@esbuild/linux-arm64@npm:0.19.12":
version: 0.19.12
resolution: "@esbuild/linux-arm64@npm:0.19.12"
@@ -3177,6 +3659,13 @@ __metadata:
languageName: node
linkType: hard
+"@esbuild/linux-arm64@npm:0.25.8":
+ version: 0.25.8
+ resolution: "@esbuild/linux-arm64@npm:0.25.8"
+ conditions: os=linux & cpu=arm64
+ languageName: node
+ linkType: hard
+
"@esbuild/linux-arm@npm:0.19.12":
version: 0.19.12
resolution: "@esbuild/linux-arm@npm:0.19.12"
@@ -3191,6 +3680,13 @@ __metadata:
languageName: node
linkType: hard
+"@esbuild/linux-arm@npm:0.25.8":
+ version: 0.25.8
+ resolution: "@esbuild/linux-arm@npm:0.25.8"
+ conditions: os=linux & cpu=arm
+ languageName: node
+ linkType: hard
+
"@esbuild/linux-ia32@npm:0.19.12":
version: 0.19.12
resolution: "@esbuild/linux-ia32@npm:0.19.12"
@@ -3205,6 +3701,13 @@ __metadata:
languageName: node
linkType: hard
+"@esbuild/linux-ia32@npm:0.25.8":
+ version: 0.25.8
+ resolution: "@esbuild/linux-ia32@npm:0.25.8"
+ conditions: os=linux & cpu=ia32
+ languageName: node
+ linkType: hard
+
"@esbuild/linux-loong64@npm:0.19.12":
version: 0.19.12
resolution: "@esbuild/linux-loong64@npm:0.19.12"
@@ -3219,6 +3722,13 @@ __metadata:
languageName: node
linkType: hard
+"@esbuild/linux-loong64@npm:0.25.8":
+ version: 0.25.8
+ resolution: "@esbuild/linux-loong64@npm:0.25.8"
+ conditions: os=linux & cpu=loong64
+ languageName: node
+ linkType: hard
+
"@esbuild/linux-mips64el@npm:0.19.12":
version: 0.19.12
resolution: "@esbuild/linux-mips64el@npm:0.19.12"
@@ -3233,6 +3743,13 @@ __metadata:
languageName: node
linkType: hard
+"@esbuild/linux-mips64el@npm:0.25.8":
+ version: 0.25.8
+ resolution: "@esbuild/linux-mips64el@npm:0.25.8"
+ conditions: os=linux & cpu=mips64el
+ languageName: node
+ linkType: hard
+
"@esbuild/linux-ppc64@npm:0.19.12":
version: 0.19.12
resolution: "@esbuild/linux-ppc64@npm:0.19.12"
@@ -3247,6 +3764,13 @@ __metadata:
languageName: node
linkType: hard
+"@esbuild/linux-ppc64@npm:0.25.8":
+ version: 0.25.8
+ resolution: "@esbuild/linux-ppc64@npm:0.25.8"
+ conditions: os=linux & cpu=ppc64
+ languageName: node
+ linkType: hard
+
"@esbuild/linux-riscv64@npm:0.19.12":
version: 0.19.12
resolution: "@esbuild/linux-riscv64@npm:0.19.12"
@@ -3261,6 +3785,13 @@ __metadata:
languageName: node
linkType: hard
+"@esbuild/linux-riscv64@npm:0.25.8":
+ version: 0.25.8
+ resolution: "@esbuild/linux-riscv64@npm:0.25.8"
+ conditions: os=linux & cpu=riscv64
+ languageName: node
+ linkType: hard
+
"@esbuild/linux-s390x@npm:0.19.12":
version: 0.19.12
resolution: "@esbuild/linux-s390x@npm:0.19.12"
@@ -3275,6 +3806,13 @@ __metadata:
languageName: node
linkType: hard
+"@esbuild/linux-s390x@npm:0.25.8":
+ version: 0.25.8
+ resolution: "@esbuild/linux-s390x@npm:0.25.8"
+ conditions: os=linux & cpu=s390x
+ languageName: node
+ linkType: hard
+
"@esbuild/linux-x64@npm:0.19.12":
version: 0.19.12
resolution: "@esbuild/linux-x64@npm:0.19.12"
@@ -3289,6 +3827,20 @@ __metadata:
languageName: node
linkType: hard
+"@esbuild/linux-x64@npm:0.25.8":
+ version: 0.25.8
+ resolution: "@esbuild/linux-x64@npm:0.25.8"
+ conditions: os=linux & cpu=x64
+ languageName: node
+ linkType: hard
+
+"@esbuild/netbsd-arm64@npm:0.25.8":
+ version: 0.25.8
+ resolution: "@esbuild/netbsd-arm64@npm:0.25.8"
+ conditions: os=netbsd & cpu=arm64
+ languageName: node
+ linkType: hard
+
"@esbuild/netbsd-x64@npm:0.19.12":
version: 0.19.12
resolution: "@esbuild/netbsd-x64@npm:0.19.12"
@@ -3303,6 +3855,20 @@ __metadata:
languageName: node
linkType: hard
+"@esbuild/netbsd-x64@npm:0.25.8":
+ version: 0.25.8
+ resolution: "@esbuild/netbsd-x64@npm:0.25.8"
+ conditions: os=netbsd & cpu=x64
+ languageName: node
+ linkType: hard
+
+"@esbuild/openbsd-arm64@npm:0.25.8":
+ version: 0.25.8
+ resolution: "@esbuild/openbsd-arm64@npm:0.25.8"
+ conditions: os=openbsd & cpu=arm64
+ languageName: node
+ linkType: hard
+
"@esbuild/openbsd-x64@npm:0.19.12":
version: 0.19.12
resolution: "@esbuild/openbsd-x64@npm:0.19.12"
@@ -3317,6 +3883,20 @@ __metadata:
languageName: node
linkType: hard
+"@esbuild/openbsd-x64@npm:0.25.8":
+ version: 0.25.8
+ resolution: "@esbuild/openbsd-x64@npm:0.25.8"
+ conditions: os=openbsd & cpu=x64
+ languageName: node
+ linkType: hard
+
+"@esbuild/openharmony-arm64@npm:0.25.8":
+ version: 0.25.8
+ resolution: "@esbuild/openharmony-arm64@npm:0.25.8"
+ conditions: os=openharmony & cpu=arm64
+ languageName: node
+ linkType: hard
+
"@esbuild/sunos-x64@npm:0.19.12":
version: 0.19.12
resolution: "@esbuild/sunos-x64@npm:0.19.12"
@@ -3331,6 +3911,13 @@ __metadata:
languageName: node
linkType: hard
+"@esbuild/sunos-x64@npm:0.25.8":
+ version: 0.25.8
+ resolution: "@esbuild/sunos-x64@npm:0.25.8"
+ conditions: os=sunos & cpu=x64
+ languageName: node
+ linkType: hard
+
"@esbuild/win32-arm64@npm:0.19.12":
version: 0.19.12
resolution: "@esbuild/win32-arm64@npm:0.19.12"
@@ -3345,6 +3932,13 @@ __metadata:
languageName: node
linkType: hard
+"@esbuild/win32-arm64@npm:0.25.8":
+ version: 0.25.8
+ resolution: "@esbuild/win32-arm64@npm:0.25.8"
+ conditions: os=win32 & cpu=arm64
+ languageName: node
+ linkType: hard
+
"@esbuild/win32-ia32@npm:0.19.12":
version: 0.19.12
resolution: "@esbuild/win32-ia32@npm:0.19.12"
@@ -3359,6 +3953,13 @@ __metadata:
languageName: node
linkType: hard
+"@esbuild/win32-ia32@npm:0.25.8":
+ version: 0.25.8
+ resolution: "@esbuild/win32-ia32@npm:0.25.8"
+ conditions: os=win32 & cpu=ia32
+ languageName: node
+ linkType: hard
+
"@esbuild/win32-x64@npm:0.19.12":
version: 0.19.12
resolution: "@esbuild/win32-x64@npm:0.19.12"
@@ -3373,6 +3974,13 @@ __metadata:
languageName: node
linkType: hard
+"@esbuild/win32-x64@npm:0.25.8":
+ version: 0.25.8
+ resolution: "@esbuild/win32-x64@npm:0.25.8"
+ conditions: os=win32 & cpu=x64
+ languageName: node
+ linkType: hard
+
"@eslint-community/eslint-utils@npm:^4.2.0, @eslint-community/eslint-utils@npm:^4.4.0":
version: 4.4.0
resolution: "@eslint-community/eslint-utils@npm:4.4.0"
@@ -4401,6 +5009,58 @@ __metadata:
languageName: node
linkType: hard
+"@floating-ui/core@npm:^1.7.3":
+ version: 1.7.3
+ resolution: "@floating-ui/core@npm:1.7.3"
+ dependencies:
+ "@floating-ui/utils": "npm:^0.2.10"
+ checksum: 10/a8952ff2673ddf28f12feeb86d90c54949e45bcb1af5758b7672850ac0dadb36d4bd61aa45dad1b6a35ba40d4756d3573afac6610b90502639d7266b91e0864e
+ languageName: node
+ linkType: hard
+
+"@floating-ui/dom@npm:^1.7.4":
+ version: 1.7.4
+ resolution: "@floating-ui/dom@npm:1.7.4"
+ dependencies:
+ "@floating-ui/core": "npm:^1.7.3"
+ "@floating-ui/utils": "npm:^0.2.10"
+ checksum: 10/d3d6a23e7b9804ba56338c7c666590258683af14b6026270d32afc1202f72b5b82cca359004bdc7830bf2463a045da6c7bd4e7d5351218cf270ff94206197971
+ languageName: node
+ linkType: hard
+
+"@floating-ui/react-dom@npm:^2.0.0, @floating-ui/react-dom@npm:^2.1.6":
+ version: 2.1.6
+ resolution: "@floating-ui/react-dom@npm:2.1.6"
+ dependencies:
+ "@floating-ui/dom": "npm:^1.7.4"
+ peerDependencies:
+ react: ">=16.8.0"
+ react-dom: ">=16.8.0"
+ checksum: 10/fbfd3319b42edb9c156e4e872f500d2edb112bc9cfd1b45892bff16ccf21c2484ddc9c416f7631c2aaaadec1b2f98b205db8a3f89eb78ca870905fcfe3917c35
+ languageName: node
+ linkType: hard
+
+"@floating-ui/react@npm:^0.27.8":
+ version: 0.27.16
+ resolution: "@floating-ui/react@npm:0.27.16"
+ dependencies:
+ "@floating-ui/react-dom": "npm:^2.1.6"
+ "@floating-ui/utils": "npm:^0.2.10"
+ tabbable: "npm:^6.0.0"
+ peerDependencies:
+ react: ">=17.0.0"
+ react-dom: ">=17.0.0"
+ checksum: 10/b9baedee124035323a8f74794ec782678faf52af1c88731ce7d2641b7e7c97748fda1e711a3c4db007a0153d93158d867f4726ee632d713d3de76ec4bdfd84e1
+ languageName: node
+ linkType: hard
+
+"@floating-ui/utils@npm:^0.2.10":
+ version: 0.2.10
+ resolution: "@floating-ui/utils@npm:0.2.10"
+ checksum: 10/b635ea865a8be2484b608b7157f5abf9ed439f351011a74b7e988439e2898199a9a8b790f52291e05bdcf119088160dc782d98cff45cc98c5a271bc6f51327ae
+ languageName: node
+ linkType: hard
+
"@fortawesome/fontawesome-common-types@npm:6.7.2":
version: 6.7.2
resolution: "@fortawesome/fontawesome-common-types@npm:6.7.2"
@@ -5941,7 +6601,7 @@ __metadata:
"@kleros/kleros-v2-eslint-config": "workspace:^"
"@kleros/kleros-v2-prettier-config": "workspace:^"
"@kleros/kleros-v2-tsconfig": "workspace:^"
- "@kleros/vea-contracts": "npm:^0.6.0"
+ "@kleros/vea-contracts": "npm:^0.7.0"
"@logtail/pino": "npm:^0.5.0"
"@nomicfoundation/hardhat-chai-matchers": "npm:^2.1.0"
"@nomicfoundation/hardhat-ethers": "npm:^3.1.0"
@@ -5955,7 +6615,7 @@ __metadata:
"@types/mocha": "npm:^10.0.10"
"@types/node": "npm:^20.17.6"
"@types/sinon": "npm:^17.0.4"
- "@wagmi/cli": "npm:^2.2.0"
+ "@wagmi/cli": "npm:^2.3.2"
abitype: "npm:^0.10.3"
chai: "npm:^4.5.0"
dotenv: "npm:^16.6.1"
@@ -5965,14 +6625,14 @@ __metadata:
gluegun: "npm:^5.2.0"
graphql: "npm:^16.9.0"
graphql-request: "npm:^7.1.2"
- hardhat: "npm:2.25.0"
- hardhat-contract-sizer: "npm:^2.10.0"
+ hardhat: "npm:2.26.3"
+ hardhat-contract-sizer: "npm:^2.10.1"
hardhat-deploy: "npm:^1.0.4"
hardhat-deploy-ethers: "npm:^0.4.2"
hardhat-deploy-tenderly: "npm:^0.2.1"
hardhat-docgen: "npm:^1.3.0"
hardhat-gas-reporter: "npm:^2.3.0"
- hardhat-tracer: "npm:^3.2.1"
+ hardhat-tracer: "npm:^3.4.0"
hardhat-watcher: "npm:^2.5.0"
isomorphic-fetch: "npm:^3.0.0"
pino: "npm:^8.21.0"
@@ -5986,7 +6646,11 @@ __metadata:
ts-node: "npm:^10.9.2"
typechain: "npm:^8.3.2"
typescript: "npm:^5.6.3"
- viem: "npm:^2.24.1"
+ peerDependencies:
+ viem: ^2.24.1
+ peerDependenciesMeta:
+ viem:
+ optional: false
languageName: unknown
linkType: soft
@@ -6127,6 +6791,7 @@ __metadata:
"@kleros/ui-components-library": "npm:^2.20.0"
"@lifi/wallet-management": "npm:^3.7.1"
"@lifi/widget": "npm:^3.18.1"
+ "@mdxeditor/editor": "npm:^3.45.0"
"@reown/appkit": "npm:^1.7.1"
"@reown/appkit-adapter-wagmi": "npm:^1.7.1"
"@sentry/react": "npm:^7.120.0"
@@ -6179,6 +6844,9 @@ __metadata:
react-scripts: "npm:^5.0.1"
react-toastify: "npm:^9.1.3"
react-use: "npm:^17.5.1"
+ rehype-raw: "npm:^7.0.0"
+ rehype-sanitize: "npm:^6.0.0"
+ remark-gfm: "npm:^3.0.1"
rimraf: "npm:^6.0.1"
styled-components: "npm:^5.3.3"
subgraph-status: "npm:^1.2.4"
@@ -6216,10 +6884,10 @@ __metadata:
languageName: node
linkType: hard
-"@kleros/vea-contracts@npm:^0.6.0":
- version: 0.6.0
- resolution: "@kleros/vea-contracts@npm:0.6.0"
- checksum: 10/1dafd94620d3392c2e00e09e7d1ca923007143f8625b4b584411a7b49404ae5630e870d3e260685964d37ccb9c4c4ab406523b8ec4dd9f89bcf6099a4f5976ec
+"@kleros/vea-contracts@npm:^0.7.0":
+ version: 0.7.0
+ resolution: "@kleros/vea-contracts@npm:0.7.0"
+ checksum: 10/bba12886020cd4bfce39938de56edf2b56472627871ef91b10b721de655e5c20f632a8cb57679927d868375218007898b12033d769b7d33cd3f18447ca093896
languageName: node
linkType: hard
@@ -6230,6 +6898,258 @@ __metadata:
languageName: node
linkType: hard
+"@lexical/clipboard@npm:0.35.0, @lexical/clipboard@npm:^0.35.0":
+ version: 0.35.0
+ resolution: "@lexical/clipboard@npm:0.35.0"
+ dependencies:
+ "@lexical/html": "npm:0.35.0"
+ "@lexical/list": "npm:0.35.0"
+ "@lexical/selection": "npm:0.35.0"
+ "@lexical/utils": "npm:0.35.0"
+ lexical: "npm:0.35.0"
+ checksum: 10/acde7547e5ad3ffa60f339a697952e3dc785c90f638bcd0e996221174a09209d584ac22ae6fe3f92814cd1cf4991546d82ce6d401ccc2084b4f0aac8b480bb88
+ languageName: node
+ linkType: hard
+
+"@lexical/code@npm:0.35.0":
+ version: 0.35.0
+ resolution: "@lexical/code@npm:0.35.0"
+ dependencies:
+ "@lexical/utils": "npm:0.35.0"
+ lexical: "npm:0.35.0"
+ prismjs: "npm:^1.30.0"
+ checksum: 10/4eea3cd640b33af2971d1e6ea893046b93c686873fa450c442837a03277b31c217a37e17d115be5e6ea8a1a9fe3a00df495403918b9fff68aef873f66413def1
+ languageName: node
+ linkType: hard
+
+"@lexical/devtools-core@npm:0.35.0":
+ version: 0.35.0
+ resolution: "@lexical/devtools-core@npm:0.35.0"
+ dependencies:
+ "@lexical/html": "npm:0.35.0"
+ "@lexical/link": "npm:0.35.0"
+ "@lexical/mark": "npm:0.35.0"
+ "@lexical/table": "npm:0.35.0"
+ "@lexical/utils": "npm:0.35.0"
+ lexical: "npm:0.35.0"
+ peerDependencies:
+ react: ">=17.x"
+ react-dom: ">=17.x"
+ checksum: 10/d14ef05df4c7b0ec67b8da820904db695747548e45064e2bd8af25c42b44b4d5835964402b1830396587acdd79a43e98224c650193bc04798225815ca273c580
+ languageName: node
+ linkType: hard
+
+"@lexical/dragon@npm:0.35.0":
+ version: 0.35.0
+ resolution: "@lexical/dragon@npm:0.35.0"
+ dependencies:
+ lexical: "npm:0.35.0"
+ checksum: 10/6c89b2c79e1aa59188d01561a59107f3816f31587e21be38f98a8508f2f4caeabf4fd54acc6aca42b27ee4ad49ce44d952f517a0bac25d9e7c1411db375b6698
+ languageName: node
+ linkType: hard
+
+"@lexical/hashtag@npm:0.35.0":
+ version: 0.35.0
+ resolution: "@lexical/hashtag@npm:0.35.0"
+ dependencies:
+ "@lexical/utils": "npm:0.35.0"
+ lexical: "npm:0.35.0"
+ checksum: 10/ed12a1b61ad05bc7288beb5a3e89fb88e55f7710c2ba22c27aea7e26078756e8c2d69f32856bb5dca64f383dd47b028206b0d36d8ffc7ec979b8ed23df8b32fb
+ languageName: node
+ linkType: hard
+
+"@lexical/history@npm:0.35.0":
+ version: 0.35.0
+ resolution: "@lexical/history@npm:0.35.0"
+ dependencies:
+ "@lexical/utils": "npm:0.35.0"
+ lexical: "npm:0.35.0"
+ checksum: 10/7cecef8407a7cdd478c82d9314aecbaa7fef8bc9c6993bfbad7edc80658a35c1b7061132c9d876edafdd066dd40b6a2ca1bdba5eda05bed2f22729356e7bdc15
+ languageName: node
+ linkType: hard
+
+"@lexical/html@npm:0.35.0":
+ version: 0.35.0
+ resolution: "@lexical/html@npm:0.35.0"
+ dependencies:
+ "@lexical/selection": "npm:0.35.0"
+ "@lexical/utils": "npm:0.35.0"
+ lexical: "npm:0.35.0"
+ checksum: 10/458beee56f4ea157d8bb56b1f8c74fe58da87b6b5a64e666f7356247f7cf62e9fab643f4c3d84f1043539c1c3165be604bbf30bc8d002443d067801a32ef8cac
+ languageName: node
+ linkType: hard
+
+"@lexical/link@npm:0.35.0, @lexical/link@npm:^0.35.0":
+ version: 0.35.0
+ resolution: "@lexical/link@npm:0.35.0"
+ dependencies:
+ "@lexical/utils": "npm:0.35.0"
+ lexical: "npm:0.35.0"
+ checksum: 10/670ae6d2b24b56bcefacb2fd6159c17bf07a6bd2fe84e3f5a6a002cab4359c90f2e1478284bca108650be9f9c52d070d0a3a09601fc6682cb834e7119633a026
+ languageName: node
+ linkType: hard
+
+"@lexical/list@npm:0.35.0, @lexical/list@npm:^0.35.0":
+ version: 0.35.0
+ resolution: "@lexical/list@npm:0.35.0"
+ dependencies:
+ "@lexical/selection": "npm:0.35.0"
+ "@lexical/utils": "npm:0.35.0"
+ lexical: "npm:0.35.0"
+ checksum: 10/8ad774ffc041cb6d2277cc160e1f04ef0cbcfee1b74dc9888c316ebf00675c68c583961993a2a3ea506674f947896adc6c2d07fa7512eedfb1caa6009b8f3af4
+ languageName: node
+ linkType: hard
+
+"@lexical/mark@npm:0.35.0":
+ version: 0.35.0
+ resolution: "@lexical/mark@npm:0.35.0"
+ dependencies:
+ "@lexical/utils": "npm:0.35.0"
+ lexical: "npm:0.35.0"
+ checksum: 10/e20244127316f03d0383dd3f3762d5d3daf904aeab28a49b54c826210ef03077ee9004304bba643735b0bc451c93f95b085b8ab2a62d8382e40636868f6acc91
+ languageName: node
+ linkType: hard
+
+"@lexical/markdown@npm:0.35.0, @lexical/markdown@npm:^0.35.0":
+ version: 0.35.0
+ resolution: "@lexical/markdown@npm:0.35.0"
+ dependencies:
+ "@lexical/code": "npm:0.35.0"
+ "@lexical/link": "npm:0.35.0"
+ "@lexical/list": "npm:0.35.0"
+ "@lexical/rich-text": "npm:0.35.0"
+ "@lexical/text": "npm:0.35.0"
+ "@lexical/utils": "npm:0.35.0"
+ lexical: "npm:0.35.0"
+ checksum: 10/79a72aa37cc66ab8878a594cc74251b0755ead239364194177c9f34ac4eaa1c3864bbd11d19733771bdb92bbf6a5a764bda43e4f182838d54666724b0a1db7d0
+ languageName: node
+ linkType: hard
+
+"@lexical/offset@npm:0.35.0":
+ version: 0.35.0
+ resolution: "@lexical/offset@npm:0.35.0"
+ dependencies:
+ lexical: "npm:0.35.0"
+ checksum: 10/588bf20540e69138cd30a441a374d6248b97a618026c3afe1d3e75a45cb47623d8010faa86491ed3bbdd57f0ae95f39372fbfb406fb7b97d663ee029b8028590
+ languageName: node
+ linkType: hard
+
+"@lexical/overflow@npm:0.35.0":
+ version: 0.35.0
+ resolution: "@lexical/overflow@npm:0.35.0"
+ dependencies:
+ lexical: "npm:0.35.0"
+ checksum: 10/05b0700d96d3a43614278fa11a3834881a1c37d4904c5731b59cc3483bffe558b6e307e2363067c59457e16776756ebb792912f3eb1c9896b5755b30eb2843a4
+ languageName: node
+ linkType: hard
+
+"@lexical/plain-text@npm:0.35.0, @lexical/plain-text@npm:^0.35.0":
+ version: 0.35.0
+ resolution: "@lexical/plain-text@npm:0.35.0"
+ dependencies:
+ "@lexical/clipboard": "npm:0.35.0"
+ "@lexical/selection": "npm:0.35.0"
+ "@lexical/utils": "npm:0.35.0"
+ lexical: "npm:0.35.0"
+ checksum: 10/2dfa06123fc93a41fa8c53f87e162f04e92fa38db5107c4680ff80049a1b7fc3516252fd993163235cc58a5f007d374642aaa5cb039269e31c0eb73b5c708670
+ languageName: node
+ linkType: hard
+
+"@lexical/react@npm:^0.35.0":
+ version: 0.35.0
+ resolution: "@lexical/react@npm:0.35.0"
+ dependencies:
+ "@floating-ui/react": "npm:^0.27.8"
+ "@lexical/devtools-core": "npm:0.35.0"
+ "@lexical/dragon": "npm:0.35.0"
+ "@lexical/hashtag": "npm:0.35.0"
+ "@lexical/history": "npm:0.35.0"
+ "@lexical/link": "npm:0.35.0"
+ "@lexical/list": "npm:0.35.0"
+ "@lexical/mark": "npm:0.35.0"
+ "@lexical/markdown": "npm:0.35.0"
+ "@lexical/overflow": "npm:0.35.0"
+ "@lexical/plain-text": "npm:0.35.0"
+ "@lexical/rich-text": "npm:0.35.0"
+ "@lexical/table": "npm:0.35.0"
+ "@lexical/text": "npm:0.35.0"
+ "@lexical/utils": "npm:0.35.0"
+ "@lexical/yjs": "npm:0.35.0"
+ lexical: "npm:0.35.0"
+ react-error-boundary: "npm:^3.1.4"
+ peerDependencies:
+ react: ">=17.x"
+ react-dom: ">=17.x"
+ checksum: 10/a1a9a174c12b2df338355fab6a7d8995f3ef082c11fd7f6eaea728885c2d1e53881cf3df3977cb2a798c296b9ae91a9ef71db893bf12ed723897949f3707b860
+ languageName: node
+ linkType: hard
+
+"@lexical/rich-text@npm:0.35.0, @lexical/rich-text@npm:^0.35.0":
+ version: 0.35.0
+ resolution: "@lexical/rich-text@npm:0.35.0"
+ dependencies:
+ "@lexical/clipboard": "npm:0.35.0"
+ "@lexical/selection": "npm:0.35.0"
+ "@lexical/utils": "npm:0.35.0"
+ lexical: "npm:0.35.0"
+ checksum: 10/d06e08bb441c991a4729720d6e974e7e427271cacd79268e7a92bb820c6ff5f682a76eaaab837f1057a028c3d592a28dc31d27e3436f99a28ad8cc0a974432eb
+ languageName: node
+ linkType: hard
+
+"@lexical/selection@npm:0.35.0, @lexical/selection@npm:^0.35.0":
+ version: 0.35.0
+ resolution: "@lexical/selection@npm:0.35.0"
+ dependencies:
+ lexical: "npm:0.35.0"
+ checksum: 10/36285d042e5f883197a2e05e39159b7515926622eaf489ba28249565eaaccd2415e94e1b888a376cbda0556f8073438736c222433d4d499f534af449ce24d89a
+ languageName: node
+ linkType: hard
+
+"@lexical/table@npm:0.35.0":
+ version: 0.35.0
+ resolution: "@lexical/table@npm:0.35.0"
+ dependencies:
+ "@lexical/clipboard": "npm:0.35.0"
+ "@lexical/utils": "npm:0.35.0"
+ lexical: "npm:0.35.0"
+ checksum: 10/ace388cfe706860e789421d192eb30183c63afb01d90c1b2f328b3f3ed7ce032ae45698bf94f2e5e4e340a73c53fed7a27cbf3b72a3d91ef5382e879a1df26bf
+ languageName: node
+ linkType: hard
+
+"@lexical/text@npm:0.35.0":
+ version: 0.35.0
+ resolution: "@lexical/text@npm:0.35.0"
+ dependencies:
+ lexical: "npm:0.35.0"
+ checksum: 10/6de985ca932d141d79cf47f0678ab40363d2a3be326e61d2dc25b9abff1b012aab299b819c489ede92f1bb72bc4bce37a1c563e9a44ffef5ebb05d0285a0e0e0
+ languageName: node
+ linkType: hard
+
+"@lexical/utils@npm:0.35.0, @lexical/utils@npm:^0.35.0":
+ version: 0.35.0
+ resolution: "@lexical/utils@npm:0.35.0"
+ dependencies:
+ "@lexical/list": "npm:0.35.0"
+ "@lexical/selection": "npm:0.35.0"
+ "@lexical/table": "npm:0.35.0"
+ lexical: "npm:0.35.0"
+ checksum: 10/be81f3e809285ebf3838200d6c00a787ba216097672555a8cab00edf8c401be9f6004032562b6432bd52a6ab5dc552486488d21636661795bcf8694ac46f51c6
+ languageName: node
+ linkType: hard
+
+"@lexical/yjs@npm:0.35.0":
+ version: 0.35.0
+ resolution: "@lexical/yjs@npm:0.35.0"
+ dependencies:
+ "@lexical/offset": "npm:0.35.0"
+ "@lexical/selection": "npm:0.35.0"
+ lexical: "npm:0.35.0"
+ peerDependencies:
+ yjs: ">=13.5.22"
+ checksum: 10/7a926fffa929e757dbf7da9d058e7ef315ff3691f3656f00d18ac1aeba5bceb357ac3dd4d2baeb74c16033802b7087f524bd3e7666f25840c88a98245590c13e
+ languageName: node
+ linkType: hard
+
"@lezer/common@npm:^1.0.0, @lezer/common@npm:^1.1.0, @lezer/common@npm:^1.2.0":
version: 1.2.1
resolution: "@lezer/common@npm:1.2.1"
@@ -6237,6 +7157,46 @@ __metadata:
languageName: node
linkType: hard
+"@lezer/common@npm:^1.0.2, @lezer/common@npm:^1.2.1":
+ version: 1.2.3
+ resolution: "@lezer/common@npm:1.2.3"
+ checksum: 10/dad24e353e4e67d88b203191361ca1dff26c01c2b7b4ae829b668a1d115929334d077217367683e39180c0556510ed2066ea8ddba2b079be7c08a7152208cc87
+ languageName: node
+ linkType: hard
+
+"@lezer/cpp@npm:^1.0.0":
+ version: 1.1.3
+ resolution: "@lezer/cpp@npm:1.1.3"
+ dependencies:
+ "@lezer/common": "npm:^1.2.0"
+ "@lezer/highlight": "npm:^1.0.0"
+ "@lezer/lr": "npm:^1.0.0"
+ checksum: 10/4ffe11d08a142fd1cf710e7a01222ab63ecd3da9a3de954f462bac55db22cce1ce7667055295149bd386afd698228f355b07b0335745579fe659c7af4978d645
+ languageName: node
+ linkType: hard
+
+"@lezer/css@npm:^1.1.0, @lezer/css@npm:^1.1.7":
+ version: 1.3.0
+ resolution: "@lezer/css@npm:1.3.0"
+ dependencies:
+ "@lezer/common": "npm:^1.2.0"
+ "@lezer/highlight": "npm:^1.0.0"
+ "@lezer/lr": "npm:^1.3.0"
+ checksum: 10/142609b690b9fef139ea947faf43253df596834805c0805c69bc8866c4366790eb1b392d65a25dae5f840ff3de676768cc3b808013435c82db20d6a0f3917e97
+ languageName: node
+ linkType: hard
+
+"@lezer/go@npm:^1.0.0":
+ version: 1.0.1
+ resolution: "@lezer/go@npm:1.0.1"
+ dependencies:
+ "@lezer/common": "npm:^1.2.0"
+ "@lezer/highlight": "npm:^1.0.0"
+ "@lezer/lr": "npm:^1.3.0"
+ checksum: 10/1b96969679a16973fc112027fb28301328454e739621e0695f0011b1e5f159bc792e829dd8d586b8fd1c34218be4d9dee2ae73fa8802dcba98da9219a38a92d9
+ languageName: node
+ linkType: hard
+
"@lezer/highlight@npm:^1.0.0":
version: 1.2.0
resolution: "@lezer/highlight@npm:1.2.0"
@@ -6246,7 +7206,7 @@ __metadata:
languageName: node
linkType: hard
-"@lezer/highlight@npm:^1.2.1":
+"@lezer/highlight@npm:^1.1.3, @lezer/highlight@npm:^1.2.0, @lezer/highlight@npm:^1.2.1":
version: 1.2.1
resolution: "@lezer/highlight@npm:1.2.1"
dependencies:
@@ -6255,6 +7215,39 @@ __metadata:
languageName: node
linkType: hard
+"@lezer/html@npm:^1.3.0":
+ version: 1.3.10
+ resolution: "@lezer/html@npm:1.3.10"
+ dependencies:
+ "@lezer/common": "npm:^1.2.0"
+ "@lezer/highlight": "npm:^1.0.0"
+ "@lezer/lr": "npm:^1.0.0"
+ checksum: 10/b69f796492c0a2c000ebba88e1b1f0dc0885ed3392c11b46a9d7c638da1a325d6a288375fbeec52d0d05437b801302299e0e57359f95a494db1e251b3d66d29c
+ languageName: node
+ linkType: hard
+
+"@lezer/java@npm:^1.0.0":
+ version: 1.1.3
+ resolution: "@lezer/java@npm:1.1.3"
+ dependencies:
+ "@lezer/common": "npm:^1.2.0"
+ "@lezer/highlight": "npm:^1.0.0"
+ "@lezer/lr": "npm:^1.0.0"
+ checksum: 10/52865205f67c9d00630c72028d2d6bbb734da04f80e6febe6edb9bbd3ba55a3c0d6cfbdfa7db0ccf7e090b59040047aa9b752ff2d4ab714f3a0139c4d45e0f80
+ languageName: node
+ linkType: hard
+
+"@lezer/javascript@npm:^1.0.0":
+ version: 1.5.4
+ resolution: "@lezer/javascript@npm:1.5.4"
+ dependencies:
+ "@lezer/common": "npm:^1.2.0"
+ "@lezer/highlight": "npm:^1.1.3"
+ "@lezer/lr": "npm:^1.3.0"
+ checksum: 10/e3cf0b57b131e163aa6ce8a66469e5c39da4db6e83cbefa3bc864575f999229ad02d5d69af56d8aa05b21db22de284c13cfbc9b8b5bb7a628b5599330cf1ef39
+ languageName: node
+ linkType: hard
+
"@lezer/json@npm:^1.0.0":
version: 1.0.2
resolution: "@lezer/json@npm:1.0.2"
@@ -6275,6 +7268,91 @@ __metadata:
languageName: node
linkType: hard
+"@lezer/lr@npm:^1.1.0, @lezer/lr@npm:^1.3.0, @lezer/lr@npm:^1.3.1, @lezer/lr@npm:^1.3.3, @lezer/lr@npm:^1.4.0":
+ version: 1.4.2
+ resolution: "@lezer/lr@npm:1.4.2"
+ dependencies:
+ "@lezer/common": "npm:^1.0.0"
+ checksum: 10/f7b505906c8d8df14c07866553cf3dae1e065b1da8b28fbb4193fd67ab8d187eb45f92759e29a2cfe4283296f0aa864b38a0a91708ecfc3e24b8f662d626e0c6
+ languageName: node
+ linkType: hard
+
+"@lezer/markdown@npm:^1.0.0":
+ version: 1.4.3
+ resolution: "@lezer/markdown@npm:1.4.3"
+ dependencies:
+ "@lezer/common": "npm:^1.0.0"
+ "@lezer/highlight": "npm:^1.0.0"
+ checksum: 10/5a638b0caa0a38007de1900196059f1f165a6684e050e7187e05c45c94cbbf90ad44eb82e5f45df3a7b69022dc4b5d9162e61232ba6f0759f5620328a6e0216e
+ languageName: node
+ linkType: hard
+
+"@lezer/php@npm:^1.0.0":
+ version: 1.0.4
+ resolution: "@lezer/php@npm:1.0.4"
+ dependencies:
+ "@lezer/common": "npm:^1.2.0"
+ "@lezer/highlight": "npm:^1.0.0"
+ "@lezer/lr": "npm:^1.1.0"
+ checksum: 10/d76ea8459958aac41abf53d9dd3e1899d663690134042f4b0095abbb2e404c3841dabbab27edfe29c32c3856c33ab62a238576c7e48701ccbf69bf9bf5e12a04
+ languageName: node
+ linkType: hard
+
+"@lezer/python@npm:^1.1.4":
+ version: 1.1.18
+ resolution: "@lezer/python@npm:1.1.18"
+ dependencies:
+ "@lezer/common": "npm:^1.2.0"
+ "@lezer/highlight": "npm:^1.0.0"
+ "@lezer/lr": "npm:^1.0.0"
+ checksum: 10/9570c661fe2cee649a6aca2ae528e75ee9fccd828eab0987b64702d7057b2e8ec2be71abd274059decb51c6a4b3748c6242c2cabc83d71f94f751362550d90c6
+ languageName: node
+ linkType: hard
+
+"@lezer/rust@npm:^1.0.0":
+ version: 1.0.2
+ resolution: "@lezer/rust@npm:1.0.2"
+ dependencies:
+ "@lezer/common": "npm:^1.2.0"
+ "@lezer/highlight": "npm:^1.0.0"
+ "@lezer/lr": "npm:^1.0.0"
+ checksum: 10/ea6152f65e42afed45e780c4adc87e19e33586de6790ac8dd2012309f22721f87454e6bfee1690e222ce30436ae380270e93cdfc9eb8cdda52930d86e1eb0c07
+ languageName: node
+ linkType: hard
+
+"@lezer/sass@npm:^1.0.0":
+ version: 1.1.0
+ resolution: "@lezer/sass@npm:1.1.0"
+ dependencies:
+ "@lezer/common": "npm:^1.2.0"
+ "@lezer/highlight": "npm:^1.0.0"
+ "@lezer/lr": "npm:^1.0.0"
+ checksum: 10/2f42dfaf5a328d4626a0a8ff8cd5973b7f52e8112541281cf1cbb1970acdc52c7c9f55c71f635bcff75a6151a55f7653d277306a15494b23b652e87d16df9ce3
+ languageName: node
+ linkType: hard
+
+"@lezer/xml@npm:^1.0.0":
+ version: 1.0.6
+ resolution: "@lezer/xml@npm:1.0.6"
+ dependencies:
+ "@lezer/common": "npm:^1.2.0"
+ "@lezer/highlight": "npm:^1.0.0"
+ "@lezer/lr": "npm:^1.0.0"
+ checksum: 10/ffdc3fd587c992f86de84bd828e1d92216484a571423b6edb7b0b1f2eb495ff14e9a234ce5fcba4bce1cb00683af50c0e7f5dfb017a0d3da77607b42e77548a2
+ languageName: node
+ linkType: hard
+
+"@lezer/yaml@npm:^1.0.0":
+ version: 1.0.3
+ resolution: "@lezer/yaml@npm:1.0.3"
+ dependencies:
+ "@lezer/common": "npm:^1.2.0"
+ "@lezer/highlight": "npm:^1.0.0"
+ "@lezer/lr": "npm:^1.4.0"
+ checksum: 10/6697b964403dc5dec9186732c5997675e5140ef5dddc8371dd28fa194d8431d8a7d5f18670be47b81a0b4ad6cbfe82e4f7c9c6f06e6f763bd100f7a38908baf5
+ languageName: node
+ linkType: hard
+
"@libp2p/crypto@npm:^5.0.0, @libp2p/crypto@npm:^5.0.9":
version: 5.0.9
resolution: "@libp2p/crypto@npm:5.0.9"
@@ -6560,6 +7638,83 @@ __metadata:
languageName: node
linkType: hard
+"@mdxeditor/editor@npm:^3.45.0":
+ version: 3.46.0
+ resolution: "@mdxeditor/editor@npm:3.46.0"
+ dependencies:
+ "@codemirror/commands": "npm:^6.2.4"
+ "@codemirror/lang-markdown": "npm:^6.2.3"
+ "@codemirror/language-data": "npm:^6.5.1"
+ "@codemirror/merge": "npm:^6.4.0"
+ "@codemirror/state": "npm:^6.4.0"
+ "@codemirror/view": "npm:^6.23.0"
+ "@codesandbox/sandpack-react": "npm:^2.20.0"
+ "@lexical/clipboard": "npm:^0.35.0"
+ "@lexical/link": "npm:^0.35.0"
+ "@lexical/list": "npm:^0.35.0"
+ "@lexical/markdown": "npm:^0.35.0"
+ "@lexical/plain-text": "npm:^0.35.0"
+ "@lexical/react": "npm:^0.35.0"
+ "@lexical/rich-text": "npm:^0.35.0"
+ "@lexical/selection": "npm:^0.35.0"
+ "@lexical/utils": "npm:^0.35.0"
+ "@mdxeditor/gurx": "npm:^1.2.4"
+ "@radix-ui/colors": "npm:^3.0.0"
+ "@radix-ui/react-dialog": "npm:^1.1.11"
+ "@radix-ui/react-icons": "npm:^1.3.2"
+ "@radix-ui/react-popover": "npm:^1.1.11"
+ "@radix-ui/react-popper": "npm:^1.2.4"
+ "@radix-ui/react-select": "npm:^2.2.2"
+ "@radix-ui/react-toggle-group": "npm:^1.1.7"
+ "@radix-ui/react-toolbar": "npm:^1.1.7"
+ "@radix-ui/react-tooltip": "npm:^1.2.4"
+ classnames: "npm:^2.3.2"
+ cm6-theme-basic-light: "npm:^0.2.0"
+ codemirror: "npm:^6.0.1"
+ downshift: "npm:^7.6.0"
+ js-yaml: "npm:4.1.0"
+ lexical: "npm:^0.35.0"
+ mdast-util-directive: "npm:^3.0.0"
+ mdast-util-from-markdown: "npm:^2.0.0"
+ mdast-util-frontmatter: "npm:^2.0.1"
+ mdast-util-gfm-strikethrough: "npm:^2.0.0"
+ mdast-util-gfm-table: "npm:^2.0.0"
+ mdast-util-gfm-task-list-item: "npm:^2.0.0"
+ mdast-util-highlight-mark: "npm:^1.2.2"
+ mdast-util-mdx: "npm:^3.0.0"
+ mdast-util-mdx-jsx: "npm:^3.0.0"
+ mdast-util-to-markdown: "npm:^2.1.0"
+ micromark-extension-directive: "npm:^3.0.0"
+ micromark-extension-frontmatter: "npm:^2.0.0"
+ micromark-extension-gfm-strikethrough: "npm:^2.0.0"
+ micromark-extension-gfm-table: "npm:^2.0.0"
+ micromark-extension-gfm-task-list-item: "npm:^2.0.1"
+ micromark-extension-highlight-mark: "npm:^1.2.0"
+ micromark-extension-mdx-jsx: "npm:^3.0.0"
+ micromark-extension-mdx-md: "npm:^2.0.0"
+ micromark-extension-mdxjs: "npm:^3.0.0"
+ micromark-factory-space: "npm:^2.0.0"
+ micromark-util-character: "npm:^2.0.1"
+ micromark-util-symbol: "npm:^2.0.0"
+ react-hook-form: "npm:^7.56.1"
+ unidiff: "npm:^1.0.2"
+ peerDependencies:
+ react: ">= 18 || >= 19"
+ react-dom: ">= 18 || >= 19"
+ checksum: 10/6b6b61e4e1b373ae1a0d14de392ee0cf5e017fa5e71d7d4d574e9bb5ca27a89f006b2cfd9761041c130a0b1ce01b43c8b4e46efafe8a500aab1f6b75e7af63c0
+ languageName: node
+ linkType: hard
+
+"@mdxeditor/gurx@npm:^1.2.4":
+ version: 1.2.4
+ resolution: "@mdxeditor/gurx@npm:1.2.4"
+ peerDependencies:
+ react: ">= 18 || >= 19"
+ react-dom: ">= 18 || >= 19"
+ checksum: 10/b3c46bb20781cf20592f3ca830227d40290e5ecf2f972ceeae8fd136b868e7bff301ac52eb2757b009eefd7f9f11e4571a0d424c8a7ad414a95e914032ab8cfa
+ languageName: node
+ linkType: hard
+
"@metamask/eth-json-rpc-provider@npm:^1.0.0":
version: 1.0.1
resolution: "@metamask/eth-json-rpc-provider@npm:1.0.1"
@@ -7469,7 +8624,7 @@ __metadata:
languageName: node
linkType: hard
-"@nomicfoundation/edr@npm:^0.11.1":
+"@nomicfoundation/edr@npm:^0.11.3":
version: 0.11.3
resolution: "@nomicfoundation/edr@npm:0.11.3"
dependencies:
@@ -7752,6 +8907,13 @@ __metadata:
languageName: node
linkType: hard
+"@open-draft/deferred-promise@npm:^2.1.0":
+ version: 2.2.0
+ resolution: "@open-draft/deferred-promise@npm:2.2.0"
+ checksum: 10/bc3bb1668a555bb87b33383cafcf207d9561e17d2ca0d9e61b7ce88e82b66e36a333d3676c1d39eb5848022c03c8145331fcdc828ba297f88cb1de9c5cef6c19
+ languageName: node
+ linkType: hard
+
"@openzeppelin/contracts-upgradeable@npm:4.9.6":
version: 4.9.6
resolution: "@openzeppelin/contracts-upgradeable@npm:4.9.6"
@@ -8056,6 +9218,703 @@ __metadata:
languageName: node
linkType: hard
+"@radix-ui/colors@npm:^3.0.0":
+ version: 3.0.0
+ resolution: "@radix-ui/colors@npm:3.0.0"
+ checksum: 10/bc9ffb01b3964f16482dc278cf6d86d85b73eae7cb94a77018fbd53b103b3d5ec1ecf77882cfbf8892f28c2c6057db8e19bf4d66234ed330a430373b092c5cfe
+ languageName: node
+ linkType: hard
+
+"@radix-ui/number@npm:1.1.1":
+ version: 1.1.1
+ resolution: "@radix-ui/number@npm:1.1.1"
+ checksum: 10/58717faf3f7aa180fdfcde7083cae0bc06677cbd08fd2bed5a3f8820deeb6f514f7d475f1fbb61e1f9a16cb2e7daf1000b2c614b0de3520fccfc04e3576e4566
+ languageName: node
+ linkType: hard
+
+"@radix-ui/primitive@npm:1.1.3":
+ version: 1.1.3
+ resolution: "@radix-ui/primitive@npm:1.1.3"
+ checksum: 10/ee27abbff0d6d305816e9314655eb35e72478ba47416bc9d5cb0581728be35e3408cfc0748313837561d635f0cb7dfaae26e61831f0e16c0fd7d669a612f2cb0
+ languageName: node
+ linkType: hard
+
+"@radix-ui/react-arrow@npm:1.1.7":
+ version: 1.1.7
+ resolution: "@radix-ui/react-arrow@npm:1.1.7"
+ dependencies:
+ "@radix-ui/react-primitive": "npm:2.1.3"
+ peerDependencies:
+ "@types/react": "*"
+ "@types/react-dom": "*"
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ "@types/react":
+ optional: true
+ "@types/react-dom":
+ optional: true
+ checksum: 10/6cdf74f06090f8994cdf6d3935a44ea3ac309163a4f59c476482c4907e8e0775f224045030abf10fa4f9e1cb7743db034429249b9e59354988e247eeb0f4fdcf
+ languageName: node
+ linkType: hard
+
+"@radix-ui/react-collection@npm:1.1.7":
+ version: 1.1.7
+ resolution: "@radix-ui/react-collection@npm:1.1.7"
+ dependencies:
+ "@radix-ui/react-compose-refs": "npm:1.1.2"
+ "@radix-ui/react-context": "npm:1.1.2"
+ "@radix-ui/react-primitive": "npm:2.1.3"
+ "@radix-ui/react-slot": "npm:1.2.3"
+ peerDependencies:
+ "@types/react": "*"
+ "@types/react-dom": "*"
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ "@types/react":
+ optional: true
+ "@types/react-dom":
+ optional: true
+ checksum: 10/cd53e2a2be82be7bc4014164cac0b42948401a203e5d0294d3947a5193f1d56bd23eb60e878a98dba50d08283254e79c3b873de5f935276b849686a868d51dd5
+ languageName: node
+ linkType: hard
+
+"@radix-ui/react-compose-refs@npm:1.1.2":
+ version: 1.1.2
+ resolution: "@radix-ui/react-compose-refs@npm:1.1.2"
+ peerDependencies:
+ "@types/react": "*"
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ "@types/react":
+ optional: true
+ checksum: 10/9a91f0213014ffa40c5b8aae4debb993be5654217e504e35aa7422887eb2d114486d37e53c482d0fffb00cd44f51b5269fcdf397b280c71666fa11b7f32f165d
+ languageName: node
+ linkType: hard
+
+"@radix-ui/react-context@npm:1.1.2":
+ version: 1.1.2
+ resolution: "@radix-ui/react-context@npm:1.1.2"
+ peerDependencies:
+ "@types/react": "*"
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ "@types/react":
+ optional: true
+ checksum: 10/156088367de42afa3c7e3acf5f0ba7cad6b359f3d17485585e80c2418434a6ed7cac2602eb73bca265d0091a1ad380f9405c069f103983e53497097ff35ba8f2
+ languageName: node
+ linkType: hard
+
+"@radix-ui/react-dialog@npm:^1.1.11":
+ version: 1.1.15
+ resolution: "@radix-ui/react-dialog@npm:1.1.15"
+ dependencies:
+ "@radix-ui/primitive": "npm:1.1.3"
+ "@radix-ui/react-compose-refs": "npm:1.1.2"
+ "@radix-ui/react-context": "npm:1.1.2"
+ "@radix-ui/react-dismissable-layer": "npm:1.1.11"
+ "@radix-ui/react-focus-guards": "npm:1.1.3"
+ "@radix-ui/react-focus-scope": "npm:1.1.7"
+ "@radix-ui/react-id": "npm:1.1.1"
+ "@radix-ui/react-portal": "npm:1.1.9"
+ "@radix-ui/react-presence": "npm:1.1.5"
+ "@radix-ui/react-primitive": "npm:2.1.3"
+ "@radix-ui/react-slot": "npm:1.2.3"
+ "@radix-ui/react-use-controllable-state": "npm:1.2.2"
+ aria-hidden: "npm:^1.2.4"
+ react-remove-scroll: "npm:^2.6.3"
+ peerDependencies:
+ "@types/react": "*"
+ "@types/react-dom": "*"
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ "@types/react":
+ optional: true
+ "@types/react-dom":
+ optional: true
+ checksum: 10/90ad9ea36d927a05bcc2701b471c2965f6d5d4f446511cd471e62235fc674186997dea081f52e18cb17a1e593828d94da3848e68864fa3acebe29df9b068b240
+ languageName: node
+ linkType: hard
+
+"@radix-ui/react-direction@npm:1.1.1":
+ version: 1.1.1
+ resolution: "@radix-ui/react-direction@npm:1.1.1"
+ peerDependencies:
+ "@types/react": "*"
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ "@types/react":
+ optional: true
+ checksum: 10/8cc330285f1d06829568042ca9aabd3295be4690ae93683033fc8632b5c4dfc60f5c1312f6e2cae27c196189c719de3cfbcf792ff74800f9ccae0ab4abc1bc92
+ languageName: node
+ linkType: hard
+
+"@radix-ui/react-dismissable-layer@npm:1.1.11":
+ version: 1.1.11
+ resolution: "@radix-ui/react-dismissable-layer@npm:1.1.11"
+ dependencies:
+ "@radix-ui/primitive": "npm:1.1.3"
+ "@radix-ui/react-compose-refs": "npm:1.1.2"
+ "@radix-ui/react-primitive": "npm:2.1.3"
+ "@radix-ui/react-use-callback-ref": "npm:1.1.1"
+ "@radix-ui/react-use-escape-keydown": "npm:1.1.1"
+ peerDependencies:
+ "@types/react": "*"
+ "@types/react-dom": "*"
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ "@types/react":
+ optional: true
+ "@types/react-dom":
+ optional: true
+ checksum: 10/c20772588423379dee47fbe1d45c238c45a3bbe612eaf64a86576bf81821975e256d92ac71f9151e91b94a73068656143a11da9a3e77de7564d2a9926468e37a
+ languageName: node
+ linkType: hard
+
+"@radix-ui/react-focus-guards@npm:1.1.3":
+ version: 1.1.3
+ resolution: "@radix-ui/react-focus-guards@npm:1.1.3"
+ peerDependencies:
+ "@types/react": "*"
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ "@types/react":
+ optional: true
+ checksum: 10/b57878f6cf0ebc3e8d7c5c6bbaad44598daac19c921551ca541c104201048a9a902f3d69196e7a09995fd46e998c309aab64dc30fa184b3609d67d187a6a9c24
+ languageName: node
+ linkType: hard
+
+"@radix-ui/react-focus-scope@npm:1.1.7":
+ version: 1.1.7
+ resolution: "@radix-ui/react-focus-scope@npm:1.1.7"
+ dependencies:
+ "@radix-ui/react-compose-refs": "npm:1.1.2"
+ "@radix-ui/react-primitive": "npm:2.1.3"
+ "@radix-ui/react-use-callback-ref": "npm:1.1.1"
+ peerDependencies:
+ "@types/react": "*"
+ "@types/react-dom": "*"
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ "@types/react":
+ optional: true
+ "@types/react-dom":
+ optional: true
+ checksum: 10/2a7cd00e39e01756999ebf0bdb3401d6a8efa489a7b19e6b629b40bad3022b7b1f616555ccb4b0505bc0ba53e13a1fb51be905db138b16ec39c4fe319fe701d3
+ languageName: node
+ linkType: hard
+
+"@radix-ui/react-icons@npm:^1.3.2":
+ version: 1.3.2
+ resolution: "@radix-ui/react-icons@npm:1.3.2"
+ peerDependencies:
+ react: ^16.x || ^17.x || ^18.x || ^19.0.0 || ^19.0.0-rc
+ checksum: 10/cf6c694a400677890d0d83cd30ac01fa638c04eefe6194cd4e3c9edff49269e97dccc01e7bb480e2dcc249b27ee4eafa5d82d72d15c5119d66f4c26db6128f36
+ languageName: node
+ linkType: hard
+
+"@radix-ui/react-id@npm:1.1.1":
+ version: 1.1.1
+ resolution: "@radix-ui/react-id@npm:1.1.1"
+ dependencies:
+ "@radix-ui/react-use-layout-effect": "npm:1.1.1"
+ peerDependencies:
+ "@types/react": "*"
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ "@types/react":
+ optional: true
+ checksum: 10/8d68e200778eb3038906870fc869b3d881f4a46715fb20cddd9c76cba42fdaaa4810a3365b6ec2daf0f185b9201fc99d009167f59c7921bc3a139722c2e976db
+ languageName: node
+ linkType: hard
+
+"@radix-ui/react-popover@npm:^1.1.11":
+ version: 1.1.15
+ resolution: "@radix-ui/react-popover@npm:1.1.15"
+ dependencies:
+ "@radix-ui/primitive": "npm:1.1.3"
+ "@radix-ui/react-compose-refs": "npm:1.1.2"
+ "@radix-ui/react-context": "npm:1.1.2"
+ "@radix-ui/react-dismissable-layer": "npm:1.1.11"
+ "@radix-ui/react-focus-guards": "npm:1.1.3"
+ "@radix-ui/react-focus-scope": "npm:1.1.7"
+ "@radix-ui/react-id": "npm:1.1.1"
+ "@radix-ui/react-popper": "npm:1.2.8"
+ "@radix-ui/react-portal": "npm:1.1.9"
+ "@radix-ui/react-presence": "npm:1.1.5"
+ "@radix-ui/react-primitive": "npm:2.1.3"
+ "@radix-ui/react-slot": "npm:1.2.3"
+ "@radix-ui/react-use-controllable-state": "npm:1.2.2"
+ aria-hidden: "npm:^1.2.4"
+ react-remove-scroll: "npm:^2.6.3"
+ peerDependencies:
+ "@types/react": "*"
+ "@types/react-dom": "*"
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ "@types/react":
+ optional: true
+ "@types/react-dom":
+ optional: true
+ checksum: 10/0ea7c8bb827e44d5c02b3f7193d9ac8085c71a01bf601b1afeb2bb0ec0124756e03db3471606e89e4d014e4de7c7066c8e2e9b81bb4b31ea321890ec33421f31
+ languageName: node
+ linkType: hard
+
+"@radix-ui/react-popper@npm:1.2.8, @radix-ui/react-popper@npm:^1.2.4":
+ version: 1.2.8
+ resolution: "@radix-ui/react-popper@npm:1.2.8"
+ dependencies:
+ "@floating-ui/react-dom": "npm:^2.0.0"
+ "@radix-ui/react-arrow": "npm:1.1.7"
+ "@radix-ui/react-compose-refs": "npm:1.1.2"
+ "@radix-ui/react-context": "npm:1.1.2"
+ "@radix-ui/react-primitive": "npm:2.1.3"
+ "@radix-ui/react-use-callback-ref": "npm:1.1.1"
+ "@radix-ui/react-use-layout-effect": "npm:1.1.1"
+ "@radix-ui/react-use-rect": "npm:1.1.1"
+ "@radix-ui/react-use-size": "npm:1.1.1"
+ "@radix-ui/rect": "npm:1.1.1"
+ peerDependencies:
+ "@types/react": "*"
+ "@types/react-dom": "*"
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ "@types/react":
+ optional: true
+ "@types/react-dom":
+ optional: true
+ checksum: 10/01366054e1e63dd9394f77afb9da3367709478a5adf4436c080fc5bbe9456170192ff9d1425d9fae5b246e1ba95173848f84b6f2a06b21b47d966367ec7cb997
+ languageName: node
+ linkType: hard
+
+"@radix-ui/react-portal@npm:1.1.9":
+ version: 1.1.9
+ resolution: "@radix-ui/react-portal@npm:1.1.9"
+ dependencies:
+ "@radix-ui/react-primitive": "npm:2.1.3"
+ "@radix-ui/react-use-layout-effect": "npm:1.1.1"
+ peerDependencies:
+ "@types/react": "*"
+ "@types/react-dom": "*"
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ "@types/react":
+ optional: true
+ "@types/react-dom":
+ optional: true
+ checksum: 10/bd6be39bf021d5c917e2474ecba411e2625171f7ef96862b9af04bbd68833bb3662a7f1fbdeb5a7a237111b10e811e76d2cd03e957dadd6e668ef16541bfbd68
+ languageName: node
+ linkType: hard
+
+"@radix-ui/react-presence@npm:1.1.5":
+ version: 1.1.5
+ resolution: "@radix-ui/react-presence@npm:1.1.5"
+ dependencies:
+ "@radix-ui/react-compose-refs": "npm:1.1.2"
+ "@radix-ui/react-use-layout-effect": "npm:1.1.1"
+ peerDependencies:
+ "@types/react": "*"
+ "@types/react-dom": "*"
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ "@types/react":
+ optional: true
+ "@types/react-dom":
+ optional: true
+ checksum: 10/4cdb05844c18877efb4b9739b46b7e5850b81d7ede994e75b5d62e8153a43c6e16b3ff9e55ff716e20b74b99b9415a94e97fd636bcb8698d5bbf7ab7b8663f9b
+ languageName: node
+ linkType: hard
+
+"@radix-ui/react-primitive@npm:2.1.3":
+ version: 2.1.3
+ resolution: "@radix-ui/react-primitive@npm:2.1.3"
+ dependencies:
+ "@radix-ui/react-slot": "npm:1.2.3"
+ peerDependencies:
+ "@types/react": "*"
+ "@types/react-dom": "*"
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ "@types/react":
+ optional: true
+ "@types/react-dom":
+ optional: true
+ checksum: 10/1dbbf932a3527f4e62f210bb72944eff605c3e38c8d3275ed5a5c570c02820ab156169756a65ad9a638d2089a828a04a7903795377384e98c87d0ca456303253
+ languageName: node
+ linkType: hard
+
+"@radix-ui/react-roving-focus@npm:1.1.11":
+ version: 1.1.11
+ resolution: "@radix-ui/react-roving-focus@npm:1.1.11"
+ dependencies:
+ "@radix-ui/primitive": "npm:1.1.3"
+ "@radix-ui/react-collection": "npm:1.1.7"
+ "@radix-ui/react-compose-refs": "npm:1.1.2"
+ "@radix-ui/react-context": "npm:1.1.2"
+ "@radix-ui/react-direction": "npm:1.1.1"
+ "@radix-ui/react-id": "npm:1.1.1"
+ "@radix-ui/react-primitive": "npm:2.1.3"
+ "@radix-ui/react-use-callback-ref": "npm:1.1.1"
+ "@radix-ui/react-use-controllable-state": "npm:1.2.2"
+ peerDependencies:
+ "@types/react": "*"
+ "@types/react-dom": "*"
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ "@types/react":
+ optional: true
+ "@types/react-dom":
+ optional: true
+ checksum: 10/0eddafa942332c95622ab8b53cce2fa25fd0dcaf4797218e9e6725da0734a81a438852cdcb3f588521018f68d38c6c5e50c64fda78c655f4e69dd45681ecc5e7
+ languageName: node
+ linkType: hard
+
+"@radix-ui/react-select@npm:^2.2.2":
+ version: 2.2.6
+ resolution: "@radix-ui/react-select@npm:2.2.6"
+ dependencies:
+ "@radix-ui/number": "npm:1.1.1"
+ "@radix-ui/primitive": "npm:1.1.3"
+ "@radix-ui/react-collection": "npm:1.1.7"
+ "@radix-ui/react-compose-refs": "npm:1.1.2"
+ "@radix-ui/react-context": "npm:1.1.2"
+ "@radix-ui/react-direction": "npm:1.1.1"
+ "@radix-ui/react-dismissable-layer": "npm:1.1.11"
+ "@radix-ui/react-focus-guards": "npm:1.1.3"
+ "@radix-ui/react-focus-scope": "npm:1.1.7"
+ "@radix-ui/react-id": "npm:1.1.1"
+ "@radix-ui/react-popper": "npm:1.2.8"
+ "@radix-ui/react-portal": "npm:1.1.9"
+ "@radix-ui/react-primitive": "npm:2.1.3"
+ "@radix-ui/react-slot": "npm:1.2.3"
+ "@radix-ui/react-use-callback-ref": "npm:1.1.1"
+ "@radix-ui/react-use-controllable-state": "npm:1.2.2"
+ "@radix-ui/react-use-layout-effect": "npm:1.1.1"
+ "@radix-ui/react-use-previous": "npm:1.1.1"
+ "@radix-ui/react-visually-hidden": "npm:1.2.3"
+ aria-hidden: "npm:^1.2.4"
+ react-remove-scroll: "npm:^2.6.3"
+ peerDependencies:
+ "@types/react": "*"
+ "@types/react-dom": "*"
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ "@types/react":
+ optional: true
+ "@types/react-dom":
+ optional: true
+ checksum: 10/ef6df1a6411a965d30f8e14387058ece020469897ad2089d1e1019d8e37487e6b3c0f9683d7c6ec217698fa85fedd419738cab089a5ebc49a04405e63aac0bf0
+ languageName: node
+ linkType: hard
+
+"@radix-ui/react-separator@npm:1.1.7":
+ version: 1.1.7
+ resolution: "@radix-ui/react-separator@npm:1.1.7"
+ dependencies:
+ "@radix-ui/react-primitive": "npm:2.1.3"
+ peerDependencies:
+ "@types/react": "*"
+ "@types/react-dom": "*"
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ "@types/react":
+ optional: true
+ "@types/react-dom":
+ optional: true
+ checksum: 10/c5c19b7991bf5395eb2b849145deeb9aa307d9fcf220380497992ff2a301753ab477d0329af51b6d500cd3c1d777edbd2504b544d9254542fb5f829ac5ddbcf3
+ languageName: node
+ linkType: hard
+
+"@radix-ui/react-slot@npm:1.2.3":
+ version: 1.2.3
+ resolution: "@radix-ui/react-slot@npm:1.2.3"
+ dependencies:
+ "@radix-ui/react-compose-refs": "npm:1.1.2"
+ peerDependencies:
+ "@types/react": "*"
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ "@types/react":
+ optional: true
+ checksum: 10/fe484c2741e31d9c20a8fb53c5790a73c0664e2bea35e27f4d484a90c42135fcfffe11a08abfcacb7a8ee2faf013471f0e856818f3ddac8ac51ceb8869e0fd08
+ languageName: node
+ linkType: hard
+
+"@radix-ui/react-toggle-group@npm:1.1.11, @radix-ui/react-toggle-group@npm:^1.1.7":
+ version: 1.1.11
+ resolution: "@radix-ui/react-toggle-group@npm:1.1.11"
+ dependencies:
+ "@radix-ui/primitive": "npm:1.1.3"
+ "@radix-ui/react-context": "npm:1.1.2"
+ "@radix-ui/react-direction": "npm:1.1.1"
+ "@radix-ui/react-primitive": "npm:2.1.3"
+ "@radix-ui/react-roving-focus": "npm:1.1.11"
+ "@radix-ui/react-toggle": "npm:1.1.10"
+ "@radix-ui/react-use-controllable-state": "npm:1.2.2"
+ peerDependencies:
+ "@types/react": "*"
+ "@types/react-dom": "*"
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ "@types/react":
+ optional: true
+ "@types/react-dom":
+ optional: true
+ checksum: 10/b20e2aa2580624621b62e72d2e44585427807e6629186dc8a46909a3bd35d9122fb4837f8e8fa9856a24b54bb2a7aa8983007da8b459303495d0d55b14396b35
+ languageName: node
+ linkType: hard
+
+"@radix-ui/react-toggle@npm:1.1.10":
+ version: 1.1.10
+ resolution: "@radix-ui/react-toggle@npm:1.1.10"
+ dependencies:
+ "@radix-ui/primitive": "npm:1.1.3"
+ "@radix-ui/react-primitive": "npm:2.1.3"
+ "@radix-ui/react-use-controllable-state": "npm:1.2.2"
+ peerDependencies:
+ "@types/react": "*"
+ "@types/react-dom": "*"
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ "@types/react":
+ optional: true
+ "@types/react-dom":
+ optional: true
+ checksum: 10/ece154bd7a0ca765040fafbe4131f753457a3d37f73dec3ae94f08f17f3889272d06f33f305ad34c986925ce8a40532ee43f6bdb7e8b99fd8bac299b01d69204
+ languageName: node
+ linkType: hard
+
+"@radix-ui/react-toolbar@npm:^1.1.7":
+ version: 1.1.11
+ resolution: "@radix-ui/react-toolbar@npm:1.1.11"
+ dependencies:
+ "@radix-ui/primitive": "npm:1.1.3"
+ "@radix-ui/react-context": "npm:1.1.2"
+ "@radix-ui/react-direction": "npm:1.1.1"
+ "@radix-ui/react-primitive": "npm:2.1.3"
+ "@radix-ui/react-roving-focus": "npm:1.1.11"
+ "@radix-ui/react-separator": "npm:1.1.7"
+ "@radix-ui/react-toggle-group": "npm:1.1.11"
+ peerDependencies:
+ "@types/react": "*"
+ "@types/react-dom": "*"
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ "@types/react":
+ optional: true
+ "@types/react-dom":
+ optional: true
+ checksum: 10/da022ae96f0a02da2c5890af3350f622425c8bb8564b1cae51ca28cfeb5dc73a8bb597bb762dfef2f738d497d207792e22231aec050c8d05071518b9c58f1f8b
+ languageName: node
+ linkType: hard
+
+"@radix-ui/react-tooltip@npm:^1.2.4":
+ version: 1.2.8
+ resolution: "@radix-ui/react-tooltip@npm:1.2.8"
+ dependencies:
+ "@radix-ui/primitive": "npm:1.1.3"
+ "@radix-ui/react-compose-refs": "npm:1.1.2"
+ "@radix-ui/react-context": "npm:1.1.2"
+ "@radix-ui/react-dismissable-layer": "npm:1.1.11"
+ "@radix-ui/react-id": "npm:1.1.1"
+ "@radix-ui/react-popper": "npm:1.2.8"
+ "@radix-ui/react-portal": "npm:1.1.9"
+ "@radix-ui/react-presence": "npm:1.1.5"
+ "@radix-ui/react-primitive": "npm:2.1.3"
+ "@radix-ui/react-slot": "npm:1.2.3"
+ "@radix-ui/react-use-controllable-state": "npm:1.2.2"
+ "@radix-ui/react-visually-hidden": "npm:1.2.3"
+ peerDependencies:
+ "@types/react": "*"
+ "@types/react-dom": "*"
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ "@types/react":
+ optional: true
+ "@types/react-dom":
+ optional: true
+ checksum: 10/e31857628d998b69616b8994f9627d387ed7bfa453b94e3b18ad2c04de83caf5fcca0ef2f304b1d343e00f183e937d883247d81e386dcc76c7c7c268484bc47c
+ languageName: node
+ linkType: hard
+
+"@radix-ui/react-use-callback-ref@npm:1.1.1":
+ version: 1.1.1
+ resolution: "@radix-ui/react-use-callback-ref@npm:1.1.1"
+ peerDependencies:
+ "@types/react": "*"
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ "@types/react":
+ optional: true
+ checksum: 10/cde8c40f1d4e79e6e71470218163a746858304bad03758ac84dc1f94247a046478e8e397518350c8d6609c84b7e78565441d7505bb3ed573afce82cfdcd19faf
+ languageName: node
+ linkType: hard
+
+"@radix-ui/react-use-controllable-state@npm:1.2.2":
+ version: 1.2.2
+ resolution: "@radix-ui/react-use-controllable-state@npm:1.2.2"
+ dependencies:
+ "@radix-ui/react-use-effect-event": "npm:0.0.2"
+ "@radix-ui/react-use-layout-effect": "npm:1.1.1"
+ peerDependencies:
+ "@types/react": "*"
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ "@types/react":
+ optional: true
+ checksum: 10/a100bff3ddecb753dab17444147273c9f70046c5949712c52174b259622eaef12acbf7ebcf289bae4e714eb84d0a7317c1aa44064cd997f327d77b62bc732a7c
+ languageName: node
+ linkType: hard
+
+"@radix-ui/react-use-effect-event@npm:0.0.2":
+ version: 0.0.2
+ resolution: "@radix-ui/react-use-effect-event@npm:0.0.2"
+ dependencies:
+ "@radix-ui/react-use-layout-effect": "npm:1.1.1"
+ peerDependencies:
+ "@types/react": "*"
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ "@types/react":
+ optional: true
+ checksum: 10/5a1950a30a399ea7e4b98154da9f536737a610de80189b7aacd4f064a89a3cd0d2a48571d527435227252e72e872bdb544ff6ffcfbdd02de2efd011be4aaa902
+ languageName: node
+ linkType: hard
+
+"@radix-ui/react-use-escape-keydown@npm:1.1.1":
+ version: 1.1.1
+ resolution: "@radix-ui/react-use-escape-keydown@npm:1.1.1"
+ dependencies:
+ "@radix-ui/react-use-callback-ref": "npm:1.1.1"
+ peerDependencies:
+ "@types/react": "*"
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ "@types/react":
+ optional: true
+ checksum: 10/0eb0756c2c55ddcde9ff01446ab01c085ab2bf799173e97db7ef5f85126f9e8600225570801a1f64740e6d14c39ffe8eed7c14d29737345a5797f4622ac96f6f
+ languageName: node
+ linkType: hard
+
+"@radix-ui/react-use-layout-effect@npm:1.1.1":
+ version: 1.1.1
+ resolution: "@radix-ui/react-use-layout-effect@npm:1.1.1"
+ peerDependencies:
+ "@types/react": "*"
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ "@types/react":
+ optional: true
+ checksum: 10/bad2ba4f206e6255263582bedfb7868773c400836f9a1b423c0b464ffe4a17e13d3f306d1ce19cf7a19a492e9d0e49747464f2656451bb7c6a99f5a57bd34de2
+ languageName: node
+ linkType: hard
+
+"@radix-ui/react-use-previous@npm:1.1.1":
+ version: 1.1.1
+ resolution: "@radix-ui/react-use-previous@npm:1.1.1"
+ peerDependencies:
+ "@types/react": "*"
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ "@types/react":
+ optional: true
+ checksum: 10/ea6ea13523a0561dda9b14b9d44e299484816a6762d7fb50b91b27b6aec89f78c85245b69d5a904750d43919dbb7ef6ce6d3823639346675aa3a5cb9de32d984
+ languageName: node
+ linkType: hard
+
+"@radix-ui/react-use-rect@npm:1.1.1":
+ version: 1.1.1
+ resolution: "@radix-ui/react-use-rect@npm:1.1.1"
+ dependencies:
+ "@radix-ui/rect": "npm:1.1.1"
+ peerDependencies:
+ "@types/react": "*"
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ "@types/react":
+ optional: true
+ checksum: 10/116461bebc49472f7497e66a9bd413541181b3d00c5e0aaeef45d790dc1fbd7c8dcea80b169ea273306228b9a3c2b70067e902d1fd5004b3057e3bbe35b9d55d
+ languageName: node
+ linkType: hard
+
+"@radix-ui/react-use-size@npm:1.1.1":
+ version: 1.1.1
+ resolution: "@radix-ui/react-use-size@npm:1.1.1"
+ dependencies:
+ "@radix-ui/react-use-layout-effect": "npm:1.1.1"
+ peerDependencies:
+ "@types/react": "*"
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ "@types/react":
+ optional: true
+ checksum: 10/64e61f65feb67ffc80e1fc4a8d5e32480fb6d68475e2640377e021178dead101568cba5f936c9c33e6c142c7cf2fb5d76ad7b23ef80e556ba142d56cf306147b
+ languageName: node
+ linkType: hard
+
+"@radix-ui/react-visually-hidden@npm:1.2.3":
+ version: 1.2.3
+ resolution: "@radix-ui/react-visually-hidden@npm:1.2.3"
+ dependencies:
+ "@radix-ui/react-primitive": "npm:2.1.3"
+ peerDependencies:
+ "@types/react": "*"
+ "@types/react-dom": "*"
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ "@types/react":
+ optional: true
+ "@types/react-dom":
+ optional: true
+ checksum: 10/42296bde1ddf4af4e7445e914c35d6bc8406d6ede49f0a959a553e75b3ed21da09fda80a81c48d8ec058ed8129ce7137499d02ee26f90f0d3eaa2417922d6509
+ languageName: node
+ linkType: hard
+
+"@radix-ui/rect@npm:1.1.1":
+ version: 1.1.1
+ resolution: "@radix-ui/rect@npm:1.1.1"
+ checksum: 10/b6c5eb787640775b53dd52fa47218a089f0a0d8220d3ebff079c0b754e1fb82d89b6bdf08a82fd0d59549bdeb52678c0cca091c302da49dcf74c3c989cb55678
+ languageName: node
+ linkType: hard
+
+"@react-hook/intersection-observer@npm:^3.1.1":
+ version: 3.1.2
+ resolution: "@react-hook/intersection-observer@npm:3.1.2"
+ dependencies:
+ "@react-hook/passive-layout-effect": "npm:^1.2.0"
+ intersection-observer: "npm:^0.10.0"
+ peerDependencies:
+ react: ">=16.8"
+ checksum: 10/fee587ca06bdfe02aa3a30b95bb9fb63cc745aafa74a34e68b2c1938b6b34e8807f02e8a9f3d656ab4b399f30cd6aaa88ef7b486ec1ee1f848e6e726d73f256d
+ languageName: node
+ linkType: hard
+
+"@react-hook/passive-layout-effect@npm:^1.2.0":
+ version: 1.2.1
+ resolution: "@react-hook/passive-layout-effect@npm:1.2.1"
+ peerDependencies:
+ react: ">=16.8"
+ checksum: 10/217cb8aa90fb8e677672319a9a466d7752890cf4357c76df000b207696e9cc717cf2ee88080671cc9dae238a82f92093ab4f61ab2f6032d2a8db958fc7d99b5d
+ languageName: node
+ linkType: hard
+
"@react-native-async-storage/async-storage@npm:^1.17.7":
version: 1.24.0
resolution: "@react-native-async-storage/async-storage@npm:1.24.0"
@@ -9251,6 +11110,13 @@ __metadata:
languageName: node
linkType: hard
+"@stitches/core@npm:^1.2.6":
+ version: 1.2.8
+ resolution: "@stitches/core@npm:1.2.8"
+ checksum: 10/bdee1772f033b20bfb1081a3bb8c3e85f2a44f381379d4c2ae21408336025e2d2578f79eec74db26824b852ebcc72de3edfc8c51418608f189aa5ffc26df667a
+ languageName: node
+ linkType: hard
+
"@surma/rollup-plugin-off-main-thread@npm:^2.2.3":
version: 2.2.3
resolution: "@surma/rollup-plugin-off-main-thread@npm:2.2.3"
@@ -10091,13 +11957,6 @@ __metadata:
languageName: node
linkType: hard
-"@types/lru-cache@npm:^5.1.0":
- version: 5.1.1
- resolution: "@types/lru-cache@npm:5.1.1"
- checksum: 10/0afadefc983306684a8ef95b6337a0d9e3f687e7e89e1f1f3f2e1ce3fbab5b018bb84cf277d781f871175a2c8f0176762b69e58b6f4296ee1b816cea94d5ef06
- languageName: node
- linkType: hard
-
"@types/mdast@npm:^3.0.0":
version: 3.0.15
resolution: "@types/mdast@npm:3.0.15"
@@ -10236,13 +12095,20 @@ __metadata:
languageName: node
linkType: hard
-"@types/prop-types@npm:*, @types/prop-types@npm:^15.0.0":
+"@types/prop-types@npm:*":
version: 15.7.12
resolution: "@types/prop-types@npm:15.7.12"
checksum: 10/ac16cc3d0a84431ffa5cfdf89579ad1e2269549f32ce0c769321fdd078f84db4fbe1b461ed5a1a496caf09e637c0e367d600c541435716a55b1d9713f5035dfe
languageName: node
linkType: hard
+"@types/prop-types@npm:^15.0.0":
+ version: 15.7.15
+ resolution: "@types/prop-types@npm:15.7.15"
+ checksum: 10/31aa2f59b28f24da6fb4f1d70807dae2aedfce090ec63eaf9ea01727a9533ef6eaf017de5bff99fbccad7d1c9e644f52c6c2ba30869465dd22b1a7221c29f356
+ languageName: node
+ linkType: hard
+
"@types/prop-types@npm:^15.7.14":
version: 15.7.14
resolution: "@types/prop-types@npm:15.7.14"
@@ -10449,7 +12315,14 @@ __metadata:
languageName: node
linkType: hard
-"@types/unist@npm:^2, @types/unist@npm:^2.0.0":
+"@types/unist@npm:^2":
+ version: 2.0.11
+ resolution: "@types/unist@npm:2.0.11"
+ checksum: 10/6d436e832bc35c6dde9f056ac515ebf2b3384a1d7f63679d12358766f9b313368077402e9c1126a14d827f10370a5485e628bf61aa91117cf4fc882423191a4e
+ languageName: node
+ linkType: hard
+
+"@types/unist@npm:^2.0.0":
version: 2.0.10
resolution: "@types/unist@npm:2.0.10"
checksum: 10/e2924e18dedf45f68a5c6ccd6015cd62f1643b1b43baac1854efa21ae9e70505db94290434a23da1137d9e31eb58e54ca175982005698ac37300a1c889f6c4aa
@@ -10999,6 +12872,39 @@ __metadata:
languageName: node
linkType: hard
+"@wagmi/cli@npm:^2.3.2":
+ version: 2.3.2
+ resolution: "@wagmi/cli@npm:2.3.2"
+ dependencies:
+ abitype: "npm:^1.0.4"
+ bundle-require: "npm:^5.1.0"
+ cac: "npm:^6.7.14"
+ change-case: "npm:^5.4.4"
+ chokidar: "npm:4.0.1"
+ dedent: "npm:^0.7.0"
+ dotenv: "npm:^16.3.1"
+ dotenv-expand: "npm:^10.0.0"
+ esbuild: "npm:~0.25.4"
+ escalade: "npm:3.2.0"
+ fdir: "npm:^6.1.1"
+ nanospinner: "npm:1.2.2"
+ pathe: "npm:^1.1.2"
+ picocolors: "npm:^1.0.0"
+ picomatch: "npm:^3.0.0"
+ prettier: "npm:^3.0.3"
+ viem: "npm:2.x"
+ zod: "npm:^3.22.2"
+ peerDependencies:
+ typescript: ">=5.0.4"
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ bin:
+ wagmi: dist/esm/cli.js
+ checksum: 10/85c6b1d4960c6d080d067f7dbac34e6a27d822690d33ef6c131b7714f6be13c5e04b2dd506fce38992ee6183ebe0fb48160e30f4cf901a27ccf34fd1b2dae529
+ languageName: node
+ linkType: hard
+
"@wagmi/connectors@npm:5.7.11, @wagmi/connectors@npm:>=5.7.11, @wagmi/connectors@npm:^5.7.11":
version: 5.7.11
resolution: "@wagmi/connectors@npm:5.7.11"
@@ -11851,7 +13757,7 @@ __metadata:
languageName: node
linkType: hard
-"acorn-jsx@npm:^5.3.2":
+"acorn-jsx@npm:^5.0.0, acorn-jsx@npm:^5.3.2":
version: 5.3.2
resolution: "acorn-jsx@npm:5.3.2"
peerDependencies:
@@ -11883,6 +13789,15 @@ __metadata:
languageName: node
linkType: hard
+"acorn@npm:^8.0.0":
+ version: 8.15.0
+ resolution: "acorn@npm:8.15.0"
+ bin:
+ acorn: bin/acorn
+ checksum: 10/77f2de5051a631cf1729c090e5759148459cdb76b5f5c70f890503d629cf5052357b0ce783c0f976dd8a93c5150f59f6d18df1def3f502396a20f81282482fa4
+ languageName: node
+ linkType: hard
+
"acorn@npm:^8.1.0, acorn@npm:^8.10.0, acorn@npm:^8.14.0, acorn@npm:^8.2.4, acorn@npm:^8.4.1, acorn@npm:^8.7.1, acorn@npm:^8.8.0, acorn@npm:^8.8.1, acorn@npm:^8.8.2":
version: 8.14.0
resolution: "acorn@npm:8.14.0"
@@ -12110,6 +14025,13 @@ __metadata:
languageName: node
linkType: hard
+"anser@npm:^2.1.1":
+ version: 2.3.2
+ resolution: "anser@npm:2.3.2"
+ checksum: 10/2bfb5fc96533919060bd2f2c199d22011f58e3d0ca48156cec7508ca5f741ea08e38fe634ae3d6902ae44b445148438f2ebcaf09f08ff3b2be20687c19cf4419
+ languageName: node
+ linkType: hard
+
"ansi-align@npm:^3.0.0":
version: 3.0.1
resolution: "ansi-align@npm:3.0.1"
@@ -12331,6 +14253,15 @@ __metadata:
languageName: node
linkType: hard
+"aria-hidden@npm:^1.2.4":
+ version: 1.2.6
+ resolution: "aria-hidden@npm:1.2.6"
+ dependencies:
+ tslib: "npm:^2.0.0"
+ checksum: 10/1914e5a36225dccdb29f0b88cc891eeca736cdc5b0c905ab1437b90b28b5286263ed3a221c75b7dc788f25b942367be0044b2ac8ccf073a72e07a50b1d964202
+ languageName: node
+ linkType: hard
+
"aria-query@npm:^5.3.1, aria-query@npm:^5.3.2":
version: 5.3.2
resolution: "aria-query@npm:5.3.2"
@@ -13621,6 +15552,17 @@ __metadata:
languageName: node
linkType: hard
+"bundle-require@npm:^5.1.0":
+ version: 5.1.0
+ resolution: "bundle-require@npm:5.1.0"
+ dependencies:
+ load-tsconfig: "npm:^0.2.3"
+ peerDependencies:
+ esbuild: ">=0.18"
+ checksum: 10/735e0220055b9bdac20bea48ec1e10dc3a205232c889ef54767900bebdc721959c4ccb221e4ea434d7ddcd693a8a4445c3d0598e4040ee313ce0ac3aae3e6178
+ languageName: node
+ linkType: hard
+
"busboy@npm:1.6.0, busboy@npm:^1.6.0":
version: 1.6.0
resolution: "busboy@npm:1.6.0"
@@ -14169,6 +16111,13 @@ __metadata:
languageName: node
linkType: hard
+"classnames@npm:^2.3.2":
+ version: 2.5.1
+ resolution: "classnames@npm:2.5.1"
+ checksum: 10/58eb394e8817021b153bb6e7d782cfb667e4ab390cb2e9dac2fc7c6b979d1cc2b2a733093955fc5c94aa79ef5c8c89f11ab77780894509be6afbb91dddd79d15
+ languageName: node
+ linkType: hard
+
"clean-css@npm:^5.2.2":
version: 5.3.2
resolution: "clean-css@npm:5.3.2"
@@ -14178,6 +16127,13 @@ __metadata:
languageName: node
linkType: hard
+"clean-set@npm:^1.1.2":
+ version: 1.1.2
+ resolution: "clean-set@npm:1.1.2"
+ checksum: 10/b460b59c82a11945052b59efa1d51405c0ba11d227f2c2140e9f7803d702b4a36354bfee0077d46a758979891aa4322211ce392c86961f11bf57e2ff774d5506
+ languageName: node
+ linkType: hard
+
"clean-stack@npm:^2.0.0":
version: 2.2.0
resolution: "clean-stack@npm:2.2.0"
@@ -14373,6 +16329,18 @@ __metadata:
languageName: node
linkType: hard
+"cm6-theme-basic-light@npm:^0.2.0":
+ version: 0.2.0
+ resolution: "cm6-theme-basic-light@npm:0.2.0"
+ peerDependencies:
+ "@codemirror/language": ^6.0.0
+ "@codemirror/state": ^6.0.0
+ "@codemirror/view": ^6.0.0
+ "@lezer/highlight": ^1.0.0
+ checksum: 10/8eb28ac7d8d7abdd8e5e4589d6abe459f1fe841940e49ea6431135c446b93af67bccab3981627c8e6377d1199f64879691570d6d1d409f9df9627bf4edceb1fc
+ languageName: node
+ linkType: hard
+
"co@npm:^4.6.0":
version: 4.6.0
resolution: "co@npm:4.6.0"
@@ -14402,6 +16370,21 @@ __metadata:
languageName: node
linkType: hard
+"codemirror@npm:^6.0.1":
+ version: 6.0.2
+ resolution: "codemirror@npm:6.0.2"
+ dependencies:
+ "@codemirror/autocomplete": "npm:^6.0.0"
+ "@codemirror/commands": "npm:^6.0.0"
+ "@codemirror/language": "npm:^6.0.0"
+ "@codemirror/lint": "npm:^6.0.0"
+ "@codemirror/search": "npm:^6.0.0"
+ "@codemirror/state": "npm:^6.0.0"
+ "@codemirror/view": "npm:^6.0.0"
+ checksum: 10/bd73c9ebbd8cb709a697fa4e2484c188c44aafce4b4d2a342807a5648c6be5bd5876f0caac47db0c1181f1ec8d86e38bd2b6efe51b971bf240fd3382bef0b371
+ languageName: node
+ linkType: hard
+
"collect-v8-coverage@npm:^1.0.0":
version: 1.0.1
resolution: "collect-v8-coverage@npm:1.0.1"
@@ -14636,6 +16619,13 @@ __metadata:
languageName: node
linkType: hard
+"compute-scroll-into-view@npm:^2.0.4":
+ version: 2.0.4
+ resolution: "compute-scroll-into-view@npm:2.0.4"
+ checksum: 10/a9015cbf464ed852d3c459c1777d5890e26925dd2e99ad438dc8cb6a0154f33f0ce6856f6c50de9dd176168d315e7223d08c4bae1e5dbe82b056dd5216c0bcc6
+ languageName: node
+ linkType: hard
+
"computeds@npm:^0.0.1":
version: 0.0.1
resolution: "computeds@npm:0.0.1"
@@ -15160,7 +17150,7 @@ __metadata:
languageName: node
linkType: hard
-"crelt@npm:^1.0.5":
+"crelt@npm:^1.0.5, crelt@npm:^1.0.6":
version: 1.0.6
resolution: "crelt@npm:1.0.6"
checksum: 10/5ed326ca6bd243b1dba6b943f665b21c2c04be03271824bc48f20dba324b0f8233e221f8c67312526d24af2b1243c023dc05a41bd8bd05d1a479fd2c72fb39c3
@@ -15610,6 +17600,16 @@ __metadata:
languageName: node
linkType: hard
+"d@npm:1, d@npm:^1.0.1, d@npm:^1.0.2":
+ version: 1.0.2
+ resolution: "d@npm:1.0.2"
+ dependencies:
+ es5-ext: "npm:^0.10.64"
+ type: "npm:^2.7.2"
+ checksum: 10/a3f45ef964622f683f6a1cb9b8dcbd75ce490cd2f4ac9794099db3d8f0e2814d412d84cd3fe522e58feb1f273117bb480f29c5381f6225f0abca82517caaa77a
+ languageName: node
+ linkType: hard
+
"dag-jose@npm:^5.0.0":
version: 5.1.1
resolution: "dag-jose@npm:5.1.1"
@@ -16051,7 +18051,7 @@ __metadata:
languageName: node
linkType: hard
-"dequal@npm:^2.0.0, dequal@npm:^2.0.3":
+"dequal@npm:^2.0.0, dequal@npm:^2.0.2, dequal@npm:^2.0.3":
version: 2.0.3
resolution: "dequal@npm:2.0.3"
checksum: 10/6ff05a7561f33603df87c45e389c9ac0a95e3c056be3da1a0c4702149e3a7f6fe5ffbb294478687ba51a9e95f3a60e8b6b9005993acd79c292c7d15f71964b6b
@@ -16135,6 +18135,13 @@ __metadata:
languageName: node
linkType: hard
+"detect-node-es@npm:^1.1.0":
+ version: 1.1.0
+ resolution: "detect-node-es@npm:1.1.0"
+ checksum: 10/e46307d7264644975b71c104b9f028ed1d3d34b83a15b8a22373640ce5ea630e5640b1078b8ea15f202b54641da71e4aa7597093bd4b91f113db520a26a37449
+ languageName: node
+ linkType: hard
+
"detect-node@npm:^2.0.4":
version: 2.1.0
resolution: "detect-node@npm:2.1.0"
@@ -16192,7 +18199,7 @@ __metadata:
languageName: node
linkType: hard
-"diff@npm:^5.0.0, diff@npm:^5.2.0":
+"diff@npm:^5.0.0, diff@npm:^5.1.0, diff@npm:^5.2.0":
version: 5.2.0
resolution: "diff@npm:5.2.0"
checksum: 10/01b7b440f83a997350a988e9d2f558366c0f90f15be19f4aa7f1bb3109a4e153dfc3b9fbf78e14ea725717017407eeaa2271e3896374a0181e8f52445740846d
@@ -16509,13 +18516,28 @@ __metadata:
languageName: node
linkType: hard
-"dotenv@npm:^16.6.1":
+"dotenv@npm:^16.0.3, dotenv@npm:^16.6.1":
version: 16.6.1
resolution: "dotenv@npm:16.6.1"
checksum: 10/1d1897144344447ffe62aa1a6d664f4cd2e0784e0aff787eeeec1940ded32f8e4b5b506d665134fc87157baa086fce07ec6383970a2b6d2e7985beaed6a4cc14
languageName: node
linkType: hard
+"downshift@npm:^7.6.0":
+ version: 7.6.2
+ resolution: "downshift@npm:7.6.2"
+ dependencies:
+ "@babel/runtime": "npm:^7.14.8"
+ compute-scroll-into-view: "npm:^2.0.4"
+ prop-types: "npm:^15.7.2"
+ react-is: "npm:^17.0.2"
+ tslib: "npm:^2.3.0"
+ peerDependencies:
+ react: ">=16.12.0"
+ checksum: 10/4ffca012d185a6eb57d5543650401323c932ae5f7227f92419aba4f04d5de2ca4f0270aa398caa289622f60ebb5f831fddf11e5d6d56981a89f7fbd7ed0a1f48
+ languageName: node
+ linkType: hard
+
"dset@npm:^3.1.2":
version: 3.1.2
resolution: "dset@npm:3.1.2"
@@ -16776,6 +18798,13 @@ __metadata:
languageName: node
linkType: hard
+"entities@npm:^6.0.0":
+ version: 6.0.1
+ resolution: "entities@npm:6.0.1"
+ checksum: 10/62af1307202884349d2867f0aac5c60d8b57102ea0b0e768b16246099512c28e239254ad772d6834e7e14cb1b6f153fc3d0c031934e3183b086c86d3838d874a
+ languageName: node
+ linkType: hard
+
"env-paths@npm:^2.2.0":
version: 2.2.1
resolution: "env-paths@npm:2.2.1"
@@ -16974,6 +19003,29 @@ __metadata:
languageName: node
linkType: hard
+"es5-ext@npm:^0.10.35, es5-ext@npm:^0.10.62, es5-ext@npm:^0.10.64, es5-ext@npm:~0.10.14":
+ version: 0.10.64
+ resolution: "es5-ext@npm:0.10.64"
+ dependencies:
+ es6-iterator: "npm:^2.0.3"
+ es6-symbol: "npm:^3.1.3"
+ esniff: "npm:^2.0.1"
+ next-tick: "npm:^1.1.0"
+ checksum: 10/0c5d8657708b1695ddc4b06f4e0b9fbdda4d2fe46d037b6bedb49a7d1931e542ec9eecf4824d59e1d357e93229deab014bb4b86485db2d41b1d68e54439689ce
+ languageName: node
+ linkType: hard
+
+"es6-iterator@npm:^2.0.3":
+ version: 2.0.3
+ resolution: "es6-iterator@npm:2.0.3"
+ dependencies:
+ d: "npm:1"
+ es5-ext: "npm:^0.10.35"
+ es6-symbol: "npm:^3.1.1"
+ checksum: 10/dbadecf3d0e467692815c2b438dfa99e5a97cbbecf4a58720adcb467a04220e0e36282399ba297911fd472c50ae4158fffba7ed0b7d4273fe322b69d03f9e3a5
+ languageName: node
+ linkType: hard
+
"es6-promise@npm:^4.0.3":
version: 4.2.8
resolution: "es6-promise@npm:4.2.8"
@@ -16990,6 +19042,16 @@ __metadata:
languageName: node
linkType: hard
+"es6-symbol@npm:^3, es6-symbol@npm:^3.1.1, es6-symbol@npm:^3.1.3":
+ version: 3.1.4
+ resolution: "es6-symbol@npm:3.1.4"
+ dependencies:
+ d: "npm:^1.0.2"
+ ext: "npm:^1.7.0"
+ checksum: 10/3743119fe61f89e2f049a6ce52bd82fab5f65d13e2faa72453b73f95c15292c3cb9bdf3747940d504517e675e45fd375554c6b5d35d2bcbefd35f5489ecba546
+ languageName: node
+ linkType: hard
+
"esbuild@npm:^0.19.0":
version: 0.19.12
resolution: "esbuild@npm:0.19.12"
@@ -17066,37 +19128,120 @@ __metadata:
optional: true
bin:
esbuild: bin/esbuild
- checksum: 10/861fa8eb2428e8d6521a4b7c7930139e3f45e8d51a86985cc29408172a41f6b18df7b3401e7e5e2d528cdf83742da601ddfdc77043ddc4f1c715a8ddb2d8a255
+ checksum: 10/861fa8eb2428e8d6521a4b7c7930139e3f45e8d51a86985cc29408172a41f6b18df7b3401e7e5e2d528cdf83742da601ddfdc77043ddc4f1c715a8ddb2d8a255
+ languageName: node
+ linkType: hard
+
+"esbuild@npm:^0.21.3":
+ version: 0.21.5
+ resolution: "esbuild@npm:0.21.5"
+ dependencies:
+ "@esbuild/aix-ppc64": "npm:0.21.5"
+ "@esbuild/android-arm": "npm:0.21.5"
+ "@esbuild/android-arm64": "npm:0.21.5"
+ "@esbuild/android-x64": "npm:0.21.5"
+ "@esbuild/darwin-arm64": "npm:0.21.5"
+ "@esbuild/darwin-x64": "npm:0.21.5"
+ "@esbuild/freebsd-arm64": "npm:0.21.5"
+ "@esbuild/freebsd-x64": "npm:0.21.5"
+ "@esbuild/linux-arm": "npm:0.21.5"
+ "@esbuild/linux-arm64": "npm:0.21.5"
+ "@esbuild/linux-ia32": "npm:0.21.5"
+ "@esbuild/linux-loong64": "npm:0.21.5"
+ "@esbuild/linux-mips64el": "npm:0.21.5"
+ "@esbuild/linux-ppc64": "npm:0.21.5"
+ "@esbuild/linux-riscv64": "npm:0.21.5"
+ "@esbuild/linux-s390x": "npm:0.21.5"
+ "@esbuild/linux-x64": "npm:0.21.5"
+ "@esbuild/netbsd-x64": "npm:0.21.5"
+ "@esbuild/openbsd-x64": "npm:0.21.5"
+ "@esbuild/sunos-x64": "npm:0.21.5"
+ "@esbuild/win32-arm64": "npm:0.21.5"
+ "@esbuild/win32-ia32": "npm:0.21.5"
+ "@esbuild/win32-x64": "npm:0.21.5"
+ dependenciesMeta:
+ "@esbuild/aix-ppc64":
+ optional: true
+ "@esbuild/android-arm":
+ optional: true
+ "@esbuild/android-arm64":
+ optional: true
+ "@esbuild/android-x64":
+ optional: true
+ "@esbuild/darwin-arm64":
+ optional: true
+ "@esbuild/darwin-x64":
+ optional: true
+ "@esbuild/freebsd-arm64":
+ optional: true
+ "@esbuild/freebsd-x64":
+ optional: true
+ "@esbuild/linux-arm":
+ optional: true
+ "@esbuild/linux-arm64":
+ optional: true
+ "@esbuild/linux-ia32":
+ optional: true
+ "@esbuild/linux-loong64":
+ optional: true
+ "@esbuild/linux-mips64el":
+ optional: true
+ "@esbuild/linux-ppc64":
+ optional: true
+ "@esbuild/linux-riscv64":
+ optional: true
+ "@esbuild/linux-s390x":
+ optional: true
+ "@esbuild/linux-x64":
+ optional: true
+ "@esbuild/netbsd-x64":
+ optional: true
+ "@esbuild/openbsd-x64":
+ optional: true
+ "@esbuild/sunos-x64":
+ optional: true
+ "@esbuild/win32-arm64":
+ optional: true
+ "@esbuild/win32-ia32":
+ optional: true
+ "@esbuild/win32-x64":
+ optional: true
+ bin:
+ esbuild: bin/esbuild
+ checksum: 10/d2ff2ca84d30cce8e871517374d6c2290835380dc7cd413b2d49189ed170d45e407be14de2cb4794cf76f75cf89955c4714726ebd3de7444b3046f5cab23ab6b
languageName: node
linkType: hard
-"esbuild@npm:^0.21.3":
- version: 0.21.5
- resolution: "esbuild@npm:0.21.5"
- dependencies:
- "@esbuild/aix-ppc64": "npm:0.21.5"
- "@esbuild/android-arm": "npm:0.21.5"
- "@esbuild/android-arm64": "npm:0.21.5"
- "@esbuild/android-x64": "npm:0.21.5"
- "@esbuild/darwin-arm64": "npm:0.21.5"
- "@esbuild/darwin-x64": "npm:0.21.5"
- "@esbuild/freebsd-arm64": "npm:0.21.5"
- "@esbuild/freebsd-x64": "npm:0.21.5"
- "@esbuild/linux-arm": "npm:0.21.5"
- "@esbuild/linux-arm64": "npm:0.21.5"
- "@esbuild/linux-ia32": "npm:0.21.5"
- "@esbuild/linux-loong64": "npm:0.21.5"
- "@esbuild/linux-mips64el": "npm:0.21.5"
- "@esbuild/linux-ppc64": "npm:0.21.5"
- "@esbuild/linux-riscv64": "npm:0.21.5"
- "@esbuild/linux-s390x": "npm:0.21.5"
- "@esbuild/linux-x64": "npm:0.21.5"
- "@esbuild/netbsd-x64": "npm:0.21.5"
- "@esbuild/openbsd-x64": "npm:0.21.5"
- "@esbuild/sunos-x64": "npm:0.21.5"
- "@esbuild/win32-arm64": "npm:0.21.5"
- "@esbuild/win32-ia32": "npm:0.21.5"
- "@esbuild/win32-x64": "npm:0.21.5"
+"esbuild@npm:~0.25.4":
+ version: 0.25.8
+ resolution: "esbuild@npm:0.25.8"
+ dependencies:
+ "@esbuild/aix-ppc64": "npm:0.25.8"
+ "@esbuild/android-arm": "npm:0.25.8"
+ "@esbuild/android-arm64": "npm:0.25.8"
+ "@esbuild/android-x64": "npm:0.25.8"
+ "@esbuild/darwin-arm64": "npm:0.25.8"
+ "@esbuild/darwin-x64": "npm:0.25.8"
+ "@esbuild/freebsd-arm64": "npm:0.25.8"
+ "@esbuild/freebsd-x64": "npm:0.25.8"
+ "@esbuild/linux-arm": "npm:0.25.8"
+ "@esbuild/linux-arm64": "npm:0.25.8"
+ "@esbuild/linux-ia32": "npm:0.25.8"
+ "@esbuild/linux-loong64": "npm:0.25.8"
+ "@esbuild/linux-mips64el": "npm:0.25.8"
+ "@esbuild/linux-ppc64": "npm:0.25.8"
+ "@esbuild/linux-riscv64": "npm:0.25.8"
+ "@esbuild/linux-s390x": "npm:0.25.8"
+ "@esbuild/linux-x64": "npm:0.25.8"
+ "@esbuild/netbsd-arm64": "npm:0.25.8"
+ "@esbuild/netbsd-x64": "npm:0.25.8"
+ "@esbuild/openbsd-arm64": "npm:0.25.8"
+ "@esbuild/openbsd-x64": "npm:0.25.8"
+ "@esbuild/openharmony-arm64": "npm:0.25.8"
+ "@esbuild/sunos-x64": "npm:0.25.8"
+ "@esbuild/win32-arm64": "npm:0.25.8"
+ "@esbuild/win32-ia32": "npm:0.25.8"
+ "@esbuild/win32-x64": "npm:0.25.8"
dependenciesMeta:
"@esbuild/aix-ppc64":
optional: true
@@ -17132,10 +19277,16 @@ __metadata:
optional: true
"@esbuild/linux-x64":
optional: true
+ "@esbuild/netbsd-arm64":
+ optional: true
"@esbuild/netbsd-x64":
optional: true
+ "@esbuild/openbsd-arm64":
+ optional: true
"@esbuild/openbsd-x64":
optional: true
+ "@esbuild/openharmony-arm64":
+ optional: true
"@esbuild/sunos-x64":
optional: true
"@esbuild/win32-arm64":
@@ -17146,7 +19297,7 @@ __metadata:
optional: true
bin:
esbuild: bin/esbuild
- checksum: 10/d2ff2ca84d30cce8e871517374d6c2290835380dc7cd413b2d49189ed170d45e407be14de2cb4794cf76f75cf89955c4714726ebd3de7444b3046f5cab23ab6b
+ checksum: 10/9897411732768e652d90fa5dfadae965e8f420d24e5f23fa0604331a1441769e2c7ee4e41ca53e926f1fb51a53af52e01fc9070fdc1a4edf3e9ec9208ee41273
languageName: node
linkType: hard
@@ -17164,6 +19315,13 @@ __metadata:
languageName: node
linkType: hard
+"escape-carriage@npm:^1.3.1":
+ version: 1.3.1
+ resolution: "escape-carriage@npm:1.3.1"
+ checksum: 10/6d7613a5875977b04eb4651f3fa14eb8f54c72aa198b603c823502fcfef9f5969afc4c76d27b2f2fc008d88764fbf4c3a6e04d549d6134e2ff7f705c99e3ddb9
+ languageName: node
+ linkType: hard
+
"escape-html@npm:~1.0.3":
version: 1.0.3
resolution: "escape-html@npm:1.0.3"
@@ -17192,6 +19350,13 @@ __metadata:
languageName: node
linkType: hard
+"escape-string-regexp@npm:^5.0.0":
+ version: 5.0.0
+ resolution: "escape-string-regexp@npm:5.0.0"
+ checksum: 10/20daabe197f3cb198ec28546deebcf24b3dbb1a5a269184381b3116d12f0532e06007f4bc8da25669d6a7f8efb68db0758df4cd981f57bc5b57f521a3e12c59e
+ languageName: node
+ linkType: hard
+
"escodegen@npm:1.8.x":
version: 1.8.1
resolution: "escodegen@npm:1.8.1"
@@ -17744,6 +19909,18 @@ __metadata:
languageName: node
linkType: hard
+"esniff@npm:^2.0.1":
+ version: 2.0.1
+ resolution: "esniff@npm:2.0.1"
+ dependencies:
+ d: "npm:^1.0.1"
+ es5-ext: "npm:^0.10.62"
+ event-emitter: "npm:^0.3.5"
+ type: "npm:^2.7.2"
+ checksum: 10/f6a2abd2f8c5fe57c5fcf53e5407c278023313d0f6c3a92688e7122ab9ac233029fd424508a196ae5bc561aa1f67d23f4e2435b1a0d378030f476596129056ac
+ languageName: node
+ linkType: hard
+
"espree@npm:^10.0.1, espree@npm:^10.3.0":
version: 10.3.0
resolution: "espree@npm:10.3.0"
@@ -17841,6 +20018,16 @@ __metadata:
languageName: node
linkType: hard
+"estree-util-visit@npm:^2.0.0":
+ version: 2.0.0
+ resolution: "estree-util-visit@npm:2.0.0"
+ dependencies:
+ "@types/estree-jsx": "npm:^1.0.0"
+ "@types/unist": "npm:^3.0.0"
+ checksum: 10/e3c39d34c8b42fc2067dfa64d460f754b43cca4b573b031a5e5bb185e02c4efc753353197815bbb094b8149a781ab76f18116bec8056b5ff375162e68bffa0bd
+ languageName: node
+ linkType: hard
+
"estree-walker@npm:^1.0.1":
version: 1.0.1
resolution: "estree-walker@npm:1.0.1"
@@ -18128,6 +20315,16 @@ __metadata:
languageName: node
linkType: hard
+"event-emitter@npm:^0.3.5":
+ version: 0.3.5
+ resolution: "event-emitter@npm:0.3.5"
+ dependencies:
+ d: "npm:1"
+ es5-ext: "npm:~0.10.14"
+ checksum: 10/a7f5ea80029193f4869782d34ef7eb43baa49cd397013add1953491b24588468efbe7e3cc9eb87d53f33397e7aab690fd74c079ec440bf8b12856f6bdb6e9396
+ languageName: node
+ linkType: hard
+
"event-target-shim@npm:^5.0.0":
version: 5.0.1
resolution: "event-target-shim@npm:5.0.1"
@@ -18306,6 +20503,15 @@ __metadata:
languageName: node
linkType: hard
+"ext@npm:^1.7.0":
+ version: 1.7.0
+ resolution: "ext@npm:1.7.0"
+ dependencies:
+ type: "npm:^2.7.2"
+ checksum: 10/666a135980b002df0e75c8ac6c389140cdc59ac953db62770479ee2856d58ce69d2f845e5f2586716350b725400f6945e51e9159573158c39f369984c72dcd84
+ languageName: node
+ linkType: hard
+
"extend@npm:^3.0.0":
version: 3.0.2
resolution: "extend@npm:3.0.2"
@@ -18506,6 +20712,15 @@ __metadata:
languageName: node
linkType: hard
+"fault@npm:^2.0.0":
+ version: 2.0.1
+ resolution: "fault@npm:2.0.1"
+ dependencies:
+ format: "npm:^0.2.0"
+ checksum: 10/c9b30f47d95769177130a9409976a899ed31eb598450fbad5b0d39f2f5f56d5f4a9ff9257e0bee8407cb0fc3ce37165657888c6aa6d78472e403893104329b72
+ languageName: node
+ linkType: hard
+
"faye-websocket@npm:^0.11.3":
version: 0.11.4
resolution: "faye-websocket@npm:0.11.4"
@@ -18899,6 +21114,13 @@ __metadata:
languageName: node
linkType: hard
+"format@npm:^0.2.0":
+ version: 0.2.2
+ resolution: "format@npm:0.2.2"
+ checksum: 10/5f878b8fc1a672c8cbefa4f293bdd977c822862577d70d53456a48b4169ec9b51677c0c995bf62c633b4e5cd673624b7c273f57923b28735a6c0c0a72c382a4a
+ languageName: node
+ linkType: hard
+
"forwarded@npm:0.2.0":
version: 0.2.0
resolution: "forwarded@npm:0.2.0"
@@ -19162,6 +21384,13 @@ __metadata:
languageName: node
linkType: hard
+"get-nonce@npm:^1.0.0":
+ version: 1.0.1
+ resolution: "get-nonce@npm:1.0.1"
+ checksum: 10/ad5104871d114a694ecc506a2d406e2331beccb961fe1e110dc25556b38bcdbf399a823a8a375976cd8889668156a9561e12ebe3fa6a4c6ba169c8466c2ff868
+ languageName: node
+ linkType: hard
+
"get-own-enumerable-property-symbols@npm:^3.0.0":
version: 3.0.2
resolution: "get-own-enumerable-property-symbols@npm:3.0.2"
@@ -19804,16 +22033,16 @@ __metadata:
languageName: node
linkType: hard
-"hardhat-contract-sizer@npm:^2.10.0":
- version: 2.10.0
- resolution: "hardhat-contract-sizer@npm:2.10.0"
+"hardhat-contract-sizer@npm:^2.10.1":
+ version: 2.10.1
+ resolution: "hardhat-contract-sizer@npm:2.10.1"
dependencies:
chalk: "npm:^4.0.0"
cli-table3: "npm:^0.6.0"
strip-ansi: "npm:^6.0.0"
peerDependencies:
hardhat: ^2.0.0
- checksum: 10/2b3011fe5333c2f1dbcfa6c73dcb1c61da9e2e045775c24bb773fe5f3ac14e9923907fef0e61fc2897e82a61997ce74e73baadb7f69dfdeccc86ae878cf67792
+ checksum: 10/521e985f0e6b5c1d06e38be8b374ae30f26ed6a72740ecfeeea1d8d5ee1341b98f699ed5587cc429e6de84da2c22df612e394ce492d393a4922702e82cc051f9
languageName: node
linkType: hard
@@ -19914,9 +22143,9 @@ __metadata:
languageName: node
linkType: hard
-"hardhat-tracer@npm:^3.2.1":
- version: 3.2.1
- resolution: "hardhat-tracer@npm:3.2.1"
+"hardhat-tracer@npm:^3.4.0":
+ version: 3.4.0
+ resolution: "hardhat-tracer@npm:3.4.0"
dependencies:
chalk: "npm:^4.1.2"
debug: "npm:^4.3.4"
@@ -19925,7 +22154,7 @@ __metadata:
peerDependencies:
chai: 4.x
hardhat: ">=2.22.5 <3.x"
- checksum: 10/963afeb42c1ed30704877c3b521afc748e60042d218cef333fc11d3246f544267c303df0effc1e2a5cac9cc8a9ec744fda6ceb4e3fc156d3e17f4cfb766f6ab1
+ checksum: 10/cdbab3bc60b73156866b5fdc27486ef75894094f67382dad28f0868ab167116787c61d9ab430a61ac49fb1787a47da9281fb421e8dc6fefc9dd4fa7660ad3f60
languageName: node
linkType: hard
@@ -19940,17 +22169,15 @@ __metadata:
languageName: node
linkType: hard
-"hardhat@npm:2.25.0":
- version: 2.25.0
- resolution: "hardhat@npm:2.25.0"
+"hardhat@npm:2.26.3":
+ version: 2.26.3
+ resolution: "hardhat@npm:2.26.3"
dependencies:
"@ethereumjs/util": "npm:^9.1.0"
"@ethersproject/abi": "npm:^5.1.2"
- "@nomicfoundation/edr": "npm:^0.11.1"
+ "@nomicfoundation/edr": "npm:^0.11.3"
"@nomicfoundation/solidity-analyzer": "npm:^0.1.0"
"@sentry/node": "npm:^5.18.1"
- "@types/bn.js": "npm:^5.1.0"
- "@types/lru-cache": "npm:^5.1.0"
adm-zip: "npm:^0.4.16"
aggregate-error: "npm:^3.0.0"
ansi-escapes: "npm:^4.3.0"
@@ -19995,7 +22222,7 @@ __metadata:
optional: true
bin:
hardhat: internal/cli/bootstrap.js
- checksum: 10/b74e83cf8b48e782dd9b7db0d640bcd68fe303c9e269686f9aa4ddcdd7b80e1ca932907003fd42fda005f38d486e4e59726b0f38fd8bf0b981e5810abcc907db
+ checksum: 10/77fabed0a9f5a5871bd071cd1eae3ce120ee878370a0d58e1a762fd49d01b68385b955c111d4a55147b1540333712ef36796fd5ee142e504aad17e2b2f746d6d
languageName: node
linkType: hard
@@ -20127,6 +22354,63 @@ __metadata:
languageName: node
linkType: hard
+"hast-util-from-parse5@npm:^8.0.0":
+ version: 8.0.3
+ resolution: "hast-util-from-parse5@npm:8.0.3"
+ dependencies:
+ "@types/hast": "npm:^3.0.0"
+ "@types/unist": "npm:^3.0.0"
+ devlop: "npm:^1.0.0"
+ hastscript: "npm:^9.0.0"
+ property-information: "npm:^7.0.0"
+ vfile: "npm:^6.0.0"
+ vfile-location: "npm:^5.0.0"
+ web-namespaces: "npm:^2.0.0"
+ checksum: 10/539c945c550cfef394a89dcff6e4de26768a748a7288ddce6f59554dd271b663b8398d58ace434264e965aaf3828fdbff86f9109d7fa639b3fe34dedcad4a5df
+ languageName: node
+ linkType: hard
+
+"hast-util-parse-selector@npm:^4.0.0":
+ version: 4.0.0
+ resolution: "hast-util-parse-selector@npm:4.0.0"
+ dependencies:
+ "@types/hast": "npm:^3.0.0"
+ checksum: 10/76087670d3b0b50b23a6cb70bca53a6176d6608307ccdbb3ed18b650b82e7c3513bfc40348f1389dc0c5ae872b9a768851f4335f44654abd7deafd6974c52402
+ languageName: node
+ linkType: hard
+
+"hast-util-raw@npm:^9.0.0":
+ version: 9.1.0
+ resolution: "hast-util-raw@npm:9.1.0"
+ dependencies:
+ "@types/hast": "npm:^3.0.0"
+ "@types/unist": "npm:^3.0.0"
+ "@ungap/structured-clone": "npm:^1.0.0"
+ hast-util-from-parse5: "npm:^8.0.0"
+ hast-util-to-parse5: "npm:^8.0.0"
+ html-void-elements: "npm:^3.0.0"
+ mdast-util-to-hast: "npm:^13.0.0"
+ parse5: "npm:^7.0.0"
+ unist-util-position: "npm:^5.0.0"
+ unist-util-visit: "npm:^5.0.0"
+ vfile: "npm:^6.0.0"
+ web-namespaces: "npm:^2.0.0"
+ zwitch: "npm:^2.0.0"
+ checksum: 10/fa304d08a9fce0f54b2baa18d15c45cb5cac695cbee3567b8ccbd9a57fa295c0fb23d238daca1cf0135ad8d538bb341dcd7d9da03f8b7d12e6980a9f8c4340ae
+ languageName: node
+ linkType: hard
+
+"hast-util-sanitize@npm:^5.0.0":
+ version: 5.0.2
+ resolution: "hast-util-sanitize@npm:5.0.2"
+ dependencies:
+ "@types/hast": "npm:^3.0.0"
+ "@ungap/structured-clone": "npm:^1.0.0"
+ unist-util-position: "npm:^5.0.0"
+ checksum: 10/920d4d78c8f73962e2440e626c02f65e832de3be5c49ddd101eee2269982489efa5aac7780e487bdebfcc407b1cb20ceea21fb48b690dd686d9a18273bffb817
+ languageName: node
+ linkType: hard
+
"hast-util-to-jsx-runtime@npm:^2.0.0":
version: 2.3.2
resolution: "hast-util-to-jsx-runtime@npm:2.3.2"
@@ -20150,6 +22434,21 @@ __metadata:
languageName: node
linkType: hard
+"hast-util-to-parse5@npm:^8.0.0":
+ version: 8.0.0
+ resolution: "hast-util-to-parse5@npm:8.0.0"
+ dependencies:
+ "@types/hast": "npm:^3.0.0"
+ comma-separated-tokens: "npm:^2.0.0"
+ devlop: "npm:^1.0.0"
+ property-information: "npm:^6.0.0"
+ space-separated-tokens: "npm:^2.0.0"
+ web-namespaces: "npm:^2.0.0"
+ zwitch: "npm:^2.0.0"
+ checksum: 10/ba59d0913ba7e914d8b0a50955c06806a6868445c56796ac9129d58185e86d7ff24037246767aba2ea904d9dee8c09b8ff303630bcd854431fdc1bbee2164c36
+ languageName: node
+ linkType: hard
+
"hast-util-whitespace@npm:^2.0.0":
version: 2.0.1
resolution: "hast-util-whitespace@npm:2.0.1"
@@ -20166,6 +22465,19 @@ __metadata:
languageName: node
linkType: hard
+"hastscript@npm:^9.0.0":
+ version: 9.0.1
+ resolution: "hastscript@npm:9.0.1"
+ dependencies:
+ "@types/hast": "npm:^3.0.0"
+ comma-separated-tokens: "npm:^2.0.0"
+ hast-util-parse-selector: "npm:^4.0.0"
+ property-information: "npm:^7.0.0"
+ space-separated-tokens: "npm:^2.0.0"
+ checksum: 10/9aa8135faf0307807cca4075bef4e3403ae1ce959ad4b9e6720892ba957d58ff98b2f60b5eb3ac67d88ae897dc918997299cd4249d7ac602a0066dd46442c5d4
+ languageName: node
+ linkType: hard
+
"he@npm:^1.2.0":
version: 1.2.0
resolution: "he@npm:1.2.0"
@@ -20351,6 +22663,13 @@ __metadata:
languageName: node
linkType: hard
+"html-void-elements@npm:^3.0.0":
+ version: 3.0.0
+ resolution: "html-void-elements@npm:3.0.0"
+ checksum: 10/59be397525465a7489028afa064c55763d9cccd1d7d9f630cca47137317f0e897a9ca26cef7e745e7cff1abc44260cfa407742b243a54261dfacd42230e94fce
+ languageName: node
+ linkType: hard
+
"html-webpack-plugin@npm:^5.5.0":
version: 5.5.3
resolution: "html-webpack-plugin@npm:5.5.3"
@@ -20887,6 +23206,13 @@ __metadata:
languageName: node
linkType: hard
+"intersection-observer@npm:^0.10.0":
+ version: 0.10.0
+ resolution: "intersection-observer@npm:0.10.0"
+ checksum: 10/d9ffce291459a2c4ada9e45f23ef805361691f93e9a41a2afe801d29e6c9b1d0054f7faddafd79ecc341d7008e1f921a2e67cadeae9692d9831af903f23fc644
+ languageName: node
+ linkType: hard
+
"invariant@npm:^2.2.4":
version: 2.2.4
resolution: "invariant@npm:2.2.4"
@@ -23121,6 +25447,13 @@ __metadata:
languageName: node
linkType: hard
+"lexical@npm:0.35.0, lexical@npm:^0.35.0":
+ version: 0.35.0
+ resolution: "lexical@npm:0.35.0"
+ checksum: 10/31cb0b683c50826f70c6ef1ca1e3a5eb276a736c6e217789c1d38a12bfef93c9f9a16ed0b8747517742067e87145365589a6e133562619777aed58501a53d7b1
+ languageName: node
+ linkType: hard
+
"lie@npm:3.1.1":
version: 3.1.1
resolution: "lie@npm:3.1.1"
@@ -23810,6 +26143,15 @@ __metadata:
languageName: node
linkType: hard
+"lz-string@npm:^1.4.4":
+ version: 1.5.0
+ resolution: "lz-string@npm:1.5.0"
+ bin:
+ lz-string: bin/bin.js
+ checksum: 10/e86f0280e99a8d8cd4eef24d8601ddae15ce54e43ac9990dfcb79e1e081c255ad24424a30d78d2ad8e51a8ce82a66a930047fed4b4aa38c6f0b392ff9300edfc
+ languageName: node
+ linkType: hard
+
"magic-string@npm:^0.25.0, magic-string@npm:^0.25.7":
version: 0.25.9
resolution: "magic-string@npm:0.25.9"
@@ -23929,6 +26271,13 @@ __metadata:
languageName: node
linkType: hard
+"markdown-table@npm:^3.0.0":
+ version: 3.0.4
+ resolution: "markdown-table@npm:3.0.4"
+ checksum: 10/bc699819e6a15607e5def0f21aa862aa061cf1f49877baa93b0185574f6ab143591afe0e18b94d9b15ea80c6a693894150dbccfacf4f6767160dc32ae393dfe0
+ languageName: node
+ linkType: hard
+
"marked@npm:^4.1.1":
version: 4.3.0
resolution: "marked@npm:4.3.0"
@@ -23976,6 +26325,35 @@ __metadata:
languageName: node
linkType: hard
+"mdast-util-directive@npm:^3.0.0":
+ version: 3.1.0
+ resolution: "mdast-util-directive@npm:3.1.0"
+ dependencies:
+ "@types/mdast": "npm:^4.0.0"
+ "@types/unist": "npm:^3.0.0"
+ ccount: "npm:^2.0.0"
+ devlop: "npm:^1.0.0"
+ mdast-util-from-markdown: "npm:^2.0.0"
+ mdast-util-to-markdown: "npm:^2.0.0"
+ parse-entities: "npm:^4.0.0"
+ stringify-entities: "npm:^4.0.0"
+ unist-util-visit-parents: "npm:^6.0.0"
+ checksum: 10/5aabd777ae8752cb9d09c7827a6690887536da8a9f85e833d5399ab8f47e5aadaa3eea78985efd041f50c658bf91b4579800dae79b20549240f52bbc2bc26335
+ languageName: node
+ linkType: hard
+
+"mdast-util-find-and-replace@npm:^2.0.0":
+ version: 2.2.2
+ resolution: "mdast-util-find-and-replace@npm:2.2.2"
+ dependencies:
+ "@types/mdast": "npm:^3.0.0"
+ escape-string-regexp: "npm:^5.0.0"
+ unist-util-is: "npm:^5.0.0"
+ unist-util-visit-parents: "npm:^5.0.0"
+ checksum: 10/59e11e853b74d8f6083950327df39e27287b383930ff836298a5100aeda5568282bb45046c27886d2156ea101580bb0689b890c29623cefa5adc74e95d9ca9ff
+ languageName: node
+ linkType: hard
+
"mdast-util-from-markdown@npm:^1.0.0":
version: 1.3.1
resolution: "mdast-util-from-markdown@npm:1.3.1"
@@ -24016,6 +26394,135 @@ __metadata:
languageName: node
linkType: hard
+"mdast-util-frontmatter@npm:^2.0.1":
+ version: 2.0.1
+ resolution: "mdast-util-frontmatter@npm:2.0.1"
+ dependencies:
+ "@types/mdast": "npm:^4.0.0"
+ devlop: "npm:^1.0.0"
+ escape-string-regexp: "npm:^5.0.0"
+ mdast-util-from-markdown: "npm:^2.0.0"
+ mdast-util-to-markdown: "npm:^2.0.0"
+ micromark-extension-frontmatter: "npm:^2.0.0"
+ checksum: 10/afd9486af6ea74a94d84a225c367ab810ad4439683ecafc1ce9fc7bb0ecacaafac82e0af529974489c145824b242509f9387f833fc01a14a83a978049772ef80
+ languageName: node
+ linkType: hard
+
+"mdast-util-gfm-autolink-literal@npm:^1.0.0":
+ version: 1.0.3
+ resolution: "mdast-util-gfm-autolink-literal@npm:1.0.3"
+ dependencies:
+ "@types/mdast": "npm:^3.0.0"
+ ccount: "npm:^2.0.0"
+ mdast-util-find-and-replace: "npm:^2.0.0"
+ micromark-util-character: "npm:^1.0.0"
+ checksum: 10/272d075cdc7937bec0179af4052bd9032a6fbb05608b387b1b075b0491c73ce012f3ff1c718cdb5fb0ed1032c1fa7570d955b59c0ab3c3c72609928754774529
+ languageName: node
+ linkType: hard
+
+"mdast-util-gfm-footnote@npm:^1.0.0":
+ version: 1.0.2
+ resolution: "mdast-util-gfm-footnote@npm:1.0.2"
+ dependencies:
+ "@types/mdast": "npm:^3.0.0"
+ mdast-util-to-markdown: "npm:^1.3.0"
+ micromark-util-normalize-identifier: "npm:^1.0.0"
+ checksum: 10/825f207afc98fd1daa0acc8adcb5754d1f0d577ccb1749245289bee7c892557668d8ee3a5ab618f42e710646cf018dcda84f3c0c608ae11718e9014e5bf4f9dc
+ languageName: node
+ linkType: hard
+
+"mdast-util-gfm-strikethrough@npm:^1.0.0":
+ version: 1.0.3
+ resolution: "mdast-util-gfm-strikethrough@npm:1.0.3"
+ dependencies:
+ "@types/mdast": "npm:^3.0.0"
+ mdast-util-to-markdown: "npm:^1.3.0"
+ checksum: 10/a9c2dc3ef46be7952d13b7063a16171bba8aa266bffe6b1e7267df02a60b4fa3734115cca311e9127db8cfcbbcd68fdd92aa26152bcd0c14372c79b254e4df2f
+ languageName: node
+ linkType: hard
+
+"mdast-util-gfm-strikethrough@npm:^2.0.0":
+ version: 2.0.0
+ resolution: "mdast-util-gfm-strikethrough@npm:2.0.0"
+ dependencies:
+ "@types/mdast": "npm:^4.0.0"
+ mdast-util-from-markdown: "npm:^2.0.0"
+ mdast-util-to-markdown: "npm:^2.0.0"
+ checksum: 10/b1abc137d78270540585ad94a7a4ed1630683312690b902389dae0ede50a6832e26d1be053687f49728e14fa8a379da9384342725d3beb4480fc30b12866ab37
+ languageName: node
+ linkType: hard
+
+"mdast-util-gfm-table@npm:^1.0.0":
+ version: 1.0.7
+ resolution: "mdast-util-gfm-table@npm:1.0.7"
+ dependencies:
+ "@types/mdast": "npm:^3.0.0"
+ markdown-table: "npm:^3.0.0"
+ mdast-util-from-markdown: "npm:^1.0.0"
+ mdast-util-to-markdown: "npm:^1.3.0"
+ checksum: 10/167f7f7a9dc17ce852f4f9bd155d7be179588e2ccf4ce3c4f23b12c1c9db5de904cdacc6f41b2d635cb84eb09a7ff5a33497585f2664a7f1e6bd6f7ab7e1197a
+ languageName: node
+ linkType: hard
+
+"mdast-util-gfm-table@npm:^2.0.0":
+ version: 2.0.0
+ resolution: "mdast-util-gfm-table@npm:2.0.0"
+ dependencies:
+ "@types/mdast": "npm:^4.0.0"
+ devlop: "npm:^1.0.0"
+ markdown-table: "npm:^3.0.0"
+ mdast-util-from-markdown: "npm:^2.0.0"
+ mdast-util-to-markdown: "npm:^2.0.0"
+ checksum: 10/a043d60d723a86f79c49cbdd1d98b80c89f4a8f9f5fa84b3880c53e132f40150972460aba9be1f44a612ef5abd6810d122c5e7e5d9c54f3ac7560cce8c305c75
+ languageName: node
+ linkType: hard
+
+"mdast-util-gfm-task-list-item@npm:^1.0.0":
+ version: 1.0.2
+ resolution: "mdast-util-gfm-task-list-item@npm:1.0.2"
+ dependencies:
+ "@types/mdast": "npm:^3.0.0"
+ mdast-util-to-markdown: "npm:^1.3.0"
+ checksum: 10/958417a7d7690728b44d65127ab9189c7feaa17aea924dd56a888c781ab3abaa4eb0c209f05c4dbf203da3d0c4df8fdace4c9471b644268bfc7fc792a018a171
+ languageName: node
+ linkType: hard
+
+"mdast-util-gfm-task-list-item@npm:^2.0.0":
+ version: 2.0.0
+ resolution: "mdast-util-gfm-task-list-item@npm:2.0.0"
+ dependencies:
+ "@types/mdast": "npm:^4.0.0"
+ devlop: "npm:^1.0.0"
+ mdast-util-from-markdown: "npm:^2.0.0"
+ mdast-util-to-markdown: "npm:^2.0.0"
+ checksum: 10/679a3ff09b52015c0088cd0616ccecc7cc9d250d56a8762aafdffc640f3f607bbd9fe047d3e7e7078e6a996e83f677be3bfcad7ac7260563825fa80a04f8e09d
+ languageName: node
+ linkType: hard
+
+"mdast-util-gfm@npm:^2.0.0":
+ version: 2.0.2
+ resolution: "mdast-util-gfm@npm:2.0.2"
+ dependencies:
+ mdast-util-from-markdown: "npm:^1.0.0"
+ mdast-util-gfm-autolink-literal: "npm:^1.0.0"
+ mdast-util-gfm-footnote: "npm:^1.0.0"
+ mdast-util-gfm-strikethrough: "npm:^1.0.0"
+ mdast-util-gfm-table: "npm:^1.0.0"
+ mdast-util-gfm-task-list-item: "npm:^1.0.0"
+ mdast-util-to-markdown: "npm:^1.0.0"
+ checksum: 10/70e6cd32af94181d409f171f984f83fc18b3efe316844c62f31816f5c1612a92517b8ed766340f23e0a6d6cb0f27a8b07d288bab6619cbdbb0c5341006bcdc4d
+ languageName: node
+ linkType: hard
+
+"mdast-util-highlight-mark@npm:^1.2.2":
+ version: 1.2.2
+ resolution: "mdast-util-highlight-mark@npm:1.2.2"
+ dependencies:
+ micromark-extension-highlight-mark: "npm:1.2.0"
+ checksum: 10/92f62acb2958e1f9e280350f707e0254f9f6363618fde528bc738c74143e5735f6393e0b0d08cce2e9f416c4f9e673d485e375bbcf1e861de055f3e50dab09b5
+ languageName: node
+ linkType: hard
+
"mdast-util-mdx-expression@npm:^2.0.0":
version: 2.0.1
resolution: "mdast-util-mdx-expression@npm:2.0.1"
@@ -24050,6 +26557,19 @@ __metadata:
languageName: node
linkType: hard
+"mdast-util-mdx@npm:^3.0.0":
+ version: 3.0.0
+ resolution: "mdast-util-mdx@npm:3.0.0"
+ dependencies:
+ mdast-util-from-markdown: "npm:^2.0.0"
+ mdast-util-mdx-expression: "npm:^2.0.0"
+ mdast-util-mdx-jsx: "npm:^3.0.0"
+ mdast-util-mdxjs-esm: "npm:^2.0.0"
+ mdast-util-to-markdown: "npm:^2.0.0"
+ checksum: 10/547d928f0d1e60d9087cd8ad301cdf2e1d14b094d2662a00292874b923bcb59323bdad3a29804c7f323ad78f4d3954361bfdaf4a9be765c4e6fe47a815df50c2
+ languageName: node
+ linkType: hard
+
"mdast-util-mdxjs-esm@npm:^2.0.0":
version: 2.0.1
resolution: "mdast-util-mdxjs-esm@npm:2.0.1"
@@ -24064,6 +26584,16 @@ __metadata:
languageName: node
linkType: hard
+"mdast-util-phrasing@npm:^3.0.0":
+ version: 3.0.1
+ resolution: "mdast-util-phrasing@npm:3.0.1"
+ dependencies:
+ "@types/mdast": "npm:^3.0.0"
+ unist-util-is: "npm:^5.0.0"
+ checksum: 10/c5b616d9b1eb76a6b351d195d94318494722525a12a89d9c8a3b091af7db3dd1fc55d294f9d29266d8159a8267b0df4a7a133bda8a3909d5331c383e1e1ff328
+ languageName: node
+ linkType: hard
+
"mdast-util-phrasing@npm:^4.0.0":
version: 4.1.0
resolution: "mdast-util-phrasing@npm:4.1.0"
@@ -24107,7 +26637,23 @@ __metadata:
languageName: node
linkType: hard
-"mdast-util-to-markdown@npm:^2.0.0":
+"mdast-util-to-markdown@npm:^1.0.0, mdast-util-to-markdown@npm:^1.3.0":
+ version: 1.5.0
+ resolution: "mdast-util-to-markdown@npm:1.5.0"
+ dependencies:
+ "@types/mdast": "npm:^3.0.0"
+ "@types/unist": "npm:^2.0.0"
+ longest-streak: "npm:^3.0.0"
+ mdast-util-phrasing: "npm:^3.0.0"
+ mdast-util-to-string: "npm:^3.0.0"
+ micromark-util-decode-string: "npm:^1.0.0"
+ unist-util-visit: "npm:^4.0.0"
+ zwitch: "npm:^2.0.0"
+ checksum: 10/713f674588a01969a2ce524a69985bd57e507377eea2c4ba69800fb305414468b30144ae9b837fbdde8c609877673140e4f56f6cabe9e0e2bc1487291e3c5144
+ languageName: node
+ linkType: hard
+
+"mdast-util-to-markdown@npm:^2.0.0, mdast-util-to-markdown@npm:^2.1.0":
version: 2.1.2
resolution: "mdast-util-to-markdown@npm:2.1.2"
dependencies:
@@ -24124,7 +26670,7 @@ __metadata:
languageName: node
linkType: hard
-"mdast-util-to-string@npm:^3.1.0":
+"mdast-util-to-string@npm:^3.0.0, mdast-util-to-string@npm:^3.1.0":
version: 3.2.0
resolution: "mdast-util-to-string@npm:3.2.0"
dependencies:
@@ -24323,7 +26869,7 @@ __metadata:
languageName: node
linkType: hard
-"micromark-core-commonmark@npm:^1.0.1":
+"micromark-core-commonmark@npm:^1.0.0, micromark-core-commonmark@npm:^1.0.1":
version: 1.1.0
resolution: "micromark-core-commonmark@npm:1.1.0"
dependencies:
@@ -24371,6 +26917,256 @@ __metadata:
languageName: node
linkType: hard
+"micromark-extension-directive@npm:^3.0.0":
+ version: 3.0.2
+ resolution: "micromark-extension-directive@npm:3.0.2"
+ dependencies:
+ devlop: "npm:^1.0.0"
+ micromark-factory-space: "npm:^2.0.0"
+ micromark-factory-whitespace: "npm:^2.0.0"
+ micromark-util-character: "npm:^2.0.0"
+ micromark-util-symbol: "npm:^2.0.0"
+ micromark-util-types: "npm:^2.0.0"
+ parse-entities: "npm:^4.0.0"
+ checksum: 10/63dbaa209722c1a77ffea6c6d5ea0f873f5e795ef08a2039f3d795320c889e5ce10fe1162500b0ff3063f8ceb1f7d727ec1d29d2df6271cbe90ec0646e061c8d
+ languageName: node
+ linkType: hard
+
+"micromark-extension-frontmatter@npm:^2.0.0":
+ version: 2.0.0
+ resolution: "micromark-extension-frontmatter@npm:2.0.0"
+ dependencies:
+ fault: "npm:^2.0.0"
+ micromark-util-character: "npm:^2.0.0"
+ micromark-util-symbol: "npm:^2.0.0"
+ micromark-util-types: "npm:^2.0.0"
+ checksum: 10/55873937494e9bfe1cc8cba3c8710e14e85ad0c9f3bb859d367268fc2204f3fe2eb70f9f83e496de0d3ea79c468fe6df879f9d475c716644c2daa90056cc8374
+ languageName: node
+ linkType: hard
+
+"micromark-extension-gfm-autolink-literal@npm:^1.0.0":
+ version: 1.0.5
+ resolution: "micromark-extension-gfm-autolink-literal@npm:1.0.5"
+ dependencies:
+ micromark-util-character: "npm:^1.0.0"
+ micromark-util-sanitize-uri: "npm:^1.0.0"
+ micromark-util-symbol: "npm:^1.0.0"
+ micromark-util-types: "npm:^1.0.0"
+ checksum: 10/1e0ccc758baef3cd0478ba84ff86fa1ec2b389042421c7cade9485b775456c1a9c3bd797393002b2c6f6abd9bdf829cb114874557bbcb8e43d16d06a464811c0
+ languageName: node
+ linkType: hard
+
+"micromark-extension-gfm-footnote@npm:^1.0.0":
+ version: 1.1.2
+ resolution: "micromark-extension-gfm-footnote@npm:1.1.2"
+ dependencies:
+ micromark-core-commonmark: "npm:^1.0.0"
+ micromark-factory-space: "npm:^1.0.0"
+ micromark-util-character: "npm:^1.0.0"
+ micromark-util-normalize-identifier: "npm:^1.0.0"
+ micromark-util-sanitize-uri: "npm:^1.0.0"
+ micromark-util-symbol: "npm:^1.0.0"
+ micromark-util-types: "npm:^1.0.0"
+ uvu: "npm:^0.5.0"
+ checksum: 10/8777073fb76d2fd01f6b2405106af6c349c1e25660c4d37cadcc61c187d71c8444870f73cefaaa67f12884d5e45c78ee3c5583561a0b330bd91c6d997113584a
+ languageName: node
+ linkType: hard
+
+"micromark-extension-gfm-strikethrough@npm:^1.0.0":
+ version: 1.0.7
+ resolution: "micromark-extension-gfm-strikethrough@npm:1.0.7"
+ dependencies:
+ micromark-util-chunked: "npm:^1.0.0"
+ micromark-util-classify-character: "npm:^1.0.0"
+ micromark-util-resolve-all: "npm:^1.0.0"
+ micromark-util-symbol: "npm:^1.0.0"
+ micromark-util-types: "npm:^1.0.0"
+ uvu: "npm:^0.5.0"
+ checksum: 10/8411ef1aa5dc83f662e8b45b085f70ddff29deb3c4259269e8a1ff656397abb755d8ea841a14be23e8585a31d3c0a5de1bd2c05f3453b66670e499d4a0004f5e
+ languageName: node
+ linkType: hard
+
+"micromark-extension-gfm-strikethrough@npm:^2.0.0":
+ version: 2.1.0
+ resolution: "micromark-extension-gfm-strikethrough@npm:2.1.0"
+ dependencies:
+ devlop: "npm:^1.0.0"
+ micromark-util-chunked: "npm:^2.0.0"
+ micromark-util-classify-character: "npm:^2.0.0"
+ micromark-util-resolve-all: "npm:^2.0.0"
+ micromark-util-symbol: "npm:^2.0.0"
+ micromark-util-types: "npm:^2.0.0"
+ checksum: 10/eaf2c7b1e3eb2a7d7f405e8abe561be083cc52b8e027225ed286490939f527d18c120df59c8d8e17fdcf284f8d014502bf3db45d8e36e3109457ece8fb1db29b
+ languageName: node
+ linkType: hard
+
+"micromark-extension-gfm-table@npm:^1.0.0":
+ version: 1.0.7
+ resolution: "micromark-extension-gfm-table@npm:1.0.7"
+ dependencies:
+ micromark-factory-space: "npm:^1.0.0"
+ micromark-util-character: "npm:^1.0.0"
+ micromark-util-symbol: "npm:^1.0.0"
+ micromark-util-types: "npm:^1.0.0"
+ uvu: "npm:^0.5.0"
+ checksum: 10/f05d86a099c941a2a309d60bf4839d16a00a93cb880cda4ab8faeb831647763fff6e03197ec15b80e1f195002afcca6afe2b95c3622b049b82d7ff8ef1c1c776
+ languageName: node
+ linkType: hard
+
+"micromark-extension-gfm-table@npm:^2.0.0":
+ version: 2.1.1
+ resolution: "micromark-extension-gfm-table@npm:2.1.1"
+ dependencies:
+ devlop: "npm:^1.0.0"
+ micromark-factory-space: "npm:^2.0.0"
+ micromark-util-character: "npm:^2.0.0"
+ micromark-util-symbol: "npm:^2.0.0"
+ micromark-util-types: "npm:^2.0.0"
+ checksum: 10/0391ead408d79a183a9bba325b0e660b85aef2cd6e442a9214afc4e0bdc3105cd7dbf41fc75465acf152883a4050b6203107c2a80bcadb304235581a1340fd8c
+ languageName: node
+ linkType: hard
+
+"micromark-extension-gfm-tagfilter@npm:^1.0.0":
+ version: 1.0.2
+ resolution: "micromark-extension-gfm-tagfilter@npm:1.0.2"
+ dependencies:
+ micromark-util-types: "npm:^1.0.0"
+ checksum: 10/55c7d9019d6a39efaaed2c2e40b0aaa137d2c4f9c94cac82e93f509a806c3a775e4c815b5d8e986617450b68861a19776e4b886307e83db452b393f15a837b39
+ languageName: node
+ linkType: hard
+
+"micromark-extension-gfm-task-list-item@npm:^1.0.0":
+ version: 1.0.5
+ resolution: "micromark-extension-gfm-task-list-item@npm:1.0.5"
+ dependencies:
+ micromark-factory-space: "npm:^1.0.0"
+ micromark-util-character: "npm:^1.0.0"
+ micromark-util-symbol: "npm:^1.0.0"
+ micromark-util-types: "npm:^1.0.0"
+ uvu: "npm:^0.5.0"
+ checksum: 10/46bb1baa10bfb785a2e3e2f975e5509260b9995d5c3aeddf77051957d218ce1af4ea737bcb6a56a930e62d42b05307b20632a400eff25cdb290789ff3170cad5
+ languageName: node
+ linkType: hard
+
+"micromark-extension-gfm-task-list-item@npm:^2.0.1":
+ version: 2.1.0
+ resolution: "micromark-extension-gfm-task-list-item@npm:2.1.0"
+ dependencies:
+ devlop: "npm:^1.0.0"
+ micromark-factory-space: "npm:^2.0.0"
+ micromark-util-character: "npm:^2.0.0"
+ micromark-util-symbol: "npm:^2.0.0"
+ micromark-util-types: "npm:^2.0.0"
+ checksum: 10/c5f72929f0dca77df01442b721356624de6657364e2264ef50fc7226305976f302a49b670836f9494ce70a9b0335d974b5ef8e6457553c4c200bfc06d6951964
+ languageName: node
+ linkType: hard
+
+"micromark-extension-gfm@npm:^2.0.0":
+ version: 2.0.3
+ resolution: "micromark-extension-gfm@npm:2.0.3"
+ dependencies:
+ micromark-extension-gfm-autolink-literal: "npm:^1.0.0"
+ micromark-extension-gfm-footnote: "npm:^1.0.0"
+ micromark-extension-gfm-strikethrough: "npm:^1.0.0"
+ micromark-extension-gfm-table: "npm:^1.0.0"
+ micromark-extension-gfm-tagfilter: "npm:^1.0.0"
+ micromark-extension-gfm-task-list-item: "npm:^1.0.0"
+ micromark-util-combine-extensions: "npm:^1.0.0"
+ micromark-util-types: "npm:^1.0.0"
+ checksum: 10/3ffd06ced4314abd0f0c72ec227f034f38dd47facbb62439ef3216d42f32433f3901d14675cf806e8d73689802a11849958b330bb5b55dd4fd5cdc64ebaf345c
+ languageName: node
+ linkType: hard
+
+"micromark-extension-highlight-mark@npm:1.2.0, micromark-extension-highlight-mark@npm:^1.2.0":
+ version: 1.2.0
+ resolution: "micromark-extension-highlight-mark@npm:1.2.0"
+ dependencies:
+ micromark-util-chunked: "npm:^2.0.0"
+ micromark-util-classify-character: "npm:^2.0.0"
+ micromark-util-resolve-all: "npm:^2.0.0"
+ micromark-util-symbol: "npm:^2.0.0"
+ micromark-util-types: "npm:^2.0.0"
+ uvu: "npm:^0.5.6"
+ checksum: 10/18474254eb7bf347ff68cc1953aa702527c8d710856d2b2252a3e59dda2fb3b7f34c0780ef18090f257270a00182380d731a7f705e5834e5795e8790aa3ea696
+ languageName: node
+ linkType: hard
+
+"micromark-extension-mdx-expression@npm:^3.0.0":
+ version: 3.0.1
+ resolution: "micromark-extension-mdx-expression@npm:3.0.1"
+ dependencies:
+ "@types/estree": "npm:^1.0.0"
+ devlop: "npm:^1.0.0"
+ micromark-factory-mdx-expression: "npm:^2.0.0"
+ micromark-factory-space: "npm:^2.0.0"
+ micromark-util-character: "npm:^2.0.0"
+ micromark-util-events-to-acorn: "npm:^2.0.0"
+ micromark-util-symbol: "npm:^2.0.0"
+ micromark-util-types: "npm:^2.0.0"
+ checksum: 10/a185e1787fe6d49d0e435690affd4b83ce319f88a08c57d2460d37d5c0a75ea64aa49a4a116b6d37f91389dc04351e1826aa834519a9f25fc31e1424962c6eb7
+ languageName: node
+ linkType: hard
+
+"micromark-extension-mdx-jsx@npm:^3.0.0":
+ version: 3.0.2
+ resolution: "micromark-extension-mdx-jsx@npm:3.0.2"
+ dependencies:
+ "@types/estree": "npm:^1.0.0"
+ devlop: "npm:^1.0.0"
+ estree-util-is-identifier-name: "npm:^3.0.0"
+ micromark-factory-mdx-expression: "npm:^2.0.0"
+ micromark-factory-space: "npm:^2.0.0"
+ micromark-util-character: "npm:^2.0.0"
+ micromark-util-events-to-acorn: "npm:^2.0.0"
+ micromark-util-symbol: "npm:^2.0.0"
+ micromark-util-types: "npm:^2.0.0"
+ vfile-message: "npm:^4.0.0"
+ checksum: 10/a85cdb7c972fbb2cc8f0a64adc808b2b62bc2d79dbdd31fcd3208ff15aafa0198b002022840b2c65b5bff6f2a8c2c4a59a32a89f3482e6e183114b476e98e25c
+ languageName: node
+ linkType: hard
+
+"micromark-extension-mdx-md@npm:^2.0.0":
+ version: 2.0.0
+ resolution: "micromark-extension-mdx-md@npm:2.0.0"
+ dependencies:
+ micromark-util-types: "npm:^2.0.0"
+ checksum: 10/8b364a69b23196075258143c8c19fa58d7d5a91f6811ec0f881b75cf024a4869994be29f84f4d281147275c5a104af8b6a7fcd98abd8fde9f5b534a1acb254e8
+ languageName: node
+ linkType: hard
+
+"micromark-extension-mdxjs-esm@npm:^3.0.0":
+ version: 3.0.0
+ resolution: "micromark-extension-mdxjs-esm@npm:3.0.0"
+ dependencies:
+ "@types/estree": "npm:^1.0.0"
+ devlop: "npm:^1.0.0"
+ micromark-core-commonmark: "npm:^2.0.0"
+ micromark-util-character: "npm:^2.0.0"
+ micromark-util-events-to-acorn: "npm:^2.0.0"
+ micromark-util-symbol: "npm:^2.0.0"
+ micromark-util-types: "npm:^2.0.0"
+ unist-util-position-from-estree: "npm:^2.0.0"
+ vfile-message: "npm:^4.0.0"
+ checksum: 10/f2e0977f9a65284b0c765d1175d55ec5d1928dae3ae90f65cc36f293cda152a97fe2007977aaf5595b1bc02298b34c96e8ce8b647c9c647c75f1ea53e92d14d2
+ languageName: node
+ linkType: hard
+
+"micromark-extension-mdxjs@npm:^3.0.0":
+ version: 3.0.0
+ resolution: "micromark-extension-mdxjs@npm:3.0.0"
+ dependencies:
+ acorn: "npm:^8.0.0"
+ acorn-jsx: "npm:^5.0.0"
+ micromark-extension-mdx-expression: "npm:^3.0.0"
+ micromark-extension-mdx-jsx: "npm:^3.0.0"
+ micromark-extension-mdx-md: "npm:^2.0.0"
+ micromark-extension-mdxjs-esm: "npm:^3.0.0"
+ micromark-util-combine-extensions: "npm:^2.0.0"
+ micromark-util-types: "npm:^2.0.0"
+ checksum: 10/66e0df7b2db05b9c88796600e354e0753594f06760abfddcac706afcd5754586c9085adb89e15447ce1450e6a5f2fa66a75f6da394e0eceb919e9c364475593e
+ languageName: node
+ linkType: hard
+
"micromark-factory-destination@npm:^1.0.0":
version: 1.1.0
resolution: "micromark-factory-destination@npm:1.1.0"
@@ -24417,6 +27213,23 @@ __metadata:
languageName: node
linkType: hard
+"micromark-factory-mdx-expression@npm:^2.0.0":
+ version: 2.0.3
+ resolution: "micromark-factory-mdx-expression@npm:2.0.3"
+ dependencies:
+ "@types/estree": "npm:^1.0.0"
+ devlop: "npm:^1.0.0"
+ micromark-factory-space: "npm:^2.0.0"
+ micromark-util-character: "npm:^2.0.0"
+ micromark-util-events-to-acorn: "npm:^2.0.0"
+ micromark-util-symbol: "npm:^2.0.0"
+ micromark-util-types: "npm:^2.0.0"
+ unist-util-position-from-estree: "npm:^2.0.0"
+ vfile-message: "npm:^4.0.0"
+ checksum: 10/afadae88a18f31afa564747101e076011c56457454b30294ae55aeea7efee8626ddc3bad0f0f43649008f89b8784782b5adec143fdf477fb352354d76f08db55
+ languageName: node
+ linkType: hard
+
"micromark-factory-space@npm:^1.0.0":
version: 1.1.0
resolution: "micromark-factory-space@npm:1.1.0"
@@ -24495,7 +27308,7 @@ __metadata:
languageName: node
linkType: hard
-"micromark-util-character@npm:^2.0.0":
+"micromark-util-character@npm:^2.0.0, micromark-util-character@npm:^2.0.1":
version: 2.1.1
resolution: "micromark-util-character@npm:2.1.1"
dependencies:
@@ -24621,6 +27434,21 @@ __metadata:
languageName: node
linkType: hard
+"micromark-util-events-to-acorn@npm:^2.0.0":
+ version: 2.0.3
+ resolution: "micromark-util-events-to-acorn@npm:2.0.3"
+ dependencies:
+ "@types/estree": "npm:^1.0.0"
+ "@types/unist": "npm:^3.0.0"
+ devlop: "npm:^1.0.0"
+ estree-util-visit: "npm:^2.0.0"
+ micromark-util-symbol: "npm:^2.0.0"
+ micromark-util-types: "npm:^2.0.0"
+ vfile-message: "npm:^4.0.0"
+ checksum: 10/0d87e49b897636dc0e84b4bd06b6fa9e6abcd40ab90c9431e36737c85c444d3db1e4f9b8f51433422b1bedc46f086890ce96671b5a795230c6b7b09cb53d9aba
+ languageName: node
+ linkType: hard
+
"micromark-util-html-tag-name@npm:^1.0.0":
version: 1.2.0
resolution: "micromark-util-html-tag-name@npm:1.2.0"
@@ -24834,6 +27662,13 @@ __metadata:
languageName: node
linkType: hard
+"mime-db@npm:^1.52.0":
+ version: 1.54.0
+ resolution: "mime-db@npm:1.54.0"
+ checksum: 10/9e7834be3d66ae7f10eaa69215732c6d389692b194f876198dca79b2b90cbf96688d9d5d05ef7987b20f749b769b11c01766564264ea5f919c88b32a29011311
+ languageName: node
+ linkType: hard
+
"mime-types@npm:^2.1.12, mime-types@npm:^2.1.27, mime-types@npm:^2.1.31, mime-types@npm:~2.1.17, mime-types@npm:~2.1.24, mime-types@npm:~2.1.34":
version: 2.1.35
resolution: "mime-types@npm:2.1.35"
@@ -25465,6 +28300,13 @@ __metadata:
languageName: node
linkType: hard
+"next-tick@npm:^1.1.0":
+ version: 1.1.0
+ resolution: "next-tick@npm:1.1.0"
+ checksum: 10/83b5cf36027a53ee6d8b7f9c0782f2ba87f4858d977342bfc3c20c21629290a2111f8374d13a81221179603ffc4364f38374b5655d17b6a8f8a8c77bdea4fe8b
+ languageName: node
+ linkType: hard
+
"next@npm:14.2.28":
version: 14.2.28
resolution: "next@npm:14.2.28"
@@ -26192,6 +29034,20 @@ __metadata:
languageName: node
linkType: hard
+"outvariant@npm:1.4.0":
+ version: 1.4.0
+ resolution: "outvariant@npm:1.4.0"
+ checksum: 10/07b9bcb9b3a2ff1b3db02af6b07d70e663082b30ddc08ff475d7c85fc623fdcc4433a4ab5b88f6902b62dbb284eef1be386aa537e14cef0519fad887ec483054
+ languageName: node
+ linkType: hard
+
+"outvariant@npm:^1.3.0, outvariant@npm:^1.4.0":
+ version: 1.4.3
+ resolution: "outvariant@npm:1.4.3"
+ checksum: 10/3a7582745850cb344d49641867a4c080858c54f4091afd91b9c0765ba6e471c2bc841348f0fff344845ddd0a4db42fd5d68c6f7ebaf32d4b676a3a9987b2488a
+ languageName: node
+ linkType: hard
+
"overlayscrollbars-react@npm:^0.5.6":
version: 0.5.6
resolution: "overlayscrollbars-react@npm:0.5.6"
@@ -26609,6 +29465,15 @@ __metadata:
languageName: node
linkType: hard
+"parse5@npm:^7.0.0":
+ version: 7.3.0
+ resolution: "parse5@npm:7.3.0"
+ dependencies:
+ entities: "npm:^6.0.0"
+ checksum: 10/b0e48be20b820c655b138b86fa6fb3a790de6c891aa2aba536524f8027b4dca4fe538f11a0e5cf2f6f847d120dbb9e4822dcaeb933ff1e10850a2ef0154d1d88
+ languageName: node
+ linkType: hard
+
"parse5@npm:^7.1.1":
version: 7.1.2
resolution: "parse5@npm:7.1.2"
@@ -28085,6 +30950,13 @@ __metadata:
languageName: node
linkType: hard
+"prismjs@npm:^1.30.0":
+ version: 1.30.0
+ resolution: "prismjs@npm:1.30.0"
+ checksum: 10/6b48a2439a82e5c6882f48ebc1564c3890e16463ba17ac10c3ad4f62d98dea5b5c915b172b63b83023a70ad4f5d7be3e8a60304420db34a161fae69dd4e3e2da
+ languageName: node
+ linkType: hard
+
"process-nextick-args@npm:~2.0.0":
version: 2.0.1
resolution: "process-nextick-args@npm:2.0.1"
@@ -28194,6 +31066,13 @@ __metadata:
languageName: node
linkType: hard
+"property-information@npm:^7.0.0":
+ version: 7.1.0
+ resolution: "property-information@npm:7.1.0"
+ checksum: 10/896d38a52ad7170de73f832d277c69e76a9605d941ebb3f0d6e56271414a7fdf95ff6d2819e68036b8a0c7d2d4d88bf1d4a5765c032cb19c2343567ee3a14b15
+ languageName: node
+ linkType: hard
+
"proto-list@npm:~1.2.1":
version: 1.2.4
resolution: "proto-list@npm:1.2.4"
@@ -28659,6 +31538,15 @@ __metadata:
languageName: node
linkType: hard
+"react-devtools-inline@npm:4.4.0":
+ version: 4.4.0
+ resolution: "react-devtools-inline@npm:4.4.0"
+ dependencies:
+ es6-symbol: "npm:^3"
+ checksum: 10/316a03bd21eb34f511e74e4e969e6a7d75d299800a4158ff59081457f024dc3aebc0c471938fd7e1c4676823fdcb546ca0d7c2d7ab74e34a9c1bdac31f2284b2
+ languageName: node
+ linkType: hard
+
"react-dom@npm:^18.0.0, react-dom@npm:^18.3.1":
version: 18.3.1
resolution: "react-dom@npm:18.3.1"
@@ -28671,6 +31559,17 @@ __metadata:
languageName: node
linkType: hard
+"react-error-boundary@npm:^3.1.4":
+ version: 3.1.4
+ resolution: "react-error-boundary@npm:3.1.4"
+ dependencies:
+ "@babel/runtime": "npm:^7.12.5"
+ peerDependencies:
+ react: ">=16.13.1"
+ checksum: 10/7418637bf352b88f35ff3798e6faa094ee046df9d422fc08f54c017892c3c0738dac661ba3d64d97209464e7a60e7fbbeffdbeaee5edc38f3aaf5f1f4a8bf610
+ languageName: node
+ linkType: hard
+
"react-error-boundary@npm:^4.1.2":
version: 4.1.2
resolution: "react-error-boundary@npm:4.1.2"
@@ -28689,6 +31588,15 @@ __metadata:
languageName: node
linkType: hard
+"react-hook-form@npm:^7.56.1":
+ version: 7.63.0
+ resolution: "react-hook-form@npm:7.63.0"
+ peerDependencies:
+ react: ^16.8.0 || ^17 || ^18 || ^19
+ checksum: 10/df07de6fce42bbcd65ed100aaea7d0e907c555c2635c253517225c84f06eab0ebd278578ada4f479ad582c18a52898c4f1cabca327a12a74b8b7e6e54718edbe
+ languageName: node
+ linkType: hard
+
"react-i18next@npm:^15.4.1":
version: 15.4.1
resolution: "react-i18next@npm:15.4.1"
@@ -28737,7 +31645,7 @@ __metadata:
languageName: node
linkType: hard
-"react-is@npm:^17.0.1":
+"react-is@npm:^17.0.1, react-is@npm:^17.0.2":
version: 17.0.2
resolution: "react-is@npm:17.0.2"
checksum: 10/73b36281e58eeb27c9cc6031301b6ae19ecdc9f18ae2d518bdb39b0ac564e65c5779405d623f1df9abf378a13858b79442480244bd579968afc1faf9a2ce5e05
@@ -28875,6 +31783,41 @@ __metadata:
languageName: node
linkType: hard
+"react-remove-scroll-bar@npm:^2.3.7":
+ version: 2.3.8
+ resolution: "react-remove-scroll-bar@npm:2.3.8"
+ dependencies:
+ react-style-singleton: "npm:^2.2.2"
+ tslib: "npm:^2.0.0"
+ peerDependencies:
+ "@types/react": "*"
+ react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
+ peerDependenciesMeta:
+ "@types/react":
+ optional: true
+ checksum: 10/6c0f8cff98b9f49a4ee2263f1eedf12926dced5ce220fbe83bd93544460e2a7ec8ec39b35d1b2a75d2fced0b2d64afeb8e66f830431ca896e05a20585f9fc350
+ languageName: node
+ linkType: hard
+
+"react-remove-scroll@npm:^2.6.3":
+ version: 2.7.1
+ resolution: "react-remove-scroll@npm:2.7.1"
+ dependencies:
+ react-remove-scroll-bar: "npm:^2.3.7"
+ react-style-singleton: "npm:^2.2.3"
+ tslib: "npm:^2.1.0"
+ use-callback-ref: "npm:^1.3.3"
+ use-sidecar: "npm:^1.1.3"
+ peerDependencies:
+ "@types/react": "*"
+ react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ "@types/react":
+ optional: true
+ checksum: 10/5e571ba35ba527047c54c9c4a271363167770556fb85ee45ead8310673197719425cc8f7a2b7f672abf530294c41c8c34bdae325a571994cc1e694b664b52734
+ languageName: node
+ linkType: hard
+
"react-router-dom@npm:^6.28.0":
version: 6.28.0
resolution: "react-router-dom@npm:6.28.0"
@@ -29006,6 +31949,22 @@ __metadata:
languageName: node
linkType: hard
+"react-style-singleton@npm:^2.2.2, react-style-singleton@npm:^2.2.3":
+ version: 2.2.3
+ resolution: "react-style-singleton@npm:2.2.3"
+ dependencies:
+ get-nonce: "npm:^1.0.0"
+ tslib: "npm:^2.0.0"
+ peerDependencies:
+ "@types/react": "*"
+ react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ "@types/react":
+ optional: true
+ checksum: 10/62498094ff3877a37f351b29e6cad9e38b2eb1ac3c0cb27ebf80aee96554f80b35e17bdb552bcd7ac8b7cb9904fea93ea5668f2057c73d38f90b5d46bb9b27ab
+ languageName: node
+ linkType: hard
+
"react-toastify@npm:^10.0.6":
version: 10.0.6
resolution: "react-toastify@npm:10.0.6"
@@ -29414,6 +32373,27 @@ __metadata:
languageName: node
linkType: hard
+"rehype-raw@npm:^7.0.0":
+ version: 7.0.0
+ resolution: "rehype-raw@npm:7.0.0"
+ dependencies:
+ "@types/hast": "npm:^3.0.0"
+ hast-util-raw: "npm:^9.0.0"
+ vfile: "npm:^6.0.0"
+ checksum: 10/65dd5809f95410ca5056efe50f5b16cb08a69c0785c6d4ec80c9280487efbaec81d342084f6cfdca5624134c1c4018705d97c37b5c0a21d9625ed8a3c88700f1
+ languageName: node
+ linkType: hard
+
+"rehype-sanitize@npm:^6.0.0":
+ version: 6.0.0
+ resolution: "rehype-sanitize@npm:6.0.0"
+ dependencies:
+ "@types/hast": "npm:^3.0.0"
+ hast-util-sanitize: "npm:^5.0.0"
+ checksum: 10/976e928b4f9da6c515e4fde7e4ae873f815c50ab1a268a3c442468eaa981d117492f991926858d69467f7b131358e441ca6d0be0f60a0034b72b3ce6dc69a387
+ languageName: node
+ linkType: hard
+
"relateurl@npm:^0.2.7":
version: 0.2.7
resolution: "relateurl@npm:0.2.7"
@@ -29432,6 +32412,18 @@ __metadata:
languageName: node
linkType: hard
+"remark-gfm@npm:^3.0.1":
+ version: 3.0.1
+ resolution: "remark-gfm@npm:3.0.1"
+ dependencies:
+ "@types/mdast": "npm:^3.0.0"
+ mdast-util-gfm: "npm:^2.0.0"
+ micromark-extension-gfm: "npm:^2.0.0"
+ unified: "npm:^10.0.0"
+ checksum: 10/8ec301f5fb1f52c548b5a6d7ca6a3422d55db73cd703f147c979d16dca003f065181f55404d6f3f49d33f1faca3fe56ae731ed7fe0acc00cd945a8e605f155f2
+ languageName: node
+ linkType: hard
+
"remark-parse@npm:^10.0.0":
version: 10.0.2
resolution: "remark-parse@npm:10.0.2"
@@ -31321,6 +34313,18 @@ __metadata:
languageName: node
linkType: hard
+"static-browser-server@npm:1.0.3":
+ version: 1.0.3
+ resolution: "static-browser-server@npm:1.0.3"
+ dependencies:
+ "@open-draft/deferred-promise": "npm:^2.1.0"
+ dotenv: "npm:^16.0.3"
+ mime-db: "npm:^1.52.0"
+ outvariant: "npm:^1.3.0"
+ checksum: 10/d047c6c8a667a054db23c3d9770cf5e9d558694f052be81886f606ccc1c6dab034eb1fc5b35d1e3bf23a8dc6ca6f9cd7e4349bfb7b5cad1c2af13058c32dea86
+ languageName: node
+ linkType: hard
+
"statuses@npm:2.0.1":
version: 2.0.1
resolution: "statuses@npm:2.0.1"
@@ -31387,6 +34391,13 @@ __metadata:
languageName: node
linkType: hard
+"strict-event-emitter@npm:^0.4.3":
+ version: 0.4.6
+ resolution: "strict-event-emitter@npm:0.4.6"
+ checksum: 10/abdbf59b6c45b599cc2f227fa473765d1510d155ebd22533e8ecb06110dfacb2ff07aece7fd528dde2b4f9e379d60f2687eee8af3fa2877c3ed88ee5b7ed2707
+ languageName: node
+ linkType: hard
+
"strict-uri-encode@npm:^2.0.0":
version: 2.0.0
resolution: "strict-uri-encode@npm:2.0.0"
@@ -32026,6 +35037,13 @@ __metadata:
languageName: node
linkType: hard
+"tabbable@npm:^6.0.0":
+ version: 6.2.0
+ resolution: "tabbable@npm:6.2.0"
+ checksum: 10/980fa73476026e99dcacfc0d6e000d41d42c8e670faf4682496d30c625495e412c4369694f2a15cf1e5252d22de3c396f2b62edbe8d60b5dadc40d09e3f2dde3
+ languageName: node
+ linkType: hard
+
"table-layout@npm:^1.0.2":
version: 1.0.2
resolution: "table-layout@npm:1.0.2"
@@ -32652,7 +35670,7 @@ __metadata:
languageName: node
linkType: hard
-"tslib@npm:^2.0.0, tslib@npm:^2.0.3, tslib@npm:^2.1.0, tslib@npm:^2.3.1, tslib@npm:^2.4.0, tslib@npm:^2.5.0, tslib@npm:^2.6.0, tslib@npm:^2.6.2, tslib@npm:^2.6.3, tslib@npm:^2.8.1":
+"tslib@npm:^2.0.0, tslib@npm:^2.0.3, tslib@npm:^2.1.0, tslib@npm:^2.3.0, tslib@npm:^2.3.1, tslib@npm:^2.4.0, tslib@npm:^2.5.0, tslib@npm:^2.6.0, tslib@npm:^2.6.2, tslib@npm:^2.6.3, tslib@npm:^2.8.1":
version: 2.8.1
resolution: "tslib@npm:2.8.1"
checksum: 10/3e2e043d5c2316461cb54e5c7fe02c30ef6dccb3384717ca22ae5c6b5bc95232a6241df19c622d9c73b809bea33b187f6dbc73030963e29950c2141bc32a79f7
@@ -32791,6 +35809,13 @@ __metadata:
languageName: node
linkType: hard
+"type@npm:^2.7.2":
+ version: 2.7.3
+ resolution: "type@npm:2.7.3"
+ checksum: 10/82e99e7795b3de3ecfe685680685e79a77aea515fad9f60b7c55fbf6d43a5c360b1e6e9443354ec8906b38cdf5325829c69f094cb7cd2a1238e85bef9026dc04
+ languageName: node
+ linkType: hard
+
"typechain@npm:^8.3.2":
version: 8.3.2
resolution: "typechain@npm:8.3.2"
@@ -33135,6 +36160,15 @@ __metadata:
languageName: node
linkType: hard
+"unidiff@npm:^1.0.2":
+ version: 1.0.4
+ resolution: "unidiff@npm:1.0.4"
+ dependencies:
+ diff: "npm:^5.1.0"
+ checksum: 10/c0771d3107c79ef63446f34c9a3574df9889486fba4f9ce50c1beb51d441d1fbc42b84c9889af68a3806f60560633f1c26a81378b5469e00ec223c99fb238f27
+ languageName: node
+ linkType: hard
+
"unified@npm:^10.0.0":
version: 10.1.2
resolution: "unified@npm:10.1.2"
@@ -33217,6 +36251,15 @@ __metadata:
languageName: node
linkType: hard
+"unist-util-position-from-estree@npm:^2.0.0":
+ version: 2.0.0
+ resolution: "unist-util-position-from-estree@npm:2.0.0"
+ dependencies:
+ "@types/unist": "npm:^3.0.0"
+ checksum: 10/d3b3048a5727c2367f64ef6dcc5b20c4717215ef8b1372ff9a7c426297c5d1e5776409938acd01531213e2cd2543218d16e73f9f862f318e9496e2c73bb18354
+ languageName: node
+ linkType: hard
+
"unist-util-position@npm:^4.0.0":
version: 4.0.4
resolution: "unist-util-position@npm:4.0.4"
@@ -33253,7 +36296,7 @@ __metadata:
languageName: node
linkType: hard
-"unist-util-visit-parents@npm:^5.1.1":
+"unist-util-visit-parents@npm:^5.0.0, unist-util-visit-parents@npm:^5.1.1":
version: 5.1.3
resolution: "unist-util-visit-parents@npm:5.1.3"
dependencies:
@@ -33491,6 +36534,37 @@ __metadata:
languageName: node
linkType: hard
+"use-callback-ref@npm:^1.3.3":
+ version: 1.3.3
+ resolution: "use-callback-ref@npm:1.3.3"
+ dependencies:
+ tslib: "npm:^2.0.0"
+ peerDependencies:
+ "@types/react": "*"
+ react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ "@types/react":
+ optional: true
+ checksum: 10/adf06a7b6a27d3651c325ac9b66d2b82ccacaed7450b85b211d123e91d9a23cb5a587fcc6db5b4fd07ac7233e5abf024d30cf02ddc2ec46bca712151c0836151
+ languageName: node
+ linkType: hard
+
+"use-sidecar@npm:^1.1.3":
+ version: 1.1.3
+ resolution: "use-sidecar@npm:1.1.3"
+ dependencies:
+ detect-node-es: "npm:^1.1.0"
+ tslib: "npm:^2.0.0"
+ peerDependencies:
+ "@types/react": "*"
+ react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ "@types/react":
+ optional: true
+ checksum: 10/2fec05eb851cdfc4a4657b1dfb434e686f346c3265ffc9db8a974bb58f8128bd4a708a3cc00e8f51655fccf81822ed4419ebed42f41610589e3aab0cf2492edb
+ languageName: node
+ linkType: hard
+
"use-sync-external-store@npm:1.2.0":
version: 1.2.0
resolution: "use-sync-external-store@npm:1.2.0"
@@ -33609,7 +36683,7 @@ __metadata:
languageName: node
linkType: hard
-"uvu@npm:^0.5.0":
+"uvu@npm:^0.5.0, uvu@npm:^0.5.6":
version: 0.5.6
resolution: "uvu@npm:0.5.6"
dependencies:
@@ -33766,6 +36840,16 @@ __metadata:
languageName: node
linkType: hard
+"vfile-location@npm:^5.0.0":
+ version: 5.0.3
+ resolution: "vfile-location@npm:5.0.3"
+ dependencies:
+ "@types/unist": "npm:^3.0.0"
+ vfile: "npm:^6.0.0"
+ checksum: 10/f481d592fd507fe242da9a00d7400ded3c91587931f24e64c54f24752d7b30321721a1c99c0d949be1f6ed5fa7f8b169054fd07c744705b65dbdd10a9e4ebfe0
+ languageName: node
+ linkType: hard
+
"vfile-message@npm:^3.0.0":
version: 3.1.4
resolution: "vfile-message@npm:3.1.4"
@@ -33829,28 +36913,6 @@ __metadata:
languageName: node
linkType: hard
-"viem@npm:2.x, viem@npm:^2.1.1":
- version: 2.21.50
- resolution: "viem@npm:2.21.50"
- dependencies:
- "@noble/curves": "npm:1.6.0"
- "@noble/hashes": "npm:1.5.0"
- "@scure/bip32": "npm:1.5.0"
- "@scure/bip39": "npm:1.4.0"
- abitype: "npm:1.0.6"
- isows: "npm:1.0.6"
- ox: "npm:0.1.2"
- webauthn-p256: "npm:0.0.10"
- ws: "npm:8.18.0"
- peerDependencies:
- typescript: ">=5.0.4"
- peerDependenciesMeta:
- typescript:
- optional: true
- checksum: 10/6525c7dfa679d48759d50a31751b1d608f055e4396506c4f48550b81655b75b53978bd2dbe39099ac200f549c7429261d3478810dbd63b36df6a0afd77f69931
- languageName: node
- linkType: hard
-
"viem@npm:>=2.23.11, viem@npm:^2.22.21, viem@npm:^2.23.10, viem@npm:^2.24.1":
version: 2.24.1
resolution: "viem@npm:2.24.1"
@@ -33872,6 +36934,28 @@ __metadata:
languageName: node
linkType: hard
+"viem@npm:^2.1.1":
+ version: 2.21.50
+ resolution: "viem@npm:2.21.50"
+ dependencies:
+ "@noble/curves": "npm:1.6.0"
+ "@noble/hashes": "npm:1.5.0"
+ "@scure/bip32": "npm:1.5.0"
+ "@scure/bip39": "npm:1.4.0"
+ abitype: "npm:1.0.6"
+ isows: "npm:1.0.6"
+ ox: "npm:0.1.2"
+ webauthn-p256: "npm:0.0.10"
+ ws: "npm:8.18.0"
+ peerDependencies:
+ typescript: ">=5.0.4"
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ checksum: 10/6525c7dfa679d48759d50a31751b1d608f055e4396506c4f48550b81655b75b53978bd2dbe39099ac200f549c7429261d3478810dbd63b36df6a0afd77f69931
+ languageName: node
+ linkType: hard
+
"viem@npm:^2.21.59":
version: 2.22.17
resolution: "viem@npm:2.22.17"
@@ -34341,6 +37425,13 @@ __metadata:
languageName: node
linkType: hard
+"web-namespaces@npm:^2.0.0":
+ version: 2.0.1
+ resolution: "web-namespaces@npm:2.0.1"
+ checksum: 10/b6d9f02f1a43d0ef0848a812d89c83801d5bbad57d8bb61f02eb6d7eb794c3736f6cc2e1191664bb26136594c8218ac609f4069722c6f56d9fc2d808fa9271c6
+ languageName: node
+ linkType: hard
+
"web3-errors@npm:^1.2.0, web3-errors@npm:^1.3.0":
version: 1.3.0
resolution: "web3-errors@npm:1.3.0"