diff --git a/.github/workflows/contracts-testing.yml b/.github/workflows/contracts-testing.yml index 3b5dd04c0..72d261633 100644 --- a/.github/workflows/contracts-testing.yml +++ b/.github/workflows/contracts-testing.yml @@ -40,14 +40,16 @@ jobs: 54.185.253.63:443 - name: Setup Node.js environment - uses: actions/setup-node@v4 + uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0 with: node-version: 18.x - - uses: actions/checkout@v4 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + submodules: recursive - name: Cache node modules - uses: actions/cache@v4 + uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0 env: cache-name: cache-node-modules with: @@ -57,28 +59,22 @@ jobs: 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 parent dependencies - # run: | - # echo "current dir: $PWD" - # yarn install - + - name: Install contracts dependencies - run: | - yarn workspace @kleros/kleros-v2-contracts install - - - name: Compile - run: | - yarn hardhat compile - working-directory: contracts - - - name: Test with coverage - run: | - yarn hardhat coverage --solcoverjs ./.solcover.js --temp artifacts --testfiles './test/**/*.ts' --show-stack-traces - working-directory: contracts + run: yarn workspace @kleros/kleros-v2-contracts install + + - name: Install Foundry + uses: foundry-rs/foundry-toolchain@8f1998e9878d786675189ef566a2e4bf24869773 # v1.2.0 + - 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@v4 + uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 with: name: code-coverage-report path: contracts/coverage diff --git a/contracts/.solcover.js b/contracts/.solcover.js index 460f8400c..8fcb481f2 100644 --- a/contracts/.solcover.js +++ b/contracts/.solcover.js @@ -5,7 +5,7 @@ const shell = require("shelljs"); // The environment variables are loaded in hardhat.config.ts module.exports = { - istanbulReporter: ["html"], + istanbulReporter: ["lcov"], onCompileComplete: async function (_config) { await run("typechain"); }, @@ -14,7 +14,7 @@ module.exports = { shell.rm("-rf", "./artifacts"); shell.rm("-rf", "./typechain"); }, - skipFiles: ["mocks", "test"], + skipFiles: ["test", "token", "kleros-v1", "proxy/mock", "gateway/mock", "rng/mock"], mocha: { timeout: 20000, grep: "@skip-on-coverage", // Find everything with this tag diff --git a/contracts/README.md b/contracts/README.md index 9ce2ab2cf..2b09dc629 100644 --- a/contracts/README.md +++ b/contracts/README.md @@ -14,9 +14,11 @@ Refresh the list of deployed contracts by running `./scripts/generateDeployments - [ChainlinkRNG](https://arbiscan.io/address/0x897d83a7d5F23555eFA15e1BE297d5503522cbA3) - [DisputeKitClassicNeo: proxy](https://arbiscan.io/address/0x70B464be85A547144C72485eBa2577E5D3A45421), [implementation](https://arbiscan.io/address/0xAF0325dbBFa812a574743Bb5A085266D31e3e03a) - [DisputeResolverNeo](https://arbiscan.io/address/0xb5526D022962A1fFf6eD32C93e8b714c901F4323) +- [DisputeResolverRulerNeo](https://arbiscan.io/address/0xb3a5FdEAF461c42caCe148e978e6FBCa97bE6140) - [DisputeTemplateRegistry: proxy](https://arbiscan.io/address/0x0cFBaCA5C72e7Ca5fFABE768E135654fB3F2a5A2), [implementation](https://arbiscan.io/address/0x57EfD43DAfCeb6C58Df57932b2B299f46fef5c87) - [EvidenceModule: proxy](https://arbiscan.io/address/0x48e052B4A6dC4F30e90930F1CeaAFd83b3981EB3), [implementation](https://arbiscan.io/address/0xE22500Fa27f696d06702367246bd17Bd2C8a4c5d) - [KlerosCoreNeo: proxy](https://arbiscan.io/address/0x991d2df165670b9cac3B022f4B68D65b664222ea), [implementation](https://arbiscan.io/address/0x17c39AB53A7072b167A74a85D47b30385c98ae89) +- [KlerosCoreRulerNeo: proxy](https://arbiscan.io/address/0xc0169e0B19aE02ac4fADD689260CF038726DFE13), [implementation](https://arbiscan.io/address/0x85093b5EDa4F2e2E2fEDae34Da91239D6a08e324) - [KlerosV2NeoEarlyUser](https://arbiscan.io/address/0xfE34a72c55e512601E7d491A9c5b36373cE34d63) - [Pinakion](https://arbiscan.io/address/0x330bD769382cFc6d50175903434CCC8D206DCAE5) - [PolicyRegistry: proxy](https://arbiscan.io/address/0x553dcbF6aB3aE06a1064b5200Df1B5A9fB403d3c), [implementation](https://arbiscan.io/address/0x15E5964C7751dF8563eA4bC000301582C79BC454) diff --git a/contracts/deployments/arbitrum/DisputeResolverRulerNeo.json b/contracts/deployments/arbitrum/DisputeResolverRulerNeo.json new file mode 100644 index 000000000..b5d45949a --- /dev/null +++ b/contracts/deployments/arbitrum/DisputeResolverRulerNeo.json @@ -0,0 +1,522 @@ +{ + "address": "0xb3a5FdEAF461c42caCe148e978e6FBCa97bE6140", + "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" + } + ], + "transactionHash": "0x1112abdc3f57ddc211ca722c574b81b13aa01739793e0cf023c8a7fcf6d373fe", + "receipt": { + "to": null, + "from": "0xf1C7c037891525E360C59f708739Ac09A7670c59", + "contractAddress": "0xb3a5FdEAF461c42caCe148e978e6FBCa97bE6140", + "transactionIndex": 2, + "gasUsed": "915878", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x1094f4f08b0e0a3bec164918a7059f883e0cd6a0a501a3490e65cc12df718df3", + "transactionHash": "0x1112abdc3f57ddc211ca722c574b81b13aa01739793e0cf023c8a7fcf6d373fe", + "logs": [], + "blockNumber": 286701355, + "cumulativeGasUsed": "979461", + "status": 1, + "byzantium": true + }, + "args": [ + "0xc0169e0B19aE02ac4fADD689260CF038726DFE13", + "0x0cFBaCA5C72e7Ca5fFABE768E135654fB3F2a5A2" + ], + "numDeployments": 1, + "solcInputHash": "6c34f81616194abf0f5b1c9c283b9294", + "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\":\"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().\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/arbitration/devtools/DisputeResolverRuler.sol\":\"DisputeResolverRuler\"},\"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/devtools/DisputeResolverRuler.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\n/// @custom:authors: [@unknownunknown1, @jaybuidl]\\n/// @custom:reviewers: []\\n/// @custom:auditors: []\\n/// @custom:bounties: []\\n\\nimport {DisputeResolver, IArbitratorV2, IDisputeTemplateRegistry} from \\\"../arbitrables/DisputeResolver.sol\\\";\\n\\npragma solidity 0.8.24;\\n\\ninterface IKlerosCoreRulerFragment {\\n function getNextDisputeID() external view returns (uint256);\\n}\\n\\n/// @title DisputeResolverRuler\\n/// It extends DisputeResolver for testing purposes of the automatic ruling modes.\\n/// The arbitrator disputeID must be known before dispute creation, otherwise the dispute cannot be retrieved during the immediate call to rule().\\ncontract DisputeResolverRuler is DisputeResolver {\\n // ************************************* //\\n // * Constructor * //\\n // ************************************* //\\n\\n /// @dev Constructor\\n /// @param _arbitrator Target global arbitrator for any disputes.\\n constructor(\\n IArbitratorV2 _arbitrator,\\n IDisputeTemplateRegistry _templateRegistry\\n ) DisputeResolver(_arbitrator, _templateRegistry) {\\n governor = msg.sender;\\n }\\n\\n // ************************************* //\\n // * State Modifiers * //\\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 override returns (uint256 arbitratorDisputeID) {\\n require(_numberOfRulingOptions > 1, \\\"Should be at least 2 ruling options.\\\");\\n\\n uint256 localDisputeID = disputes.length;\\n DisputeStruct storage dispute = disputes.push();\\n dispute.arbitratorExtraData = _arbitratorExtraData;\\n dispute.numberOfRulingOptions = _numberOfRulingOptions;\\n\\n // Keep track of the upcoming dispute ID before dispute creation, so rule() can be called immediately after.\\n arbitratorDisputeID = IKlerosCoreRulerFragment(address(arbitrator)).getNextDisputeID();\\n arbitratorDisputeIDToLocalID[arbitratorDisputeID] = localDisputeID;\\n uint256 templateId = templateRegistry.setDisputeTemplate(\\\"\\\", _disputeTemplate, _disputeTemplateDataMappings);\\n emit DisputeRequest(arbitrator, arbitratorDisputeID, localDisputeID, templateId, _disputeTemplateUri);\\n\\n arbitrator.createDispute{value: msg.value}(_numberOfRulingOptions, _arbitratorExtraData);\\n }\\n}\\n\",\"keccak256\":\"0x310d715738bcb1210bb6094787f6c6cc8032664f9484e2137106474b749ff273\",\"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": "0x608060405234801561001057600080fd5b50604051610eee380380610eee83398101604081905261002f9161008b565b60008054600180546001600160a01b03199081166001600160a01b0396871617909155600280548216949095169390931790935591811633918216171790556100c5565b6001600160a01b038116811461008857600080fd5b50565b6000806040838503121561009e57600080fd5b82516100a981610073565b60208401519092506100ba81610073565b809150509250929050565b610e1a806100d46000396000f3fe60806040526004361061009c5760003560e01c8063908bb29511610064578063908bb29514610170578063a0af81f014610191578063dc653511146101b1578063e09997d9146101c4578063e4c0aaf4146101f1578063fc548f081461021157600080fd5b80630c340a24146100a1578063311a6c56146100de5780634660ebbe14610100578063564a565d146101205780636cc6cde114610150575b600080fd5b3480156100ad57600080fd5b506000546100c1906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156100ea57600080fd5b506100fe6100f93660046108c9565b610231565b005b34801561010c57600080fd5b506100fe61011b366004610903565b6103d1565b34801561012c57600080fd5b5061014061013b366004610927565b61041d565b6040516100d59493929190610986565b34801561015c57600080fd5b506001546100c1906001600160a01b031681565b61018361017e3660046109fe565b6104eb565b6040519081526020016100d5565b34801561019d57600080fd5b506002546100c1906001600160a01b031681565b6101836101bf366004610a88565b61055a565b3480156101d057600080fd5b506101836101df366004610927565b60046020526000908152604090205481565b3480156101fd57600080fd5b506100fe61020c366004610903565b6105b9565b34801561021d57600080fd5b506100fe61022c366004610903565b610605565b600082815260046020526040812054600380549192918390811061025757610257610b96565b6000918252602090912060015460049092020191506001600160a01b031633146102d65760405162461bcd60e51b815260206004820152602560248201527f4f6e6c79207468652061726269747261746f722063616e2065786563757465206044820152643a3434b99760d91b60648201526084015b60405180910390fd5b806003015483111561031c5760405162461bcd60e51b815260206004820152600f60248201526e24b73b30b634b210393ab634b7339760891b60448201526064016102cd565b600181015460ff161561037d5760405162461bcd60e51b8152602060048201526024808201527f54686973206469737075746520686173206265656e2072756c656420616c726560448201526330b23c9760e11b60648201526084016102cd565b6001818101805460ff1916909117905560028101839055604051838152849033907f394027a5fa6e098a1191094d1719d6929b9abc535fcc0c8f448d6a4e756222769060200160405180910390a350505050565b6000546001600160a01b031633146103fb5760405162461bcd60e51b81526004016102cd90610bac565b600280546001600160a01b0319166001600160a01b0392909216919091179055565b6003818154811061042d57600080fd5b906000526020600020906004020160009150905080600001805461045090610bee565b80601f016020809104026020016040519081016040528092919081815260200182805461047c90610bee565b80156104c95780601f1061049e576101008083540402835291602001916104c9565b820191906000526020600020905b8154815290600101906020018083116104ac57829003601f168201915b5050505060018301546002840154600390940154929360ff9091169290915084565b60006105508686604051806020016040528060008152506040518060200160405280600081525088888080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508a9250610651915050565b9695505050505050565b60006105ae878787878080601f016020809104026020016040519081016040528093929190818152602001838380828437600092018290525060408051602081019091529081528a93509150889050610651565b979650505050505050565b6000546001600160a01b031633146105e35760405162461bcd60e51b81526004016102cd90610bac565b600080546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b0316331461062f5760405162461bcd60e51b81526004016102cd90610bac565b600180546001600160a01b0319166001600160a01b0392909216919091179055565b6000600182116106af5760405162461bcd60e51b8152602060048201526024808201527f53686f756c64206265206174206c6561737420322072756c696e67206f70746960448201526337b7399760e11b60648201526084016102cd565b60038054600181018255600091909152600481027fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b01806106f1898b83610c79565b50600381018490556001546040805163db8a173b60e01b815290516001600160a01b039092169163db8a173b916004808201926020929091908290030181865afa158015610743573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107679190610d3a565b600081815260046020819052604080832086905560025490516312a6505d60e21b815293965091926001600160a01b0390921691634a994174916107af918c918c9101610d53565b6020604051808303816000875af11580156107ce573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107f29190610d3a565b60015460405191925085916001600160a01b03909116907f8bd32f430ff060e6bd204709b3790c9807987263d3230c580dc80b5f89e271869061083a90879086908c90610d8f565b60405180910390a360015460405163c13517e160e01b81526001600160a01b039091169063c13517e19034906108789089908f908f90600401610dae565b60206040518083038185885af1158015610896573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906108bb9190610d3a565b505050509695505050505050565b600080604083850312156108dc57600080fd5b50508035926020909101359150565b6001600160a01b038116811461090057600080fd5b50565b60006020828403121561091557600080fd5b8135610920816108eb565b9392505050565b60006020828403121561093957600080fd5b5035919050565b6000815180845260005b818110156109665760208185018101518683018201520161094a565b506000602082860101526020601f19601f83011685010191505092915050565b6080815260006109996080830187610940565b9415156020830152506040810192909252606090910152919050565b60008083601f8401126109c757600080fd5b50813567ffffffffffffffff8111156109df57600080fd5b6020830191508360208285010111156109f757600080fd5b9250929050565b600080600080600060608688031215610a1657600080fd5b853567ffffffffffffffff80821115610a2e57600080fd5b610a3a89838a016109b5565b90975095506020880135915080821115610a5357600080fd5b50610a60888289016109b5565b96999598509660400135949350505050565b634e487b7160e01b600052604160045260246000fd5b60008060008060008060808789031215610aa157600080fd5b863567ffffffffffffffff80821115610ab957600080fd5b610ac58a838b016109b5565b90985096506020890135915080821115610ade57600080fd5b610aea8a838b016109b5565b90965094506040890135915080821115610b0357600080fd5b818901915089601f830112610b1757600080fd5b813581811115610b2957610b29610a72565b604051601f8201601f19908116603f01168101908382118183101715610b5157610b51610a72565b816040528281528c6020848701011115610b6a57600080fd5b826020860160208301376000602084830101528096505050505050606087013590509295509295509295565b634e487b7160e01b600052603260045260246000fd5b60208082526022908201527f416363657373206e6f7420616c6c6f7765643a20476f7665726e6f72206f6e6c6040820152613c9760f11b606082015260800190565b600181811c90821680610c0257607f821691505b602082108103610c2257634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115610c74576000816000526020600020601f850160051c81016020861015610c515750805b601f850160051c820191505b81811015610c7057828155600101610c5d565b5050505b505050565b67ffffffffffffffff831115610c9157610c91610a72565b610ca583610c9f8354610bee565b83610c28565b6000601f841160018114610cd95760008515610cc15750838201355b600019600387901b1c1916600186901b178355610d33565b600083815260209020601f19861690835b82811015610d0a5786850135825560209485019460019092019101610cea565b5086821015610d275760001960f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b600060208284031215610d4c57600080fd5b5051919050565b6060815260006060820152608060208201526000610d746080830185610940565b8281036040840152610d868185610940565b95945050505050565b838152826020820152606060408201526000610d866060830184610940565b83815260406020820152816040820152818360608301376000818301606090810191909152601f909201601f191601019291505056fea26469706673582212205a8e65d1dfc327ea0f1f71dae2dae97c38359baa8ee8493fab431b5809c2307a64736f6c63430008180033", + "deployedBytecode": "0x60806040526004361061009c5760003560e01c8063908bb29511610064578063908bb29514610170578063a0af81f014610191578063dc653511146101b1578063e09997d9146101c4578063e4c0aaf4146101f1578063fc548f081461021157600080fd5b80630c340a24146100a1578063311a6c56146100de5780634660ebbe14610100578063564a565d146101205780636cc6cde114610150575b600080fd5b3480156100ad57600080fd5b506000546100c1906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156100ea57600080fd5b506100fe6100f93660046108c9565b610231565b005b34801561010c57600080fd5b506100fe61011b366004610903565b6103d1565b34801561012c57600080fd5b5061014061013b366004610927565b61041d565b6040516100d59493929190610986565b34801561015c57600080fd5b506001546100c1906001600160a01b031681565b61018361017e3660046109fe565b6104eb565b6040519081526020016100d5565b34801561019d57600080fd5b506002546100c1906001600160a01b031681565b6101836101bf366004610a88565b61055a565b3480156101d057600080fd5b506101836101df366004610927565b60046020526000908152604090205481565b3480156101fd57600080fd5b506100fe61020c366004610903565b6105b9565b34801561021d57600080fd5b506100fe61022c366004610903565b610605565b600082815260046020526040812054600380549192918390811061025757610257610b96565b6000918252602090912060015460049092020191506001600160a01b031633146102d65760405162461bcd60e51b815260206004820152602560248201527f4f6e6c79207468652061726269747261746f722063616e2065786563757465206044820152643a3434b99760d91b60648201526084015b60405180910390fd5b806003015483111561031c5760405162461bcd60e51b815260206004820152600f60248201526e24b73b30b634b210393ab634b7339760891b60448201526064016102cd565b600181015460ff161561037d5760405162461bcd60e51b8152602060048201526024808201527f54686973206469737075746520686173206265656e2072756c656420616c726560448201526330b23c9760e11b60648201526084016102cd565b6001818101805460ff1916909117905560028101839055604051838152849033907f394027a5fa6e098a1191094d1719d6929b9abc535fcc0c8f448d6a4e756222769060200160405180910390a350505050565b6000546001600160a01b031633146103fb5760405162461bcd60e51b81526004016102cd90610bac565b600280546001600160a01b0319166001600160a01b0392909216919091179055565b6003818154811061042d57600080fd5b906000526020600020906004020160009150905080600001805461045090610bee565b80601f016020809104026020016040519081016040528092919081815260200182805461047c90610bee565b80156104c95780601f1061049e576101008083540402835291602001916104c9565b820191906000526020600020905b8154815290600101906020018083116104ac57829003601f168201915b5050505060018301546002840154600390940154929360ff9091169290915084565b60006105508686604051806020016040528060008152506040518060200160405280600081525088888080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508a9250610651915050565b9695505050505050565b60006105ae878787878080601f016020809104026020016040519081016040528093929190818152602001838380828437600092018290525060408051602081019091529081528a93509150889050610651565b979650505050505050565b6000546001600160a01b031633146105e35760405162461bcd60e51b81526004016102cd90610bac565b600080546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b0316331461062f5760405162461bcd60e51b81526004016102cd90610bac565b600180546001600160a01b0319166001600160a01b0392909216919091179055565b6000600182116106af5760405162461bcd60e51b8152602060048201526024808201527f53686f756c64206265206174206c6561737420322072756c696e67206f70746960448201526337b7399760e11b60648201526084016102cd565b60038054600181018255600091909152600481027fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b01806106f1898b83610c79565b50600381018490556001546040805163db8a173b60e01b815290516001600160a01b039092169163db8a173b916004808201926020929091908290030181865afa158015610743573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107679190610d3a565b600081815260046020819052604080832086905560025490516312a6505d60e21b815293965091926001600160a01b0390921691634a994174916107af918c918c9101610d53565b6020604051808303816000875af11580156107ce573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107f29190610d3a565b60015460405191925085916001600160a01b03909116907f8bd32f430ff060e6bd204709b3790c9807987263d3230c580dc80b5f89e271869061083a90879086908c90610d8f565b60405180910390a360015460405163c13517e160e01b81526001600160a01b039091169063c13517e19034906108789089908f908f90600401610dae565b60206040518083038185885af1158015610896573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906108bb9190610d3a565b505050509695505050505050565b600080604083850312156108dc57600080fd5b50508035926020909101359150565b6001600160a01b038116811461090057600080fd5b50565b60006020828403121561091557600080fd5b8135610920816108eb565b9392505050565b60006020828403121561093957600080fd5b5035919050565b6000815180845260005b818110156109665760208185018101518683018201520161094a565b506000602082860101526020601f19601f83011685010191505092915050565b6080815260006109996080830187610940565b9415156020830152506040810192909252606090910152919050565b60008083601f8401126109c757600080fd5b50813567ffffffffffffffff8111156109df57600080fd5b6020830191508360208285010111156109f757600080fd5b9250929050565b600080600080600060608688031215610a1657600080fd5b853567ffffffffffffffff80821115610a2e57600080fd5b610a3a89838a016109b5565b90975095506020880135915080821115610a5357600080fd5b50610a60888289016109b5565b96999598509660400135949350505050565b634e487b7160e01b600052604160045260246000fd5b60008060008060008060808789031215610aa157600080fd5b863567ffffffffffffffff80821115610ab957600080fd5b610ac58a838b016109b5565b90985096506020890135915080821115610ade57600080fd5b610aea8a838b016109b5565b90965094506040890135915080821115610b0357600080fd5b818901915089601f830112610b1757600080fd5b813581811115610b2957610b29610a72565b604051601f8201601f19908116603f01168101908382118183101715610b5157610b51610a72565b816040528281528c6020848701011115610b6a57600080fd5b826020860160208301376000602084830101528096505050505050606087013590509295509295509295565b634e487b7160e01b600052603260045260246000fd5b60208082526022908201527f416363657373206e6f7420616c6c6f7765643a20476f7665726e6f72206f6e6c6040820152613c9760f11b606082015260800190565b600181811c90821680610c0257607f821691505b602082108103610c2257634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115610c74576000816000526020600020601f850160051c81016020861015610c515750805b601f850160051c820191505b81811015610c7057828155600101610c5d565b5050505b505050565b67ffffffffffffffff831115610c9157610c91610a72565b610ca583610c9f8354610bee565b83610c28565b6000601f841160018114610cd95760008515610cc15750838201355b600019600387901b1c1916600186901b178355610d33565b600083815260209020601f19861690835b82811015610d0a5786850135825560209485019460019092019101610cea565b5086821015610d275760001960f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b600060208284031215610d4c57600080fd5b5051919050565b6060815260006060820152608060208201526000610d746080830185610940565b8281036040840152610d868185610940565b95945050505050565b838152826020820152606060408201526000610d866060830184610940565b83815260406020820152816040820152818360608301376000818301606090810191909152601f909201601f191601019291505056fea26469706673582212205a8e65d1dfc327ea0f1f71dae2dae97c38359baa8ee8493fab431b5809c2307a64736f6c63430008180033", + "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’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.", + "_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’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.", + "params": { + "_arbitratorDisputeID": "ID of the dispute in arbitrator contract.", + "_ruling": "The ruling choice of the arbitration." + } + } + }, + "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().", + "version": 1 + }, + "userdoc": { + "kind": "user", + "methods": {}, + "version": 1 + }, + "storageLayout": { + "storage": [ + { + "astId": 15541, + "contract": "src/arbitration/devtools/DisputeResolverRuler.sol:DisputeResolverRuler", + "label": "governor", + "offset": 0, + "slot": "0", + "type": "t_address" + }, + { + "astId": 15544, + "contract": "src/arbitration/devtools/DisputeResolverRuler.sol:DisputeResolverRuler", + "label": "arbitrator", + "offset": 0, + "slot": "1", + "type": "t_contract(IArbitratorV2)21857" + }, + { + "astId": 15547, + "contract": "src/arbitration/devtools/DisputeResolverRuler.sol:DisputeResolverRuler", + "label": "templateRegistry", + "offset": 0, + "slot": "2", + "type": "t_contract(IDisputeTemplateRegistry)22028" + }, + { + "astId": 15551, + "contract": "src/arbitration/devtools/DisputeResolverRuler.sol:DisputeResolverRuler", + "label": "disputes", + "offset": 0, + "slot": "3", + "type": "t_array(t_struct(DisputeStruct)15539_storage)dyn_storage" + }, + { + "astId": 15555, + "contract": "src/arbitration/devtools/DisputeResolverRuler.sol:DisputeResolverRuler", + "label": "arbitratorDisputeIDToLocalID", + "offset": 0, + "slot": "4", + "type": "t_mapping(t_uint256,t_uint256)" + } + ], + "types": { + "t_address": { + "encoding": "inplace", + "label": "address", + "numberOfBytes": "20" + }, + "t_array(t_struct(DisputeStruct)15539_storage)dyn_storage": { + "base": "t_struct(DisputeStruct)15539_storage", + "encoding": "dynamic_array", + "label": "struct DisputeResolver.DisputeStruct[]", + "numberOfBytes": "32" + }, + "t_bool": { + "encoding": "inplace", + "label": "bool", + "numberOfBytes": "1" + }, + "t_bytes_storage": { + "encoding": "bytes", + "label": "bytes", + "numberOfBytes": "32" + }, + "t_contract(IArbitratorV2)21857": { + "encoding": "inplace", + "label": "contract IArbitratorV2", + "numberOfBytes": "20" + }, + "t_contract(IDisputeTemplateRegistry)22028": { + "encoding": "inplace", + "label": "contract IDisputeTemplateRegistry", + "numberOfBytes": "20" + }, + "t_mapping(t_uint256,t_uint256)": { + "encoding": "mapping", + "key": "t_uint256", + "label": "mapping(uint256 => uint256)", + "numberOfBytes": "32", + "value": "t_uint256" + }, + "t_struct(DisputeStruct)15539_storage": { + "encoding": "inplace", + "label": "struct DisputeResolver.DisputeStruct", + "members": [ + { + "astId": 15532, + "contract": "src/arbitration/devtools/DisputeResolverRuler.sol:DisputeResolverRuler", + "label": "arbitratorExtraData", + "offset": 0, + "slot": "0", + "type": "t_bytes_storage" + }, + { + "astId": 15534, + "contract": "src/arbitration/devtools/DisputeResolverRuler.sol:DisputeResolverRuler", + "label": "isRuled", + "offset": 0, + "slot": "1", + "type": "t_bool" + }, + { + "astId": 15536, + "contract": "src/arbitration/devtools/DisputeResolverRuler.sol:DisputeResolverRuler", + "label": "ruling", + "offset": 0, + "slot": "2", + "type": "t_uint256" + }, + { + "astId": 15538, + "contract": "src/arbitration/devtools/DisputeResolverRuler.sol:DisputeResolverRuler", + "label": "numberOfRulingOptions", + "offset": 0, + "slot": "3", + "type": "t_uint256" + } + ], + "numberOfBytes": "128" + }, + "t_uint256": { + "encoding": "inplace", + "label": "uint256", + "numberOfBytes": "32" + } + } + } +} diff --git a/contracts/deployments/arbitrum/KlerosCoreRulerNeo.json b/contracts/deployments/arbitrum/KlerosCoreRulerNeo.json new file mode 100644 index 000000000..9fd6d468f --- /dev/null +++ b/contracts/deployments/arbitrum/KlerosCoreRulerNeo.json @@ -0,0 +1,1602 @@ +{ + "address": "0xc0169e0B19aE02ac4fADD689260CF038726DFE13", + "abi": [ + { + "stateMutability": "payable", + "type": "fallback" + }, + { + "stateMutability": "payable", + "type": "receive" + }, + { + "inputs": [], + "name": "AlreadyInitialized", + "type": "error" + }, + { + "inputs": [], + "name": "AppealFeesNotEnough", + "type": "error" + }, + { + "inputs": [], + "name": "ArbitrationFeesNotEnough", + "type": "error" + }, + { + "inputs": [], + "name": "DisputeNotAppealable", + "type": "error" + }, + { + "inputs": [], + "name": "FailedDelegateCall", + "type": "error" + }, + { + "inputs": [], + "name": "GovernorOnly", + "type": "error" + }, + { + "inputs": [], + "name": "GovernorOrInstructorOnly", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidForkingCourtAsParent", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "implementation", + "type": "address" + } + ], + "name": "InvalidImplementation", + "type": "error" + }, + { + "inputs": [], + "name": "NoRulerSet", + "type": "error" + }, + { + "inputs": [], + "name": "NotInitializing", + "type": "error" + }, + { + "inputs": [], + "name": "RulerOnly", + "type": "error" + }, + { + "inputs": [], + "name": "RulingAlreadyExecuted", + "type": "error" + }, + { + "inputs": [], + "name": "RulingModeNotSet", + "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": "UnsuccessfulCall", + "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": "contract IArbitrableV2", + "name": "_arbitrable", + "type": "address" + }, + { + "indexed": true, + "internalType": "enum KlerosCoreRuler.RulingMode", + "name": "mode", + "type": "uint8" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "_disputeID", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_ruling", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bool", + "name": "tied", + "type": "bool" + }, + { + "indexed": false, + "internalType": "bool", + "name": "overridden", + "type": "bool" + } + ], + "name": "AutoRuled", + "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]" + } + ], + "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": 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 KlerosCoreRuler.Period", + "name": "_period", + "type": "uint8" + } + ], + "name": "NewPeriod", + "type": "event" + }, + { + "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", + "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": "uint256", + "name": "_disputeID", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_numberOfChoices", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "", + "type": "bytes" + }, + { + "internalType": "bool", + "name": "_jump", + "type": "bool" + } + ], + "name": "appeal", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_disputeID", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "_jump", + "type": "bool" + } + ], + "name": "appealCost", + "outputs": [ + { + "internalType": "uint256", + "name": "cost", + "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": "contract IERC20", + "name": "_pinakion", + "type": "address" + } + ], + "name": "changePinakion", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IArbitrableV2", + "name": "_arbitrable", + "type": "address" + }, + { + "internalType": "address", + "name": "_newRuler", + "type": "address" + } + ], + "name": "changeRuler", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "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": "changeRulingModeToAutomaticPreset", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IArbitrableV2", + "name": "_arbitrable", + "type": "address" + } + ], + "name": "changeRulingModeToAutomaticRandom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IArbitrableV2", + "name": "_arbitrable", + "type": "address" + } + ], + "name": "changeRulingModeToManual", + "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]" + } + ], + "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": "disputes", + "outputs": [ + { + "internalType": "uint96", + "name": "courtID", + "type": "uint96" + }, + { + "internalType": "contract IArbitrableV2", + "name": "arbitrated", + "type": "address" + }, + { + "internalType": "enum KlerosCoreRuler.Period", + "name": "period", + "type": "uint8" + }, + { + "internalType": "bool", + "name": "ruled", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_disputeID", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_round", + "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" + }, + { + "internalType": "uint256", + "name": "_ruling", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "tied", + "type": "bool" + }, + { + "internalType": "bool", + "name": "overridden", + "type": "bool" + } + ], + "name": "executeRuling", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "getNextDisputeID", + "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": "totalFeesForJurors", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "sumFeeRewardPaid", + "type": "uint256" + }, + { + "internalType": "contract IERC20", + "name": "feeToken", + "type": "address" + } + ], + "internalType": "struct KlerosCoreRuler.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": "contract IERC20", + "name": "_pinakion", + "type": "address" + }, + { + "internalType": "uint256[4]", + "name": "_courtParameters", + "type": "uint256[4]" + } + ], + "name": "initialize", + "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": "contract IArbitrableV2", + "name": "arbitrable", + "type": "address" + } + ], + "name": "rulers", + "outputs": [ + { + "internalType": "address", + "name": "ruler", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "disputeID", + "type": "uint256" + } + ], + "name": "rulingResults", + "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": "contract IArbitrableV2", + "name": "arbitrable", + "type": "address" + } + ], + "name": "settings", + "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" + } + ], + "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": "address", + "name": "_implementation", + "type": "address" + }, + { + "internalType": "bytes", + "name": "_data", + "type": "bytes" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + } + ], + "transactionHash": "0x467a826ff2b4ec23bed9936441307123e1609acf8ce0cf70f4fffe7c2d25671f", + "receipt": { + "to": null, + "from": "0xf1C7c037891525E360C59f708739Ac09A7670c59", + "contractAddress": "0xc0169e0B19aE02ac4fADD689260CF038726DFE13", + "transactionIndex": 2, + "gasUsed": "314451", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000100004000000000000000000000000000060008000000000000000000000000220000000000000000000800000080000000000000000000000000000000000000000000000800000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000060000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x905e9059a1f41a82e3c5c67e027ff256285596bc1cef98acdbd330f043a8a44d", + "transactionHash": "0x467a826ff2b4ec23bed9936441307123e1609acf8ce0cf70f4fffe7c2d25671f", + "logs": [ + { + "transactionIndex": 2, + "blockNumber": 286701284, + "transactionHash": "0x467a826ff2b4ec23bed9936441307123e1609acf8ce0cf70f4fffe7c2d25671f", + "address": "0xc0169e0B19aE02ac4fADD689260CF038726DFE13", + "topics": [ + "0x0c907a651f88974ed0d9423aacc8b998c40eedf39920e2c3bdae0adcc486a761", + "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000000000000000000000000000000" + ], + "data": "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002710000000000000000000000000000000000000000000000000016345785d8a000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "logIndex": 0, + "blockHash": "0x905e9059a1f41a82e3c5c67e027ff256285596bc1cef98acdbd330f043a8a44d" + }, + { + "transactionIndex": 2, + "blockNumber": 286701284, + "transactionHash": "0x467a826ff2b4ec23bed9936441307123e1609acf8ce0cf70f4fffe7c2d25671f", + "address": "0xc0169e0B19aE02ac4fADD689260CF038726DFE13", + "topics": [ + "0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000000001", + "logIndex": 1, + "blockHash": "0x905e9059a1f41a82e3c5c67e027ff256285596bc1cef98acdbd330f043a8a44d" + } + ], + "blockNumber": 286701284, + "cumulativeGasUsed": "348983", + "status": 1, + "byzantium": true + }, + "args": [ + "0x85093b5EDa4F2e2E2fEDae34Da91239D6a08e324", + "0x05d3177d000000000000000000000000f1c7c037891525e360c59f708739ac09a7670c59000000000000000000000000330bd769382cfc6d50175903434ccc8d206dcae500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002710000000000000000000000000000000000000000000000000016345785d8a00000000000000000000000000000000000000000000000000000000000000000010" + ], + "numDeployments": 1, + "solcInputHash": "072c3d36aa3704de09a27a044cf00231", + "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\":\"KlerosCoreRulerProxy\"},\"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": "0x608060405234801561001057600080fd5b5060405161030238038061030283398101604081905261002f91610151565b8181817f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc55805160001461010e576000826001600160a01b031682604051610077919061021f565b600060405180830381855af49150503d80600081146100b2576040519150601f19603f3d011682016040523d82523d6000602084013e6100b7565b606091505b505090508061010c5760405162461bcd60e51b815260206004820152601860248201527f50726f787920436f6e7374727563746f72206661696c65640000000000000000604482015260640160405180910390fd5b505b5050505061023b565b634e487b7160e01b600052604160045260246000fd5b60005b83811015610148578181015183820152602001610130565b50506000910152565b6000806040838503121561016457600080fd5b82516001600160a01b038116811461017b57600080fd5b60208401519092506001600160401b038082111561019857600080fd5b818501915085601f8301126101ac57600080fd5b8151818111156101be576101be610117565b604051601f8201601f19908116603f011681019083821181831017156101e6576101e6610117565b816040528281528860208487010111156101ff57600080fd5b61021083602083016020880161012d565b80955050505050509250929050565b6000825161023181846020870161012d565b9190910192915050565b60b9806102496000396000f3fe608060405236603757603560317f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5490565b6060565b005b603560317f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5490565b3660008037600080366000845af43d6000803e808015607e573d6000f35b3d6000fdfea26469706673582212205e24db8a42d0caaa77ce845dfb341502dc3b700c5ccf0c51c4cf914535a4a64564736f6c63430008180033", + "deployedBytecode": "0x608060405236603757603560317f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5490565b6060565b005b603560317f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5490565b3660008037600080366000845af43d6000803e808015607e573d6000f35b3d6000fdfea26469706673582212205e24db8a42d0caaa77ce845dfb341502dc3b700c5ccf0c51c4cf914535a4a64564736f6c63430008180033", + "execute": { + "methodName": "initialize", + "args": [ + "0xf1C7c037891525E360C59f708739Ac09A7670c59", + "0x330bD769382cFc6d50175903434CCC8D206DCAE5", + [ + 0, + 10000, + "100000000000000000", + 16 + ] + ] + }, + "implementation": "0x85093b5EDa4F2e2E2fEDae34Da91239D6a08e324", + "devdoc": { + "kind": "dev", + "methods": {}, + "version": 1 + }, + "userdoc": { + "kind": "user", + "methods": {}, + "version": 1 + }, + "storageLayout": { + "storage": [], + "types": null + } +} diff --git a/contracts/deployments/arbitrum/KlerosCoreRulerNeo_Implementation.json b/contracts/deployments/arbitrum/KlerosCoreRulerNeo_Implementation.json new file mode 100644 index 000000000..5461d6c22 --- /dev/null +++ b/contracts/deployments/arbitrum/KlerosCoreRulerNeo_Implementation.json @@ -0,0 +1,2221 @@ +{ + "address": "0x85093b5EDa4F2e2E2fEDae34Da91239D6a08e324", + "abi": [ + { + "inputs": [], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "AlreadyInitialized", + "type": "error" + }, + { + "inputs": [], + "name": "AppealFeesNotEnough", + "type": "error" + }, + { + "inputs": [], + "name": "ArbitrationFeesNotEnough", + "type": "error" + }, + { + "inputs": [], + "name": "DisputeNotAppealable", + "type": "error" + }, + { + "inputs": [], + "name": "FailedDelegateCall", + "type": "error" + }, + { + "inputs": [], + "name": "GovernorOnly", + "type": "error" + }, + { + "inputs": [], + "name": "GovernorOrInstructorOnly", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidForkingCourtAsParent", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "implementation", + "type": "address" + } + ], + "name": "InvalidImplementation", + "type": "error" + }, + { + "inputs": [], + "name": "NoRulerSet", + "type": "error" + }, + { + "inputs": [], + "name": "NotInitializing", + "type": "error" + }, + { + "inputs": [], + "name": "RulerOnly", + "type": "error" + }, + { + "inputs": [], + "name": "RulingAlreadyExecuted", + "type": "error" + }, + { + "inputs": [], + "name": "RulingModeNotSet", + "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": "UnsuccessfulCall", + "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": "contract IArbitrableV2", + "name": "_arbitrable", + "type": "address" + }, + { + "indexed": true, + "internalType": "enum KlerosCoreRuler.RulingMode", + "name": "mode", + "type": "uint8" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "_disputeID", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_ruling", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bool", + "name": "tied", + "type": "bool" + }, + { + "indexed": false, + "internalType": "bool", + "name": "overridden", + "type": "bool" + } + ], + "name": "AutoRuled", + "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]" + } + ], + "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": 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 KlerosCoreRuler.Period", + "name": "_period", + "type": "uint8" + } + ], + "name": "NewPeriod", + "type": "event" + }, + { + "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", + "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": "uint256", + "name": "_disputeID", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_numberOfChoices", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "", + "type": "bytes" + }, + { + "internalType": "bool", + "name": "_jump", + "type": "bool" + } + ], + "name": "appeal", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_disputeID", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "_jump", + "type": "bool" + } + ], + "name": "appealCost", + "outputs": [ + { + "internalType": "uint256", + "name": "cost", + "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": "contract IERC20", + "name": "_pinakion", + "type": "address" + } + ], + "name": "changePinakion", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IArbitrableV2", + "name": "_arbitrable", + "type": "address" + }, + { + "internalType": "address", + "name": "_newRuler", + "type": "address" + } + ], + "name": "changeRuler", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "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": "changeRulingModeToAutomaticPreset", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IArbitrableV2", + "name": "_arbitrable", + "type": "address" + } + ], + "name": "changeRulingModeToAutomaticRandom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IArbitrableV2", + "name": "_arbitrable", + "type": "address" + } + ], + "name": "changeRulingModeToManual", + "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]" + } + ], + "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": "disputes", + "outputs": [ + { + "internalType": "uint96", + "name": "courtID", + "type": "uint96" + }, + { + "internalType": "contract IArbitrableV2", + "name": "arbitrated", + "type": "address" + }, + { + "internalType": "enum KlerosCoreRuler.Period", + "name": "period", + "type": "uint8" + }, + { + "internalType": "bool", + "name": "ruled", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_disputeID", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_round", + "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" + }, + { + "internalType": "uint256", + "name": "_ruling", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "tied", + "type": "bool" + }, + { + "internalType": "bool", + "name": "overridden", + "type": "bool" + } + ], + "name": "executeRuling", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "getNextDisputeID", + "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": "totalFeesForJurors", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "sumFeeRewardPaid", + "type": "uint256" + }, + { + "internalType": "contract IERC20", + "name": "feeToken", + "type": "address" + } + ], + "internalType": "struct KlerosCoreRuler.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": "contract IERC20", + "name": "_pinakion", + "type": "address" + }, + { + "internalType": "uint256[4]", + "name": "_courtParameters", + "type": "uint256[4]" + } + ], + "name": "initialize", + "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": "contract IArbitrableV2", + "name": "arbitrable", + "type": "address" + } + ], + "name": "rulers", + "outputs": [ + { + "internalType": "address", + "name": "ruler", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "disputeID", + "type": "uint256" + } + ], + "name": "rulingResults", + "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": "contract IArbitrableV2", + "name": "arbitrable", + "type": "address" + } + ], + "name": "settings", + "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" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newImplementation", + "type": "address" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "upgradeToAndCall", + "outputs": [], + "stateMutability": "payable", + "type": "function" + } + ], + "transactionHash": "0xf4d87406caaf352d4a0c65a9f9963300a2e4fd4f762ca428155ac8c93e11ce48", + "receipt": { + "to": null, + "from": "0xf1C7c037891525E360C59f708739Ac09A7670c59", + "contractAddress": "0x85093b5EDa4F2e2E2fEDae34Da91239D6a08e324", + "transactionIndex": 5, + "gasUsed": "2957987", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000004400000000000000000000000000000000000000000000000000000000000800000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x86b9c352bef894ed240b7fca2b89945fd86b54ea9672c8843a8061568921982b", + "transactionHash": "0xf4d87406caaf352d4a0c65a9f9963300a2e4fd4f762ca428155ac8c93e11ce48", + "logs": [ + { + "transactionIndex": 5, + "blockNumber": 286701267, + "transactionHash": "0xf4d87406caaf352d4a0c65a9f9963300a2e4fd4f762ca428155ac8c93e11ce48", + "address": "0x85093b5EDa4F2e2E2fEDae34Da91239D6a08e324", + "topics": [ + "0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2" + ], + "data": "0x000000000000000000000000000000000000000000000000ffffffffffffffff", + "logIndex": 50, + "blockHash": "0x86b9c352bef894ed240b7fca2b89945fd86b54ea9672c8843a8061568921982b" + } + ], + "blockNumber": 286701267, + "cumulativeGasUsed": "4476604", + "status": 1, + "byzantium": true + }, + "args": [], + "numDeployments": 1, + "solcInputHash": "6c34f81616194abf0f5b1c9c283b9294", + "metadata": "{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"AlreadyInitialized\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"AppealFeesNotEnough\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ArbitrationFeesNotEnough\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputeNotAppealable\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedDelegateCall\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"GovernorOnly\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"GovernorOrInstructorOnly\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidForkingCourtAsParent\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"implementation\",\"type\":\"address\"}],\"name\":\"InvalidImplementation\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NoRulerSet\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotInitializing\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RulerOnly\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RulingAlreadyExecuted\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RulingModeNotSet\",\"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\":\"UnsuccessfulCall\",\"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\":\"contract IArbitrableV2\",\"name\":\"_arbitrable\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"enum KlerosCoreRuler.RulingMode\",\"name\":\"mode\",\"type\":\"uint8\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_disputeID\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_ruling\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"tied\",\"type\":\"bool\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"overridden\",\"type\":\"bool\"}],\"name\":\"AutoRuled\",\"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]\"}],\"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\":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 KlerosCoreRuler.Period\",\"name\":\"_period\",\"type\":\"uint8\"}],\"name\":\"NewPeriod\",\"type\":\"event\"},{\"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\",\"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\":\"uint256\",\"name\":\"_disputeID\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_numberOfChoices\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"},{\"internalType\":\"bool\",\"name\":\"_jump\",\"type\":\"bool\"}],\"name\":\"appeal\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_disputeID\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"_jump\",\"type\":\"bool\"}],\"name\":\"appealCost\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"cost\",\"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\":\"contract IERC20\",\"name\":\"_pinakion\",\"type\":\"address\"}],\"name\":\"changePinakion\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract IArbitrableV2\",\"name\":\"_arbitrable\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_newRuler\",\"type\":\"address\"}],\"name\":\"changeRuler\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"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\":\"changeRulingModeToAutomaticPreset\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract IArbitrableV2\",\"name\":\"_arbitrable\",\"type\":\"address\"}],\"name\":\"changeRulingModeToAutomaticRandom\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract IArbitrableV2\",\"name\":\"_arbitrable\",\"type\":\"address\"}],\"name\":\"changeRulingModeToManual\",\"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]\"}],\"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\":\"disputes\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"courtID\",\"type\":\"uint96\"},{\"internalType\":\"contract IArbitrableV2\",\"name\":\"arbitrated\",\"type\":\"address\"},{\"internalType\":\"enum KlerosCoreRuler.Period\",\"name\":\"period\",\"type\":\"uint8\"},{\"internalType\":\"bool\",\"name\":\"ruled\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_disputeID\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_round\",\"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\"},{\"internalType\":\"uint256\",\"name\":\"_ruling\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"tied\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"overridden\",\"type\":\"bool\"}],\"name\":\"executeRuling\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getNextDisputeID\",\"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\":\"totalFeesForJurors\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"sumFeeRewardPaid\",\"type\":\"uint256\"},{\"internalType\":\"contract IERC20\",\"name\":\"feeToken\",\"type\":\"address\"}],\"internalType\":\"struct KlerosCoreRuler.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\":\"contract IERC20\",\"name\":\"_pinakion\",\"type\":\"address\"},{\"internalType\":\"uint256[4]\",\"name\":\"_courtParameters\",\"type\":\"uint256[4]\"}],\"name\":\"initialize\",\"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\":\"contract IArbitrableV2\",\"name\":\"arbitrable\",\"type\":\"address\"}],\"name\":\"rulers\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"ruler\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"disputeID\",\"type\":\"uint256\"}],\"name\":\"rulingResults\",\"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\":\"contract IArbitrableV2\",\"name\":\"arbitrable\",\"type\":\"address\"}],\"name\":\"settings\",\"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\"}],\"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\":{\"appeal(uint256,uint256,bytes,bool)\":{\"details\":\"Appeals the ruling of a specified dispute.\",\"params\":{\"_disputeID\":\"The ID of the dispute.\",\"_jump\":\"Whether to jump to the parent court or not.\"}},\"appealCost(uint256,bool)\":{\"details\":\"Gets the cost of appealing a specified dispute.\",\"params\":{\"_disputeID\":\"The ID of the dispute.\",\"_jump\":\"Whether to jump to the parent court or not.\"},\"returns\":{\"cost\":\"The appeal cost.\"}},\"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.\"}},\"changePinakion(address)\":{\"details\":\"Changes the `pinakion` storage variable.\",\"params\":{\"_pinakion\":\"The new value for the `pinakion` storage variable.\"}},\"constructor\":{\"details\":\"Constructor, initializing the implementation to reduce attack surface.\"},\"createCourt(uint96,bool,uint256,uint256,uint256,uint256,uint256[4])\":{\"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.\",\"_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.\"}},\"execute(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.\",\"_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,uint256,bool,bool)\":{\"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.\"}},\"initialize(address,address,uint256[4])\":{\"details\":\"Initializer (constructor equivalent for upgradable contracts).\",\"params\":{\"_courtParameters\":\"Numeric parameters of General court (minStake, alpha, feeForJuror and jurorsForCourtJump respectively).\",\"_governor\":\"The governor's address.\",\"_pinakion\":\"The address of the token 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.\"},\"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\":\"KlerosCoreRuler Core arbitrator contract for development and testing 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/devtools/KlerosCoreRuler.sol\":\"KlerosCoreRuler\"},\"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/devtools/KlerosCoreRuler.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.24;\\n\\nimport {IArbitrableV2, IArbitratorV2} from \\\"../interfaces/IArbitratorV2.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 KlerosCoreRuler\\n/// Core arbitrator contract for development and testing purposes.\\ncontract KlerosCoreRuler is IArbitratorV2, UUPSProxiable, Initializable {\\n using SafeERC20 for IERC20;\\n\\n // ************************************* //\\n // * Enums / Structs * //\\n // ************************************* //\\n\\n enum RulingMode {\\n uninitialized,\\n manual, // executeRuling() is called manually.\\n automaticRandom, // The ruling is given randomly automatically.\\n automaticPreset // The ruling is given automatically with a preset value.\\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 RulerSettings {\\n RulingMode rulingMode; // The ruling mode of the arbitrator.\\n uint256 presetRuling; // The ruling to give in case of automatic ruling mode.\\n bool presetTied; // Whether the ruling is tied or not.\\n bool presetOverridden; // Whether the ruling is overridden or not.\\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 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 Round[] rounds;\\n }\\n\\n struct Round {\\n uint256 totalFeesForJurors; // The total juror fees paid in this round.\\n uint256 sumFeeRewardPaid; // Total sum of arbitration fees paid to coherent jurors as a reward in this round.\\n IERC20 feeToken; // The token used for paying fees in this round.\\n }\\n\\n struct CurrencyRate {\\n bool feePaymentAccepted;\\n uint64 rateInEth;\\n uint8 rateDecimals;\\n }\\n\\n struct RulingResult {\\n uint256 ruling;\\n bool tied;\\n bool overridden;\\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 governor; // The governor of the contract.\\n IERC20 public pinakion; // The Pinakion token contract.\\n Court[] public courts; // The courts.\\n Dispute[] public disputes; // The disputes.\\n mapping(IERC20 => CurrencyRate) public currencyRates; // The price of each token in ETH.\\n mapping(IArbitrableV2 arbitrable => address ruler) public rulers; // The ruler of each arbitrable contract.\\n mapping(IArbitrableV2 arbitrable => RulerSettings) public settings; // The settings of each arbitrable contract.\\n mapping(uint256 disputeID => RulingResult) public rulingResults; // The ruling results of each dispute.\\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 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 );\\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 CourtJump(\\n uint256 indexed _disputeID,\\n uint256 indexed _roundID,\\n uint96 indexed _fromCourtID,\\n uint96 _toCourtID\\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 AutoRuled(\\n IArbitrableV2 indexed _arbitrable,\\n RulingMode indexed mode,\\n uint256 indexed _disputeID,\\n uint256 _ruling,\\n bool tied,\\n bool overridden\\n );\\n event RulerSettingsChanged(IArbitrableV2 indexed _arbitrable, RulerSettings _settings);\\n event RulerChanged(IArbitrableV2 indexed _arbitrable, address indexed _oldRuler, address indexed _newRuler);\\n\\n // ************************************* //\\n // * Function Modifiers * //\\n // ************************************* //\\n\\n modifier onlyByGovernor() {\\n if (governor != msg.sender) revert GovernorOnly();\\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 _pinakion The address of the token contract.\\n /// @param _courtParameters Numeric parameters of General court (minStake, alpha, feeForJuror and jurorsForCourtJump respectively).\\n function initialize(\\n address _governor,\\n IERC20 _pinakion,\\n uint256[4] memory _courtParameters\\n ) external reinitializer(1) {\\n governor = _governor;\\n pinakion = _pinakion;\\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 = false;\\n court.minStake = _courtParameters[0];\\n court.alpha = _courtParameters[1];\\n court.feeForJuror = _courtParameters[2];\\n court.jurorsForCourtJump = _courtParameters[3];\\n court.timesPerPeriod = [0, 0, 0, 0];\\n\\n emit CourtCreated(\\n 1,\\n court.parent,\\n court.hiddenVotes,\\n _courtParameters[0],\\n _courtParameters[1],\\n _courtParameters[2],\\n _courtParameters[3],\\n court.timesPerPeriod\\n );\\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 `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 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 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 ) external onlyByGovernor {\\n if (_parent == FORKING_COURT) revert InvalidForkingCourtAsParent();\\n\\n uint256 courtID = courts.length;\\n Court storage court = courts.push();\\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 );\\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 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 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 function changeRulingModeToManual(IArbitrableV2 _arbitrable) external {\\n if (rulers[_arbitrable] == address(0)) rulers[_arbitrable] = msg.sender;\\n if (rulers[_arbitrable] != msg.sender) revert RulerOnly();\\n\\n delete settings[_arbitrable];\\n RulerSettings storage arbitratedSettings = settings[_arbitrable];\\n arbitratedSettings.rulingMode = RulingMode.manual;\\n emit RulerSettingsChanged(_arbitrable, arbitratedSettings);\\n }\\n\\n function changeRulingModeToAutomaticRandom(IArbitrableV2 _arbitrable) external {\\n if (rulers[_arbitrable] == address(0)) rulers[_arbitrable] = msg.sender;\\n if (rulers[_arbitrable] != msg.sender) revert RulerOnly();\\n\\n delete settings[_arbitrable];\\n RulerSettings storage arbitratedSettings = settings[_arbitrable];\\n arbitratedSettings.rulingMode = RulingMode.automaticRandom;\\n emit RulerSettingsChanged(_arbitrable, arbitratedSettings);\\n }\\n\\n function changeRulingModeToAutomaticPreset(\\n IArbitrableV2 _arbitrable,\\n uint256 _presetRuling,\\n bool _presetTied,\\n bool _presetOverridden\\n ) external {\\n if (rulers[_arbitrable] == address(0)) rulers[_arbitrable] = msg.sender;\\n if (rulers[_arbitrable] != msg.sender) revert RulerOnly();\\n\\n delete settings[_arbitrable];\\n RulerSettings storage arbitratedSettings = settings[_arbitrable];\\n arbitratedSettings.rulingMode = RulingMode.automaticPreset;\\n arbitratedSettings.presetRuling = _presetRuling;\\n arbitratedSettings.presetTied = _presetTied;\\n arbitratedSettings.presetOverridden = _presetOverridden;\\n emit RulerSettingsChanged(_arbitrable, arbitratedSettings);\\n }\\n\\n function changeRuler(IArbitrableV2 _arbitrable, address _newRuler) external {\\n if (rulers[_arbitrable] != msg.sender) revert RulerOnly();\\n rulers[_arbitrable] = _newRuler;\\n emit RulerChanged(_arbitrable, msg.sender, _newRuler);\\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, , ) = _unpackExtraData(_extraData);\\n disputeID = disputes.length;\\n Dispute storage dispute = disputes.push();\\n dispute.courtID = courtID;\\n dispute.arbitrated = IArbitrableV2(msg.sender);\\n\\n Round storage round = dispute.rounds.push();\\n round.totalFeesForJurors = _feeAmount;\\n round.feeToken = IERC20(_feeToken);\\n\\n _autoRule(disputeID, _numberOfChoices);\\n\\n emit DisputeCreation(disputeID, IArbitrableV2(msg.sender));\\n }\\n\\n function _autoRule(uint256 _disputeID, uint256 _numberOfChoices) internal {\\n Dispute storage dispute = disputes[_disputeID];\\n uint256 roundID = dispute.rounds.length - 1;\\n RulerSettings storage arbitratedSettings = settings[dispute.arbitrated];\\n if (arbitratedSettings.rulingMode == RulingMode.uninitialized) revert RulingModeNotSet();\\n if (arbitratedSettings.rulingMode == RulingMode.manual) {\\n // NOP\\n } else if (arbitratedSettings.rulingMode == RulingMode.automaticPreset) {\\n emit AutoRuled(\\n dispute.arbitrated,\\n RulingMode.automaticPreset,\\n _disputeID,\\n arbitratedSettings.presetRuling,\\n arbitratedSettings.presetTied,\\n arbitratedSettings.presetOverridden\\n );\\n this.executeRuling(\\n _disputeID,\\n arbitratedSettings.presetRuling,\\n arbitratedSettings.presetTied,\\n arbitratedSettings.presetOverridden\\n );\\n this.execute(_disputeID, roundID);\\n } else if (arbitratedSettings.rulingMode == RulingMode.automaticRandom) {\\n uint256 pseudoRandomNumber = uint256(keccak256(abi.encodePacked(blockhash(block.number - 1)))) %\\n _numberOfChoices; // Not secure but it's just a dev tool for testing, sue me\\n bool tied = pseudoRandomNumber & 4 == 0;\\n bool overridden = pseudoRandomNumber & 2 == 0;\\n emit AutoRuled(\\n dispute.arbitrated,\\n RulingMode.automaticRandom,\\n _disputeID,\\n pseudoRandomNumber,\\n tied,\\n overridden\\n );\\n this.executeRuling(_disputeID, pseudoRandomNumber, tied, overridden);\\n this.execute(_disputeID, roundID);\\n }\\n }\\n\\n /// @dev Appeals the ruling of a specified dispute.\\n /// @param _disputeID The ID of the dispute.\\n /// @param _jump Whether to jump to the parent court or not.\\n function appeal(\\n uint256 _disputeID,\\n uint256 _numberOfChoices,\\n bytes memory /*_extraData*/,\\n bool _jump\\n ) external payable {\\n if (msg.value < appealCost(_disputeID, _jump)) revert AppealFeesNotEnough();\\n\\n Dispute storage dispute = disputes[_disputeID];\\n if (rulers[dispute.arbitrated] != msg.sender) revert RulerOnly();\\n if (dispute.period != Period.appeal) revert DisputeNotAppealable();\\n\\n uint96 newCourtID = dispute.courtID;\\n\\n if (_jump) {\\n // Jump to parent court.\\n newCourtID = courts[newCourtID].parent;\\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\\n Round storage extraRound = dispute.rounds.push();\\n extraRound.totalFeesForJurors = msg.value;\\n\\n emit AppealDecision(_disputeID, dispute.arbitrated);\\n emit NewPeriod(_disputeID, Period.evidence);\\n\\n _autoRule(_disputeID, _numberOfChoices);\\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 function execute(uint256 _disputeID, uint256 _round) external {\\n Dispute storage dispute = disputes[_disputeID];\\n address account = rulers[dispute.arbitrated];\\n if (account == address(0)) revert NoRulerSet();\\n\\n // Transfer the fees back to the ruler\\n Round storage round = dispute.rounds[_round];\\n uint256 feeReward = round.totalFeesForJurors;\\n round.sumFeeRewardPaid += feeReward;\\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(account, _disputeID, _round, 1, int256(0), int256(feeReward), round.feeToken);\\n }\\n\\n /// @dev Executes a specified dispute's ruling.\\n /// @param _disputeID The ID of the dispute.\\n function executeRuling(uint256 _disputeID, uint256 _ruling, bool tied, bool overridden) external {\\n Dispute storage dispute = disputes[_disputeID];\\n if (dispute.ruled) revert RulingAlreadyExecuted();\\n if (msg.sender != rulers[dispute.arbitrated] && msg.sender != address(this)) revert RulerOnly();\\n\\n rulingResults[_disputeID] = RulingResult(_ruling, tied, overridden);\\n dispute.ruled = true;\\n dispute.arbitrated.rule(_disputeID, _ruling);\\n\\n emit Ruling(dispute.arbitrated, _disputeID, _ruling);\\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, ) = _unpackExtraData(_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 /// @param _jump Whether to jump to the parent court or not.\\n /// @return cost The appeal cost.\\n function appealCost(uint256 _disputeID, bool _jump) 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 uint256 nbVotes = round.totalFeesForJurors / court.feeForJuror;\\n if (_jump) {\\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 * ((nbVotes * 2) + 1);\\n }\\n } else {\\n // Stay in current court.\\n cost = court.feeForJuror * ((nbVotes * 2) + 1);\\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 RulingResult storage rulingResult = rulingResults[_disputeID];\\n return (rulingResult.ruling, rulingResult.tied, rulingResult.overridden);\\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 getTimesPerPeriod(uint96 _courtID) external view returns (uint256[4] memory timesPerPeriod) {\\n timesPerPeriod = courts[_courtID].timesPerPeriod;\\n }\\n\\n function getNextDisputeID() external view returns (uint256) {\\n return disputes.length;\\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 Court storage court = courts[dispute.courtID];\\n return dispute.rounds[dispute.rounds.length - 1].totalFeesForJurors / court.feeForJuror;\\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 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 _unpackExtraData(\\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) {\\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 GovernorOrInstructorOnly();\\n error RulerOnly();\\n error NoRulerSet();\\n error RulingModeNotSet();\\n error UnsuccessfulCall();\\n error InvalidForkingCourtAsParent();\\n error ArbitrationFeesNotEnough();\\n error TokenNotAccepted();\\n error AppealFeesNotEnough();\\n error DisputeNotAppealable();\\n error RulingAlreadyExecuted();\\n error TransferFailed();\\n}\\n\",\"keccak256\":\"0xb8a370ce083224d6aa6e3eefe1f2c5ef8bbc10f3d957277e09fa5d9b10607afe\",\"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/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. DEPRECATED, as its main purpose was to accommodate forest structure which is not used now.\\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 CannotStakeZeroWhenNoStake\\n}\\n\",\"keccak256\":\"0x5bbda7c304b3681b90feae33be694d04dc129edd60e1d07cb593b895fdc9cd4e\",\"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": "0x60a0604052306080523480156200001557600080fd5b506200002062000026565b620000d9565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0e805468010000000000000000900460ff1615620000765760405162dc149f60e41b815260040160405180910390fd5b80546001600160401b0390811614620000d65780546001600160401b0319166001600160401b0390811782556040519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50565b60805161336562000103600039600081816113350152818161135e015261155b01526133656000f3fe6080604052600436106101e95760003560e01c8063564a565d11610113578063d98493f6116100ab578063e6d49cdf1161006f578063e6d49cdf14610727578063f6506db414610767578063f7434ea914610787578063fbf405b0146107a7578063fc6f8f16146107c757600080fd5b8063d98493f614610665578063d9ee095f14610685578063db8a173b14610698578063e2373ab3146106ad578063e4c0aaf41461070757600080fd5b8063564a565d146105175780636736b70c14610547578063751accd0146105675780637934c0be1461058757806382d02237146105a757806386541b24146105c75780638a9bb02a146105e7578063c13517e114610632578063c71f42531461064557600080fd5b80632177470c116101865780632177470c146103ec578063379f0a171461040c5780633cfd118414610442578063405d51ae1461046f57806343818d661461048f57806347cdcc1d146104af5780634f1ef286146104cf57806352d1902d146104e25780635601eaea146104f757600080fd5b8062f5822c146101ee57806301fcf74d146102105780630219da791461024357806305d3177d146102b65780630c340a24146102d65780630e3993a41461030e5780631860592b1461032e5780631c3db16d1461034e5780631f5a0dd21461038b575b600080fd5b3480156101fa57600080fd5b5061020e610209366004612900565b6107e7565b005b34801561021c57600080fd5b5061023061022b366004612932565b610834565b6040519081526020015b60405180910390f35b34801561024f57600080fd5b5061028e61025e366004612900565b60046020526000908152604090205460ff808216916001600160401b0361010082041691600160481b9091041683565b6040805193151584526001600160401b03909216602084015260ff169082015260600161023a565b3480156102c257600080fd5b5061020e6102d13660046129e5565b610990565b3480156102e257600080fd5b506000546102f6906001600160a01b031681565b6040516001600160a01b03909116815260200161023a565b34801561031a57600080fd5b5061020e610329366004612900565b610be9565b34801561033a57600080fd5b50610230610349366004612a2d565b610cf4565b34801561035a57600080fd5b5061036e610369366004612a59565b610d4e565b60408051938452911515602084015215159082015260600161023a565b34801561039757600080fd5b506103ab6103a6366004612a59565b610d78565b604080516001600160601b0390981688529515156020880152948601939093526060850191909152608084015260a0830152151560c082015260e00161023a565b3480156103f857600080fd5b5061020e610407366004612a72565b610dd7565b34801561041857600080fd5b506102f6610427366004612900565b6005602052600090815260409020546001600160a01b031681565b34801561044e57600080fd5b5061046261045d366004612ad8565b610f9f565b60405161023a9190612b16565b34801561047b57600080fd5b5061020e61048a366004612b24565b611009565b34801561049b57600080fd5b5061020e6104aa366004612900565b6111c9565b3480156104bb57600080fd5b5061020e6104ca366004612b92565b61128e565b61020e6104dd366004612c4c565b611321565b3480156104ee57600080fd5b5061023061154e565b34801561050357600080fd5b5061020e610512366004612c9b565b6115ac565b34801561052357600080fd5b50610537610532366004612a59565b61171e565b60405161023a9493929190612ce7565b34801561055357600080fd5b5061020e610562366004612d24565b611773565b34801561057357600080fd5b5061020e610582366004612d5c565b611884565b34801561059357600080fd5b5061020e6105a2366004612db4565b61192e565b3480156105b357600080fd5b5061020e6105c2366004612de2565b6119ad565b3480156105d357600080fd5b5061020e6105e2366004612b24565b611a6a565b3480156105f357600080fd5b50610607610602366004612c9b565b611b5e565b604080518251815260208084015190820152918101516001600160a01b03169082015260600161023a565b610230610640366004612e3f565b611c0b565b34801561065157600080fd5b50610230610660366004612a59565b611c43565b34801561067157600080fd5b50610230610680366004612eb7565b611ced565b61020e610693366004612f02565b611d32565b3480156106a457600080fd5b50600354610230565b3480156106b957600080fd5b506106f76106c8366004612900565b60066020526000908152604090208054600182015460029092015460ff91821692918181169161010090041684565b60405161023a9493929190612f69565b34801561071357600080fd5b5061020e610722366004612900565b611f7f565b34801561073357600080fd5b5061036e610742366004612a59565b6007602052600090815260409020805460019091015460ff8082169161010090041683565b34801561077357600080fd5b50610230610782366004612f94565b611fcc565b34801561079357600080fd5b506102306107a2366004612ffa565b6120b0565b3480156107b357600080fd5b506001546102f6906001600160a01b031681565b3480156107d357600080fd5b506102306107e2366004612a59565b6120fc565b6000546001600160a01b031633146108125760405163c383977560e01b815260040160405180910390fd5b600180546001600160a01b0319166001600160a01b0392909216919091179055565b6000806003848154811061084a5761084a61302e565b60009182526020822060026003909202019081018054919350906108709060019061305a565b815481106108805761088061302e565b6000918252602082208454600280546003909402909201945090916001600160601b039091169081106108b5576108b561302e565b90600052602060002090600b020190506000816004015483600001546108db9190613083565b9050851561095e5783546001600160601b031660001901610905576001600160ff1b039450610986565b610910816002613097565b61091b9060016130ae565b82546002805490916001600160601b031690811061093b5761093b61302e565b90600052602060002090600b0201600401546109579190613097565b9450610986565b610969816002613097565b6109749060016130ae565b82600401546109839190613097565b94505b5050505092915050565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0e805460019190600160401b900460ff16806109d9575080546001600160401b03808416911610155b156109f65760405162dc149f60e41b815260040160405180910390fd5b805468ffffffffffffffffff19166001600160401b03831617600160401b178155600080546001600160a01b038088166001600160a01b0319928316178355600180549188169190921617815560028054818452808201909155600b9101027f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace0180546001600160601b031916815590604051908082528060200260200182016040528015610aaf578160200160208202803683370190505b508051610ac691600184019160209091019061280d565b50805460ff60601b19168155835160028201556020808501516003830155604080860151600480850191909155606080880151600586015582516080810184526000808252948101859052928301849052820192909252610b2c91600684019190612858565b50805484516020860151604080880151606089015191516001600160601b038616956001957f0c907a651f88974ed0d9423aacc8b998c40eedf39920e2c3bdae0adcc486a76195610b9295600160601b90930460ff1694919390929060068b01906130c1565b60405180910390a350805460ff60401b191681556040516001600160401b03831681527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15050505050565b6001600160a01b0381811660009081526005602052604090205416610c31576001600160a01b038116600090815260056020526040902080546001600160a01b031916331790555b6001600160a01b03818116600090815260056020526040902054163314610c6b576040516301627e2760e61b815260040160405180910390fd5b6001600160a01b0381166000908152600660205260408120805460ff191680825560018083019390935560028201805461ffff19169055909190829082805b0217905550816001600160a01b03167ffe3754ab712090753cf700ac7b99f8a5e0f9c69b698312c2cfd0236b852f83f482604051610ce8919061311d565b60405180910390a25050565b6001600160a01b03821660009081526004602052604081205461010081046001600160401b031690610d3190600160481b900460ff16600a613246565b610d3b9084613097565b610d459190613083565b90505b92915050565b6000818152600760205260409020805460019091015460ff808216916101009004165b9193909250565b60028181548110610d8857600080fd5b60009182526020909120600b9091020180546002820154600383015460048401546005850154600a909501546001600160601b038516965060ff600160601b9095048516959394929391921687565b600060038581548110610dec57610dec61302e565b906000526020600020906003020190508060010160019054906101000a900460ff1615610e2c5760405163c977f8d360e01b815260040160405180910390fd5b8054600160601b90046001600160a01b03908116600090815260056020526040902054163314801590610e5f5750333014155b15610e7d576040516301627e2760e61b815260040160405180910390fd5b60408051606081018252858152841515602080830191825285151583850190815260008a815260079092529084902092518355905160019283018054925161ffff1990931691151561ff001990811692909217610100931515840217905591840180549092161790558154905163188d362b60e11b81526004810187905260248101869052600160601b9091046001600160a01b03169063311a6c5690604401600060405180830381600087803b158015610f3757600080fd5b505af1158015610f4b573d6000803e3d6000fd5b50508254604051878152889350600160601b9091046001600160a01b031691507f394027a5fa6e098a1191094d1719d6929b9abc535fcc0c8f448d6a4e756222769060200160405180910390a35050505050565b610fa761288b565b6002826001600160601b031681548110610fc357610fc361302e565b6000918252602090912060408051608081019182905292600b029091016006019060049082845b815481526020019060010190808311610fea5750505050509050919050565b6000546001600160a01b031633146110345760405163c383977560e01b815260040160405180910390fd5b6001600160601b03871661105b57604051631ef4f64960e01b815260040160405180910390fd5b6002805460018101825560009182527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace600b82020180546001600160601b0319166001600160601b038b1617815590916040519080825280602002602001820160405280156110d4578160200160208202803683370190505b5080516110eb91600184019160209091019061280d565b50805460ff60601b1916600160601b89151502178155600281018790556003810186905560048082018690556005820185905561112e90600683019085906128a9565b506002896001600160601b03168154811061114b5761114b61302e565b600091825260208083206001600b909302018201805492830181558352909120018290556040516001600160601b038a169083907f0c907a651f88974ed0d9423aacc8b998c40eedf39920e2c3bdae0adcc486a761906111b6908c908c908c908c908c908c90613255565b60405180910390a3505050505050505050565b6001600160a01b0381811660009081526005602052604090205416611211576001600160a01b038116600090815260056020526040902080546001600160a01b031916331790555b6001600160a01b0381811660009081526005602052604090205416331461124b576040516301627e2760e61b815260040160405180910390fd5b6001600160a01b0381166000908152600660205260408120805460ff19168082556001808301939093556002808301805461ffff19169055919283919083610caa565b6001600160a01b038281166000908152600560205260409020541633146112c8576040516301627e2760e61b815260040160405180910390fd5b6001600160a01b0382811660008181526005602052604080822080546001600160a01b0319169486169485179055513392917ff512a4524e61d860055823df1f2a5f33de24eb2a03dc3de501015ad501d4e36f91a45050565b61132a8261212b565b306001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614806113a857507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031661139c6000805160206133108339815191525490565b6001600160a01b031614155b156113c65760405163703e46dd60e11b815260040160405180910390fd5b816001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015611420575060408051601f3d908101601f1916820190925261141d91810190613288565b60015b61144d57604051630c76093760e01b81526001600160a01b03831660048201526024015b60405180910390fd5b600080516020613310833981519152811461147e57604051632a87526960e21b815260048101829052602401611444565b6000805160206133108339815191528390556040516001600160a01b038416907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a2815115611549576000836001600160a01b0316836040516114e591906132a1565b600060405180830381855af49150503d8060008114611520576040519150601f19603f3d011682016040523d82523d6000602084013e611525565b606091505b5050905080611547576040516339b21b5d60e11b815260040160405180910390fd5b505b505050565b6000306001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146115995760405163703e46dd60e11b815260040160405180910390fd5b5060008051602061331083398151915290565b6000600383815481106115c1576115c161302e565b60009182526020808320600390920290910180546001600160a01b03600160601b90910481168452600590925260409092205491925016806116165760405163f4612fe560e01b815260040160405180910390fd5b600082600201848154811061162d5761162d61302e565b906000526020600020906003020190506000816000015490508082600101600082825461165a91906130ae565b909155505060028201546001600160a01b031661169c576040516001600160a01b0384169082156108fc029083906000818181858888f19350505050506116b7565b60028201546116b5906001600160a01b03168483612159565b505b60028201546040805160018152600060208201529081018390526001600160a01b03918216606082015286918891908616907f8975b837fe0d18616c65abb8b843726a32b552ee4feca009944fa658bbb282e79060800160405180910390a4505050505050565b6003818154811061172e57600080fd5b6000918252602090912060039091020180546001909101546001600160601b0382169250600160601b9091046001600160a01b03169060ff8082169161010090041684565b6001600160a01b03848116600090815260056020526040902054166117bb576001600160a01b038416600090815260056020526040902080546001600160a01b031916331790555b6001600160a01b038481166000908152600560205260409020541633146117f5576040516301627e2760e61b815260040160405180910390fd5b6001600160a01b03841660008181526006602052604090819020805460028201805460ff1990921660031783556001830188905561ffff1990911686151561ff001916176101008615150217905590519091907ffe3754ab712090753cf700ac7b99f8a5e0f9c69b698312c2cfd0236b852f83f49061187590849061311d565b60405180910390a25050505050565b6000546001600160a01b031633146118af5760405163c383977560e01b815260040160405180910390fd5b6000836001600160a01b031683836040516118ca91906132a1565b60006040518083038185875af1925050503d8060008114611907576040519150601f19603f3d011682016040523d82523d6000602084013e61190c565b606091505b5050905080611547576040516322092f2f60e11b815260040160405180910390fd5b6000546001600160a01b031633146119595760405163c383977560e01b815260040160405180910390fd5b6001600160a01b038216600081815260046020526040808220805460ff191685151590811790915590519092917f541615e167511d757a7067a700eb54431b256bb458dfdce0ac58bf2ed0aefd4491a35050565b6000546001600160a01b031633146119d85760405163c383977560e01b815260040160405180910390fd5b6001600160a01b038316600081815260046020908152604091829020805469ffffffffffffffffff0019166101006001600160401b03881690810260ff60481b191691909117600160481b60ff8816908102919091179092558351908152918201527fe6996b7f03e9bd02228b99d3d946932e3197f505f60542c4cfbc919441d8a4e6910160405180910390a2505050565b6000546001600160a01b03163314611a955760405163c383977560e01b815260040160405180910390fd5b60006002886001600160601b031681548110611ab357611ab361302e565b60009182526020909120600b9091020160028101879055805460ff60601b1916600160601b8915150217815560038101869055600480820186905560058201859055909150611b0890600683019084906128a9565b50876001600160601b03167f709b1f5fda58af9a4f52dacd1ec404840a8148455700cce155a2bd8cf127ef1a888888888888604051611b4c96959493929190613255565b60405180910390a25050505050505050565b611b8b6040518060600160405280600081526020016000815260200160006001600160a01b031681525090565b60038381548110611b9e57611b9e61302e565b90600052602060002090600302016002018281548110611bc057611bc061302e565b6000918252602091829020604080516060810182526003909302909101805483526001810154938301939093526002909201546001600160a01b031691810191909152905092915050565b6000611c16826120b0565b341015611c3657604051630e3360f160e21b815260040160405180910390fd5b610d458383600034612222565b60008060038381548110611c5957611c5961302e565b600091825260208220600390910201805460028054929450916001600160601b03909116908110611c8c57611c8c61302e565b90600052602060002090600b0201905080600401548260020160018460020180549050611cb9919061305a565b81548110611cc957611cc961302e565b906000526020600020906003020160000154611ce59190613083565b949350505050565b6000611ce58261034986868080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506120b092505050565b611d3c8482610834565b341015611d5c57604051633191f8f160e01b815260040160405180910390fd5b600060038581548110611d7157611d7161302e565b6000918252602080832060039092029091018054600160601b90046001600160a01b0390811684526005909252604090922054919250163314611dc7576040516301627e2760e61b815260040160405180910390fd5b6003600182015460ff166004811115611de257611de2612cbd565b14611e00576040516337cdefcb60e21b815260040160405180910390fd5b80546001600160601b03168215611eb2576002816001600160601b031681548110611e2d57611e2d61302e565b60009182526020909120600b909102015482546001600160601b039182169250168114611eb257815460028301546001600160601b0390911690611e739060019061305a565b6040516001600160601b038416815288907f736e3f52761298c8c0823e1ebf482ed3c5ecb304f743d2d91a7c006e8e8d7a1f9060200160405180910390a45b81546001600160601b0319166001600160601b0382161782556001808301805460ff191690556002830180549182018155600090815260208120346003909302019182558354604051600160601b9091046001600160a01b03169189917f9c9b64db9e130f48381bf697abf638e73117dbfbfd7a4484f2da3ba188f4187d9190a3867f4e6f5cf43b95303e86aee81683df63992061723a829ee012db21dad388756b916000604051611f6491906132d0565b60405180910390a2611f768787612317565b50505050505050565b6000546001600160a01b03163314611faa5760405163c383977560e01b815260040160405180910390fd5b600080546001600160a01b0319166001600160a01b0392909216919091179055565b6001600160a01b03821660009081526004602052604081205460ff166120055760405163e51cf7bf60e01b815260040160405180910390fd5b612010858585611ced565b82101561203057604051630e3360f160e21b815260040160405180910390fd5b6120456001600160a01b0384163330856126bc565b612062576040516312171d8360e31b815260040160405180910390fd5b6120a68686868080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508892508791506122229050565b9695505050505050565b60008060006120be84612798565b5091509150806002836001600160601b0316815481106120e0576120e061302e565b90600052602060002090600b020160040154611ce59190613097565b6000600382815481106121115761211161302e565b600091825260209091206002600390920201015492915050565b6000546001600160a01b031633146121565760405163c383977560e01b815260040160405180910390fd5b50565b6040516001600160a01b03838116602483015260448201839052600091829182919087169060640160408051601f198184030181529181526020820180516001600160e01b031663a9059cbb60e01b179052516121b691906132a1565b6000604051808303816000865af19150503d80600081146121f3576040519150601f19603f3d011682016040523d82523d6000602084013e6121f8565b606091505b50915091508180156120a65750805115806120a65750808060200190518101906120a691906132de565b60008061222e85612798565b505060038054600180820183556001600160601b03841633600160601b02177fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b8385029081019182557fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85d018054928301815560009081526020902091909302018681556002810180546001600160a01b0319166001600160a01b038a16179055909450919250906122df8489612317565b604051339085907f141dfc18aa6a56fc816f44f0e9e2f1ebc92b15ab167770e17db5b084c10ed99590600090a3505050949350505050565b60006003838154811061232c5761232c61302e565b90600052602060002090600302019050600060018260020180549050612352919061305a565b8254600160601b90046001600160a01b03166000908152600660205260408120919250815460ff16600381111561238b5761238b612cbd565b036123a95760405163d8f2465160e01b815260040160405180910390fd5b6001815460ff1660038111156123c1576123c1612cbd565b146126b5576003815460ff1660038111156123de576123de612cbd565b0361252d578460038454600184015460028501546040805192835260ff80831615156020850152610100909204909116151590820152600160601b9091046001600160a01b0316907f45c27c7ea7135714f09b069efa7497d57c38017d4e919c5535ba31dbd5b597e69060600160405180910390a46001810154600282015460405163085dd1c360e21b815260048101889052602481019290925260ff8082161515604484015261010090910416151560648201523090632177470c90608401600060405180830381600087803b1580156124b857600080fd5b505af11580156124cc573d6000803e3d6000fd5b5050604051632b00f57560e11b81526004810188905260248101859052309250635601eaea9150604401600060405180830381600087803b15801561251057600080fd5b505af1158015612524573d6000803e3d6000fd5b505050506126b5565b6002815460ff16600381111561254557612545612cbd565b036126b55760008461255860014361305a565b6040805191406020830152016040516020818303038152906040528051906020012060001c61258791906132fb565b90506004811615600280831615908890875460408051878152861515602082015285151591810191909152600160601b9091046001600160a01b0316907f45c27c7ea7135714f09b069efa7497d57c38017d4e919c5535ba31dbd5b597e69060600160405180910390a460405163085dd1c360e21b81526004810189905260248101849052821515604482015281151560648201523090632177470c90608401600060405180830381600087803b15801561264157600080fd5b505af1158015612655573d6000803e3d6000fd5b5050604051632b00f57560e11b8152600481018b905260248101889052309250635601eaea9150604401600060405180830381600087803b15801561269957600080fd5b505af11580156126ad573d6000803e3d6000fd5b505050505050505b5050505050565b6040516001600160a01b038481166024830152838116604483015260648201839052600091829182919088169060840160408051601f198184030181529181526020820180516001600160e01b03166323b872dd60e01b1790525161272191906132a1565b6000604051808303816000865af19150503d806000811461275e576040519150601f19603f3d011682016040523d82523d6000602084013e612763565b606091505b509150915081801561278d57508051158061278d57508080602001905181019061278d91906132de565b979650505050505050565b600080600060408451106127fe575050506020810151604082015160608301516001600160601b03831615806127d957506002546001600160601b03841610155b156127e357600192505b816000036127f057600391505b806127f9575060015b610d71565b50600193600393508492509050565b828054828255906000526020600020908101928215612848579160200282015b8281111561284857825182559160200191906001019061282d565b506128549291506128d6565b5090565b8260048101928215612848579160200282015b82811115612848578251829060ff1690559160200191906001019061286b565b60405180608001604052806004906020820280368337509192915050565b8260048101928215612848579160200282018281111561284857825182559160200191906001019061282d565b5b8082111561285457600081556001016128d7565b6001600160a01b038116811461215657600080fd5b60006020828403121561291257600080fd5b813561291d816128eb565b9392505050565b801515811461215657600080fd5b6000806040838503121561294557600080fd5b82359150602083013561295781612924565b809150509250929050565b634e487b7160e01b600052604160045260246000fd5b600082601f83011261298957600080fd5b604051608081018181106001600160401b03821117156129ab576129ab612962565b6040528060808401858111156129c057600080fd5b845b818110156129da5780358352602092830192016129c2565b509195945050505050565b600080600060c084860312156129fa57600080fd5b8335612a05816128eb565b92506020840135612a15816128eb565b9150612a248560408601612978565b90509250925092565b60008060408385031215612a4057600080fd5b8235612a4b816128eb565b946020939093013593505050565b600060208284031215612a6b57600080fd5b5035919050565b60008060008060808587031215612a8857600080fd5b84359350602085013592506040850135612aa181612924565b91506060850135612ab181612924565b939692955090935050565b80356001600160601b0381168114612ad357600080fd5b919050565b600060208284031215612aea57600080fd5b610d4582612abc565b8060005b6004811015611547578151845260209384019390910190600101612af7565b60808101610d488284612af3565b6000806000806000806000610140888a031215612b4057600080fd5b612b4988612abc565b96506020880135612b5981612924565b955060408801359450606088013593506080880135925060a08801359150612b848960c08a01612978565b905092959891949750929550565b60008060408385031215612ba557600080fd5b8235612bb0816128eb565b91506020830135612957816128eb565b600082601f830112612bd157600080fd5b81356001600160401b0380821115612beb57612beb612962565b604051601f8301601f19908116603f01168101908282118183101715612c1357612c13612962565b81604052838152866020858801011115612c2c57600080fd5b836020870160208301376000602085830101528094505050505092915050565b60008060408385031215612c5f57600080fd5b8235612c6a816128eb565b915060208301356001600160401b03811115612c8557600080fd5b612c9185828601612bc0565b9150509250929050565b60008060408385031215612cae57600080fd5b50508035926020909101359150565b634e487b7160e01b600052602160045260246000fd5b60058110612ce357612ce3612cbd565b9052565b6001600160601b03851681526001600160a01b038416602082015260808101612d136040830185612cd3565b821515606083015295945050505050565b60008060008060808587031215612d3a57600080fd5b8435612d45816128eb565b9350602085013592506040850135612aa181612924565b600080600060608486031215612d7157600080fd5b8335612d7c816128eb565b92506020840135915060408401356001600160401b03811115612d9e57600080fd5b612daa86828701612bc0565b9150509250925092565b60008060408385031215612dc757600080fd5b8235612dd2816128eb565b9150602083013561295781612924565b600080600060608486031215612df757600080fd5b8335612e02816128eb565b925060208401356001600160401b0381168114612e1e57600080fd5b9150604084013560ff81168114612e3457600080fd5b809150509250925092565b60008060408385031215612e5257600080fd5b8235915060208301356001600160401b03811115612c8557600080fd5b60008083601f840112612e8157600080fd5b5081356001600160401b03811115612e9857600080fd5b602083019150836020828501011115612eb057600080fd5b9250929050565b600080600060408486031215612ecc57600080fd5b83356001600160401b03811115612ee257600080fd5b612eee86828701612e6f565b9094509250506020840135612e34816128eb565b60008060008060808587031215612f1857600080fd5b843593506020850135925060408501356001600160401b03811115612f3c57600080fd5b612f4887828801612bc0565b9250506060850135612ab181612924565b60048110612ce357612ce3612cbd565b60808101612f778287612f59565b602082019490945291151560408301521515606090910152919050565b600080600080600060808688031215612fac57600080fd5b8535945060208601356001600160401b03811115612fc957600080fd5b612fd588828901612e6f565b9095509350506040860135612fe9816128eb565b949793965091946060013592915050565b60006020828403121561300c57600080fd5b81356001600160401b0381111561302257600080fd5b611ce584828501612bc0565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b81810381811115610d4857610d48613044565b634e487b7160e01b600052601260045260246000fd5b6000826130925761309261306d565b500490565b8082028115828204841417610d4857610d48613044565b80820180821115610d4857610d48613044565b6000610120820190508715158252602087602084015286604084015285606084015284608084015260a083018460005b600481101561310e578154835291830191600191820191016130f1565b50505050979650505050505050565b60006080820190506131338260ff855416612f59565b60018301546020830152600283015460ff81161515604084015260ff8160081c16151560608401525092915050565b600181815b8085111561319d57816000190482111561318357613183613044565b8085161561319057918102915b93841c9390800290613167565b509250929050565b6000826131b457506001610d48565b816131c157506000610d48565b81600181146131d757600281146131e1576131fd565b6001915050610d48565b60ff8411156131f2576131f2613044565b50506001821b610d48565b5060208310610133831016604e8410600b8410161715613220575081810a610d48565b61322a8383613162565b806000190482111561323e5761323e613044565b029392505050565b6000610d4560ff8416836131a5565b600061012082019050871515825286602083015285604083015284606083015283608083015261278d60a0830184612af3565b60006020828403121561329a57600080fd5b5051919050565b6000825160005b818110156132c257602081860181015185830152016132a8565b506000920191825250919050565b60208101610d488284612cd3565b6000602082840312156132f057600080fd5b815161291d81612924565b60008261330a5761330a61306d565b50069056fe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbca26469706673582212204bcdc26480adc94ceb9c089d1af202275da9840934fdb8dead13e3defee11c1164736f6c63430008180033", + "deployedBytecode": "0x6080604052600436106101e95760003560e01c8063564a565d11610113578063d98493f6116100ab578063e6d49cdf1161006f578063e6d49cdf14610727578063f6506db414610767578063f7434ea914610787578063fbf405b0146107a7578063fc6f8f16146107c757600080fd5b8063d98493f614610665578063d9ee095f14610685578063db8a173b14610698578063e2373ab3146106ad578063e4c0aaf41461070757600080fd5b8063564a565d146105175780636736b70c14610547578063751accd0146105675780637934c0be1461058757806382d02237146105a757806386541b24146105c75780638a9bb02a146105e7578063c13517e114610632578063c71f42531461064557600080fd5b80632177470c116101865780632177470c146103ec578063379f0a171461040c5780633cfd118414610442578063405d51ae1461046f57806343818d661461048f57806347cdcc1d146104af5780634f1ef286146104cf57806352d1902d146104e25780635601eaea146104f757600080fd5b8062f5822c146101ee57806301fcf74d146102105780630219da791461024357806305d3177d146102b65780630c340a24146102d65780630e3993a41461030e5780631860592b1461032e5780631c3db16d1461034e5780631f5a0dd21461038b575b600080fd5b3480156101fa57600080fd5b5061020e610209366004612900565b6107e7565b005b34801561021c57600080fd5b5061023061022b366004612932565b610834565b6040519081526020015b60405180910390f35b34801561024f57600080fd5b5061028e61025e366004612900565b60046020526000908152604090205460ff808216916001600160401b0361010082041691600160481b9091041683565b6040805193151584526001600160401b03909216602084015260ff169082015260600161023a565b3480156102c257600080fd5b5061020e6102d13660046129e5565b610990565b3480156102e257600080fd5b506000546102f6906001600160a01b031681565b6040516001600160a01b03909116815260200161023a565b34801561031a57600080fd5b5061020e610329366004612900565b610be9565b34801561033a57600080fd5b50610230610349366004612a2d565b610cf4565b34801561035a57600080fd5b5061036e610369366004612a59565b610d4e565b60408051938452911515602084015215159082015260600161023a565b34801561039757600080fd5b506103ab6103a6366004612a59565b610d78565b604080516001600160601b0390981688529515156020880152948601939093526060850191909152608084015260a0830152151560c082015260e00161023a565b3480156103f857600080fd5b5061020e610407366004612a72565b610dd7565b34801561041857600080fd5b506102f6610427366004612900565b6005602052600090815260409020546001600160a01b031681565b34801561044e57600080fd5b5061046261045d366004612ad8565b610f9f565b60405161023a9190612b16565b34801561047b57600080fd5b5061020e61048a366004612b24565b611009565b34801561049b57600080fd5b5061020e6104aa366004612900565b6111c9565b3480156104bb57600080fd5b5061020e6104ca366004612b92565b61128e565b61020e6104dd366004612c4c565b611321565b3480156104ee57600080fd5b5061023061154e565b34801561050357600080fd5b5061020e610512366004612c9b565b6115ac565b34801561052357600080fd5b50610537610532366004612a59565b61171e565b60405161023a9493929190612ce7565b34801561055357600080fd5b5061020e610562366004612d24565b611773565b34801561057357600080fd5b5061020e610582366004612d5c565b611884565b34801561059357600080fd5b5061020e6105a2366004612db4565b61192e565b3480156105b357600080fd5b5061020e6105c2366004612de2565b6119ad565b3480156105d357600080fd5b5061020e6105e2366004612b24565b611a6a565b3480156105f357600080fd5b50610607610602366004612c9b565b611b5e565b604080518251815260208084015190820152918101516001600160a01b03169082015260600161023a565b610230610640366004612e3f565b611c0b565b34801561065157600080fd5b50610230610660366004612a59565b611c43565b34801561067157600080fd5b50610230610680366004612eb7565b611ced565b61020e610693366004612f02565b611d32565b3480156106a457600080fd5b50600354610230565b3480156106b957600080fd5b506106f76106c8366004612900565b60066020526000908152604090208054600182015460029092015460ff91821692918181169161010090041684565b60405161023a9493929190612f69565b34801561071357600080fd5b5061020e610722366004612900565b611f7f565b34801561073357600080fd5b5061036e610742366004612a59565b6007602052600090815260409020805460019091015460ff8082169161010090041683565b34801561077357600080fd5b50610230610782366004612f94565b611fcc565b34801561079357600080fd5b506102306107a2366004612ffa565b6120b0565b3480156107b357600080fd5b506001546102f6906001600160a01b031681565b3480156107d357600080fd5b506102306107e2366004612a59565b6120fc565b6000546001600160a01b031633146108125760405163c383977560e01b815260040160405180910390fd5b600180546001600160a01b0319166001600160a01b0392909216919091179055565b6000806003848154811061084a5761084a61302e565b60009182526020822060026003909202019081018054919350906108709060019061305a565b815481106108805761088061302e565b6000918252602082208454600280546003909402909201945090916001600160601b039091169081106108b5576108b561302e565b90600052602060002090600b020190506000816004015483600001546108db9190613083565b9050851561095e5783546001600160601b031660001901610905576001600160ff1b039450610986565b610910816002613097565b61091b9060016130ae565b82546002805490916001600160601b031690811061093b5761093b61302e565b90600052602060002090600b0201600401546109579190613097565b9450610986565b610969816002613097565b6109749060016130ae565b82600401546109839190613097565b94505b5050505092915050565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0e805460019190600160401b900460ff16806109d9575080546001600160401b03808416911610155b156109f65760405162dc149f60e41b815260040160405180910390fd5b805468ffffffffffffffffff19166001600160401b03831617600160401b178155600080546001600160a01b038088166001600160a01b0319928316178355600180549188169190921617815560028054818452808201909155600b9101027f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace0180546001600160601b031916815590604051908082528060200260200182016040528015610aaf578160200160208202803683370190505b508051610ac691600184019160209091019061280d565b50805460ff60601b19168155835160028201556020808501516003830155604080860151600480850191909155606080880151600586015582516080810184526000808252948101859052928301849052820192909252610b2c91600684019190612858565b50805484516020860151604080880151606089015191516001600160601b038616956001957f0c907a651f88974ed0d9423aacc8b998c40eedf39920e2c3bdae0adcc486a76195610b9295600160601b90930460ff1694919390929060068b01906130c1565b60405180910390a350805460ff60401b191681556040516001600160401b03831681527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15050505050565b6001600160a01b0381811660009081526005602052604090205416610c31576001600160a01b038116600090815260056020526040902080546001600160a01b031916331790555b6001600160a01b03818116600090815260056020526040902054163314610c6b576040516301627e2760e61b815260040160405180910390fd5b6001600160a01b0381166000908152600660205260408120805460ff191680825560018083019390935560028201805461ffff19169055909190829082805b0217905550816001600160a01b03167ffe3754ab712090753cf700ac7b99f8a5e0f9c69b698312c2cfd0236b852f83f482604051610ce8919061311d565b60405180910390a25050565b6001600160a01b03821660009081526004602052604081205461010081046001600160401b031690610d3190600160481b900460ff16600a613246565b610d3b9084613097565b610d459190613083565b90505b92915050565b6000818152600760205260409020805460019091015460ff808216916101009004165b9193909250565b60028181548110610d8857600080fd5b60009182526020909120600b9091020180546002820154600383015460048401546005850154600a909501546001600160601b038516965060ff600160601b9095048516959394929391921687565b600060038581548110610dec57610dec61302e565b906000526020600020906003020190508060010160019054906101000a900460ff1615610e2c5760405163c977f8d360e01b815260040160405180910390fd5b8054600160601b90046001600160a01b03908116600090815260056020526040902054163314801590610e5f5750333014155b15610e7d576040516301627e2760e61b815260040160405180910390fd5b60408051606081018252858152841515602080830191825285151583850190815260008a815260079092529084902092518355905160019283018054925161ffff1990931691151561ff001990811692909217610100931515840217905591840180549092161790558154905163188d362b60e11b81526004810187905260248101869052600160601b9091046001600160a01b03169063311a6c5690604401600060405180830381600087803b158015610f3757600080fd5b505af1158015610f4b573d6000803e3d6000fd5b50508254604051878152889350600160601b9091046001600160a01b031691507f394027a5fa6e098a1191094d1719d6929b9abc535fcc0c8f448d6a4e756222769060200160405180910390a35050505050565b610fa761288b565b6002826001600160601b031681548110610fc357610fc361302e565b6000918252602090912060408051608081019182905292600b029091016006019060049082845b815481526020019060010190808311610fea5750505050509050919050565b6000546001600160a01b031633146110345760405163c383977560e01b815260040160405180910390fd5b6001600160601b03871661105b57604051631ef4f64960e01b815260040160405180910390fd5b6002805460018101825560009182527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace600b82020180546001600160601b0319166001600160601b038b1617815590916040519080825280602002602001820160405280156110d4578160200160208202803683370190505b5080516110eb91600184019160209091019061280d565b50805460ff60601b1916600160601b89151502178155600281018790556003810186905560048082018690556005820185905561112e90600683019085906128a9565b506002896001600160601b03168154811061114b5761114b61302e565b600091825260208083206001600b909302018201805492830181558352909120018290556040516001600160601b038a169083907f0c907a651f88974ed0d9423aacc8b998c40eedf39920e2c3bdae0adcc486a761906111b6908c908c908c908c908c908c90613255565b60405180910390a3505050505050505050565b6001600160a01b0381811660009081526005602052604090205416611211576001600160a01b038116600090815260056020526040902080546001600160a01b031916331790555b6001600160a01b0381811660009081526005602052604090205416331461124b576040516301627e2760e61b815260040160405180910390fd5b6001600160a01b0381166000908152600660205260408120805460ff19168082556001808301939093556002808301805461ffff19169055919283919083610caa565b6001600160a01b038281166000908152600560205260409020541633146112c8576040516301627e2760e61b815260040160405180910390fd5b6001600160a01b0382811660008181526005602052604080822080546001600160a01b0319169486169485179055513392917ff512a4524e61d860055823df1f2a5f33de24eb2a03dc3de501015ad501d4e36f91a45050565b61132a8261212b565b306001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614806113a857507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031661139c6000805160206133108339815191525490565b6001600160a01b031614155b156113c65760405163703e46dd60e11b815260040160405180910390fd5b816001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015611420575060408051601f3d908101601f1916820190925261141d91810190613288565b60015b61144d57604051630c76093760e01b81526001600160a01b03831660048201526024015b60405180910390fd5b600080516020613310833981519152811461147e57604051632a87526960e21b815260048101829052602401611444565b6000805160206133108339815191528390556040516001600160a01b038416907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a2815115611549576000836001600160a01b0316836040516114e591906132a1565b600060405180830381855af49150503d8060008114611520576040519150601f19603f3d011682016040523d82523d6000602084013e611525565b606091505b5050905080611547576040516339b21b5d60e11b815260040160405180910390fd5b505b505050565b6000306001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146115995760405163703e46dd60e11b815260040160405180910390fd5b5060008051602061331083398151915290565b6000600383815481106115c1576115c161302e565b60009182526020808320600390920290910180546001600160a01b03600160601b90910481168452600590925260409092205491925016806116165760405163f4612fe560e01b815260040160405180910390fd5b600082600201848154811061162d5761162d61302e565b906000526020600020906003020190506000816000015490508082600101600082825461165a91906130ae565b909155505060028201546001600160a01b031661169c576040516001600160a01b0384169082156108fc029083906000818181858888f19350505050506116b7565b60028201546116b5906001600160a01b03168483612159565b505b60028201546040805160018152600060208201529081018390526001600160a01b03918216606082015286918891908616907f8975b837fe0d18616c65abb8b843726a32b552ee4feca009944fa658bbb282e79060800160405180910390a4505050505050565b6003818154811061172e57600080fd5b6000918252602090912060039091020180546001909101546001600160601b0382169250600160601b9091046001600160a01b03169060ff8082169161010090041684565b6001600160a01b03848116600090815260056020526040902054166117bb576001600160a01b038416600090815260056020526040902080546001600160a01b031916331790555b6001600160a01b038481166000908152600560205260409020541633146117f5576040516301627e2760e61b815260040160405180910390fd5b6001600160a01b03841660008181526006602052604090819020805460028201805460ff1990921660031783556001830188905561ffff1990911686151561ff001916176101008615150217905590519091907ffe3754ab712090753cf700ac7b99f8a5e0f9c69b698312c2cfd0236b852f83f49061187590849061311d565b60405180910390a25050505050565b6000546001600160a01b031633146118af5760405163c383977560e01b815260040160405180910390fd5b6000836001600160a01b031683836040516118ca91906132a1565b60006040518083038185875af1925050503d8060008114611907576040519150601f19603f3d011682016040523d82523d6000602084013e61190c565b606091505b5050905080611547576040516322092f2f60e11b815260040160405180910390fd5b6000546001600160a01b031633146119595760405163c383977560e01b815260040160405180910390fd5b6001600160a01b038216600081815260046020526040808220805460ff191685151590811790915590519092917f541615e167511d757a7067a700eb54431b256bb458dfdce0ac58bf2ed0aefd4491a35050565b6000546001600160a01b031633146119d85760405163c383977560e01b815260040160405180910390fd5b6001600160a01b038316600081815260046020908152604091829020805469ffffffffffffffffff0019166101006001600160401b03881690810260ff60481b191691909117600160481b60ff8816908102919091179092558351908152918201527fe6996b7f03e9bd02228b99d3d946932e3197f505f60542c4cfbc919441d8a4e6910160405180910390a2505050565b6000546001600160a01b03163314611a955760405163c383977560e01b815260040160405180910390fd5b60006002886001600160601b031681548110611ab357611ab361302e565b60009182526020909120600b9091020160028101879055805460ff60601b1916600160601b8915150217815560038101869055600480820186905560058201859055909150611b0890600683019084906128a9565b50876001600160601b03167f709b1f5fda58af9a4f52dacd1ec404840a8148455700cce155a2bd8cf127ef1a888888888888604051611b4c96959493929190613255565b60405180910390a25050505050505050565b611b8b6040518060600160405280600081526020016000815260200160006001600160a01b031681525090565b60038381548110611b9e57611b9e61302e565b90600052602060002090600302016002018281548110611bc057611bc061302e565b6000918252602091829020604080516060810182526003909302909101805483526001810154938301939093526002909201546001600160a01b031691810191909152905092915050565b6000611c16826120b0565b341015611c3657604051630e3360f160e21b815260040160405180910390fd5b610d458383600034612222565b60008060038381548110611c5957611c5961302e565b600091825260208220600390910201805460028054929450916001600160601b03909116908110611c8c57611c8c61302e565b90600052602060002090600b0201905080600401548260020160018460020180549050611cb9919061305a565b81548110611cc957611cc961302e565b906000526020600020906003020160000154611ce59190613083565b949350505050565b6000611ce58261034986868080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506120b092505050565b611d3c8482610834565b341015611d5c57604051633191f8f160e01b815260040160405180910390fd5b600060038581548110611d7157611d7161302e565b6000918252602080832060039092029091018054600160601b90046001600160a01b0390811684526005909252604090922054919250163314611dc7576040516301627e2760e61b815260040160405180910390fd5b6003600182015460ff166004811115611de257611de2612cbd565b14611e00576040516337cdefcb60e21b815260040160405180910390fd5b80546001600160601b03168215611eb2576002816001600160601b031681548110611e2d57611e2d61302e565b60009182526020909120600b909102015482546001600160601b039182169250168114611eb257815460028301546001600160601b0390911690611e739060019061305a565b6040516001600160601b038416815288907f736e3f52761298c8c0823e1ebf482ed3c5ecb304f743d2d91a7c006e8e8d7a1f9060200160405180910390a45b81546001600160601b0319166001600160601b0382161782556001808301805460ff191690556002830180549182018155600090815260208120346003909302019182558354604051600160601b9091046001600160a01b03169189917f9c9b64db9e130f48381bf697abf638e73117dbfbfd7a4484f2da3ba188f4187d9190a3867f4e6f5cf43b95303e86aee81683df63992061723a829ee012db21dad388756b916000604051611f6491906132d0565b60405180910390a2611f768787612317565b50505050505050565b6000546001600160a01b03163314611faa5760405163c383977560e01b815260040160405180910390fd5b600080546001600160a01b0319166001600160a01b0392909216919091179055565b6001600160a01b03821660009081526004602052604081205460ff166120055760405163e51cf7bf60e01b815260040160405180910390fd5b612010858585611ced565b82101561203057604051630e3360f160e21b815260040160405180910390fd5b6120456001600160a01b0384163330856126bc565b612062576040516312171d8360e31b815260040160405180910390fd5b6120a68686868080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508892508791506122229050565b9695505050505050565b60008060006120be84612798565b5091509150806002836001600160601b0316815481106120e0576120e061302e565b90600052602060002090600b020160040154611ce59190613097565b6000600382815481106121115761211161302e565b600091825260209091206002600390920201015492915050565b6000546001600160a01b031633146121565760405163c383977560e01b815260040160405180910390fd5b50565b6040516001600160a01b03838116602483015260448201839052600091829182919087169060640160408051601f198184030181529181526020820180516001600160e01b031663a9059cbb60e01b179052516121b691906132a1565b6000604051808303816000865af19150503d80600081146121f3576040519150601f19603f3d011682016040523d82523d6000602084013e6121f8565b606091505b50915091508180156120a65750805115806120a65750808060200190518101906120a691906132de565b60008061222e85612798565b505060038054600180820183556001600160601b03841633600160601b02177fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b8385029081019182557fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85d018054928301815560009081526020902091909302018681556002810180546001600160a01b0319166001600160a01b038a16179055909450919250906122df8489612317565b604051339085907f141dfc18aa6a56fc816f44f0e9e2f1ebc92b15ab167770e17db5b084c10ed99590600090a3505050949350505050565b60006003838154811061232c5761232c61302e565b90600052602060002090600302019050600060018260020180549050612352919061305a565b8254600160601b90046001600160a01b03166000908152600660205260408120919250815460ff16600381111561238b5761238b612cbd565b036123a95760405163d8f2465160e01b815260040160405180910390fd5b6001815460ff1660038111156123c1576123c1612cbd565b146126b5576003815460ff1660038111156123de576123de612cbd565b0361252d578460038454600184015460028501546040805192835260ff80831615156020850152610100909204909116151590820152600160601b9091046001600160a01b0316907f45c27c7ea7135714f09b069efa7497d57c38017d4e919c5535ba31dbd5b597e69060600160405180910390a46001810154600282015460405163085dd1c360e21b815260048101889052602481019290925260ff8082161515604484015261010090910416151560648201523090632177470c90608401600060405180830381600087803b1580156124b857600080fd5b505af11580156124cc573d6000803e3d6000fd5b5050604051632b00f57560e11b81526004810188905260248101859052309250635601eaea9150604401600060405180830381600087803b15801561251057600080fd5b505af1158015612524573d6000803e3d6000fd5b505050506126b5565b6002815460ff16600381111561254557612545612cbd565b036126b55760008461255860014361305a565b6040805191406020830152016040516020818303038152906040528051906020012060001c61258791906132fb565b90506004811615600280831615908890875460408051878152861515602082015285151591810191909152600160601b9091046001600160a01b0316907f45c27c7ea7135714f09b069efa7497d57c38017d4e919c5535ba31dbd5b597e69060600160405180910390a460405163085dd1c360e21b81526004810189905260248101849052821515604482015281151560648201523090632177470c90608401600060405180830381600087803b15801561264157600080fd5b505af1158015612655573d6000803e3d6000fd5b5050604051632b00f57560e11b8152600481018b905260248101889052309250635601eaea9150604401600060405180830381600087803b15801561269957600080fd5b505af11580156126ad573d6000803e3d6000fd5b505050505050505b5050505050565b6040516001600160a01b038481166024830152838116604483015260648201839052600091829182919088169060840160408051601f198184030181529181526020820180516001600160e01b03166323b872dd60e01b1790525161272191906132a1565b6000604051808303816000865af19150503d806000811461275e576040519150601f19603f3d011682016040523d82523d6000602084013e612763565b606091505b509150915081801561278d57508051158061278d57508080602001905181019061278d91906132de565b979650505050505050565b600080600060408451106127fe575050506020810151604082015160608301516001600160601b03831615806127d957506002546001600160601b03841610155b156127e357600192505b816000036127f057600391505b806127f9575060015b610d71565b50600193600393508492509050565b828054828255906000526020600020908101928215612848579160200282015b8281111561284857825182559160200191906001019061282d565b506128549291506128d6565b5090565b8260048101928215612848579160200282015b82811115612848578251829060ff1690559160200191906001019061286b565b60405180608001604052806004906020820280368337509192915050565b8260048101928215612848579160200282018281111561284857825182559160200191906001019061282d565b5b8082111561285457600081556001016128d7565b6001600160a01b038116811461215657600080fd5b60006020828403121561291257600080fd5b813561291d816128eb565b9392505050565b801515811461215657600080fd5b6000806040838503121561294557600080fd5b82359150602083013561295781612924565b809150509250929050565b634e487b7160e01b600052604160045260246000fd5b600082601f83011261298957600080fd5b604051608081018181106001600160401b03821117156129ab576129ab612962565b6040528060808401858111156129c057600080fd5b845b818110156129da5780358352602092830192016129c2565b509195945050505050565b600080600060c084860312156129fa57600080fd5b8335612a05816128eb565b92506020840135612a15816128eb565b9150612a248560408601612978565b90509250925092565b60008060408385031215612a4057600080fd5b8235612a4b816128eb565b946020939093013593505050565b600060208284031215612a6b57600080fd5b5035919050565b60008060008060808587031215612a8857600080fd5b84359350602085013592506040850135612aa181612924565b91506060850135612ab181612924565b939692955090935050565b80356001600160601b0381168114612ad357600080fd5b919050565b600060208284031215612aea57600080fd5b610d4582612abc565b8060005b6004811015611547578151845260209384019390910190600101612af7565b60808101610d488284612af3565b6000806000806000806000610140888a031215612b4057600080fd5b612b4988612abc565b96506020880135612b5981612924565b955060408801359450606088013593506080880135925060a08801359150612b848960c08a01612978565b905092959891949750929550565b60008060408385031215612ba557600080fd5b8235612bb0816128eb565b91506020830135612957816128eb565b600082601f830112612bd157600080fd5b81356001600160401b0380821115612beb57612beb612962565b604051601f8301601f19908116603f01168101908282118183101715612c1357612c13612962565b81604052838152866020858801011115612c2c57600080fd5b836020870160208301376000602085830101528094505050505092915050565b60008060408385031215612c5f57600080fd5b8235612c6a816128eb565b915060208301356001600160401b03811115612c8557600080fd5b612c9185828601612bc0565b9150509250929050565b60008060408385031215612cae57600080fd5b50508035926020909101359150565b634e487b7160e01b600052602160045260246000fd5b60058110612ce357612ce3612cbd565b9052565b6001600160601b03851681526001600160a01b038416602082015260808101612d136040830185612cd3565b821515606083015295945050505050565b60008060008060808587031215612d3a57600080fd5b8435612d45816128eb565b9350602085013592506040850135612aa181612924565b600080600060608486031215612d7157600080fd5b8335612d7c816128eb565b92506020840135915060408401356001600160401b03811115612d9e57600080fd5b612daa86828701612bc0565b9150509250925092565b60008060408385031215612dc757600080fd5b8235612dd2816128eb565b9150602083013561295781612924565b600080600060608486031215612df757600080fd5b8335612e02816128eb565b925060208401356001600160401b0381168114612e1e57600080fd5b9150604084013560ff81168114612e3457600080fd5b809150509250925092565b60008060408385031215612e5257600080fd5b8235915060208301356001600160401b03811115612c8557600080fd5b60008083601f840112612e8157600080fd5b5081356001600160401b03811115612e9857600080fd5b602083019150836020828501011115612eb057600080fd5b9250929050565b600080600060408486031215612ecc57600080fd5b83356001600160401b03811115612ee257600080fd5b612eee86828701612e6f565b9094509250506020840135612e34816128eb565b60008060008060808587031215612f1857600080fd5b843593506020850135925060408501356001600160401b03811115612f3c57600080fd5b612f4887828801612bc0565b9250506060850135612ab181612924565b60048110612ce357612ce3612cbd565b60808101612f778287612f59565b602082019490945291151560408301521515606090910152919050565b600080600080600060808688031215612fac57600080fd5b8535945060208601356001600160401b03811115612fc957600080fd5b612fd588828901612e6f565b9095509350506040860135612fe9816128eb565b949793965091946060013592915050565b60006020828403121561300c57600080fd5b81356001600160401b0381111561302257600080fd5b611ce584828501612bc0565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b81810381811115610d4857610d48613044565b634e487b7160e01b600052601260045260246000fd5b6000826130925761309261306d565b500490565b8082028115828204841417610d4857610d48613044565b80820180821115610d4857610d48613044565b6000610120820190508715158252602087602084015286604084015285606084015284608084015260a083018460005b600481101561310e578154835291830191600191820191016130f1565b50505050979650505050505050565b60006080820190506131338260ff855416612f59565b60018301546020830152600283015460ff81161515604084015260ff8160081c16151560608401525092915050565b600181815b8085111561319d57816000190482111561318357613183613044565b8085161561319057918102915b93841c9390800290613167565b509250929050565b6000826131b457506001610d48565b816131c157506000610d48565b81600181146131d757600281146131e1576131fd565b6001915050610d48565b60ff8411156131f2576131f2613044565b50506001821b610d48565b5060208310610133831016604e8410600b8410161715613220575081810a610d48565b61322a8383613162565b806000190482111561323e5761323e613044565b029392505050565b6000610d4560ff8416836131a5565b600061012082019050871515825286602083015285604083015284606083015283608083015261278d60a0830184612af3565b60006020828403121561329a57600080fd5b5051919050565b6000825160005b818110156132c257602081860181015185830152016132a8565b506000920191825250919050565b60208101610d488284612cd3565b6000602082840312156132f057600080fd5b815161291d81612924565b60008261330a5761330a61306d565b50069056fe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbca26469706673582212204bcdc26480adc94ceb9c089d1af202275da9840934fdb8dead13e3defee11c1164736f6c63430008180033", + "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": { + "appeal(uint256,uint256,bytes,bool)": { + "details": "Appeals the ruling of a specified dispute.", + "params": { + "_disputeID": "The ID of the dispute.", + "_jump": "Whether to jump to the parent court or not." + } + }, + "appealCost(uint256,bool)": { + "details": "Gets the cost of appealing a specified dispute.", + "params": { + "_disputeID": "The ID of the dispute.", + "_jump": "Whether to jump to the parent court or not." + }, + "returns": { + "cost": "The appeal cost." + } + }, + "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." + } + }, + "changePinakion(address)": { + "details": "Changes the `pinakion` storage variable.", + "params": { + "_pinakion": "The new value for the `pinakion` storage variable." + } + }, + "constructor": { + "details": "Constructor, initializing the implementation to reduce attack surface." + }, + "createCourt(uint96,bool,uint256,uint256,uint256,uint256,uint256[4])": { + "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.", + "_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." + } + }, + "execute(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.", + "_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,uint256,bool,bool)": { + "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." + } + }, + "initialize(address,address,uint256[4])": { + "details": "Initializer (constructor equivalent for upgradable contracts).", + "params": { + "_courtParameters": "Numeric parameters of General court (minStake, alpha, feeForJuror and jurorsForCourtJump respectively).", + "_governor": "The governor's address.", + "_pinakion": "The address of the token 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." + }, + "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": "KlerosCoreRuler Core arbitrator contract for development and testing 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 + }, + "storageLayout": { + "storage": [ + { + "astId": 16346, + "contract": "src/arbitration/devtools/KlerosCoreRuler.sol:KlerosCoreRuler", + "label": "governor", + "offset": 0, + "slot": "0", + "type": "t_address" + }, + { + "astId": 16349, + "contract": "src/arbitration/devtools/KlerosCoreRuler.sol:KlerosCoreRuler", + "label": "pinakion", + "offset": 0, + "slot": "1", + "type": "t_contract(IERC20)1755" + }, + { + "astId": 16353, + "contract": "src/arbitration/devtools/KlerosCoreRuler.sol:KlerosCoreRuler", + "label": "courts", + "offset": 0, + "slot": "2", + "type": "t_array(t_struct(Court)16297_storage)dyn_storage" + }, + { + "astId": 16357, + "contract": "src/arbitration/devtools/KlerosCoreRuler.sol:KlerosCoreRuler", + "label": "disputes", + "offset": 0, + "slot": "3", + "type": "t_array(t_struct(Dispute)16312_storage)dyn_storage" + }, + { + "astId": 16363, + "contract": "src/arbitration/devtools/KlerosCoreRuler.sol:KlerosCoreRuler", + "label": "currencyRates", + "offset": 0, + "slot": "4", + "type": "t_mapping(t_contract(IERC20)1755,t_struct(CurrencyRate)16327_storage)" + }, + { + "astId": 16368, + "contract": "src/arbitration/devtools/KlerosCoreRuler.sol:KlerosCoreRuler", + "label": "rulers", + "offset": 0, + "slot": "5", + "type": "t_mapping(t_contract(IArbitrableV2)21759,t_address)" + }, + { + "astId": 16374, + "contract": "src/arbitration/devtools/KlerosCoreRuler.sol:KlerosCoreRuler", + "label": "settings", + "offset": 0, + "slot": "6", + "type": "t_mapping(t_contract(IArbitrableV2)21759,t_struct(RulerSettings)16275_storage)" + }, + { + "astId": 16379, + "contract": "src/arbitration/devtools/KlerosCoreRuler.sol:KlerosCoreRuler", + "label": "rulingResults", + "offset": 0, + "slot": "7", + "type": "t_mapping(t_uint256,t_struct(RulingResult)16334_storage)" + } + ], + "types": { + "t_address": { + "encoding": "inplace", + "label": "address", + "numberOfBytes": "20" + }, + "t_array(t_struct(Court)16297_storage)dyn_storage": { + "base": "t_struct(Court)16297_storage", + "encoding": "dynamic_array", + "label": "struct KlerosCoreRuler.Court[]", + "numberOfBytes": "32" + }, + "t_array(t_struct(Dispute)16312_storage)dyn_storage": { + "base": "t_struct(Dispute)16312_storage", + "encoding": "dynamic_array", + "label": "struct KlerosCoreRuler.Dispute[]", + "numberOfBytes": "32" + }, + "t_array(t_struct(Round)16320_storage)dyn_storage": { + "base": "t_struct(Round)16320_storage", + "encoding": "dynamic_array", + "label": "struct KlerosCoreRuler.Round[]", + "numberOfBytes": "32" + }, + "t_array(t_uint256)4_storage": { + "base": "t_uint256", + "encoding": "inplace", + "label": "uint256[4]", + "numberOfBytes": "128" + }, + "t_array(t_uint256)dyn_storage": { + "base": "t_uint256", + "encoding": "dynamic_array", + "label": "uint256[]", + "numberOfBytes": "32" + }, + "t_bool": { + "encoding": "inplace", + "label": "bool", + "numberOfBytes": "1" + }, + "t_contract(IArbitrableV2)21759": { + "encoding": "inplace", + "label": "contract IArbitrableV2", + "numberOfBytes": "20" + }, + "t_contract(IERC20)1755": { + "encoding": "inplace", + "label": "contract IERC20", + "numberOfBytes": "20" + }, + "t_enum(Period)16265": { + "encoding": "inplace", + "label": "enum KlerosCoreRuler.Period", + "numberOfBytes": "1" + }, + "t_enum(RulingMode)16259": { + "encoding": "inplace", + "label": "enum KlerosCoreRuler.RulingMode", + "numberOfBytes": "1" + }, + "t_mapping(t_contract(IArbitrableV2)21759,t_address)": { + "encoding": "mapping", + "key": "t_contract(IArbitrableV2)21759", + "label": "mapping(contract IArbitrableV2 => address)", + "numberOfBytes": "32", + "value": "t_address" + }, + "t_mapping(t_contract(IArbitrableV2)21759,t_struct(RulerSettings)16275_storage)": { + "encoding": "mapping", + "key": "t_contract(IArbitrableV2)21759", + "label": "mapping(contract IArbitrableV2 => struct KlerosCoreRuler.RulerSettings)", + "numberOfBytes": "32", + "value": "t_struct(RulerSettings)16275_storage" + }, + "t_mapping(t_contract(IERC20)1755,t_struct(CurrencyRate)16327_storage)": { + "encoding": "mapping", + "key": "t_contract(IERC20)1755", + "label": "mapping(contract IERC20 => struct KlerosCoreRuler.CurrencyRate)", + "numberOfBytes": "32", + "value": "t_struct(CurrencyRate)16327_storage" + }, + "t_mapping(t_uint256,t_struct(RulingResult)16334_storage)": { + "encoding": "mapping", + "key": "t_uint256", + "label": "mapping(uint256 => struct KlerosCoreRuler.RulingResult)", + "numberOfBytes": "32", + "value": "t_struct(RulingResult)16334_storage" + }, + "t_struct(Court)16297_storage": { + "encoding": "inplace", + "label": "struct KlerosCoreRuler.Court", + "members": [ + { + "astId": 16277, + "contract": "src/arbitration/devtools/KlerosCoreRuler.sol:KlerosCoreRuler", + "label": "parent", + "offset": 0, + "slot": "0", + "type": "t_uint96" + }, + { + "astId": 16279, + "contract": "src/arbitration/devtools/KlerosCoreRuler.sol:KlerosCoreRuler", + "label": "hiddenVotes", + "offset": 12, + "slot": "0", + "type": "t_bool" + }, + { + "astId": 16282, + "contract": "src/arbitration/devtools/KlerosCoreRuler.sol:KlerosCoreRuler", + "label": "children", + "offset": 0, + "slot": "1", + "type": "t_array(t_uint256)dyn_storage" + }, + { + "astId": 16284, + "contract": "src/arbitration/devtools/KlerosCoreRuler.sol:KlerosCoreRuler", + "label": "minStake", + "offset": 0, + "slot": "2", + "type": "t_uint256" + }, + { + "astId": 16286, + "contract": "src/arbitration/devtools/KlerosCoreRuler.sol:KlerosCoreRuler", + "label": "alpha", + "offset": 0, + "slot": "3", + "type": "t_uint256" + }, + { + "astId": 16288, + "contract": "src/arbitration/devtools/KlerosCoreRuler.sol:KlerosCoreRuler", + "label": "feeForJuror", + "offset": 0, + "slot": "4", + "type": "t_uint256" + }, + { + "astId": 16290, + "contract": "src/arbitration/devtools/KlerosCoreRuler.sol:KlerosCoreRuler", + "label": "jurorsForCourtJump", + "offset": 0, + "slot": "5", + "type": "t_uint256" + }, + { + "astId": 16294, + "contract": "src/arbitration/devtools/KlerosCoreRuler.sol:KlerosCoreRuler", + "label": "timesPerPeriod", + "offset": 0, + "slot": "6", + "type": "t_array(t_uint256)4_storage" + }, + { + "astId": 16296, + "contract": "src/arbitration/devtools/KlerosCoreRuler.sol:KlerosCoreRuler", + "label": "disabled", + "offset": 0, + "slot": "10", + "type": "t_bool" + } + ], + "numberOfBytes": "352" + }, + "t_struct(CurrencyRate)16327_storage": { + "encoding": "inplace", + "label": "struct KlerosCoreRuler.CurrencyRate", + "members": [ + { + "astId": 16322, + "contract": "src/arbitration/devtools/KlerosCoreRuler.sol:KlerosCoreRuler", + "label": "feePaymentAccepted", + "offset": 0, + "slot": "0", + "type": "t_bool" + }, + { + "astId": 16324, + "contract": "src/arbitration/devtools/KlerosCoreRuler.sol:KlerosCoreRuler", + "label": "rateInEth", + "offset": 1, + "slot": "0", + "type": "t_uint64" + }, + { + "astId": 16326, + "contract": "src/arbitration/devtools/KlerosCoreRuler.sol:KlerosCoreRuler", + "label": "rateDecimals", + "offset": 9, + "slot": "0", + "type": "t_uint8" + } + ], + "numberOfBytes": "32" + }, + "t_struct(Dispute)16312_storage": { + "encoding": "inplace", + "label": "struct KlerosCoreRuler.Dispute", + "members": [ + { + "astId": 16299, + "contract": "src/arbitration/devtools/KlerosCoreRuler.sol:KlerosCoreRuler", + "label": "courtID", + "offset": 0, + "slot": "0", + "type": "t_uint96" + }, + { + "astId": 16302, + "contract": "src/arbitration/devtools/KlerosCoreRuler.sol:KlerosCoreRuler", + "label": "arbitrated", + "offset": 12, + "slot": "0", + "type": "t_contract(IArbitrableV2)21759" + }, + { + "astId": 16305, + "contract": "src/arbitration/devtools/KlerosCoreRuler.sol:KlerosCoreRuler", + "label": "period", + "offset": 0, + "slot": "1", + "type": "t_enum(Period)16265" + }, + { + "astId": 16307, + "contract": "src/arbitration/devtools/KlerosCoreRuler.sol:KlerosCoreRuler", + "label": "ruled", + "offset": 1, + "slot": "1", + "type": "t_bool" + }, + { + "astId": 16311, + "contract": "src/arbitration/devtools/KlerosCoreRuler.sol:KlerosCoreRuler", + "label": "rounds", + "offset": 0, + "slot": "2", + "type": "t_array(t_struct(Round)16320_storage)dyn_storage" + } + ], + "numberOfBytes": "96" + }, + "t_struct(Round)16320_storage": { + "encoding": "inplace", + "label": "struct KlerosCoreRuler.Round", + "members": [ + { + "astId": 16314, + "contract": "src/arbitration/devtools/KlerosCoreRuler.sol:KlerosCoreRuler", + "label": "totalFeesForJurors", + "offset": 0, + "slot": "0", + "type": "t_uint256" + }, + { + "astId": 16316, + "contract": "src/arbitration/devtools/KlerosCoreRuler.sol:KlerosCoreRuler", + "label": "sumFeeRewardPaid", + "offset": 0, + "slot": "1", + "type": "t_uint256" + }, + { + "astId": 16319, + "contract": "src/arbitration/devtools/KlerosCoreRuler.sol:KlerosCoreRuler", + "label": "feeToken", + "offset": 0, + "slot": "2", + "type": "t_contract(IERC20)1755" + } + ], + "numberOfBytes": "96" + }, + "t_struct(RulerSettings)16275_storage": { + "encoding": "inplace", + "label": "struct KlerosCoreRuler.RulerSettings", + "members": [ + { + "astId": 16268, + "contract": "src/arbitration/devtools/KlerosCoreRuler.sol:KlerosCoreRuler", + "label": "rulingMode", + "offset": 0, + "slot": "0", + "type": "t_enum(RulingMode)16259" + }, + { + "astId": 16270, + "contract": "src/arbitration/devtools/KlerosCoreRuler.sol:KlerosCoreRuler", + "label": "presetRuling", + "offset": 0, + "slot": "1", + "type": "t_uint256" + }, + { + "astId": 16272, + "contract": "src/arbitration/devtools/KlerosCoreRuler.sol:KlerosCoreRuler", + "label": "presetTied", + "offset": 0, + "slot": "2", + "type": "t_bool" + }, + { + "astId": 16274, + "contract": "src/arbitration/devtools/KlerosCoreRuler.sol:KlerosCoreRuler", + "label": "presetOverridden", + "offset": 1, + "slot": "2", + "type": "t_bool" + } + ], + "numberOfBytes": "96" + }, + "t_struct(RulingResult)16334_storage": { + "encoding": "inplace", + "label": "struct KlerosCoreRuler.RulingResult", + "members": [ + { + "astId": 16329, + "contract": "src/arbitration/devtools/KlerosCoreRuler.sol:KlerosCoreRuler", + "label": "ruling", + "offset": 0, + "slot": "0", + "type": "t_uint256" + }, + { + "astId": 16331, + "contract": "src/arbitration/devtools/KlerosCoreRuler.sol:KlerosCoreRuler", + "label": "tied", + "offset": 0, + "slot": "1", + "type": "t_bool" + }, + { + "astId": 16333, + "contract": "src/arbitration/devtools/KlerosCoreRuler.sol:KlerosCoreRuler", + "label": "overridden", + "offset": 1, + "slot": "1", + "type": "t_bool" + } + ], + "numberOfBytes": "64" + }, + "t_uint256": { + "encoding": "inplace", + "label": "uint256", + "numberOfBytes": "32" + }, + "t_uint64": { + "encoding": "inplace", + "label": "uint64", + "numberOfBytes": "8" + }, + "t_uint8": { + "encoding": "inplace", + "label": "uint8", + "numberOfBytes": "1" + }, + "t_uint96": { + "encoding": "inplace", + "label": "uint96", + "numberOfBytes": "12" + } + } + } +} diff --git a/contracts/deployments/arbitrum/KlerosCoreRulerNeo_Proxy.json b/contracts/deployments/arbitrum/KlerosCoreRulerNeo_Proxy.json new file mode 100644 index 000000000..89a258aaa --- /dev/null +++ b/contracts/deployments/arbitrum/KlerosCoreRulerNeo_Proxy.json @@ -0,0 +1,95 @@ +{ + "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" + } + ], + "transactionHash": "0x467a826ff2b4ec23bed9936441307123e1609acf8ce0cf70f4fffe7c2d25671f", + "receipt": { + "to": null, + "from": "0xf1C7c037891525E360C59f708739Ac09A7670c59", + "contractAddress": "0xc0169e0B19aE02ac4fADD689260CF038726DFE13", + "transactionIndex": 2, + "gasUsed": "314451", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000100004000000000000000000000000000060008000000000000000000000000220000000000000000000800000080000000000000000000000000000000000000000000000800000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000060000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x905e9059a1f41a82e3c5c67e027ff256285596bc1cef98acdbd330f043a8a44d", + "transactionHash": "0x467a826ff2b4ec23bed9936441307123e1609acf8ce0cf70f4fffe7c2d25671f", + "logs": [ + { + "transactionIndex": 2, + "blockNumber": 286701284, + "transactionHash": "0x467a826ff2b4ec23bed9936441307123e1609acf8ce0cf70f4fffe7c2d25671f", + "address": "0xc0169e0B19aE02ac4fADD689260CF038726DFE13", + "topics": [ + "0x0c907a651f88974ed0d9423aacc8b998c40eedf39920e2c3bdae0adcc486a761", + "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000000000000000000000000000000" + ], + "data": "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002710000000000000000000000000000000000000000000000000016345785d8a000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "logIndex": 0, + "blockHash": "0x905e9059a1f41a82e3c5c67e027ff256285596bc1cef98acdbd330f043a8a44d" + }, + { + "transactionIndex": 2, + "blockNumber": 286701284, + "transactionHash": "0x467a826ff2b4ec23bed9936441307123e1609acf8ce0cf70f4fffe7c2d25671f", + "address": "0xc0169e0B19aE02ac4fADD689260CF038726DFE13", + "topics": [ + "0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000000001", + "logIndex": 1, + "blockHash": "0x905e9059a1f41a82e3c5c67e027ff256285596bc1cef98acdbd330f043a8a44d" + } + ], + "blockNumber": 286701284, + "cumulativeGasUsed": "348983", + "status": 1, + "byzantium": true + }, + "args": [ + "0x85093b5EDa4F2e2E2fEDae34Da91239D6a08e324", + "0x05d3177d000000000000000000000000f1c7c037891525e360c59f708739ac09a7670c59000000000000000000000000330bd769382cfc6d50175903434ccc8d206dcae500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002710000000000000000000000000000000000000000000000000016345785d8a00000000000000000000000000000000000000000000000000000000000000000010" + ], + "numDeployments": 1, + "solcInputHash": "072c3d36aa3704de09a27a044cf00231", + "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\":\"KlerosCoreRulerProxy\"},\"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": "0x608060405234801561001057600080fd5b5060405161030238038061030283398101604081905261002f91610151565b8181817f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc55805160001461010e576000826001600160a01b031682604051610077919061021f565b600060405180830381855af49150503d80600081146100b2576040519150601f19603f3d011682016040523d82523d6000602084013e6100b7565b606091505b505090508061010c5760405162461bcd60e51b815260206004820152601860248201527f50726f787920436f6e7374727563746f72206661696c65640000000000000000604482015260640160405180910390fd5b505b5050505061023b565b634e487b7160e01b600052604160045260246000fd5b60005b83811015610148578181015183820152602001610130565b50506000910152565b6000806040838503121561016457600080fd5b82516001600160a01b038116811461017b57600080fd5b60208401519092506001600160401b038082111561019857600080fd5b818501915085601f8301126101ac57600080fd5b8151818111156101be576101be610117565b604051601f8201601f19908116603f011681019083821181831017156101e6576101e6610117565b816040528281528860208487010111156101ff57600080fd5b61021083602083016020880161012d565b80955050505050509250929050565b6000825161023181846020870161012d565b9190910192915050565b60b9806102496000396000f3fe608060405236603757603560317f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5490565b6060565b005b603560317f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5490565b3660008037600080366000845af43d6000803e808015607e573d6000f35b3d6000fdfea26469706673582212205e24db8a42d0caaa77ce845dfb341502dc3b700c5ccf0c51c4cf914535a4a64564736f6c63430008180033", + "deployedBytecode": "0x608060405236603757603560317f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5490565b6060565b005b603560317f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5490565b3660008037600080366000845af43d6000803e808015607e573d6000f35b3d6000fdfea26469706673582212205e24db8a42d0caaa77ce845dfb341502dc3b700c5ccf0c51c4cf914535a4a64564736f6c63430008180033", + "devdoc": { + "kind": "dev", + "methods": {}, + "version": 1 + }, + "userdoc": { + "kind": "user", + "methods": {}, + "version": 1 + }, + "storageLayout": { + "storage": [], + "types": null + } +} diff --git a/contracts/lib/forge-std b/contracts/lib/forge-std index 066ff16c5..8f24d6b04 160000 --- a/contracts/lib/forge-std +++ b/contracts/lib/forge-std @@ -1 +1 @@ -Subproject commit 066ff16c5c03e6f931cd041fd366bc4be1fae82a +Subproject commit 8f24d6b04c92975e0795b5868aa0d783251cdeaa diff --git a/contracts/package.json b/contracts/package.json index d9729185b..e2441d609 100644 --- a/contracts/package.json +++ b/contracts/package.json @@ -22,6 +22,7 @@ "clean": "hardhat clean", "check": "hardhat check", "test": "TS_NODE_TRANSPILE_ONLY=1 hardhat test", + "coverage": "scripts/coverage.sh", "start": "hardhat node --tags nop", "start-local": "hardhat node --tags Arbitration,HomeArbitrable --hostname 0.0.0.0", "deploy": "hardhat deploy", diff --git a/contracts/scripts/coverage.sh b/contracts/scripts/coverage.sh new file mode 100755 index 000000000..4f7327a91 --- /dev/null +++ b/contracts/scripts/coverage.sh @@ -0,0 +1,62 @@ +#!/usr/bin/env bash + +set -e # exit on error + +rm -rf coverage +mkdir -p coverage + +# Generate the Forge coverage report +forge clean +if [ "$CI" != "true" ]; then + forge coverage --report summary --report lcov --report-file coverage/lcov-forge.info +else + # FIXME: Temporarily workaround a CI issue + touch coverage/lcov-forge.info +fi + +# Generate the Hardhat coverage report +yarn clean +yarn hardhat coverage --solcoverjs ./.solcover.js --temp artifacts --show-stack-traces --testfiles "test/**/*.ts" +mv coverage/lcov.info coverage/lcov-hardhat.info + +# Make the Hardhat report paths relative for consistency with Forge coverage report +sed -i -e 's/\/.*\/kleros-v2\/contracts\///g' coverage/lcov-hardhat.info + +# Merge the two reports +lcov \ + --ignore-errors format \ + --ignore-errors inconsistent \ + --ignore-errors empty \ + --rc max_message_count=3 \ + --rc derive_function_end_line=0 \ + --rc branch_coverage=1 \ + --add-tracefile coverage/lcov-hardhat.info \ + --add-tracefile coverage/lcov-forge.info \ + --output-file coverage/merged-lcov.info + +# Filter out unnecessary contracts from the report +lcov \ + --ignore-errors format \ + --ignore-errors inconsistent \ + --ignore-errors empty \ + --ignore-errors unused \ + --rc max_message_count=3 \ + --rc branch_coverage=1 \ + --rc derive_function_end_line=0 \ + --remove coverage/merged-lcov.info \ + --output-file coverage/filtered-lcov.info \ + "../node_modules" "src/test" "src/token" "src/kleros-v1" "src/proxy/mock" "src/gateway/mock" "src/rng/mock" + +# Open more granular breakdown in browser +if [ "$CI" != "true" ]; then + # Generate the HTML report + genhtml coverage/filtered-lcov.info \ + --ignore-errors format \ + --ignore-errors inconsistent \ + --ignore-errors empty \ + --ignore-errors category \ + --rc branch_coverage=1 \ + --rc max_message_count=3 \ + -o coverage + open coverage/index.html +fi diff --git a/contracts/src/arbitration/KlerosCoreBase.sol b/contracts/src/arbitration/KlerosCoreBase.sol index ce6ed6202..2e062e473 100644 --- a/contracts/src/arbitration/KlerosCoreBase.sol +++ b/contracts/src/arbitration/KlerosCoreBase.sol @@ -113,7 +113,7 @@ abstract contract KlerosCoreBase is IArbitratorV2 { event AppealDecision(uint256 indexed _disputeID, IArbitrableV2 indexed _arbitrable); event Draw(address indexed _address, uint256 indexed _disputeID, uint256 _roundID, uint256 _voteID); event CourtCreated( - uint256 indexed _courtID, + uint96 indexed _courtID, uint96 indexed _parent, bool _hiddenVotes, uint256 _minStake, @@ -237,8 +237,10 @@ abstract contract KlerosCoreBase is IArbitratorV2 { sortitionModule.createTree(bytes32(uint256(GENERAL_COURT)), _sortitionExtraData); + uint256[] memory supportedDisputeKits = new uint256[](1); + supportedDisputeKits[0] = DISPUTE_KIT_CLASSIC; emit CourtCreated( - 1, + GENERAL_COURT, court.parent, _hiddenVotes, _courtParameters[0], @@ -246,7 +248,7 @@ abstract contract KlerosCoreBase is IArbitratorV2 { _courtParameters[2], _courtParameters[3], _timesPerPeriod, - new uint256[](0) + supportedDisputeKits ); _enableDisputeKit(GENERAL_COURT, DISPUTE_KIT_CLASSIC, true); } @@ -351,7 +353,7 @@ abstract contract KlerosCoreBase is IArbitratorV2 { if (_supportedDisputeKits[i] == 0 || _supportedDisputeKits[i] >= disputeKits.length) { revert WrongDisputeKitIndex(); } - court.supportedDisputeKits[_supportedDisputeKits[i]] = true; + _enableDisputeKit(uint96(courtID), _supportedDisputeKits[i], true); } // Check that Classic DK support was added. if (!court.supportedDisputeKits[DISPUTE_KIT_CLASSIC]) revert MustSupportDisputeKitClassic(); @@ -370,7 +372,7 @@ abstract contract KlerosCoreBase is IArbitratorV2 { // Update the parent. courts[_parent].children.push(courtID); emit CourtCreated( - courtID, + uint96(courtID), _parent, _hiddenVotes, _minStake, @@ -1061,7 +1063,7 @@ abstract contract KlerosCoreBase is IArbitratorV2 { bool _alreadyTransferred, OnError _onError ) internal returns (bool) { - if (_courtID == FORKING_COURT || _courtID > courts.length) { + if (_courtID == FORKING_COURT || _courtID >= courts.length) { _stakingFailed(_onError, StakingResult.CannotStakeInThisCourt); // Staking directly into the forking court is not allowed. return false; } @@ -1102,6 +1104,7 @@ abstract contract KlerosCoreBase is IArbitratorV2 { if (_result == StakingResult.CannotStakeInMoreCourts) revert StakingInTooManyCourts(); if (_result == StakingResult.CannotStakeInThisCourt) revert StakingNotPossibeInThisCourt(); 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. @@ -1147,13 +1150,11 @@ abstract contract KlerosCoreBase is IArbitratorV2 { error SortitionModuleOnly(); error UnsuccessfulCall(); error InvalidDisputKitParent(); - error DepthLevelMax(); error MinStakeLowerThanParentCourt(); error UnsupportedDisputeKit(); error InvalidForkingCourtAsParent(); error WrongDisputeKitIndex(); error CannotDisableClassicDK(); - error ArraysLengthMismatch(); error StakingInTooManyCourts(); error StakingNotPossibeInThisCourt(); error StakingLessThanCourtMinStake(); @@ -1177,4 +1178,5 @@ abstract contract KlerosCoreBase is IArbitratorV2 { error TransferFailed(); error WhenNotPausedOnly(); error WhenPausedOnly(); + error StakingZeroWhenNoStake(); } diff --git a/contracts/src/arbitration/SortitionModuleBase.sol b/contracts/src/arbitration/SortitionModuleBase.sol index 24e32e6ea..642f9b627 100644 --- a/contracts/src/arbitration/SortitionModuleBase.sol +++ b/contracts/src/arbitration/SortitionModuleBase.sol @@ -206,13 +206,14 @@ abstract contract SortitionModuleBase is ISortitionModule { DelayedStake storage delayedStake = delayedStakes[i]; // Delayed stake could've been manually removed already. In this case simply move on to the next item. if (delayedStake.account != address(0)) { + // Nullify the index so the delayed stake won't get deleted before its own execution. + delete latestDelayedStakeIndex[delayedStake.account][delayedStake.courtID]; core.setStakeBySortitionModule( delayedStake.account, delayedStake.courtID, delayedStake.stake, delayedStake.alreadyTransferred ); - delete latestDelayedStakeIndex[delayedStake.account][delayedStake.courtID]; delete delayedStakes[i]; } } @@ -265,13 +266,16 @@ abstract contract SortitionModuleBase is ISortitionModule { uint256 currentStake = stakeOf(_account, _courtID); uint256 nbCourts = juror.courtIDs.length; - if (_newStake == 0 && (nbCourts >= MAX_STAKE_PATHS || currentStake == 0)) { + if (currentStake == 0 && nbCourts >= MAX_STAKE_PATHS) { return (0, 0, StakingResult.CannotStakeInMoreCourts); // Prevent staking beyond MAX_STAKE_PATHS but unstaking is always allowed. } - if (phase != Phase.staking) { - pnkWithdrawal = _deleteDelayedStake(_courtID, _account); + if (currentStake == 0 && _newStake == 0) { + return (0, 0, StakingResult.CannotStakeZeroWhenNoStake); // Forbid staking 0 amount when current stake is 0 to avoid flaky behaviour. + } + pnkWithdrawal = _deleteDelayedStake(_courtID, _account); + 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; diff --git a/contracts/src/arbitration/dispute-kits/DisputeKitClassic.sol b/contracts/src/arbitration/dispute-kits/DisputeKitClassic.sol index 0aa857091..12d4e45c5 100644 --- a/contracts/src/arbitration/dispute-kits/DisputeKitClassic.sol +++ b/contracts/src/arbitration/dispute-kits/DisputeKitClassic.sol @@ -238,7 +238,6 @@ contract DisputeKitClassic is IDisputeKit, Initializable, UUPSProxiable { (uint96 courtID, , , , ) = core.disputes(_coreDisputeID); bytes32 key = bytes32(uint256(courtID)); // Get the ID of the tree. - // TODO: Handle the situation when no one has staked yet. drawnAddress = sortitionModule.draw(key, _coreDisputeID, _nonce); if (_postDrawCheck(_coreDisputeID, drawnAddress)) { @@ -603,6 +602,10 @@ contract DisputeKitClassic is IDisputeKit, Initializable, UUPSProxiable { /// @param _coreDisputeID ID of the dispute in the core contract. /// @param _juror Chosen address. /// @return Whether the address can be drawn or not. + /// Note that we don't 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 since we check for insolvency anyway. function _postDrawCheck(uint256 _coreDisputeID, address _juror) internal view returns (bool) { (uint96 courtID, , , , ) = core.disputes(_coreDisputeID); uint256 lockedAmountPerJuror = core diff --git a/contracts/src/arbitration/dispute-kits/DisputeKitSybilResistant.sol b/contracts/src/arbitration/dispute-kits/DisputeKitSybilResistant.sol index 40b805c05..dc571cfbf 100644 --- a/contracts/src/arbitration/dispute-kits/DisputeKitSybilResistant.sol +++ b/contracts/src/arbitration/dispute-kits/DisputeKitSybilResistant.sol @@ -255,7 +255,6 @@ contract DisputeKitSybilResistant is IDisputeKit, Initializable, UUPSProxiable { (uint96 courtID, , , , ) = core.disputes(_coreDisputeID); bytes32 key = bytes32(uint256(courtID)); // Get the ID of the tree. - // TODO: Handle the situation when no one has staked yet. drawnAddress = sortitionModule.draw(key, _coreDisputeID, _nonce); if (_postDrawCheck(_coreDisputeID, drawnAddress) && !round.alreadyDrawn[drawnAddress]) { @@ -621,6 +620,10 @@ contract DisputeKitSybilResistant is IDisputeKit, Initializable, UUPSProxiable { /// @param _coreDisputeID ID of the dispute in the core contract. /// @param _juror Chosen address. /// @return Whether the address can be drawn or not. + /// Note that we don't 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 since we check for insolvency anyway. function _postDrawCheck(uint256 _coreDisputeID, address _juror) internal view returns (bool) { (uint96 courtID, , , , ) = core.disputes(_coreDisputeID); uint256 lockedAmountPerJuror = core diff --git a/contracts/src/arbitration/interfaces/IDisputeKit.sol b/contracts/src/arbitration/interfaces/IDisputeKit.sol index 86430f663..32e0bb7fb 100644 --- a/contracts/src/arbitration/interfaces/IDisputeKit.sol +++ b/contracts/src/arbitration/interfaces/IDisputeKit.sol @@ -41,6 +41,7 @@ interface IDisputeKit { /// @param _coreDisputeID The ID of the dispute 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. function createDispute( uint256 _coreDisputeID, uint256 _numberOfChoices, diff --git a/contracts/src/libraries/Constants.sol b/contracts/src/libraries/Constants.sol index 44e9b4cd6..f393b4792 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. +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 DISPUTE_KIT_CLASSIC = 1; // Index of the default DK. 0 index is skipped. // Sortition Module @@ -33,5 +33,6 @@ enum StakingResult { CannotStakeInThisCourt, CannotStakeLessThanMinStake, CannotStakeMoreThanMaxStakePerJuror, - CannotStakeMoreThanMaxTotalStaked + CannotStakeMoreThanMaxTotalStaked, + CannotStakeZeroWhenNoStake } diff --git a/contracts/src/test/KlerosCoreMock.sol b/contracts/src/test/KlerosCoreMock.sol new file mode 100644 index 000000000..76bb75f2c --- /dev/null +++ b/contracts/src/test/KlerosCoreMock.sol @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: MIT + +/// @custom:authors: [@unknownunknown1] +/// @custom:reviewers: [] +/// @custom:auditors: [] +/// @custom:bounties: [] +/// @custom:deployments: [] + +pragma solidity 0.8.24; + +import "../arbitration/KlerosCore.sol"; + +/// @title KlerosCoreMock +/// KlerosCore with view functions to use in Foundry tests. +contract KlerosCoreMock is KlerosCore { + function getCourtChildren(uint256 _courtId) external view returns (uint256[] memory children) { + children = courts[_courtId].children; + } + + function extraDataToCourtIDMinJurorsDisputeKit( + bytes memory _extraData + ) external view returns (uint96 courtID, uint256 minJurors, uint256 disputeKitID) { + (courtID, minJurors, disputeKitID) = _extraDataToCourtIDMinJurorsDisputeKit(_extraData); + } +} diff --git a/contracts/src/test/SortitionModuleMock.sol b/contracts/src/test/SortitionModuleMock.sol new file mode 100644 index 000000000..bfe911dfe --- /dev/null +++ b/contracts/src/test/SortitionModuleMock.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: MIT + +/** + * @custom:authors: [unknownunknown1] + * @custom:reviewers: [] + * @custom:auditors: [] + * @custom:bounties: [] + * @custom:deployments: [] + */ + +pragma solidity 0.8.24; + +import "../arbitration/SortitionModule.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]; + K = tree.K; + nodeLength = tree.nodes.length; + } +} diff --git a/contracts/test/arbitration/index.ts b/contracts/test/arbitration/index.ts index 5c861c537..fa2bc24f3 100644 --- a/contracts/test/arbitration/index.ts +++ b/contracts/test/arbitration/index.ts @@ -30,7 +30,7 @@ describe("DisputeKitClassic", async () => { expect(events2[0].args._feeForJuror).to.equal(ethers.parseUnits("0.1", 18)); expect(events2[0].args._jurorsForCourtJump).to.equal(256); expect(events2[0].args._timesPerPeriod).to.deep.equal([0, 0, 0, 10]); - expect(events2[0].args._supportedDisputeKits).to.deep.equal([]); + expect(events2[0].args._supportedDisputeKits).to.deep.equal([1]); const events3 = await core.queryFilter(core.filters.DisputeKitEnabled()); expect(events3.length).to.equal(1); diff --git a/contracts/test/foundry/Contract.t.sol b/contracts/test/foundry/Contract.t.sol deleted file mode 100644 index e69de29bb..000000000 diff --git a/contracts/test/foundry/KlerosCore.t.sol b/contracts/test/foundry/KlerosCore.t.sol new file mode 100644 index 000000000..56e33c9c5 --- /dev/null +++ b/contracts/test/foundry/KlerosCore.t.sol @@ -0,0 +1,2706 @@ +// 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, IArbitratorV2} from "../../src/test/KlerosCoreMock.sol"; +import {IDisputeKit} from "../../src/arbitration/interfaces/IDisputeKit.sol"; +import {DisputeKitClassic} 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"; + +contract KlerosCoreTest is Test { + event Initialized(uint64 version); + + KlerosCoreMock core; + DisputeKitClassic disputeKit; + SortitionModuleMock sortitionModule; + BlockHashRNG rng; + PNK pinakion; + TestERC20 feeToken; + 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"); + + 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)", governor, address(proxyCore)); + + 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 + ); + 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)", governor, address(proxyCore)); + + 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 + ); + } + + // ****************************************** // + // * 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.StakingNotPossibeInThisCourt.selector); + vm.prank(staker1); + core.setStake(FORKING_COURT, 1000); + + uint96 badCourtID = 2; + vm.expectRevert(KlerosCoreBase.StakingNotPossibeInThisCourt.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); + 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); + 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.StakeDelayedAlreadyTransferred(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, true, "Should be flagged as transferred"); + + (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, 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)), 1500, "Wrong token balance of the core"); + assertEq(pinakion.balanceOf(staker1), 999999999999998500, "Wrong token balance of staker1"); + assertEq(pinakion.allowance(staker1, address(core)), 999999999999998500, "Wrong allowance amount"); + } + + 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.StakeDelayedNotTransferred(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 will remain + 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, 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 see that locked tokens will count when increasing the stake. We check that the court won't take the full stake + // but only the remaining part. + vm.prank(staker1); + core.setStake(GENERAL_COURT, 5000); + + (totalStaked, totalLocked, stakedInCourt, nbCourts) = sortitionModule.getJurorBalance(staker1, GENERAL_COURT); + assertEq(totalStaked, 5000, "Wrong amount total staked"); + 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)), 5000, "Locked tokens should stay in the core"); + assertEq(pinakion.balanceOf(staker1), 999999999999995000, "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); + + vm.prank(staker1); + core.setStake(GENERAL_COURT, 1500); + assertEq(pinakion.balanceOf(address(core)), 11500, "Wrong token balance of the core"); + assertEq(pinakion.balanceOf(staker1), 999999999999998500, "Wrong token balance of staker1"); + + vm.prank(staker2); + core.setStake(GENERAL_COURT, 0); + assertEq(pinakion.balanceOf(staker2), 999999999999990000, "Wrong token balance of staker2"); // Balance should not change since wrong phase + + vm.prank(staker1); + vm.expectEmit(true, true, true, true); + emit SortitionModuleBase.StakeDelayedAlreadyTransferredWithdrawn(staker1, GENERAL_COURT, 1500); + 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); + + // First delayed stake should be nullified + 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"); + + (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 for staker2"); + + (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, true, "Should be true for staker1"); + + assertEq(pinakion.balanceOf(address(core)), 11800, "Wrong token balance of the core"); + assertEq(pinakion.balanceOf(staker1), 999999999999998200, "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 since he has consecutive delayed stakes + assertEq(totalStaked, 1800, "Wrong amount total staked"); + assertEq(totalLocked, 0, "Wrong amount locked"); + assertEq(stakedInCourt, 0, "Wrong amount staked in court"); + assertEq(nbCourts, 1, "Wrong amount staked in court"); + + 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)), 1800, "Wrong token balance of the core"); + + vm.expectEmit(true, true, true, true); + emit SortitionModuleBase.StakeSet(staker1, GENERAL_COURT, 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_deleteDelayedStake() public { + // Check that the delayed stake gets deleted without execution if the juror changed his stake in staking phase before its execution. + 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 + + vm.prank(staker1); + core.setStake(GENERAL_COURT, 1500); // Create delayed stake + + (uint256 totalStaked, , uint256 stakedInCourt, ) = sortitionModule.getJurorBalance(staker1, GENERAL_COURT); + assertEq(totalStaked, 1500, "Wrong amount total staked"); + assertEq(stakedInCourt, 1000, "Wrong amount staked in court"); + assertEq(pinakion.balanceOf(staker1), 999999999999998500, "Wrong token balance of the staker1"); + assertEq(pinakion.balanceOf(address(core)), 1500, "Wrong token balance of the core"); + + (address account, uint96 courtID, uint256 stake, bool alreadyTransferred) = sortitionModule.delayedStakes(1); + assertEq(account, staker1, "Wrong account"); + assertEq(courtID, GENERAL_COURT, "Wrong court id"); + assertEq(stake, 1500, "Wrong amount for delayed stake"); + assertEq(alreadyTransferred, true, "Should be true"); + + vm.warp(block.timestamp + maxDrawingTime); + sortitionModule.passPhase(); // Staking phase + + vm.prank(staker1); + core.setStake(GENERAL_COURT, 1700); // Set stake 2nd time, this time in staking phase to see that the delayed stake will be nullified. + + (totalStaked, , stakedInCourt, ) = sortitionModule.getJurorBalance(staker1, GENERAL_COURT); + assertEq(totalStaked, 1700, "Wrong amount total staked"); + assertEq(stakedInCourt, 1700, "Wrong amount staked in court"); + assertEq(pinakion.balanceOf(staker1), 999999999999998300, "Wrong token balance of the staker1"); + assertEq(pinakion.balanceOf(address(core)), 1700, "Wrong token balance of the core"); + + sortitionModule.executeDelayedStakes(1); + (account, courtID, stake, alreadyTransferred) = sortitionModule.delayedStakes(1); + // Check that delayed stake is deleted + 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"); + } + + 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, false); + } + + // *************************************** // + // * 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 DisputeKitClassic.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"); + + ( + 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, but the current stake will only allow 1. + + (uint256 totalStaked, uint256 totalLocked, uint256 stakedInCourt, ) = sortitionModule.getJurorBalance( + staker1, + GENERAL_COURT + ); + assertEq(totalStaked, 1500, "Wrong amount total staked"); + assertEq(totalLocked, 1000, "Wrong amount locked"); // 1000 per draw + assertEq(stakedInCourt, 1500, "Wrong amount staked in court"); + assertEq(sortitionModule.disputesWithoutJurors(), 1, "Wrong disputesWithoutJurors count"); + + KlerosCoreBase.Round memory round = core.getRoundInfo(disputeID, 0); + assertEq(round.drawIterations, 3, "Wrong drawIterations number"); + + vm.prank(staker1); + core.setStake(GENERAL_COURT, 3000); // Set stake to the minimal amount to cover the full dispute. The stake will be updated in Drawing phase since it's an increase. + + vm.expectEmit(true, true, true, true); + emit SortitionModuleBase.StakeLocked(staker1, 1000, false); + vm.expectEmit(true, true, true, true); + emit KlerosCoreBase.Draw(staker1, disputeID, roundID, 1); // VoteID = 1 + vm.expectEmit(true, true, true, true); + emit SortitionModuleBase.StakeLocked(staker1, 1000, false); + vm.expectEmit(true, true, true, true); + emit KlerosCoreBase.Draw(staker1, disputeID, roundID, 2); // VoteID = 2 + + core.draw(disputeID, DEFAULT_NB_OF_JURORS); + + (totalStaked, totalLocked, stakedInCourt, ) = sortitionModule.getJurorBalance(staker1, GENERAL_COURT); + assertEq(totalStaked, 3000, "Wrong amount total staked"); + assertEq(totalLocked, 3000, "Wrong amount locked"); // 1000 per draw and the juror was drawn 3 times + assertEq(stakedInCourt, 1500, "Wrong amount staked in court"); + assertEq(sortitionModule.disputesWithoutJurors(), 0, "Wrong disputesWithoutJurors count"); + + round = core.getRoundInfo(disputeID, roundID); + assertEq(round.drawIterations, 5, "Wrong drawIterations number"); // It's 5 because we needed only 2 iterations to draw the rest of the jurors + + 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_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 DisputeKitClassic.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 DisputeKitClassic.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 commit must match the choice in courts with hidden votes.")); + disputeKit.castVote(disputeID, voteIDs, 2, salt, "XYZ"); + + vm.prank(staker1); + vm.expectRevert(bytes("The commit must match the choice 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 caller 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 empty"); + 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"); + + 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_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 DisputeKitClassic.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 DisputeKitClassic.Contribution(disputeID, 0, 1, crowdfunder1, 0.42 ether); + vm.expectEmit(true, true, true, true); + emit DisputeKitClassic.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)", governor, address(core)); + + 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 DisputeKitClassic.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_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"); + + 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); + + vm.expectEmit(true, true, true, true); + emit SortitionModuleBase.StakeSet(staker1, newCourtID, 0); + vm.expectEmit(true, true, true, true); + emit SortitionModuleBase.StakeSet(staker1, GENERAL_COURT, 0); + 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"); + 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_RewardUnstaked() public { + // Reward the juror who fully unstaked earlier. Return the locked tokens + 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); + + 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); + + (uint256 totalStaked, uint256 totalLocked, uint256 stakedInCourt, uint256 nbCourts) = sortitionModule + .getJurorBalance(staker1, GENERAL_COURT); + assertEq(totalStaked, 0, "Should be unstaked"); + assertEq(totalLocked, 3000, "Wrong amount locked"); + assertEq(stakedInCourt, 0, "Should be unstaked"); + assertEq(nbCourts, 0, "Should be 0 courts"); + + assertEq(pinakion.balanceOf(address(core)), 3000, "Wrong token balance of the core"); + assertEq(pinakion.balanceOf(staker1), 999999999999997000, "Wrong token balance of staker1"); + + core.execute(disputeID, 0, 6); + + 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 + + assertEq(pinakion.balanceOf(address(core)), 0, "Wrong token balance of the core"); + assertEq(pinakion.balanceOf(staker1), 1 ether, "Wrong token balance of staker1"); + } + + 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 DisputeKitClassic.Withdrawal(disputeID, 0, 1, crowdfunder1, 0.63 ether); + disputeKit.withdrawFeesAndRewards(disputeID, payable(crowdfunder1), 0, 1); + + vm.expectEmit(true, true, true, true); + emit DisputeKitClassic.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"); + } +} diff --git a/contracts/test/rng/index.ts b/contracts/test/rng/index.ts index 6fec0e12b..3d4906721 100644 --- a/contracts/test/rng/index.ts +++ b/contracts/test/rng/index.ts @@ -45,6 +45,7 @@ describe("BlockHashRNG", async () => { await tx.wait(); const [rn] = abiCoder.decode(["uint"], ethers.getBytes(`${trace.returnValue}`)); expect(rn).to.not.equal(0); + await tx.wait(); }); it("Should return zero for a block number in the future", async () => { @@ -53,6 +54,7 @@ describe("BlockHashRNG", async () => { await tx.wait(); const [rn] = abiCoder.decode(["uint"], ethers.getBytes(`${trace.returnValue}`)); expect(rn).to.equal(0); + await tx.wait(); }); }); @@ -83,6 +85,7 @@ describe("ChainlinkRNG", async () => { const rn = await rng.receiveRandomness(0); expect(rn).to.equal(expectedRn); + await tx.wait(); }); it("Should return only the last random number when multiple requests are made", async () => { @@ -116,6 +119,7 @@ describe("ChainlinkRNG", async () => { // Should return only the last random number const rn = await rng.receiveRandomness(0); expect(rn).to.equal(expectedRn2); + await tx.wait(); }); }); @@ -145,6 +149,7 @@ describe("RandomizerRNG", async () => { const rn = await rng.receiveRandomness(0); expect(rn).to.equal(expectedRn); + await tx.wait(); }); it("Should return only the last random number when multiple requests are made", async () => { @@ -177,5 +182,6 @@ describe("RandomizerRNG", async () => { // Should return only the last random number const rn = await rng.receiveRandomness(0); expect(rn).to.equal(expectedRn2); + await tx.wait(); }); }); diff --git a/cspell.json b/cspell.json index c671ffe5b..0ab3e541c 100644 --- a/cspell.json +++ b/cspell.json @@ -21,6 +21,7 @@ "commitlint", "consts", "COOLDOWN", + "crowdfunder", "datetime", "devnet", "Devnet", @@ -47,6 +48,8 @@ "uncommify", "Unslashed", "unstake", + "unstaked", + "Unstaking", "Upgradability", "UUPS", "viem", diff --git a/kleros-app/package.json b/kleros-app/package.json index e05ec415f..43ddf0468 100644 --- a/kleros-app/package.json +++ b/kleros-app/package.json @@ -1,6 +1,6 @@ { "name": "@kleros/kleros-app", - "version": "2.0.1", + "version": "2.0.2", "description": "Library for Kleros DApps with reusable abstractions and components.", "repository": "git@github.com:kleros/kleros-v2.git", "homepage": "https://github.com/kleros/kleros-v2/tree/master/kleros-app#readme", diff --git a/kleros-app/src/lib/atlas/hooks/useSessionStorage.ts b/kleros-app/src/lib/atlas/hooks/useSessionStorage.ts index 5cac8fb6e..0d5e6e79b 100644 --- a/kleros-app/src/lib/atlas/hooks/useSessionStorage.ts +++ b/kleros-app/src/lib/atlas/hooks/useSessionStorage.ts @@ -7,6 +7,9 @@ export function useSessionStorage(keyName: string, defaultValue: T) { return value ? JSON.parse(value) : defaultValue; } catch (err) { + // eslint-disable-next-line no-console + console.log("useSessionStorage:", { err }); + return defaultValue; } }); diff --git a/kleros-app/src/lib/atlas/providers/AtlasProvider.tsx b/kleros-app/src/lib/atlas/providers/AtlasProvider.tsx index 89178035c..1701faf47 100644 --- a/kleros-app/src/lib/atlas/providers/AtlasProvider.tsx +++ b/kleros-app/src/lib/atlas/providers/AtlasProvider.tsx @@ -25,6 +25,7 @@ import { import { GraphQLError } from "graphql"; import { isUndefined } from "../../../utils"; import { useSessionStorage } from "../hooks/useSessionStorage"; +import { fetchRestrictions, Role } from "../utils/fetchRestrictions"; interface IAtlasProvider { isVerified: boolean; @@ -44,6 +45,7 @@ interface IAtlasProvider { isError: boolean; } >; + roleRestrictions: Role[] | undefined; } const Context = createContext(undefined); @@ -73,7 +75,7 @@ export const AtlasProvider: React.FC<{ config: AtlasConfig; children?: React.Rea } : undefined; return new GraphQLClient(`${config.uri}/graphql`, { headers }); - }, [authToken]); + }, [authToken, config.uri]); /** * @description verifies user authorisation @@ -142,6 +144,22 @@ export const AtlasProvider: React.FC<{ config: AtlasConfig; children?: React.Rea queryClient ); + const { data: roleRestrictions } = useQuery( + { + queryKey: [`RoleRestrictions`], + enabled: Boolean(config.product), + staleTime: Infinity, + queryFn: async () => { + try { + return await fetchRestrictions(atlasGqlClient, config.product); + } catch { + return undefined; + } + }, + }, + queryClient + ); + useEffect(() => { if (!isVerified) return; refetchUser(); @@ -255,6 +273,17 @@ export const AtlasProvider: React.FC<{ config: AtlasConfig; children?: React.Rea async (file: File, role: Roles) => { try { if (!address || !isVerified || !config.uri || !authToken) return null; + + if (roleRestrictions) { + const restrictions = roleRestrictions.find((supportedRoles) => Roles[supportedRoles.name] === role); + + if (!restrictions) throw new Error("Unsupported role."); + if (!restrictions.restriction.allowedMimeTypes.includes(file.type)) throw new Error("Unsupported file type."); + if (file.size > restrictions.restriction.maxSize) + throw new Error( + `File too big. Max allowed size : ${(restrictions.restriction.maxSize / (1024 * 1024)).toFixed(2)} mb.` + ); + } setIsUploadingFile(true); const hash = await fetchWithAuthErrorHandling(() => @@ -267,7 +296,7 @@ export const AtlasProvider: React.FC<{ config: AtlasConfig; children?: React.Rea setIsUploadingFile(false); } }, - [address, isVerified, setIsUploadingFile, authToken, config.uri, config.product] + [address, isVerified, setIsUploadingFile, authToken, config.uri, config.product, roleRestrictions] ); /** @@ -309,6 +338,7 @@ export const AtlasProvider: React.FC<{ config: AtlasConfig; children?: React.Rea isUploadingFile, uploadFile, confirmEmail, + roleRestrictions, }), [ isVerified, @@ -324,6 +354,7 @@ export const AtlasProvider: React.FC<{ config: AtlasConfig; children?: React.Rea isUploadingFile, uploadFile, confirmEmail, + roleRestrictions, ] )} > diff --git a/kleros-app/src/lib/atlas/utils/fetchRestrictions.ts b/kleros-app/src/lib/atlas/utils/fetchRestrictions.ts new file mode 100644 index 000000000..8a0b27347 --- /dev/null +++ b/kleros-app/src/lib/atlas/utils/fetchRestrictions.ts @@ -0,0 +1,40 @@ +import { gql, type GraphQLClient } from "graphql-request"; +import { Products } from "."; + +export type Role = { + name: string; + restriction: { + maxSize: number; + allowedMimeTypes: string[]; + }; +}; + +type FetchRolesResponse = { + roles: Role[]; +}; + +const query = gql` + query Roles($product: Products!) { + roles(product: $product) { + name + restriction { + maxSize + allowedMimeTypes + } + } + } +`; + +export async function fetchRestrictions(client: GraphQLClient, product: Products): Promise { + return client + .request(query, { product }) + .then((response) => response.roles) + .catch((errors) => { + // eslint-disable-next-line no-console + console.log("Error fetching roles :", { errors }); + const errorMessage = Array.isArray(errors?.response?.errors) + ? errors.response.errors[0]?.message + : "Error fetching roles"; + throw Error(errorMessage); + }); +} diff --git a/package.json b/package.json index c1a21a434..6550c5e39 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,8 @@ "web-devtools", "eslint-config", "prettier-config", - "tsconfig" + "tsconfig", + "kleros-app" ], "packageManager": "yarn@4.5.1", "volta": { diff --git a/scripts/cancel-all-netlify-builds.sh b/scripts/cancel-all-netlify-builds.sh index f9f923069..d5ff73751 100755 --- a/scripts/cancel-all-netlify-builds.sh +++ b/scripts/cancel-all-netlify-builds.sh @@ -1,24 +1,36 @@ #!/usr/bin/env bash -function cancelSiteDeploy() #sideId +function cancelSiteDeploy() #siteId { - local sideId=$1 - readarray -t builds < <(netlify api listSiteDeploys -d '{ "site_id": "'$sideId'", "state": "new"}' | jq --compact-output '.[]') + local siteId=$1 + readarray -t builds < <(netlify api listSiteDeploys -d '{ "site_id": "'$siteId'", "state": "new"}' | jq --compact-output '.[]') for build in "${builds[@]}" do local name=$(jq -r .name <<< $build) local branch=$(jq -r .branch <<< $build) - if [[ "$branch" == "dev" || "$branch" == "master" ]]; then - continue; + if [[ "$branch" =~ ^dependabot/ || "$branch" =~ ^renovate/ ]]; then + echo "Cancelling build for $name $branch" + netlify api cancelSiteDeploy -d '{ "deploy_id": "'$(jq -r .id <<< $build)'"}' > /dev/null fi - echo "Cancelling build for $name $branch" - netlify api cancelSiteDeploy -d '{ "deploy_id": "'$(jq -r .id <<< $build)'"}' > /dev/null done } # netlify api listSites | jq '. | map([.name, .id])' -v2Site="86d94ae8-f655-46a4-a859-d68696173f3a" -v2ContractsSite="dd8bc215-e054-407f-92ef-d61511720928" +sites=( + # v2Testnet + "86d94ae8-f655-46a4-a859-d68696173f3a" + # v2DevtoolsTestnet + "7b25b1a8-5fd4-41f7-8fd0-7fe4202229fb" + # v2Uni + "085e1305-e434-4d36-91a4-88e8cbc3aa46" + # v2Neo + "46f40014-ff00-4a9a-a1a2-4fefeeb1606a" + # v2DevtoolsNeo + "45cc81df-58a8-46cb-902f-1ccd3314ec70" + # v2ContractsSite + "dd8bc215-e054-407f-92ef-d61511720928" +) -cancelSiteDeploy $v2Site -cancelSiteDeploy $v2ContractsSite +for site in "${sites[@]}"; do + cancelSiteDeploy $site +done diff --git a/web-devtools/src/app/(main)/dispute-template/FetchDisputeRequestInput.tsx b/web-devtools/src/app/(main)/dispute-template/FetchDisputeRequestInput.tsx index bf5f75272..a14d08133 100644 --- a/web-devtools/src/app/(main)/dispute-template/FetchDisputeRequestInput.tsx +++ b/web-devtools/src/app/(main)/dispute-template/FetchDisputeRequestInput.tsx @@ -45,19 +45,9 @@ const StyledA = styled.a` const presets = [ { - title: "Escrow", - txnHash: "0x2565b756e500240544f7fc36f938462c7efbbd2e343c57979f81fecdf1054e23", - chainId: 421614, - }, - { - title: "Curated Lists", - txnHash: "0xa7981830bf8144ab2070f3a639bd36b204c4c48ee1fafef66abaf60272418ed4", - chainId: 421614, - }, - { - title: "Trump-Harris", - txnHash: "0x86db91678cf3f8c4503e37340cf2cd93bffcba84f9c43a98c090f6a4c76d8793", - chainId: 421614, + title: "Dispute Resolver - Compensation Claim", + txnHash: "0x01db1d330acef1a0df007b0f9dcb56b7a88aeb49687f95cb5c58d5c36526ef70", + chainId: 42161, }, ]; diff --git a/web-devtools/src/app/(main)/ruler/SelectArbitrable.tsx b/web-devtools/src/app/(main)/ruler/SelectArbitrable.tsx index 87ba1d53e..75fd74069 100644 --- a/web-devtools/src/app/(main)/ruler/SelectArbitrable.tsx +++ b/web-devtools/src/app/(main)/ruler/SelectArbitrable.tsx @@ -133,12 +133,17 @@ const SelectArbitrable: React.FC = () => { [publicClient, setArbitrable] ); + const [[chainId, address]] = Object.entries(klerosCoreAddress); + if (chainId !== DEFAULT_CHAIN.toString()) { + console.error(`Kleros Core is not deployed on chain ${chainId}`); + } + return ( Ruler Address: - - {shortenAddress(klerosCoreAddress[DEFAULT_CHAIN])} + + {shortenAddress(address)} diff --git a/web-devtools/src/consts/chains.ts b/web-devtools/src/consts/chains.ts index 23afcf66a..0a22df36f 100644 --- a/web-devtools/src/consts/chains.ts +++ b/web-devtools/src/consts/chains.ts @@ -1,13 +1,16 @@ -import { type Chain, mainnet, arbitrumSepolia, gnosisChiado } from "viem/chains"; +import { type Chain, mainnet, arbitrumSepolia, gnosisChiado, arbitrum, gnosis } from "viem/chains"; + +import { isProductionDeployment } from "./index"; + +export const DEFAULT_CHAIN = isProductionDeployment() ? arbitrum.id : arbitrumSepolia.id; export const SUPPORTED_CHAINS: Record = { - [arbitrumSepolia.id]: arbitrumSepolia, + [isProductionDeployment() ? arbitrum.id : arbitrumSepolia.id]: isProductionDeployment() ? arbitrum : arbitrumSepolia, }; export const QUERY_CHAINS: Record = { - [gnosisChiado.id]: gnosisChiado, + [isProductionDeployment() ? gnosis.id : gnosisChiado.id]: isProductionDeployment() ? gnosis : gnosisChiado, [mainnet.id]: mainnet, }; export const ALL_CHAINS = [...Object.values(SUPPORTED_CHAINS), ...Object.values(QUERY_CHAINS)]; -export const DEFAULT_CHAIN = arbitrumSepolia.id; diff --git a/web-devtools/src/context/Web3Provider.tsx b/web-devtools/src/context/Web3Provider.tsx index 4e2651a18..80783db39 100644 --- a/web-devtools/src/context/Web3Provider.tsx +++ b/web-devtools/src/context/Web3Provider.tsx @@ -6,7 +6,8 @@ import { createConfig, fallback, http, WagmiProvider, webSocket } from "wagmi"; import { mainnet, arbitrumSepolia, arbitrum, gnosisChiado, sepolia, gnosis } from "wagmi/chains"; import { walletConnect } from "wagmi/connectors"; -import { ALL_CHAINS } from "consts/chains"; +import { ALL_CHAINS, DEFAULT_CHAIN } from "consts/chains"; +import { isProductionDeployment } from "consts/index"; import { theme } from "styles/Theme"; @@ -15,6 +16,8 @@ if (!alchemyApiKey) { throw new Error("Alchemy API key is not set in NEXT_PUBLIC_ALCHEMY_API_KEY environment variable."); } +const isProduction = isProductionDeployment(); + // https://github.com/alchemyplatform/alchemy-sdk-js/blob/c4440cb/src/types/types.ts#L98-L153 const alchemyToViemChain: Record = { [arbitrumSepolia.id]: "arb-sepolia", @@ -36,12 +39,27 @@ function alchemyURL(protocol: AlchemyProtocol, chainId: number): string { return `${protocol}://${network}.g.alchemy.com/v2/${alchemyApiKey}`; } +export const getChainRpcUrl = (protocol: AlchemyProtocol, chainId: number) => { + return alchemyURL(protocol, chainId); +}; + +export const getDefaultChainRpcUrl = (protocol: AlchemyProtocol) => { + return getChainRpcUrl(protocol, DEFAULT_CHAIN); +}; + export const getTransports = () => { const alchemyTransport = (chain: Chain) => fallback([http(alchemyURL("https", chain.id)), webSocket(alchemyURL("wss", chain.id))]); + const defaultTransport = (chain: Chain) => + fallback([http(chain.rpcUrls.default?.http?.[0]), webSocket(chain.rpcUrls.default?.webSocket?.[0])]); return { - [arbitrumSepolia.id]: alchemyTransport(arbitrumSepolia), + [isProduction ? arbitrum.id : arbitrumSepolia.id]: isProduction + ? alchemyTransport(arbitrum) + : alchemyTransport(arbitrumSepolia), + [isProduction ? gnosis.id : gnosisChiado.id]: isProduction + ? defaultTransport(gnosis) + : defaultTransport(gnosisChiado), [mainnet.id]: alchemyTransport(mainnet), // Always enabled for ENS resolution }; }; @@ -54,7 +72,7 @@ if (!projectId) { throw new Error("WalletConnect project ID is not set in NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID environment variable."); } -const wagmiConfig = createConfig({ +export const wagmiConfig = createConfig({ chains, transports, connectors: [walletConnect({ projectId })], @@ -63,7 +81,7 @@ const wagmiConfig = createConfig({ createWeb3Modal({ wagmiConfig, projectId, - defaultChain: arbitrumSepolia, + defaultChain: isProduction ? arbitrum : arbitrumSepolia, themeVariables: { "--w3m-color-mix": theme.klerosUIComponentsPrimaryPurple, "--w3m-color-mix-strength": 20, diff --git a/web-devtools/src/utils/getDisputeRequestParamsFromTxn.ts b/web-devtools/src/utils/getDisputeRequestParamsFromTxn.ts index 785f99fa4..ed532b452 100644 --- a/web-devtools/src/utils/getDisputeRequestParamsFromTxn.ts +++ b/web-devtools/src/utils/getDisputeRequestParamsFromTxn.ts @@ -1,9 +1,9 @@ import { getPublicClient } from "@wagmi/core"; import { type GetTransactionReceiptReturnType, decodeEventLog, getEventSelector } from "viem"; +import { wagmiConfig } from "context/Web3Provider"; import { iArbitrableV2Abi } from "hooks/contracts/generated"; import { isUndefined } from "utils/isUndefined"; -import { wagmiConfig } from "utils/wagmiConfig"; export const getDisputeRequestParamsFromTxn = async (hash: `0x${string}`, chainId: number) => { try { diff --git a/web-devtools/src/utils/wagmiConfig.ts b/web-devtools/src/utils/wagmiConfig.ts deleted file mode 100644 index e7eb88ff5..000000000 --- a/web-devtools/src/utils/wagmiConfig.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { type Chain } from "viem"; -import { createConfig, fallback, http, webSocket } from "wagmi"; -import { mainnet, arbitrumSepolia, arbitrum, gnosisChiado } from "wagmi/chains"; - -import { ALL_CHAINS } from "consts/chains"; -import { isProductionDeployment } from "consts/index"; - -const chains = ALL_CHAINS as [Chain, ...Chain[]]; - -export const alchemyApiKey = process.env.NEXT_PUBLIC_ALCHEMY_API_KEY ?? ""; - -type AlchemyProtocol = "https" | "wss"; -type AlchemyChain = "arb-sepolia" | "eth-mainnet" | "arb"; -const alchemyURL = (protocol: AlchemyProtocol, chain: AlchemyChain) => - `${protocol}://${chain}.g.alchemy.com/v2/${alchemyApiKey}`; -const alchemyTransport = (chain: AlchemyChain) => - fallback([webSocket(alchemyURL("wss", chain)), http(alchemyURL("https", chain))]); - -const transports = { - [isProductionDeployment() ? arbitrum.id : arbitrumSepolia.id]: isProductionDeployment() - ? alchemyTransport("arb") - : alchemyTransport("arb-sepolia"), - [mainnet.id]: alchemyTransport("eth-mainnet"), - [gnosisChiado.id]: fallback([webSocket("wss://rpc.chiadochain.net/wss"), http("https://rpc.chiadochain.net")]), -}; - -export const wagmiConfig = createConfig({ - chains: chains, - transports: transports, -}); diff --git a/web-devtools/wagmi.config.ts b/web-devtools/wagmi.config.ts index 1391f0b5b..ce00ca961 100644 --- a/web-devtools/wagmi.config.ts +++ b/web-devtools/wagmi.config.ts @@ -4,13 +4,13 @@ import { parse, join } from "path"; import { type Config, type ContractConfig, defineConfig } from "@wagmi/cli"; import { react, actions } from "@wagmi/cli/plugins"; import dotenv from "dotenv"; -import { Abi, Chain } from "viem"; +import { type Chain, type Abi } from "viem"; +import { arbitrum, arbitrumSepolia, gnosis, gnosisChiado, mainnet, sepolia } from "viem/chains"; import IArbitrableV2 from "@kleros/kleros-v2-contracts/artifacts/src/arbitration/interfaces/IArbitrableV2.sol/IArbitrableV2.json" with { type: "json" }; import IHomeGateway from "@kleros/kleros-v2-contracts/artifacts/src/gateway/interfaces/IHomeGateway.sol/IHomeGateway.json" with { type: "json" }; import { ArbitratorTypes, getArbitratorType } from "./src/consts/arbitratorTypes"; -import { arbitrum, arbitrumSepolia, gnosis, gnosisChiado, mainnet, sepolia } from "viem/chains"; dotenv.config(); @@ -27,7 +27,14 @@ const readArtifacts = async (type: ArbitratorTypes, viemChainName: string, hardh type === ArbitratorTypes.vanilla ? "" : ArbitratorTypes[type].toString().charAt(0).toUpperCase() + ArbitratorTypes[type].toString().slice(1); - const vanillaArtifacts = ["KlerosCore", "DisputeKitClassic", "SortitionModule", "DisputeResolver", "KlerosCoreRuler"]; + const vanillaArtifacts = [ + "KlerosCore", + "DisputeKitClassic", + "SortitionModule", + "DisputeResolver", + "KlerosCoreRuler", + "DisputeResolverRuler", + ]; const typeSpecificArtifacts = vanillaArtifacts.map((artifact) => `${artifact}${artifactSuffix}`); const chainMap: Record = { diff --git a/web/package.json b/web/package.json index 426b2a9ac..80f81b0cf 100644 --- a/web/package.json +++ b/web/package.json @@ -78,7 +78,7 @@ }, "dependencies": { "@cyntler/react-doc-viewer": "^1.17.0", - "@kleros/kleros-app": "^2.0.1", + "@kleros/kleros-app": "^2.0.2", "@kleros/kleros-sdk": "workspace:^", "@kleros/kleros-v2-contracts": "workspace:^", "@kleros/ui-components-library": "^2.19.0", diff --git a/web/src/assets/svgs/icons/law-balance.svg b/web/src/assets/svgs/icons/law-balance.svg index c8a97deec..473e946a3 100644 --- a/web/src/assets/svgs/icons/law-balance.svg +++ b/web/src/assets/svgs/icons/law-balance.svg @@ -1,4 +1,4 @@ - + diff --git a/web/src/components/DisputePreview/Policies.tsx b/web/src/components/DisputePreview/Policies.tsx index b0f856f4f..a2d0774c9 100644 --- a/web/src/components/DisputePreview/Policies.tsx +++ b/web/src/components/DisputePreview/Policies.tsx @@ -1,5 +1,5 @@ import React from "react"; -import styled from "styled-components"; +import styled, { css } from "styled-components"; import PaperclipIcon from "svgs/icons/paperclip.svg"; import PolicyIcon from "svgs/icons/policy.svg"; @@ -7,8 +7,8 @@ import PolicyIcon from "svgs/icons/policy.svg"; import { getIpfsUrl } from "utils/getIpfsUrl"; import { isUndefined } from "utils/index"; -import { responsiveSize } from "styles/responsiveSize"; import { hoverShortTransitionTiming } from "styles/commonStyles"; +import { landscapeStyle } from "styles/landscapeStyle"; import { InternalLink } from "components/InternalLink"; @@ -17,9 +17,15 @@ const Container = styled.div` align-items: center; flex-direction: row; flex-wrap: wrap; - gap: 8px 16px; - padding: ${responsiveSize(12, 20)} ${responsiveSize(8, 32)}; + gap: 12px 16px; + padding: 12px 16px 20px; background-color: ${({ theme }) => theme.mediumBlue}; + + ${landscapeStyle( + () => css` + padding: 20px 32px; + ` + )} `; const StyledP = styled.p` diff --git a/web/src/components/DisputeView/CardLabels/index.tsx b/web/src/components/DisputeView/CardLabels/index.tsx index 6595bbf34..523539ddf 100644 --- a/web/src/components/DisputeView/CardLabels/index.tsx +++ b/web/src/components/DisputeView/CardLabels/index.tsx @@ -30,7 +30,7 @@ const Container = styled.div<{ isList: boolean }>` ${({ isList }) => !isList && css` - margin-top: 16px; + margin-top: 24px; width: 100%; flex-wrap: wrap; flex-direction: row; diff --git a/web/src/components/DisputeView/DisputeCardView.tsx b/web/src/components/DisputeView/DisputeCardView.tsx index 8ebffae44..3cb231c5a 100644 --- a/web/src/components/DisputeView/DisputeCardView.tsx +++ b/web/src/components/DisputeView/DisputeCardView.tsx @@ -1,5 +1,5 @@ import React from "react"; -import styled from "styled-components"; +import styled, { css } from "styled-components"; import { Link } from "react-router-dom"; @@ -7,8 +7,8 @@ import { Card } from "@kleros/ui-components-library"; import { Periods } from "consts/periods"; -import { responsiveSize } from "styles/responsiveSize"; import { hoverShortTransitionTiming } from "styles/commonStyles"; +import { landscapeStyle } from "styles/landscapeStyle"; import { StyledSkeleton } from "components/StyledSkeleton"; @@ -19,26 +19,36 @@ const StyledCard = styled(Card)` ${hoverShortTransitionTiming} width: 100%; height: 100%; - max-height: 335px; min-height: 290px; `; const CardContainer = styled.div` height: calc(100% - 45px); - padding: ${responsiveSize(20, 24)} ${responsiveSize(8, 24)}; + padding: 20px 16px; display: flex; flex-direction: column; justify-content: space-between; + + ${landscapeStyle( + () => css` + padding: 20px 24px; + ` + )} +`; + +const StyledCaseCardTitle = styled.h3` + margin-bottom: 20px; `; const StyledCaseCardTitleSkeleton = styled(StyledSkeleton)` - margin-bottom: 16px; + margin-bottom: 20px; `; const TruncatedTitle = ({ text, maxLength }) => { const truncatedText = text.length <= maxLength ? text : text.slice(0, maxLength) + "…"; - return

{truncatedText}

; + return {truncatedText}; }; + interface IDisputeCardView { title: string; disputeID?: string; diff --git a/web/src/components/DisputeView/DisputeInfo/DisputeInfoCard.tsx b/web/src/components/DisputeView/DisputeInfo/DisputeInfoCard.tsx index 68d729164..6bc83242d 100644 --- a/web/src/components/DisputeView/DisputeInfo/DisputeInfoCard.tsx +++ b/web/src/components/DisputeView/DisputeInfo/DisputeInfoCard.tsx @@ -12,7 +12,6 @@ import { FieldItem, IDisputeInfo } from "./index"; const Container = styled.div` display: flex; width: 100%; - gap: 8px; flex-direction: column; justify-content: flex-end; `; diff --git a/web/src/components/DisputeView/PeriodBanner.tsx b/web/src/components/DisputeView/PeriodBanner.tsx index 722989793..6a5287afa 100644 --- a/web/src/components/DisputeView/PeriodBanner.tsx +++ b/web/src/components/DisputeView/PeriodBanner.tsx @@ -4,6 +4,7 @@ import styled, { Theme, css, useTheme } from "styled-components"; import { Periods } from "consts/periods"; import { responsiveSize } from "styles/responsiveSize"; +import { landscapeStyle } from "styles/landscapeStyle"; interface IContainer { isCard: boolean; @@ -20,7 +21,7 @@ const Container = styled.div` align-items: center; gap: 8px; justify-content: space-between; - padding: 0 ${({ isCard }) => (isCard ? responsiveSize(8, 24) : responsiveSize(8, 24, 900))}; + padding: 0 ${({ isCard }) => (isCard ? "16px" : "24px")}; flex-shrink: 0; ${({ frontColor, backgroundColor, isCard }) => { return ` @@ -28,6 +29,12 @@ const Container = styled.div` ${isCard && `background-color: ${backgroundColor};`}; `; }}; + + ${landscapeStyle( + () => css` + padding: 0 24px; + ` + )} `; const StyledLabel = styled.label<{ frontColor: string; withDot?: boolean; isCard?: boolean }>` diff --git a/web/src/components/EvidenceCard.tsx b/web/src/components/EvidenceCard.tsx index dcc75e456..0a328b29d 100644 --- a/web/src/components/EvidenceCard.tsx +++ b/web/src/components/EvidenceCard.tsx @@ -30,7 +30,7 @@ const StyledCard = styled(Card)` const TopContent = styled.div` display: flex; flex-direction: column; - padding: ${responsiveSize(8, 20)} ${responsiveSize(8, 24)}; + padding: 16px; gap: 4px; overflow-wrap: break-word; @@ -45,17 +45,24 @@ const TopContent = styled.div` display: inline-block; margin: 0; } + + ${landscapeStyle( + () => css` + padding: 20px 24px; + ` + )} `; const IndexAndName = styled.div` display: flex; flex-direction: row; align-items: center; - gap: 6px; + gap: 5px; `; const Index = styled.p` display: inline-block; + color: ${({ theme }) => theme.secondaryText}; `; const StyledReactMarkdown = styled(ReactMarkdown)` @@ -76,12 +83,18 @@ const BottomShade = styled.div` flex-wrap: wrap; align-items: center; justify-content: space-between; - padding: 12px ${responsiveSize(8, 24)}; + padding: 16px; > * { flex-basis: 1; flex-shrink: 0; margin: 0; } + + ${landscapeStyle( + () => css` + padding: 12px 24px; + ` + )} `; const BottomLeftContent = styled.div` @@ -218,7 +231,7 @@ const EvidenceCard: React.FC = ({ - #{index}: + #{index}.

{name}

{name && description ? {description} :

{evidence}

} diff --git a/web/src/components/FavoriteCases.tsx b/web/src/components/FavoriteCases.tsx index 51717d4d1..a742b7b96 100644 --- a/web/src/components/FavoriteCases.tsx +++ b/web/src/components/FavoriteCases.tsx @@ -9,6 +9,7 @@ import { isUndefined } from "utils/index"; import { DisputeDetailsFragment, useCasesQuery } from "queries/useCasesQuery"; import { responsiveSize } from "styles/responsiveSize"; +import { hoverShortTransitionTiming } from "styles/commonStyles"; import DisputeView from "components/DisputeView"; import { SkeletonDisputeCard } from "components/StyledSkeleton"; @@ -18,7 +19,7 @@ const Container = styled.div` `; const Title = styled.h1` - margin-bottom: 4px; + margin: 0; font-size: ${responsiveSize(20, 24)}; `; @@ -30,11 +31,20 @@ const DisputeContainer = styled.div` gap: var(--gap); `; +const TitleAndClearLabel = styled.div` + display: flex; + flex-direction: row; + gap: 12px; + align-items: center; + margin-bottom: ${responsiveSize(12, 24)}; +`; + const StyledLabel = styled.label` - display: block; + ${hoverShortTransitionTiming} color: ${({ theme }) => theme.primaryBlue}; cursor: pointer; - margin-bottom: ${responsiveSize(12, 16)}; + margin-top: 6px; + :hover { color: ${({ theme }) => theme.secondaryBlue}; } @@ -61,8 +71,10 @@ const FavoriteCases: React.FC = () => { return starredCaseIds.length > 0 && (isUndefined(disputes) || disputes.length > 0) ? ( - Favorite Cases - Clear all + + Favorite Cases + Clear all + {isUndefined(disputes) ? Array.from({ length: 3 }).map((_, index) => ) diff --git a/web/src/components/FileViewer/index.tsx b/web/src/components/FileViewer/index.tsx index fa67a9bb1..39b025a53 100644 --- a/web/src/components/FileViewer/index.tsx +++ b/web/src/components/FileViewer/index.tsx @@ -20,6 +20,10 @@ const Wrapper = styled.div` const StyledDocViewer = styled(DocViewer)` background-color: ${({ theme }) => theme.whiteBackground} !important; + + #pdf-controls { + z-index: 3; + } `; /** diff --git a/web/src/components/Verdict/FinalDecision.tsx b/web/src/components/Verdict/FinalDecision.tsx index 12020a2b8..40729df8e 100644 --- a/web/src/components/Verdict/FinalDecision.tsx +++ b/web/src/components/Verdict/FinalDecision.tsx @@ -1,5 +1,5 @@ import React, { useMemo } from "react"; -import styled from "styled-components"; +import styled, { css } from "styled-components"; import Skeleton from "react-loading-skeleton"; import { useParams } from "react-router-dom"; @@ -19,7 +19,7 @@ import { isUndefined } from "utils/index"; import { useDisputeDetailsQuery } from "queries/useDisputeDetailsQuery"; -import { responsiveSize } from "styles/responsiveSize"; +import { landscapeStyle } from "styles/landscapeStyle"; import RulingAndRewardsIndicators from "./RulingAndRewardsIndicators"; import AnswerDisplay from "./Answer"; @@ -35,7 +35,7 @@ const JuryContainer = styled.div` flex-direction: row; flex-wrap: wrap; align-items: center; - gap: 4px 7px; + gap: 5px 7px; h3 { line-height: 21px; @@ -48,7 +48,7 @@ const VerdictContainer = styled.div` flex-direction: row; align-items: center; flex-wrap: wrap; - gap: ${responsiveSize(6, 8)}; + gap: 8px; `; const JuryDecisionTag = styled.small` @@ -57,7 +57,13 @@ const JuryDecisionTag = styled.small` `; const StyledDivider = styled(Divider)` - margin: ${responsiveSize(16, 24)} 0px; + margin: 16px 0px; + + ${landscapeStyle( + () => css` + margin: 24px 0px; + ` + )} `; const ReStyledArrowLink = styled(StyledArrowLink)` diff --git a/web/src/context/Web3Provider.tsx b/web/src/context/Web3Provider.tsx index 342ac5ed9..138525a56 100644 --- a/web/src/context/Web3Provider.tsx +++ b/web/src/context/Web3Provider.tsx @@ -3,7 +3,7 @@ import React from "react"; import { createWeb3Modal } from "@web3modal/wagmi/react"; import { type Chain } from "viem"; import { createConfig, fallback, http, WagmiProvider, webSocket } from "wagmi"; -import { mainnet, arbitrumSepolia, arbitrum, gnosisChiado, gnosis, sepolia } from "wagmi/chains"; +import { mainnet, arbitrumSepolia, arbitrum, gnosisChiado, sepolia, gnosis } from "wagmi/chains"; import { walletConnect } from "wagmi/connectors"; import { configureSDK } from "@kleros/kleros-sdk/src/sdk"; @@ -13,22 +13,33 @@ import { isProductionDeployment } from "consts/index"; import { lightTheme } from "styles/themes"; -const alchemyApiKey = import.meta.env.ALCHEMY_API_KEY ?? ""; +const alchemyApiKey = import.meta.env.ALCHEMY_API_KEY; +if (!alchemyApiKey) { + throw new Error("Alchemy API key is not set in ALCHEMY_API_KEY environment variable."); +} + const isProduction = isProductionDeployment(); -// https://github.com/alchemyplatform/alchemy-sdk-js/blob/96b3f62/src/types/types.ts#L98-L119 -const alchemyToViemChain = { - [arbitrum.id]: "arb-mainnet", +// https://github.com/alchemyplatform/alchemy-sdk-js/blob/c4440cb/src/types/types.ts#L98-L153 +const alchemyToViemChain: Record = { [arbitrumSepolia.id]: "arb-sepolia", + [arbitrum.id]: "arb-mainnet", [mainnet.id]: "eth-mainnet", [sepolia.id]: "eth-sepolia", + [gnosis.id]: "gnosis-mainnet", + [gnosisChiado.id]: "gnosis-chiado", }; type AlchemyProtocol = "https" | "wss"; -// https://github.com/alchemyplatform/alchemy-sdk-js/blob/96b3f62/src/util/const.ts#L16-L18 -const alchemyURL = (protocol: AlchemyProtocol, chainId: number) => - `${protocol}://${alchemyToViemChain[chainId]}.g.alchemy.com/v2/${alchemyApiKey}`; +// https://github.com/alchemyplatform/alchemy-sdk-js/blob/c4440cb/src/util/const.ts#L16-L18 +function alchemyURL(protocol: AlchemyProtocol, chainId: number): string { + const network = alchemyToViemChain[chainId]; + if (!network) { + throw new Error(`Unsupported chain ID: ${chainId}`); + } + return `${protocol}://${network}.g.alchemy.com/v2/${alchemyApiKey}`; +} export const getChainRpcUrl = (protocol: AlchemyProtocol, chainId: number) => { return alchemyURL(protocol, chainId); @@ -57,7 +68,12 @@ export const getTransports = () => { const chains = ALL_CHAINS as [Chain, ...Chain[]]; const transports = getTransports(); -const projectId = import.meta.env.WALLETCONNECT_PROJECT_ID ?? ""; + +const projectId = import.meta.env.WALLETCONNECT_PROJECT_ID; +if (!projectId) { + throw new Error("WalletConnect project ID is not set in WALLETCONNECT_PROJECT_ID environment variable."); +} + const wagmiConfig = createConfig({ chains, transports, @@ -74,7 +90,7 @@ configureSDK({ createWeb3Modal({ wagmiConfig, projectId, - defaultChain: isProductionDeployment() ? arbitrum : arbitrumSepolia, + defaultChain: isProduction ? arbitrum : arbitrumSepolia, themeVariables: { "--w3m-color-mix": lightTheme.primaryPurple, "--w3m-color-mix-strength": 20, diff --git a/web/src/layout/Footer/index.tsx b/web/src/layout/Footer/index.tsx index 472c3c3ff..bebb00c29 100644 --- a/web/src/layout/Footer/index.tsx +++ b/web/src/layout/Footer/index.tsx @@ -12,22 +12,22 @@ import LightButton from "components/LightButton"; import { ExternalLink } from "components/ExternalLink"; const Container = styled.div` - height: 122px; + height: 114px; width: 100%; background-color: ${({ theme }) => (theme.name === "dark" ? theme.lightBlue : theme.primaryPurple)}; display: flex; flex-direction: column; justify-content: center; align-items: center; - padding: 0 32px 8px 32px; - gap: 24px; + padding: 8px; + gap: 16px; ${landscapeStyle( () => css` height: 64px; flex-direction: row; justify-content: space-between; - padding-bottom: 0; + padding: 0 32px; ` )} `; diff --git a/web/src/pages/Cases/AttachmentDisplay/Header.tsx b/web/src/pages/Cases/AttachmentDisplay/Header.tsx index 669274e86..4f5c87ad7 100644 --- a/web/src/pages/Cases/AttachmentDisplay/Header.tsx +++ b/web/src/pages/Cases/AttachmentDisplay/Header.tsx @@ -34,7 +34,7 @@ const StyledPaperClip = styled(PaperClip)` width: ${responsiveSize(16, 24)}; height: ${responsiveSize(16, 24)}; path { - fill: ${({ theme }) => theme.primaryPurple}; + fill: ${({ theme }) => theme.secondaryPurple}B0; } `; diff --git a/web/src/pages/Cases/CaseDetails/Appeal/OptionCard.tsx b/web/src/pages/Cases/CaseDetails/Appeal/OptionCard.tsx index 78d5077bd..1fa2ec2d9 100644 --- a/web/src/pages/Cases/CaseDetails/Appeal/OptionCard.tsx +++ b/web/src/pages/Cases/CaseDetails/Appeal/OptionCard.tsx @@ -1,26 +1,32 @@ import React, { useMemo } from "react"; -import styled from "styled-components"; +import styled, { css } from "styled-components"; -import { responsiveSize } from "styles/responsiveSize"; import { hoverShortTransitionTiming } from "styles/commonStyles"; +import { landscapeStyle } from "styles/landscapeStyle"; + +import { Card, Radio, LinearProgress } from "@kleros/ui-components-library"; import { useMeasure } from "react-use"; import { formatEther } from "viem"; -import { Card, Radio, LinearProgress } from "@kleros/ui-components-library"; +import { isUndefined } from "utils/index"; import Gavel from "svgs/icons/gavel.svg"; -import { isUndefined } from "utils/index"; - -const StyledCard = styled(Card)` +const StyledCard = styled(Card)<{ canBeSelected: boolean }>` ${hoverShortTransitionTiming} width: 100%; - padding: ${responsiveSize(12, 24)} ${responsiveSize(8, 24)}; + padding: 16px; - &:hover { - cursor: pointer; + :hover { + cursor: ${({ canBeSelected }) => (canBeSelected ? "pointer" : "auto")}; } + + ${landscapeStyle( + () => css` + padding: 24px; + ` + )} `; const WinnerLabel = styled.label<{ winner: boolean }>` @@ -97,8 +103,9 @@ const OptionCard: React.FC = ({ else if (funding > 0n) return [`Funded with ${formatEther(funding)} ETH.`, 30]; else return ["0 ETH contributed to this option", 0]; }, [funding, required]); + return ( - + {text} diff --git a/web/src/pages/Cases/CaseDetails/Appeal/index.tsx b/web/src/pages/Cases/CaseDetails/Appeal/index.tsx index 11ebdf704..b50a217f1 100644 --- a/web/src/pages/Cases/CaseDetails/Appeal/index.tsx +++ b/web/src/pages/Cases/CaseDetails/Appeal/index.tsx @@ -13,7 +13,13 @@ import AppealHistory from "./AppealHistory"; import Classic from "./Classic"; const Container = styled.div` - padding: ${responsiveSize(16, 32)} ${responsiveSize(8, 32)}; + padding: 16px; + + ${landscapeStyle( + () => css` + padding: 32px; + ` + )} `; export const AppealHeader = styled.div` diff --git a/web/src/pages/Cases/CaseDetails/Evidence/index.tsx b/web/src/pages/Cases/CaseDetails/Evidence/index.tsx index 8541deec3..e27947f27 100644 --- a/web/src/pages/Cases/CaseDetails/Evidence/index.tsx +++ b/web/src/pages/Cases/CaseDetails/Evidence/index.tsx @@ -1,5 +1,5 @@ import React, { useCallback, useMemo, useRef, useState } from "react"; -import styled from "styled-components"; +import styled, { css } from "styled-components"; import { useParams } from "react-router-dom"; import { useDebounce } from "react-use"; @@ -8,26 +8,32 @@ import { Button } from "@kleros/ui-components-library"; import DownArrow from "svgs/icons/arrow-down.svg"; +import { spamEvidencesIds } from "consts/index"; + import { useDisputeDetailsQuery } from "queries/useDisputeDetailsQuery"; import { useEvidences } from "queries/useEvidences"; -import { responsiveSize } from "styles/responsiveSize"; +import { landscapeStyle } from "styles/landscapeStyle"; import EvidenceCard from "components/EvidenceCard"; import { SkeletonEvidenceCard } from "components/StyledSkeleton"; import EvidenceSearch from "./EvidenceSearch"; import { Divider } from "components/Divider"; -import { spamEvidencesIds } from "src/consts"; const Container = styled.div` width: 100%; display: flex; flex-direction: column; gap: 16px; - align-items: center; - padding: ${responsiveSize(16, 32)} ${responsiveSize(8, 32)}; + padding: 20px 16px 16px; + + ${landscapeStyle( + () => css` + padding: 32px; + ` + )} `; const StyledLabel = styled.label` diff --git a/web/src/pages/Cases/CaseDetails/Overview/index.tsx b/web/src/pages/Cases/CaseDetails/Overview/index.tsx index 6cdae7044..32e9cd0f6 100644 --- a/web/src/pages/Cases/CaseDetails/Overview/index.tsx +++ b/web/src/pages/Cases/CaseDetails/Overview/index.tsx @@ -1,5 +1,5 @@ import React, { useMemo } from "react"; -import styled from "styled-components"; +import styled, { css } from "styled-components"; import { useParams } from "react-router-dom"; import { formatEther } from "viem"; @@ -11,7 +11,7 @@ import { getLocalRounds } from "utils/getLocalRounds"; import { useCourtPolicy } from "queries/useCourtPolicy"; import { useDisputeDetailsQuery } from "queries/useDisputeDetailsQuery"; -import { responsiveSize } from "styles/responsiveSize"; +import { landscapeStyle } from "styles/landscapeStyle"; import { DisputeContext } from "components/DisputePreview/DisputeContext"; import { Policies } from "components/DisputePreview/Policies"; @@ -24,8 +24,15 @@ const Container = styled.div` height: auto; display: flex; flex-direction: column; - gap: ${responsiveSize(16, 24)}; - padding: ${responsiveSize(16, 32)} ${responsiveSize(8, 32)}; + gap: 16px; + padding: 20px 16px 16px; + + ${landscapeStyle( + () => css` + padding: 32px; + gap: 24px; + ` + )} `; interface IOverview { diff --git a/web/src/pages/Cases/CaseDetails/Voting/PendingVotesBox.tsx b/web/src/pages/Cases/CaseDetails/Voting/PendingVotesBox.tsx index 3635a56d2..397140329 100644 --- a/web/src/pages/Cases/CaseDetails/Voting/PendingVotesBox.tsx +++ b/web/src/pages/Cases/CaseDetails/Voting/PendingVotesBox.tsx @@ -12,7 +12,7 @@ const StyledBox = styled(Box)` border-radius: 3px; padding: 16px; display: flex; - gap: 8px; + gap: 10px; align-items: center; margin-bottom: -4px; > p { diff --git a/web/src/pages/Cases/CaseDetails/Voting/VotesDetails/AccordionTitle.tsx b/web/src/pages/Cases/CaseDetails/Voting/VotesDetails/AccordionTitle.tsx index 4eaed0799..b36e0a2a6 100644 --- a/web/src/pages/Cases/CaseDetails/Voting/VotesDetails/AccordionTitle.tsx +++ b/web/src/pages/Cases/CaseDetails/Voting/VotesDetails/AccordionTitle.tsx @@ -10,18 +10,18 @@ import { isUndefined } from "utils/index"; import { shortenAddress } from "utils/shortenAddress"; import { landscapeStyle } from "styles/landscapeStyle"; -import { responsiveSize } from "styles/responsiveSize"; const TitleContainer = styled.div` display: flex; flex-direction: column; align-items: start; - gap: ${responsiveSize(8, 12)}; + gap: 11px; flex-wrap: wrap; ${landscapeStyle( () => css` flex-direction: row; align-items: center; + gap: 12px; ` )} `; diff --git a/web/src/pages/Cases/CaseDetails/Voting/VotesDetails/index.tsx b/web/src/pages/Cases/CaseDetails/Voting/VotesDetails/index.tsx index 6a6eb0e6b..99cc657e9 100644 --- a/web/src/pages/Cases/CaseDetails/Voting/VotesDetails/index.tsx +++ b/web/src/pages/Cases/CaseDetails/Voting/VotesDetails/index.tsx @@ -1,5 +1,5 @@ import React, { useMemo } from "react"; -import styled from "styled-components"; +import styled, { css } from "styled-components"; import { Card, CustomAccordion } from "@kleros/ui-components-library"; @@ -8,7 +8,8 @@ import { DrawnJuror } from "utils/getDrawnJurorsWithCount"; import { getVoteChoice } from "utils/getVoteChoice"; import { isUndefined } from "utils/index"; -import { responsiveSize } from "styles/responsiveSize"; +import { hoverShortTransitionTiming } from "styles/commonStyles"; +import { landscapeStyle } from "styles/landscapeStyle"; import InfoCard from "components/InfoCard"; @@ -27,21 +28,43 @@ const StyledAccordion = styled(CustomAccordion)` } [class*="accordion-button"] { - padding: 12px ${responsiveSize(8, 16)} !important; + padding: 16px !important; margin: 4px 0; } [class*="Body"] { - padding: ${responsiveSize(6, 10)} ${responsiveSize(4, 16)}; + padding: 8px; } + + ${landscapeStyle( + () => css` + [class*="accordion-button"] { + padding: 12px 16px !important; + } + [class*="Body"] { + padding: 12px 16px; + } + ` + )} `; const StyledCard = styled(Card)` + ${hoverShortTransitionTiming} width: 100%; height: auto; - padding: 11.5px ${responsiveSize(8, 18)}; + padding: 16px; border: 1px solid ${({ theme }) => theme.stroke}; margin: 4px 0; + + :hover { + background-color: ${({ theme }) => theme.lightGrey}BB; + } + + ${landscapeStyle( + () => css` + padding: 12px 16px; + ` + )} `; const AccordionContentContainer = styled.div` diff --git a/web/src/pages/Cases/CaseDetails/Voting/index.tsx b/web/src/pages/Cases/CaseDetails/Voting/index.tsx index fdfcac398..8b9146292 100644 --- a/web/src/pages/Cases/CaseDetails/Voting/index.tsx +++ b/web/src/pages/Cases/CaseDetails/Voting/index.tsx @@ -1,5 +1,5 @@ import React, { useMemo, useState } from "react"; -import styled from "styled-components"; +import styled, { css } from "styled-components"; import Skeleton from "react-loading-skeleton"; import { useParams } from "react-router-dom"; @@ -18,6 +18,7 @@ import { useAppealCost } from "queries/useAppealCost"; import { useDisputeDetailsQuery } from "queries/useDisputeDetailsQuery"; import { responsiveSize } from "styles/responsiveSize"; +import { landscapeStyle } from "styles/landscapeStyle"; import { getPeriodEndTimestamp } from "components/DisputeView"; import InfoCard from "components/InfoCard"; @@ -27,8 +28,13 @@ import Classic from "./Classic"; import VotingHistory from "./VotingHistory"; const Container = styled.div` - padding: ${responsiveSize(16, 32)} ${responsiveSize(8, 32)}; - padding-bottom: ${responsiveSize(8, 16)}; + padding: 20px 16px 16px; + + ${landscapeStyle( + () => css` + padding: 32px 32px 16px; + ` + )} `; const InfoCardContainer = styled.div` diff --git a/web/src/pages/Cases/index.tsx b/web/src/pages/Cases/index.tsx index 7783ec823..dc7bacd9c 100644 --- a/web/src/pages/Cases/index.tsx +++ b/web/src/pages/Cases/index.tsx @@ -1,11 +1,11 @@ import React from "react"; -import styled from "styled-components"; -import { MAX_WIDTH_LANDSCAPE } from "styles/landscapeStyle"; - -import { Routes, Route } from "react-router-dom"; +import styled, { css } from "styled-components"; +import { MAX_WIDTH_LANDSCAPE, landscapeStyle } from "styles/landscapeStyle"; import { responsiveSize } from "styles/responsiveSize"; +import { Routes, Route } from "react-router-dom"; + import AttachmentDisplay from "./AttachmentDisplay"; import CaseDetails from "./CaseDetails"; import CasesFetcher from "./CasesFetcher"; @@ -13,9 +13,15 @@ import CasesFetcher from "./CasesFetcher"; const Container = styled.div` width: 100%; background-color: ${({ theme }) => theme.lightBackground}; - padding: ${responsiveSize(32, 48)} ${responsiveSize(8, 132)} ${responsiveSize(40, 60)}; + padding: 32px 16px 40px; max-width: ${MAX_WIDTH_LANDSCAPE}; margin: 0 auto; + + ${landscapeStyle( + () => css` + padding: 48px ${responsiveSize(0, 132)} 60px; + ` + )} `; const Cases: React.FC = () => ( diff --git a/web/src/pages/Courts/CourtDetails/StakePanel/InputDisplay.tsx b/web/src/pages/Courts/CourtDetails/StakePanel/InputDisplay.tsx index 45818bba7..c8bca450e 100644 --- a/web/src/pages/Courts/CourtDetails/StakePanel/InputDisplay.tsx +++ b/web/src/pages/Courts/CourtDetails/StakePanel/InputDisplay.tsx @@ -1,8 +1,6 @@ import React, { useState, useMemo, useEffect } from "react"; import styled from "styled-components"; -import { hoverShortTransitionTiming } from "styles/commonStyles"; - import { useParams } from "react-router-dom"; import { useDebounce } from "react-use"; @@ -12,6 +10,10 @@ import { commify, uncommify } from "utils/commify"; import { formatPNK, roundNumberDown } from "utils/format"; import { isUndefined } from "utils/index"; +import { useCourtDetails } from "queries/useCourtDetails"; + +import { hoverShortTransitionTiming } from "styles/commonStyles"; + import { NumberInputField } from "components/NumberInputField"; import StakeWithdrawButton, { ActionType } from "./StakeWithdrawButton"; @@ -75,6 +77,7 @@ const InputDisplay: React.FC = ({ action, amount, setAmount }) => const { id } = useParams(); const { balance, jurorBalance } = usePnkData({ courtId: id }); + const { data: courtDetails } = useCourtDetails(id); const parsedBalance = formatPNK(balance ?? 0n, 0, true); @@ -88,10 +91,18 @@ const InputDisplay: React.FC = ({ action, amount, setAmount }) => setErrorMsg("Insufficient balance to stake this amount"); } else if (!isStaking && jurorBalance && parsedAmount > jurorBalance[2]) { setErrorMsg("Insufficient staked amount to withdraw this amount"); + } else if ( + action === ActionType.stake && + courtDetails && + jurorBalance && + parsedAmount !== 0n && + jurorBalance[2] + parsedAmount < BigInt(courtDetails?.court?.minStake) + ) { + setErrorMsg(`Min Stake in court is: ${formatPNK(courtDetails?.court?.minStake)} PNK`); } else { setErrorMsg(undefined); } - }, [parsedAmount, isStaking, balance, jurorBalance]); + }, [parsedAmount, isStaking, balance, jurorBalance, action, courtDetails]); return ( <> diff --git a/web/src/pages/Courts/CourtDetails/StakePanel/Simulator/index.tsx b/web/src/pages/Courts/CourtDetails/StakePanel/Simulator/index.tsx index e350dd9d4..77aff9496 100644 --- a/web/src/pages/Courts/CourtDetails/StakePanel/Simulator/index.tsx +++ b/web/src/pages/Courts/CourtDetails/StakePanel/Simulator/index.tsx @@ -2,7 +2,6 @@ import React, { useMemo } from "react"; import styled, { css } from "styled-components"; import { landscapeStyle } from "styles/landscapeStyle"; -import { responsiveSize } from "styles/responsiveSize"; import { useParams } from "react-router-dom"; import Skeleton from "react-loading-skeleton"; @@ -35,10 +34,16 @@ const Container = styled.div` flex-direction: column; background-color: ${({ theme }) => theme.lightBlue}; box-shadow: 0px 4px 12px rgba(0, 0, 0, 0.1); - padding: ${responsiveSize(16, 20)} ${responsiveSize(8, 20)}; + padding: 16px; border-radius: 8px; border: 1px solid ${({ theme }) => theme.mediumBlue}; justify-content: center; + + ${landscapeStyle( + () => css` + padding: 20px; + ` + )} `; const ItemsContainer = styled.div` diff --git a/web/src/pages/Courts/CourtDetails/StakePanel/StakeWithdrawButton.tsx b/web/src/pages/Courts/CourtDetails/StakePanel/StakeWithdrawButton.tsx index 5d0717a72..240f580cb 100644 --- a/web/src/pages/Courts/CourtDetails/StakePanel/StakeWithdrawButton.tsx +++ b/web/src/pages/Courts/CourtDetails/StakePanel/StakeWithdrawButton.tsx @@ -15,14 +15,14 @@ import { useSimulatePnkIncreaseAllowance, useWritePnkIncreaseAllowance, } from "hooks/contracts/generated"; -import { useCourtDetails } from "hooks/queries/useCourtDetails"; import { useLockOverlayScroll } from "hooks/useLockOverlayScroll"; import { usePnkData } from "hooks/usePNKData"; -import { formatETH } from "utils/format"; import { isUndefined } from "utils/index"; import { parseWagmiError } from "utils/parseWagmiError"; import { refetchWithRetry } from "utils/refecthWithRetry"; +import { useCourtDetails } from "queries/useCourtDetails"; + import { EnsureChain } from "components/EnsureChain"; import StakeWithdrawPopup from "./StakeWithdrawPopup"; @@ -67,9 +67,8 @@ const StakeWithdrawButton: React.FC = ({ const controllerRef = useRef(null); useLockOverlayScroll(isPopupOpen); - const { data: courtDetails } = useCourtDetails(id); const { balance, jurorBalance, allowance, refetchAllowance } = usePnkData({ courtId: id }); - + const { data: courtDetails } = useCourtDetails(id); const publicClient = usePublicClient(); const isStaking = action === ActionType.stake; @@ -181,6 +180,16 @@ const StakeWithdrawButton: React.FC = ({ ) ); }); + } else { + updatePopupState( + signal, + getStakeSteps( + StakeSteps.StakeFailed, + ...commonArgs, + undefined, + new Error("Simulation Failed. Please restart the process.") + ) + ); } }, [setStake, setStakeConfig, publicClient, amount, theme, action] @@ -248,20 +257,20 @@ const StakeWithdrawButton: React.FC = ({ useEffect(() => { if (isPopupOpen) return; - if ( - action === ActionType.stake && - targetStake !== 0n && - courtDetails && - targetStake < BigInt(courtDetails.court?.minStake) - ) { - setErrorMsg(`Min Stake in court is: ${formatETH(courtDetails?.court?.minStake)}`); - } else if (setStakeError || allowanceError) { + if (setStakeError || allowanceError) { setErrorMsg(parseWagmiError(setStakeError || allowanceError)); } - }, [setStakeError, setErrorMsg, targetStake, courtDetails, allowanceError, isPopupOpen, action]); + }, [setStakeError, setErrorMsg, targetStake, allowanceError, isPopupOpen]); const isDisabled = useMemo(() => { - if (parsedAmount == 0n) return true; + if ( + parsedAmount == 0n || + (action === ActionType.stake && + targetStake !== 0n && + courtDetails && + targetStake < BigInt(courtDetails?.court?.minStake)) + ) + return true; if (isAllowance) { return isUndefined(increaseAllowanceConfig) || isSimulatingAllowance || !isUndefined(allowanceError); } @@ -275,6 +284,9 @@ const StakeWithdrawButton: React.FC = ({ setStakeError, allowanceError, isAllowance, + targetStake, + action, + courtDetails, ]); const closePopup = () => { diff --git a/web/src/pages/Courts/CourtDetails/Stats.tsx b/web/src/pages/Courts/CourtDetails/Stats.tsx index 5d41d915b..9f292cb6c 100644 --- a/web/src/pages/Courts/CourtDetails/Stats.tsx +++ b/web/src/pages/Courts/CourtDetails/Stats.tsx @@ -31,12 +31,12 @@ import { StyledSkeleton } from "components/StyledSkeleton"; const StyledAccordion = styled(Accordion)` > * > button { - padding: 12px ${responsiveSize(8, 24)} !important; + padding: 12px 16px !important; justify-content: unset; } //adds padding to body container > * > div > div { - padding: 0; + padding: 0 8px 8px; } [class*="accordion-item"] { margin: 0; @@ -47,6 +47,9 @@ const StyledAccordion = styled(Accordion)` > * > div > div { padding: 0 24px; } + > * > button { + padding: 12px 24px !important; + } ` )} `; diff --git a/web/src/pages/Courts/CourtDetails/index.tsx b/web/src/pages/Courts/CourtDetails/index.tsx index dfabb58ea..fd3f3d610 100644 --- a/web/src/pages/Courts/CourtDetails/index.tsx +++ b/web/src/pages/Courts/CourtDetails/index.tsx @@ -59,11 +59,17 @@ const ButtonContainer = styled.div` `; const StyledCard = styled(Card)` - padding: ${responsiveSize(16, 32)} ${responsiveSize(8, 32)}; + padding: 16px; margin-top: 12px; width: 100%; height: auto; min-height: 100px; + + ${landscapeStyle( + () => css` + padding: 32px; + ` + )} `; const StyledBreadcrumb = styled(Breadcrumb)` diff --git a/web/src/pages/Courts/index.tsx b/web/src/pages/Courts/index.tsx index 963f87f57..fb0419bcc 100644 --- a/web/src/pages/Courts/index.tsx +++ b/web/src/pages/Courts/index.tsx @@ -1,8 +1,8 @@ import React from "react"; -import styled from "styled-components"; +import styled, { css } from "styled-components"; +import { MAX_WIDTH_LANDSCAPE, landscapeStyle } from "styles/landscapeStyle"; import { responsiveSize } from "styles/responsiveSize"; -import { MAX_WIDTH_LANDSCAPE } from "styles/landscapeStyle"; import { Routes, Route, Navigate } from "react-router-dom"; @@ -12,9 +12,15 @@ import TopSearch from "./TopSearch"; const Container = styled.div` width: 100%; background-color: ${({ theme }) => theme.lightBackground}; - padding: ${responsiveSize(32, 48)} ${responsiveSize(8, 132)} ${responsiveSize(40, 60)}; + padding: 32px 16px 40px; max-width: ${MAX_WIDTH_LANDSCAPE}; margin: 0 auto; + + ${landscapeStyle( + () => css` + padding: 48px ${responsiveSize(0, 132)} 60px; + ` + )} `; const Courts: React.FC = () => { diff --git a/web/src/pages/Dashboard/Courts/CourtCard/Stake.tsx b/web/src/pages/Dashboard/Courts/CourtCard/Stake.tsx index 21b291642..c1617b621 100644 --- a/web/src/pages/Dashboard/Courts/CourtCard/Stake.tsx +++ b/web/src/pages/Dashboard/Courts/CourtCard/Stake.tsx @@ -12,7 +12,7 @@ import PnkIcon from "svgs/icons/pnk.svg"; const Container = styled.div` display: flex; flex-direction: row; - gap: 16px; + gap: 8px; width: 100%; justify-content: flex-start; align-items: center; @@ -20,6 +20,7 @@ const Container = styled.div` ${landscapeStyle( () => css` width: auto; + gap: 12px; ` )} `; diff --git a/web/src/pages/Dashboard/Courts/CourtCard/index.tsx b/web/src/pages/Dashboard/Courts/CourtCard/index.tsx index 79bc7b82c..360f97ca6 100644 --- a/web/src/pages/Dashboard/Courts/CourtCard/index.tsx +++ b/web/src/pages/Dashboard/Courts/CourtCard/index.tsx @@ -15,18 +15,21 @@ const Container = styled(_Card)` justify-content: space-between; height: auto; width: 100%; - padding: 21px 20px 25px 20px; + padding: 20px 16px 24px; border-left: 5px solid ${({ theme }) => theme.secondaryPurple}; flex-wrap: wrap; - gap: 20px; + gap: 16px; + + :hover { + cursor: auto; + } ${({ theme }) => (theme.name === "light" ? `box-shadow: 0px 2px 3px 0px ${theme.stroke};` : "")} ${landscapeStyle( - () => - css` - padding: 21.5px 32px; - ` + () => css` + padding: 21.5px 32px; + ` )} `; @@ -38,7 +41,7 @@ interface ICourtCard { const CourtCard: React.FC = ({ name, stake, id }) => { return ( - + diff --git a/web/src/pages/Dashboard/Courts/index.tsx b/web/src/pages/Dashboard/Courts/index.tsx index aaa17a4bc..c74dabfd4 100644 --- a/web/src/pages/Dashboard/Courts/index.tsx +++ b/web/src/pages/Dashboard/Courts/index.tsx @@ -21,7 +21,7 @@ const Container = styled.div` const CourtCardsContainer = styled.div` display: flex; flex-direction: column; - gap: 4px; + gap: 12px; z-index: 0; ${landscapeStyle( diff --git a/web/src/pages/Dashboard/index.tsx b/web/src/pages/Dashboard/index.tsx index 51fc446ab..bdf806288 100644 --- a/web/src/pages/Dashboard/index.tsx +++ b/web/src/pages/Dashboard/index.tsx @@ -1,5 +1,5 @@ import React, { useMemo } from "react"; -import styled from "styled-components"; +import styled, { css } from "styled-components"; import { useNavigate, useParams } from "react-router-dom"; import { useAccount } from "wagmi"; @@ -12,7 +12,7 @@ import { useUserQuery } from "queries/useUser"; import { OrderDirection } from "src/graphql/graphql"; -import { MAX_WIDTH_LANDSCAPE } from "styles/landscapeStyle"; +import { MAX_WIDTH_LANDSCAPE, landscapeStyle } from "styles/landscapeStyle"; import { responsiveSize } from "styles/responsiveSize"; import CasesDisplay from "components/CasesDisplay"; @@ -26,9 +26,15 @@ import JurorInfo from "./JurorInfo"; const Container = styled.div` width: 100%; background-color: ${({ theme }) => theme.lightBackground}; - padding: ${responsiveSize(32, 48)} ${responsiveSize(8, 132)} ${responsiveSize(40, 60)}; + padding: 32px 16px 40px; max-width: ${MAX_WIDTH_LANDSCAPE}; margin: 0 auto; + + ${landscapeStyle( + () => css` + padding: 48px ${responsiveSize(0, 132)} 60px; + ` + )} `; const StyledCasesDisplay = styled(CasesDisplay)` diff --git a/web/src/pages/GetPnk/index.tsx b/web/src/pages/GetPnk/index.tsx index 26eb36651..6ea2f3268 100644 --- a/web/src/pages/GetPnk/index.tsx +++ b/web/src/pages/GetPnk/index.tsx @@ -1,7 +1,7 @@ import React from "react"; -import styled from "styled-components"; +import styled, { css } from "styled-components"; -import { MAX_WIDTH_LANDSCAPE } from "styles/landscapeStyle"; +import { MAX_WIDTH_LANDSCAPE, landscapeStyle } from "styles/landscapeStyle"; import { responsiveSize } from "styles/responsiveSize"; import { isProductionDeployment } from "consts/index"; @@ -19,7 +19,7 @@ const Wrapper = styled.div` const Container = styled.div` width: 100%; background-color: ${({ theme }) => theme.lightBackground}; - padding: 16px ${responsiveSize(8, 132)} ${responsiveSize(40, 60)}; + padding: 16px 16px 40px; max-width: ${MAX_WIDTH_LANDSCAPE}; margin: 0 auto; display: flex; @@ -27,6 +27,12 @@ const Container = styled.div` align-items: center; justify-content: center; gap: 24px; + + ${landscapeStyle( + () => css` + padding: 16px ${responsiveSize(0, 132)} 60px; + ` + )} `; const GetPnk: React.FC = () => ( diff --git a/web/src/pages/Home/Community/index.tsx b/web/src/pages/Home/Community/index.tsx index d4c003c51..0127fb9e0 100644 --- a/web/src/pages/Home/Community/index.tsx +++ b/web/src/pages/Home/Community/index.tsx @@ -26,7 +26,7 @@ const StyledCard = styled(Card)` gap: 12px; flex-direction: column; flex-wrap: wrap; - padding: ${responsiveSize(12, 24)} ${responsiveSize(8, 24)}; + padding: 16px; align-items: flex-start; ${landscapeStyle( diff --git a/web/src/pages/Home/CourtOverview/BarChart.tsx b/web/src/pages/Home/CourtOverview/BarChart.tsx index 647a863c9..82b7af9b4 100644 --- a/web/src/pages/Home/CourtOverview/BarChart.tsx +++ b/web/src/pages/Home/CourtOverview/BarChart.tsx @@ -21,7 +21,6 @@ const formatter = new Intl.NumberFormat("en", { notation: "compact" }); const BarContainer = styled.div` height: 220px; - margin-top: 16px; `; ChartJS.register(BarElement); diff --git a/web/src/pages/Home/CourtOverview/Chart.tsx b/web/src/pages/Home/CourtOverview/Chart.tsx index 94cf8f3bb..8152d4521 100644 --- a/web/src/pages/Home/CourtOverview/Chart.tsx +++ b/web/src/pages/Home/CourtOverview/Chart.tsx @@ -20,6 +20,7 @@ const Container = styled.div` margin-bottom: ${responsiveSize(16, 32)}; display: flex; flex-direction: column; + gap: 16px; `; const StyledDropdown = styled(DropdownSelect)` diff --git a/web/src/pages/Home/CourtOverview/ExtraStats.tsx b/web/src/pages/Home/CourtOverview/ExtraStats.tsx index 75b921706..3ecafc8fc 100644 --- a/web/src/pages/Home/CourtOverview/ExtraStats.tsx +++ b/web/src/pages/Home/CourtOverview/ExtraStats.tsx @@ -1,7 +1,7 @@ import React, { useState } from "react"; -import styled from "styled-components"; +import styled, { css } from "styled-components"; -import { responsiveSize } from "styles/responsiveSize"; +import { landscapeStyle } from "styles/landscapeStyle"; import { DropdownSelect } from "@kleros/ui-components-library"; @@ -15,9 +15,16 @@ import ExtraStatsDisplay from "components/ExtraStatsDisplay"; const StyledCard = styled.div` display: flex; flex-wrap: wrap; - gap: 12px 24px; + gap: 12px 16px; justify-content: center; - margin-top: ${responsiveSize(12, 16)}; + margin-top: 12px; + + ${landscapeStyle( + () => css` + margin-top: 16px; + gap: 16px 24px; + ` + )} `; const StyledLabel = styled.label` diff --git a/web/src/pages/Home/CourtOverview/Header.tsx b/web/src/pages/Home/CourtOverview/Header.tsx index 9c233199d..bc1cfa2d1 100644 --- a/web/src/pages/Home/CourtOverview/Header.tsx +++ b/web/src/pages/Home/CourtOverview/Header.tsx @@ -1,12 +1,12 @@ import React from "react"; import styled from "styled-components"; -import { responsiveSize } from "styles/responsiveSize"; - import { Button } from "@kleros/ui-components-library"; import Bookmark from "svgs/icons/bookmark.svg"; +import { responsiveSize } from "styles/responsiveSize"; + import { InternalLink } from "components/InternalLink"; const StyledHeader = styled.div` diff --git a/web/src/pages/Home/CourtOverview/Stats.tsx b/web/src/pages/Home/CourtOverview/Stats.tsx index aa756203b..503bd6a70 100644 --- a/web/src/pages/Home/CourtOverview/Stats.tsx +++ b/web/src/pages/Home/CourtOverview/Stats.tsx @@ -1,5 +1,5 @@ import React from "react"; -import styled from "styled-components"; +import styled, { css } from "styled-components"; import { Card } from "@kleros/ui-components-library"; @@ -17,18 +17,24 @@ import { calculateSubtextRender } from "utils/calculateSubtextRender"; import { formatETH, formatPNK, formatUnitsWei, formatUSD } from "utils/format"; import { isUndefined } from "utils/index"; -import { responsiveSize } from "styles/responsiveSize"; +import { landscapeStyle } from "styles/landscapeStyle"; import StatDisplay, { IStatDisplay } from "components/StatDisplay"; import { StyledSkeleton } from "components/StyledSkeleton"; const StyledCard = styled(Card)` + display: grid; + grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); width: auto; height: fit-content; gap: 16px 8px; - padding: ${responsiveSize(16, 24)} ${responsiveSize(8, 24)}; - display: grid; - grid-template-columns: repeat(auto-fit, minmax(152px, 1fr)); + padding: 16px; + + ${landscapeStyle( + () => css` + padding: 24px; + ` + )} `; const getLastOrZero = (src: HomePageQuery["counters"], stat: HomePageQueryDataPoints) => @@ -45,7 +51,7 @@ interface IStat { const stats: IStat[] = [ { - title: "PNK staked", + title: "PNK Staked", coinId: 0, getText: (counters) => formatPNK(getLastOrZero(counters, "stakedPNK")), getSubtext: (counters, coinPrice) => @@ -63,7 +69,7 @@ const stats: IStat[] = [ icon: EthereumIcon, }, { - title: "PNK redistributed", + title: "PNK Redistributed", coinId: 0, getText: (counters) => formatPNK(getLastOrZero(counters, "redistributedPNK")), getSubtext: (counters, coinPrice) => @@ -72,7 +78,7 @@ const stats: IStat[] = [ icon: PNKRedistributedIcon, }, { - title: "Active jurors", + title: "Active Jurors", getText: (counters) => getLastOrZero(counters, "activeJurors"), color: "green", icon: JurorIcon, diff --git a/web/src/pages/Home/CourtOverview/TimeSeriesChart.tsx b/web/src/pages/Home/CourtOverview/TimeSeriesChart.tsx index 594f6efb9..bdfd07d6d 100644 --- a/web/src/pages/Home/CourtOverview/TimeSeriesChart.tsx +++ b/web/src/pages/Home/CourtOverview/TimeSeriesChart.tsx @@ -16,7 +16,6 @@ import "chartjs-adapter-moment"; const LineContainer = styled.div` height: 220px; - margin-top: 16px; `; ChartJS.register(CategoryScale, LinearScale, PointElement, LineElement, TimeScale, Tooltip); diff --git a/web/src/pages/Home/TopJurors/Header/Coherence.tsx b/web/src/pages/Home/TopJurors/Header/Coherence.tsx index 23d6c6d6b..b4823abcb 100644 --- a/web/src/pages/Home/TopJurors/Header/Coherence.tsx +++ b/web/src/pages/Home/TopJurors/Header/Coherence.tsx @@ -1,9 +1,9 @@ import React from "react"; import styled, { css } from "styled-components"; -import { useWindowSize } from "react-use"; +import { landscapeStyle } from "styles/landscapeStyle"; -import { BREAKPOINT_LANDSCAPE, landscapeStyle } from "styles/landscapeStyle"; +import useIsDesktop from "hooks/useIsDesktop"; import WithHelpTooltip from "components/WithHelpTooltip"; @@ -32,13 +32,11 @@ const coherentVotesTooltipMsg = "the juror voted"; const Coherence: React.FC = () => { - const { width } = useWindowSize(); + const isDesktop = useIsDesktop(); + return ( - BREAKPOINT_LANDSCAPE ? "top" : "left"} - tooltipMsg={coherentVotesTooltipMsg} - > + ); }; diff --git a/web/src/pages/Home/TopJurors/Header/MobileHeader.tsx b/web/src/pages/Home/TopJurors/Header/MobileHeader.tsx index 5218967de..bc84c71d9 100644 --- a/web/src/pages/Home/TopJurors/Header/MobileHeader.tsx +++ b/web/src/pages/Home/TopJurors/Header/MobileHeader.tsx @@ -1,11 +1,10 @@ import React from "react"; import styled, { css } from "styled-components"; -import { landscapeStyle } from "styles/landscapeStyle"; -import { responsiveSize } from "styles/responsiveSize"; - import { useToggle } from "react-use"; +import { landscapeStyle } from "styles/landscapeStyle"; + import HowItWorks from "components/HowItWorks"; import JurorLevels from "components/Popup/MiniGuides/JurorLevels"; @@ -14,15 +13,17 @@ const Container = styled.div` justify-content: space-between; width: 100%; background-color: ${({ theme }) => theme.lightBlue}; - padding: 16px ${responsiveSize(8, 24)}; - border 1px solid ${({ theme }) => theme.stroke}; + padding: 16px; + border: 1px solid ${({ theme }) => theme.stroke}; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom: none; flex-wrap: wrap; + ${landscapeStyle( () => css` display: none; + padding: 16px 24px; ` )} `; diff --git a/web/src/pages/Home/TopJurors/Header/Rewards.tsx b/web/src/pages/Home/TopJurors/Header/Rewards.tsx index 5365c3c7b..29f493d03 100644 --- a/web/src/pages/Home/TopJurors/Header/Rewards.tsx +++ b/web/src/pages/Home/TopJurors/Header/Rewards.tsx @@ -3,6 +3,8 @@ import styled, { css } from "styled-components"; import { landscapeStyle } from "styles/landscapeStyle"; +import useIsDesktop from "hooks/useIsDesktop"; + import WithHelpTooltip from "components/WithHelpTooltip"; const Container = styled.div` @@ -16,14 +18,13 @@ const Container = styled.div` } ${landscapeStyle( - () => - css` - font-size: 14px !important; - justify-content: center; - &::before { - content: "Total Rewards"; - } - ` + () => css` + font-size: 14px !important; + justify-content: center; + &::before { + content: "Total Rewards"; + } + ` )} `; @@ -33,10 +34,14 @@ const totalRewardsTooltipMsg = "is coherent with the final ruling receive the Juror Rewards composed of " + "arbitration fees (ETH) + PNK redistribution between jurors."; -const Rewards: React.FC = () => ( - - - -); +const Rewards: React.FC = () => { + const isDesktop = useIsDesktop(); + + return ( + + + + ); +}; export default Rewards; diff --git a/web/src/pages/Home/TopJurors/JurorCard/DesktopCard.tsx b/web/src/pages/Home/TopJurors/JurorCard/DesktopCard.tsx index 7e1785965..4185b988a 100644 --- a/web/src/pages/Home/TopJurors/JurorCard/DesktopCard.tsx +++ b/web/src/pages/Home/TopJurors/JurorCard/DesktopCard.tsx @@ -3,6 +3,7 @@ import styled, { css } from "styled-components"; import { landscapeStyle } from "styles/landscapeStyle"; import { responsiveSize } from "styles/responsiveSize"; +import { hoverShortTransitionTiming } from "styles/commonStyles"; import Coherence from "./Coherence"; import JurorLevel from "./JurorLevel"; @@ -11,6 +12,7 @@ import Rank from "./Rank"; import Rewards from "./Rewards"; const Container = styled.div` + ${hoverShortTransitionTiming} display: none; width: 100%; background-color: ${({ theme }) => theme.whiteBackground}; @@ -28,6 +30,10 @@ const Container = styled.div` column-gap: ${responsiveSize(12, 28, 900)}; ` )} + + :hover { + background-color: ${({ theme }) => theme.lightGrey}BB; + } `; interface IDesktopCard { diff --git a/web/src/pages/Home/TopJurors/JurorCard/MobileCard.tsx b/web/src/pages/Home/TopJurors/JurorCard/MobileCard.tsx index d8963bd65..7bf467191 100644 --- a/web/src/pages/Home/TopJurors/JurorCard/MobileCard.tsx +++ b/web/src/pages/Home/TopJurors/JurorCard/MobileCard.tsx @@ -2,6 +2,7 @@ import React from "react"; import styled, { css } from "styled-components"; import { landscapeStyle } from "styles/landscapeStyle"; +import { hoverShortTransitionTiming } from "styles/commonStyles"; import HeaderCoherence from "../Header/Coherence"; import HeaderRewards from "../Header/Rewards"; @@ -13,22 +14,27 @@ import Rank from "./Rank"; import Rewards from "./Rewards"; const Container = styled.div` + ${hoverShortTransitionTiming} display: flex; justify-content: space-between; flex-wrap: wrap; width: 100%; background-color: ${({ theme }) => theme.whiteBackground}; - padding: 8px 8px 12px; + padding: 8px 16px 12px; border: 1px solid ${({ theme }) => theme.stroke}; border-top: none; align-items: center; - gap: 18px; + gap: 16px; ${landscapeStyle( () => css` display: none; ` )} + + :hover { + background-color: ${({ theme }) => theme.lightGrey}BB; + } `; const TopSide = styled.div` @@ -50,7 +56,7 @@ const HeaderRewardsAndRewards = styled.div` display: flex; flex-direction: column; width: 100%; - gap: 5px; + gap: 8px; `; const BottomSide = styled.div` @@ -64,7 +70,7 @@ const HeaderCoherenceAndCoherence = styled.div` display: flex; flex-direction: column; align-items: flex-end; - gap: 5px; + gap: 8px; svg { margin-right: 0; diff --git a/web/src/pages/Home/TopJurors/JurorCard/Rewards.tsx b/web/src/pages/Home/TopJurors/JurorCard/Rewards.tsx index 90aa61b10..59ba64f6c 100644 --- a/web/src/pages/Home/TopJurors/JurorCard/Rewards.tsx +++ b/web/src/pages/Home/TopJurors/JurorCard/Rewards.tsx @@ -5,6 +5,7 @@ import EthIcon from "svgs/icons/eth.svg"; import PnkIcon from "svgs/icons/kleros.svg"; import { useUserQuery } from "hooks/queries/useUser"; +import useIsDesktop from "hooks/useIsDesktop"; import { getFormattedRewards } from "utils/jurorRewardConfig"; import { landscapeStyle } from "styles/landscapeStyle"; @@ -48,11 +49,17 @@ const Rewards: React.FC = ({ address }) => { const formattedRewards = getFormattedRewards(userData, {}); const ethReward = formattedRewards.find((r) => r.token === "ETH")?.amount; const pnkReward = formattedRewards.find((r) => r.token === "PNK")?.amount; + const isDesktop = useIsDesktop(); return ( - + + diff --git a/web/src/pages/Home/index.tsx b/web/src/pages/Home/index.tsx index 65a861ba5..da6f92fbe 100644 --- a/web/src/pages/Home/index.tsx +++ b/web/src/pages/Home/index.tsx @@ -1,7 +1,7 @@ import React from "react"; -import styled from "styled-components"; +import styled, { css } from "styled-components"; -import { MAX_WIDTH_LANDSCAPE } from "styles/landscapeStyle"; +import { MAX_WIDTH_LANDSCAPE, landscapeStyle } from "styles/landscapeStyle"; import { responsiveSize } from "styles/responsiveSize"; import { HomePageProvider } from "hooks/useHomePageContext"; @@ -22,9 +22,15 @@ const Wrapper = styled.div` const Container = styled.div` width: 100%; background-color: ${({ theme }) => theme.lightBackground}; - padding: 16px ${responsiveSize(8, 132)} ${responsiveSize(40, 60)}; + padding: 16px 16px 40px; max-width: ${MAX_WIDTH_LANDSCAPE}; margin: 0 auto; + + ${landscapeStyle( + () => css` + padding: 16px ${responsiveSize(0, 132)} 60px; + ` + )} `; const Home: React.FC = () => ( diff --git a/yarn.lock b/yarn.lock index de4ae4dd2..22ada6080 100644 --- a/yarn.lock +++ b/yarn.lock @@ -572,6 +572,17 @@ __metadata: languageName: node linkType: hard +"@babel/parser@npm:^7.25.3": + version: 7.26.3 + resolution: "@babel/parser@npm:7.26.3" + dependencies: + "@babel/types": "npm:^7.26.3" + bin: + parser: ./bin/babel-parser.js + checksum: 10/e7e3814b2dc9ee3ed605d38223471fa7d3a84cbe9474d2b5fa7ac57dc1ddf75577b1fd3a93bf7db8f41f28869bda795cddd80223f980be23623b6434bf4c88a8 + languageName: node + linkType: hard + "@babel/plugin-bugfix-firefox-class-in-computed-class-key@npm:^7.24.7": version: 7.24.7 resolution: "@babel/plugin-bugfix-firefox-class-in-computed-class-key@npm:7.24.7" @@ -1896,6 +1907,16 @@ __metadata: languageName: node linkType: hard +"@babel/types@npm:^7.26.3": + version: 7.26.3 + resolution: "@babel/types@npm:7.26.3" + dependencies: + "@babel/helper-string-parser": "npm:^7.25.9" + "@babel/helper-validator-identifier": "npm:^7.25.9" + checksum: 10/c31d0549630a89abfa11410bf82a318b0c87aa846fbf5f9905e47ba5e2aa44f41cc746442f105d622c519e4dc532d35a8d8080460ff4692f9fc7485fbf3a00eb + languageName: node + linkType: hard + "@balena/dockerignore@npm:^1.0.2": version: 1.0.2 resolution: "@balena/dockerignore@npm:1.0.2" @@ -5349,9 +5370,9 @@ __metadata: languageName: node linkType: hard -"@kleros/kleros-app@npm:^2.0.1": - version: 2.0.1 - resolution: "@kleros/kleros-app@npm:2.0.1" +"@kleros/kleros-app@npm:^2.0.2": + version: 2.0.2 + resolution: "@kleros/kleros-app@npm:2.0.2" dependencies: jose: "npm:^5.9.6" peerDependencies: @@ -5362,10 +5383,44 @@ __metadata: react-dom: ^18.3.1 viem: ^2.21.42 wagmi: ^2.13.0 - checksum: 10/a193e49fe82738eaa7df3b82857fd74a5407e6ed166edeacd2352bbd149a49ea3cfde98f130fe0473f006761260cbf2475bc4fa138ad05650540eec43b9755d1 + checksum: 10/89cf0536fed4bbb887772daa529d7cad209cea0e5105bcd366fe5e4bc7c5c14fca21aa201ba4d848c7e8addd3fc4921ac54e237afe2a5b7224c9cd219f72e08b languageName: node linkType: hard +"@kleros/kleros-app@workspace:kleros-app": + version: 0.0.0-use.local + resolution: "@kleros/kleros-app@workspace:kleros-app" + dependencies: + "@eslint/compat": "npm:^1.2.3" + "@eslint/eslintrc": "npm:^3.2.0" + "@eslint/js": "npm:^9.15.0" + "@kleros/kleros-v2-eslint-config": "workspace:^" + "@kleros/kleros-v2-prettier-config": "workspace:^" + "@types/react": "npm:^18.3.12" + "@types/react-dom": "npm:^18.3.1" + "@typescript-eslint/eslint-plugin": "npm:^8.15.0" + "@typescript-eslint/parser": "npm:^8.15.0" + eslint: "npm:^9.15.0" + eslint-config-prettier: "npm:^9.1.0" + eslint-plugin-import: "npm:^2.31.0" + globals: "npm:^15.12.0" + jose: "npm:^5.9.6" + rimraf: "npm:^6.0.1" + typescript: "npm:^5.6.3" + vite: "npm:^5.4.11" + vite-plugin-dts: "npm:^4.3.0" + vite-plugin-node-polyfills: "npm:^0.22.0" + peerDependencies: + "@tanstack/react-query": ^5.59.20 + graphql: ^16.9.0 + graphql-request: ^7.1.2 + react: ^18.3.1 + react-dom: ^18.3.1 + viem: ^2.21.42 + wagmi: ^2.13.0 + languageName: unknown + linkType: soft + "@kleros/kleros-sdk@workspace:^, @kleros/kleros-sdk@workspace:kleros-sdk": version: 0.0.0-use.local resolution: "@kleros/kleros-sdk@workspace:kleros-sdk" @@ -5566,7 +5621,7 @@ __metadata: "@eslint/js": "npm:^9.15.0" "@graphql-codegen/cli": "npm:^5.0.3" "@graphql-codegen/client-preset": "npm:^4.5.1" - "@kleros/kleros-app": "npm:^2.0.1" + "@kleros/kleros-app": "npm:^2.0.2" "@kleros/kleros-sdk": "workspace:^" "@kleros/kleros-v2-contracts": "workspace:^" "@kleros/kleros-v2-eslint-config": "workspace:^" @@ -6350,6 +6405,59 @@ __metadata: languageName: node linkType: hard +"@microsoft/api-extractor-model@npm:7.30.0": + version: 7.30.0 + resolution: "@microsoft/api-extractor-model@npm:7.30.0" + dependencies: + "@microsoft/tsdoc": "npm:~0.15.1" + "@microsoft/tsdoc-config": "npm:~0.17.1" + "@rushstack/node-core-library": "npm:5.10.0" + checksum: 10/7556760448fee6bbc0b7d4f32bd70a5d2f0b78153e2614d9834d007130f81d42338c1ccbc63e95b270bc8c3f9a50d943c4bbfe48e588e3acbbf4d8553cf40631 + languageName: node + linkType: hard + +"@microsoft/api-extractor@npm:^7.47.11": + version: 7.48.0 + resolution: "@microsoft/api-extractor@npm:7.48.0" + dependencies: + "@microsoft/api-extractor-model": "npm:7.30.0" + "@microsoft/tsdoc": "npm:~0.15.1" + "@microsoft/tsdoc-config": "npm:~0.17.1" + "@rushstack/node-core-library": "npm:5.10.0" + "@rushstack/rig-package": "npm:0.5.3" + "@rushstack/terminal": "npm:0.14.3" + "@rushstack/ts-command-line": "npm:4.23.1" + lodash: "npm:~4.17.15" + minimatch: "npm:~3.0.3" + resolve: "npm:~1.22.1" + semver: "npm:~7.5.4" + source-map: "npm:~0.6.1" + typescript: "npm:5.4.2" + bin: + api-extractor: bin/api-extractor + checksum: 10/18db5236b65a727dfd6c29a508ec9affdc31648dedf82461d4c1ecb01c2fb04ba00da6c40dff478e365dc9491d477d3462c8edb04262cf066df3cb6ef9fc8912 + languageName: node + linkType: hard + +"@microsoft/tsdoc-config@npm:~0.17.1": + version: 0.17.1 + resolution: "@microsoft/tsdoc-config@npm:0.17.1" + dependencies: + "@microsoft/tsdoc": "npm:0.15.1" + ajv: "npm:~8.12.0" + jju: "npm:~1.4.0" + resolve: "npm:~1.22.2" + checksum: 10/19f57b752413916c7ad14466650f48ba1acaf674411b6a44065e93f762d391e501cb553eeb8ae3834f1f1f064ddc83a26bdbd8026c9b2c0c194fe90818078eb9 + languageName: node + linkType: hard + +"@microsoft/tsdoc@npm:0.15.1, @microsoft/tsdoc@npm:~0.15.1": + version: 0.15.1 + resolution: "@microsoft/tsdoc@npm:0.15.1" + checksum: 10/1a92612883088fe184dba596e7ba7a0daef0e6981caeca22bad6ad551d2247294f12e368537d0d8192525cf5743f7f15fcc2ad7b3b849f26a09a15ffdd89fd0c + languageName: node + linkType: hard + "@motionone/animation@npm:^10.15.1": version: 10.15.1 resolution: "@motionone/animation@npm:10.15.1" @@ -8015,7 +8123,7 @@ __metadata: languageName: node linkType: hard -"@rollup/pluginutils@npm:^5.0.1, @rollup/pluginutils@npm:^5.1.3": +"@rollup/pluginutils@npm:^5.0.1, @rollup/pluginutils@npm:^5.1.0, @rollup/pluginutils@npm:^5.1.3": version: 5.1.3 resolution: "@rollup/pluginutils@npm:5.1.3" dependencies: @@ -8157,6 +8265,64 @@ __metadata: languageName: node linkType: hard +"@rushstack/node-core-library@npm:5.10.0": + version: 5.10.0 + resolution: "@rushstack/node-core-library@npm:5.10.0" + dependencies: + ajv: "npm:~8.13.0" + ajv-draft-04: "npm:~1.0.0" + ajv-formats: "npm:~3.0.1" + fs-extra: "npm:~7.0.1" + import-lazy: "npm:~4.0.0" + jju: "npm:~1.4.0" + resolve: "npm:~1.22.1" + semver: "npm:~7.5.4" + peerDependencies: + "@types/node": "*" + peerDependenciesMeta: + "@types/node": + optional: true + checksum: 10/4cfe66726ad07647177a86831bcdf54cfeb5d2b8a940dac9c5df886c8e4acd7dd1fccb5236660320c59043d42dcef3f84f2ee6789eb0a07c2d6302c70dc217c9 + languageName: node + linkType: hard + +"@rushstack/rig-package@npm:0.5.3": + version: 0.5.3 + resolution: "@rushstack/rig-package@npm:0.5.3" + dependencies: + resolve: "npm:~1.22.1" + strip-json-comments: "npm:~3.1.1" + checksum: 10/b58a3925a41d7a0e79f4fde7c400a379683cc7b0073c447aba6d36231529a37e7d2f4559f459be785ad862ecb01b618b2d0ff60661046e5223437356155ccb14 + languageName: node + linkType: hard + +"@rushstack/terminal@npm:0.14.3": + version: 0.14.3 + resolution: "@rushstack/terminal@npm:0.14.3" + dependencies: + "@rushstack/node-core-library": "npm:5.10.0" + supports-color: "npm:~8.1.1" + peerDependencies: + "@types/node": "*" + peerDependenciesMeta: + "@types/node": + optional: true + checksum: 10/80c603f984293488cc988d17baa95e6d4ce1c70ff44b2ed7196aa156b4480f5a63213026709668db062a94564b59c006eff21a0ef3b74f6633b648624e4a0f89 + languageName: node + linkType: hard + +"@rushstack/ts-command-line@npm:4.23.1": + version: 4.23.1 + resolution: "@rushstack/ts-command-line@npm:4.23.1" + dependencies: + "@rushstack/terminal": "npm:0.14.3" + "@types/argparse": "npm:1.0.38" + argparse: "npm:~1.0.9" + string-argv: "npm:~0.3.1" + checksum: 10/4cfa4ede60b37299c93efec3be3770adf95680aeae9d0c28fcc9fb4f04dbf63958e9a37c1cf947b47cff25bbc3596a65f0a64c094e544a60e47c026d6b9a8c70 + languageName: node + linkType: hard + "@safe-global/safe-apps-provider@npm:0.18.4": version: 0.18.4 resolution: "@safe-global/safe-apps-provider@npm:0.18.4" @@ -9477,6 +9643,13 @@ __metadata: languageName: node linkType: hard +"@types/argparse@npm:1.0.38": + version: 1.0.38 + resolution: "@types/argparse@npm:1.0.38" + checksum: 10/26ed7e3f1e3595efdb883a852f5205f971b798e4c28b7e30a32c5298eee596e8b45834ce831f014d250b9730819ab05acff5b31229666d3af4ba465b4697d0eb + languageName: node + linkType: hard + "@types/babel__core@npm:^7.0.0, @types/babel__core@npm:^7.1.14": version: 7.20.1 resolution: "@types/babel__core@npm:7.20.1" @@ -10639,6 +10812,56 @@ __metadata: languageName: node linkType: hard +"@volar/language-core@npm:2.4.10, @volar/language-core@npm:~2.4.1": + version: 2.4.10 + resolution: "@volar/language-core@npm:2.4.10" + dependencies: + "@volar/source-map": "npm:2.4.10" + checksum: 10/2bfc33a5cf215810ff9f9e058e2cb3d1148e21ff69164fa854b6933673db0521cfac8313f7ad3fba8f314d22945fbe2a8ae572888bdf816a820cfa17d4c75ee3 + languageName: node + linkType: hard + +"@volar/source-map@npm:2.4.10": + version: 2.4.10 + resolution: "@volar/source-map@npm:2.4.10" + checksum: 10/8067c4a52bb54709bb74639419242ada294348f05cd5e22bc4a3cdfe4f7b18b9292c8b231805a56bda306890b97a3969e57d4da49d294e2b6122ec1e74f707e2 + languageName: node + linkType: hard + +"@volar/typescript@npm:^2.4.4": + version: 2.4.10 + resolution: "@volar/typescript@npm:2.4.10" + dependencies: + "@volar/language-core": "npm:2.4.10" + path-browserify: "npm:^1.0.1" + vscode-uri: "npm:^3.0.8" + checksum: 10/dab415048adac8c260d824092ccac47023600cc580032c3f409d88953bacd3f2568ff666cfcf49d63ef2babec86325886d5dc32ed492335248bfd5580bbadc29 + languageName: node + linkType: hard + +"@vue/compiler-core@npm:3.5.13": + version: 3.5.13 + resolution: "@vue/compiler-core@npm:3.5.13" + dependencies: + "@babel/parser": "npm:^7.25.3" + "@vue/shared": "npm:3.5.13" + entities: "npm:^4.5.0" + estree-walker: "npm:^2.0.2" + source-map-js: "npm:^1.2.0" + checksum: 10/22f042bb47c8a1edb9d602e24da8092ab542d5640f0459a9b99ecf35f90e96678f870209dd30f774f5340c6d817d3c5a46ca49cefb9659ee5b228bd42d1f076a + languageName: node + linkType: hard + +"@vue/compiler-dom@npm:^3.4.0": + version: 3.5.13 + resolution: "@vue/compiler-dom@npm:3.5.13" + dependencies: + "@vue/compiler-core": "npm:3.5.13" + "@vue/shared": "npm:3.5.13" + checksum: 10/5dc628c52091264a443c2d7326b759d7d3999c7e9c00078c2eb370b778e60b9f2ef258a8decf2fd97c8fa0923f895d449eabc1e5bc3d8a45d3ef99c9eb0599d7 + languageName: node + linkType: hard + "@vue/compiler-sfc@npm:2.7.14": version: 2.7.14 resolution: "@vue/compiler-sfc@npm:2.7.14" @@ -10650,6 +10873,16 @@ __metadata: languageName: node linkType: hard +"@vue/compiler-vue2@npm:^2.7.16": + version: 2.7.16 + resolution: "@vue/compiler-vue2@npm:2.7.16" + dependencies: + de-indent: "npm:^1.0.2" + he: "npm:^1.2.0" + checksum: 10/739ad06be19206b2715707c226a070509bcf28c31b539a6fc932d220eb7b0c09109d71fded573ed0c4073429793a3513ca4a4e69ad4f7afc0c5bc3c28639e871 + languageName: node + linkType: hard + "@vue/component-compiler-utils@npm:^3.1.0": version: 3.3.0 resolution: "@vue/component-compiler-utils@npm:3.3.0" @@ -10670,6 +10903,34 @@ __metadata: languageName: node linkType: hard +"@vue/language-core@npm:2.1.6": + version: 2.1.6 + resolution: "@vue/language-core@npm:2.1.6" + dependencies: + "@volar/language-core": "npm:~2.4.1" + "@vue/compiler-dom": "npm:^3.4.0" + "@vue/compiler-vue2": "npm:^2.7.16" + "@vue/shared": "npm:^3.4.0" + computeds: "npm:^0.0.1" + minimatch: "npm:^9.0.3" + muggle-string: "npm:^0.4.1" + path-browserify: "npm:^1.0.1" + peerDependencies: + typescript: "*" + peerDependenciesMeta: + typescript: + optional: true + checksum: 10/640d4af0031975620cd3a8050bb4b0f4ed333f241ded195e3bf8c4e571c720b4e3bec3947caf2b10e4e2de19deb7621982d15439de3732d510cd43e325c74a50 + languageName: node + linkType: hard + +"@vue/shared@npm:3.5.13, @vue/shared@npm:^3.4.0": + version: 3.5.13 + resolution: "@vue/shared@npm:3.5.13" + checksum: 10/5c0c24f443533392dde08c3e4272ff2e19af9762f90baeaa808850e05106537bbd9e2d2ad2081d979b8c4bc89902395b46036b67f74c60b76025924de37833b1 + languageName: node + linkType: hard + "@wagmi/cli@npm:^2.1.18": version: 2.1.18 resolution: "@wagmi/cli@npm:2.1.18" @@ -12061,6 +12322,18 @@ __metadata: languageName: node linkType: hard +"ajv-draft-04@npm:~1.0.0": + version: 1.0.0 + resolution: "ajv-draft-04@npm:1.0.0" + peerDependencies: + ajv: ^8.5.0 + peerDependenciesMeta: + ajv: + optional: true + checksum: 10/3f11fa0e7f7359bef6608657f02ab78e9cc62b1fb7bdd860db0d00351b3863a1189c1a23b72466d2d82726cab4eb20725c76f5e7c134a89865e2bfd0e6828137 + languageName: node + linkType: hard + "ajv-formats@npm:^2.1.1": version: 2.1.1 resolution: "ajv-formats@npm:2.1.1" @@ -12075,6 +12348,20 @@ __metadata: languageName: node linkType: hard +"ajv-formats@npm:~3.0.1": + version: 3.0.1 + resolution: "ajv-formats@npm:3.0.1" + dependencies: + ajv: "npm:^8.0.0" + peerDependencies: + ajv: ^8.0.0 + peerDependenciesMeta: + ajv: + optional: true + checksum: 10/5679b9f9ced9d0213a202a37f3aa91efcffe59a6de1a6e3da5c873344d3c161820a1f11cc29899661fee36271fd2895dd3851b6461c902a752ad661d1c1e8722 + languageName: node + linkType: hard + "ajv-keywords@npm:^3.4.1, ajv-keywords@npm:^3.5.2": version: 3.5.2 resolution: "ajv-keywords@npm:3.5.2" @@ -12119,7 +12406,7 @@ __metadata: languageName: node linkType: hard -"ajv@npm:^8.0.0, ajv@npm:^8.0.1, ajv@npm:^8.11.0, ajv@npm:^8.12.0, ajv@npm:^8.6.0, ajv@npm:^8.9.0": +"ajv@npm:^8.0.0, ajv@npm:^8.0.1, ajv@npm:^8.11.0, ajv@npm:^8.12.0, ajv@npm:^8.6.0, ajv@npm:^8.9.0, ajv@npm:~8.13.0": version: 8.13.0 resolution: "ajv@npm:8.13.0" dependencies: @@ -12131,6 +12418,18 @@ __metadata: languageName: node linkType: hard +"ajv@npm:~8.12.0": + version: 8.12.0 + resolution: "ajv@npm:8.12.0" + dependencies: + fast-deep-equal: "npm:^3.1.1" + json-schema-traverse: "npm:^1.0.0" + require-from-string: "npm:^2.0.2" + uri-js: "npm:^4.2.2" + checksum: 10/b406f3b79b5756ac53bfe2c20852471b08e122bc1ee4cde08ae4d6a800574d9cd78d60c81c69c63ff81e4da7cd0b638fafbb2303ae580d49cf1600b9059efb85 + languageName: node + linkType: hard + "amdefine@npm:>=0.0.4": version: 1.0.1 resolution: "amdefine@npm:1.0.1" @@ -12381,7 +12680,7 @@ __metadata: languageName: node linkType: hard -"argparse@npm:^1.0.7": +"argparse@npm:^1.0.7, argparse@npm:~1.0.9": version: 1.0.10 resolution: "argparse@npm:1.0.10" dependencies: @@ -14884,7 +15183,7 @@ __metadata: languageName: node linkType: hard -"compare-versions@npm:^6.0.0": +"compare-versions@npm:^6.0.0, compare-versions@npm:^6.1.1": version: 6.1.1 resolution: "compare-versions@npm:6.1.1" checksum: 10/9325c0fadfba81afa0ec17e6fc2ef823ba785c693089698b8d9374e5460509f1916a88591644d4cb4045c9a58e47fafbcc0724fe8bf446d2a875a3d6eeddf165 @@ -14922,6 +15221,13 @@ __metadata: languageName: node linkType: hard +"computeds@npm:^0.0.1": + version: 0.0.1 + resolution: "computeds@npm:0.0.1" + checksum: 10/738625ccec6e483124d0ac79ec5474ab5c9df103ea05afc1fd840eed7d9004e3d6009b7bc806df564d66ad915c1ee1fb017bd91b2b32606a252ea9870b6a4026 + languageName: node + linkType: hard + "concat-map@npm:0.0.1": version: 0.0.1 resolution: "concat-map@npm:0.0.1" @@ -16112,6 +16418,18 @@ __metadata: languageName: node linkType: hard +"debug@npm:^4.3.6": + version: 4.4.0 + resolution: "debug@npm:4.4.0" + dependencies: + ms: "npm:^2.1.3" + peerDependenciesMeta: + supports-color: + optional: true + checksum: 10/1847944c2e3c2c732514b93d11886575625686056cd765336212dc15de2d2b29612b6cd80e1afba767bb8e1803b778caf9973e98169ef1a24a7a7009e1820367 + languageName: node + linkType: hard + "decamelize-keys@npm:^1.1.0": version: 1.1.1 resolution: "decamelize-keys@npm:1.1.1" @@ -17118,7 +17436,7 @@ __metadata: languageName: node linkType: hard -"entities@npm:^4.2.0, entities@npm:^4.4.0": +"entities@npm:^4.2.0, entities@npm:^4.4.0, entities@npm:^4.5.0": version: 4.5.0 resolution: "entities@npm:4.5.0" checksum: 10/ede2a35c9bce1aeccd055a1b445d41c75a14a2bb1cd22e242f20cf04d236cdcd7f9c859eb83f76885327bfae0c25bf03303665ee1ce3d47c5927b98b0e3e3d48 @@ -19343,7 +19661,7 @@ __metadata: languageName: node linkType: hard -"fs-extra@npm:^7.0.0, fs-extra@npm:^7.0.1": +"fs-extra@npm:^7.0.0, fs-extra@npm:^7.0.1, fs-extra@npm:~7.0.1": version: 7.0.1 resolution: "fs-extra@npm:7.0.1" dependencies: @@ -21268,6 +21586,13 @@ __metadata: languageName: node linkType: hard +"import-lazy@npm:~4.0.0": + version: 4.0.0 + resolution: "import-lazy@npm:4.0.0" + checksum: 10/943309cc8eb01ada12700448c288b0384f77a1bc33c7e00fa4cb223c665f467a13ce9aaceb8d2e4cf586b07c1d2828040263dcc069873ce63cfc2ac6fd087971 + languageName: node + linkType: hard + "import-local@npm:^3.0.2": version: 3.1.0 resolution: "import-local@npm:3.1.0" @@ -23413,6 +23738,13 @@ __metadata: languageName: node linkType: hard +"jju@npm:~1.4.0": + version: 1.4.0 + resolution: "jju@npm:1.4.0" + checksum: 10/1067ff8ce02221faac5a842116ed0ec79a53312a111d0bf8342a80bd02c0a3fdf0b8449694a65947db0a3e8420e8b326dffb489c7dd5866efc380c0d1708a707 + languageName: node + linkType: hard + "jmespath@npm:^0.16.0": version: 0.16.0 resolution: "jmespath@npm:0.16.0" @@ -23922,6 +24254,13 @@ __metadata: languageName: node linkType: hard +"kolorist@npm:^1.8.0": + version: 1.8.0 + resolution: "kolorist@npm:1.8.0" + checksum: 10/71d5d122951cc65f2f14c3e1d7f8fd91694b374647d4f6deec3816d018cd04a44edd9578d93e00c82c2053b925e5d30a0565746c4171f4ca9fce1a13bd5f3315 + languageName: node + linkType: hard + "kubo-rpc-client@npm:^3.0.1": version: 3.0.1 resolution: "kubo-rpc-client@npm:3.0.1" @@ -24576,7 +24915,7 @@ __metadata: languageName: node linkType: hard -"lodash@npm:^4.17.11, lodash@npm:^4.17.12, lodash@npm:^4.17.15, lodash@npm:^4.17.20, lodash@npm:^4.17.21, lodash@npm:^4.7.0, lodash@npm:~4.17.0": +"lodash@npm:^4.17.11, lodash@npm:^4.17.12, lodash@npm:^4.17.15, lodash@npm:^4.17.20, lodash@npm:^4.17.21, lodash@npm:^4.7.0, lodash@npm:~4.17.0, lodash@npm:~4.17.15": version: 4.17.21 resolution: "lodash@npm:4.17.21" checksum: 10/c08619c038846ea6ac754abd6dd29d2568aa705feb69339e836dfa8d8b09abbb2f859371e86863eda41848221f9af43714491467b5b0299122431e202bb0c532 @@ -24795,6 +25134,15 @@ __metadata: languageName: node linkType: hard +"magic-string@npm:^0.30.11": + version: 0.30.15 + resolution: "magic-string@npm:0.30.15" + dependencies: + "@jridgewell/sourcemap-codec": "npm:^1.5.0" + checksum: 10/321f6e3156ac65d938fb7e08b3eaef9f4f5718180b7507f37bb55273f1faf979ab42e3b550a9e5dbbacf1c9a0f416157ab01c08619938734dcbbe02e2ef10872 + languageName: node + linkType: hard + "magic-string@npm:^0.30.3, magic-string@npm:^0.30.4, magic-string@npm:^0.30.5": version: 0.30.13 resolution: "magic-string@npm:0.30.13" @@ -25898,7 +26246,7 @@ __metadata: languageName: node linkType: hard -"minimatch@npm:3.0.8": +"minimatch@npm:3.0.8, minimatch@npm:~3.0.3": version: 3.0.8 resolution: "minimatch@npm:3.0.8" dependencies: @@ -25934,7 +26282,7 @@ __metadata: languageName: node linkType: hard -"minimatch@npm:^9.0.4, minimatch@npm:^9.0.5": +"minimatch@npm:^9.0.3, minimatch@npm:^9.0.4, minimatch@npm:^9.0.5": version: 9.0.5 resolution: "minimatch@npm:9.0.5" dependencies: @@ -26220,6 +26568,13 @@ __metadata: languageName: node linkType: hard +"muggle-string@npm:^0.4.1": + version: 0.4.1 + resolution: "muggle-string@npm:0.4.1" + checksum: 10/8fa2ea08f497c04069718bd3fd1909b382114dacbad832d10967ca72690de43f5f8492d8ccfbf827d6be63868ed5fc10395e7b7c082aa95997eea498586c6620 + languageName: node + linkType: hard + "multiaddr-to-uri@npm:^8.0.0": version: 8.0.0 resolution: "multiaddr-to-uri@npm:8.0.0" @@ -30780,7 +31135,7 @@ __metadata: languageName: node linkType: hard -"resolve@npm:^1.1.6, resolve@npm:^1.1.7, resolve@npm:^1.10.0, resolve@npm:^1.10.1, resolve@npm:^1.14.2, resolve@npm:^1.17.0, resolve@npm:^1.19.0, resolve@npm:^1.20.0, resolve@npm:^1.22.2, resolve@npm:^1.22.4": +"resolve@npm:^1.1.6, resolve@npm:^1.1.7, resolve@npm:^1.10.0, resolve@npm:^1.10.1, resolve@npm:^1.14.2, resolve@npm:^1.17.0, resolve@npm:^1.19.0, resolve@npm:^1.20.0, resolve@npm:^1.22.2, resolve@npm:^1.22.4, resolve@npm:~1.22.1, resolve@npm:~1.22.2": version: 1.22.8 resolution: "resolve@npm:1.22.8" dependencies: @@ -30822,7 +31177,7 @@ __metadata: languageName: node linkType: hard -"resolve@patch:resolve@npm%3A^1.1.6#optional!builtin, resolve@patch:resolve@npm%3A^1.1.7#optional!builtin, resolve@patch:resolve@npm%3A^1.10.0#optional!builtin, resolve@patch:resolve@npm%3A^1.10.1#optional!builtin, resolve@patch:resolve@npm%3A^1.14.2#optional!builtin, resolve@patch:resolve@npm%3A^1.17.0#optional!builtin, resolve@patch:resolve@npm%3A^1.19.0#optional!builtin, resolve@patch:resolve@npm%3A^1.20.0#optional!builtin, resolve@patch:resolve@npm%3A^1.22.2#optional!builtin, resolve@patch:resolve@npm%3A^1.22.4#optional!builtin": +"resolve@patch:resolve@npm%3A^1.1.6#optional!builtin, resolve@patch:resolve@npm%3A^1.1.7#optional!builtin, resolve@patch:resolve@npm%3A^1.10.0#optional!builtin, resolve@patch:resolve@npm%3A^1.10.1#optional!builtin, resolve@patch:resolve@npm%3A^1.14.2#optional!builtin, resolve@patch:resolve@npm%3A^1.17.0#optional!builtin, resolve@patch:resolve@npm%3A^1.19.0#optional!builtin, resolve@patch:resolve@npm%3A^1.20.0#optional!builtin, resolve@patch:resolve@npm%3A^1.22.2#optional!builtin, resolve@patch:resolve@npm%3A^1.22.4#optional!builtin, resolve@patch:resolve@npm%3A~1.22.1#optional!builtin, resolve@patch:resolve@npm%3A~1.22.2#optional!builtin": version: 1.22.8 resolution: "resolve@patch:resolve@npm%3A1.22.8#optional!builtin::version=1.22.8&hash=c3c19d" dependencies: @@ -31471,7 +31826,7 @@ __metadata: languageName: node linkType: hard -"semver@npm:7.5.4": +"semver@npm:7.5.4, semver@npm:~7.5.4": version: 7.5.4 resolution: "semver@npm:7.5.4" dependencies: @@ -32591,7 +32946,7 @@ __metadata: languageName: node linkType: hard -"string-argv@npm:0.3.2": +"string-argv@npm:0.3.2, string-argv@npm:~0.3.1": version: 0.3.2 resolution: "string-argv@npm:0.3.2" checksum: 10/f9d3addf887026b4b5f997a271149e93bf71efc8692e7dc0816e8807f960b18bcb9787b45beedf0f97ff459575ee389af3f189d8b649834cac602f2e857e75af @@ -32901,7 +33256,7 @@ __metadata: languageName: node linkType: hard -"strip-json-comments@npm:^3.1.0, strip-json-comments@npm:^3.1.1": +"strip-json-comments@npm:^3.1.0, strip-json-comments@npm:^3.1.1, strip-json-comments@npm:~3.1.1": version: 3.1.1 resolution: "strip-json-comments@npm:3.1.1" checksum: 10/492f73e27268f9b1c122733f28ecb0e7e8d8a531a6662efbd08e22cccb3f9475e90a1b82cab06a392f6afae6d2de636f977e231296400d0ec5304ba70f166443 @@ -33108,7 +33463,7 @@ __metadata: languageName: node linkType: hard -"supports-color@npm:^8.0.0, supports-color@npm:^8.1.1": +"supports-color@npm:^8.0.0, supports-color@npm:^8.1.1, supports-color@npm:~8.1.1": version: 8.1.1 resolution: "supports-color@npm:8.1.1" dependencies: @@ -34287,6 +34642,16 @@ __metadata: languageName: node linkType: hard +"typescript@npm:5.4.2": + version: 5.4.2 + resolution: "typescript@npm:5.4.2" + bin: + tsc: bin/tsc + tsserver: bin/tsserver + checksum: 10/f8cfdc630ab1672f004e9561eb2916935b2d267792d07ce93e97fc601c7a65191af32033d5e9c0169b7dc37da7db9bf320f7432bc84527cb7697effaa4e4559d + languageName: node + linkType: hard + "typescript@npm:^4.6.4 || ^5.2.2, typescript@npm:^5.6.3": version: 5.6.3 resolution: "typescript@npm:5.6.3" @@ -34297,6 +34662,16 @@ __metadata: languageName: node linkType: hard +"typescript@patch:typescript@npm%3A5.4.2#optional!builtin": + version: 5.4.2 + resolution: "typescript@patch:typescript@npm%3A5.4.2#optional!builtin::version=5.4.2&hash=5adc0c" + bin: + tsc: bin/tsc + tsserver: bin/tsserver + checksum: 10/f5f9a4133c2670761f0166eae5b3bafbc4a3fc24f0f42a93c9c893d9e9d6e66ea066969c5e7483fa66b4ae0e99125592553f3b92fd3599484de8be13b0615176 + languageName: node + linkType: hard + "typescript@patch:typescript@npm%3A^4.6.4 || ^5.2.2#optional!builtin, typescript@patch:typescript@npm%3A^5.6.3#optional!builtin": version: 5.6.3 resolution: "typescript@patch:typescript@npm%3A5.6.3#optional!builtin::version=5.6.3&hash=8c6c40" @@ -35265,6 +35640,29 @@ __metadata: languageName: node linkType: hard +"vite-plugin-dts@npm:^4.3.0": + version: 4.3.0 + resolution: "vite-plugin-dts@npm:4.3.0" + dependencies: + "@microsoft/api-extractor": "npm:^7.47.11" + "@rollup/pluginutils": "npm:^5.1.0" + "@volar/typescript": "npm:^2.4.4" + "@vue/language-core": "npm:2.1.6" + compare-versions: "npm:^6.1.1" + debug: "npm:^4.3.6" + kolorist: "npm:^1.8.0" + local-pkg: "npm:^0.5.0" + magic-string: "npm:^0.30.11" + peerDependencies: + typescript: "*" + vite: "*" + peerDependenciesMeta: + vite: + optional: true + checksum: 10/bbf59fb9d4ab9420f3fd2be2090439a072c4a57194cf6ee987ae990d1d95e2d9b16fae1a7c26578705d6a396a81eb6346ec522216e1f7cfc4f4d891fc29bd839 + languageName: node + linkType: hard + "vite-plugin-node-polyfills@npm:^0.21.0": version: 0.21.0 resolution: "vite-plugin-node-polyfills@npm:0.21.0" @@ -35277,6 +35675,18 @@ __metadata: languageName: node linkType: hard +"vite-plugin-node-polyfills@npm:^0.22.0": + version: 0.22.0 + resolution: "vite-plugin-node-polyfills@npm:0.22.0" + dependencies: + "@rollup/plugin-inject": "npm:^5.0.5" + node-stdlib-browser: "npm:^1.2.0" + peerDependencies: + vite: ^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0 + checksum: 10/004a68987d271c04e1a7b9df38f8fca32b1e4a261b464f69895af5ea90e40cbb31e18170435613cb9f2edc735589267ff51772c8793f6f567ba2849da8d36ec4 + languageName: node + linkType: hard + "vite-plugin-svgr@npm:^4.3.0": version: 4.3.0 resolution: "vite-plugin-svgr@npm:4.3.0" @@ -35413,6 +35823,13 @@ __metadata: languageName: node linkType: hard +"vscode-uri@npm:^3.0.8": + version: 3.0.8 + resolution: "vscode-uri@npm:3.0.8" + checksum: 10/e882d6b679e0d053cbc042893c0951a135d899a192b62cd07f0a8924f11ae722067a8d6b1b5b147034becf57faf9fff9fb543b17b749fd0f17db1f54f783f07c + languageName: node + linkType: hard + "vue-hot-reload-api@npm:^2.3.0": version: 2.3.4 resolution: "vue-hot-reload-api@npm:2.3.4"