Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Arbitration competition changes #543

Merged
merged 14 commits into from
Dec 6, 2023
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
# Audit Competition for HATs-Arbitration-Contracts
This repository is for the audit competition for the HATs-Arbitration-Contracts.
To participate, submit your findings only by using the on-chain submission process on https://app.hats.finance/vulnerability .
## How to participate
- follow the instructions on https://app.hats.finance/
## Good luck!
We look forward to seeing your findings.
* * *
# <img src="https://raw.githubusercontent.com/hats-finance/icons/main/hats.svg" alt="Hats.Finance" text="sds" height="40px"> Hats.Finance | Contracts

[![Coverage Status](https://coveralls.io/repos/github/hats-finance/hats-contracts/badge.svg?t=Ko4Ndz&kill_cache=2)](https://coveralls.io/github/hats-finance/hats-contracts)
Expand Down
11 changes: 9 additions & 2 deletions contracts/HATArbitrator.sol
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ contract HATArbitrator is IHATArbitrator, Ownable {
public disputersBonds; // bonds provided by disputers
mapping(address => mapping(IHATClaimsManager => mapping(bytes32 => bool)))
public bondClaimable; // whether a given bond is reclaimable by the disputer
mapping(IHATClaimsManager => mapping(bytes32 => bool)) public claimDisputesDismissed; // claims of which disputes were dismissed
mapping(IHATClaimsManager => mapping(bytes32 => uint256)) public totalBondsOnClaim; // total amount of bonds ona given claim
mapping(IHATClaimsManager => mapping(bytes32 => Resolution)) public resolutions; // resolutions of disputes by the expert committee
mapping(IHATClaimsManager => mapping(bytes32 => uint256))
Expand Down Expand Up @@ -160,6 +161,7 @@ contract HATArbitrator is IHATArbitrator, Ownable {
onlyChallengedActiveClaim(_vault, _claimId)
onlyUnresolvedDispute(_vault, _claimId)
{
claimDisputesDismissed[_vault][_claimId] = true;
resolutions[_vault][_claimId].resolvedAt = block.timestamp;
token.safeTransfer(msg.sender, totalBondsOnClaim[_vault][_claimId]);

Expand Down Expand Up @@ -267,10 +269,14 @@ contract HATArbitrator is IHATArbitrator, Ownable {
/** @notice See {IHATArbitrator-reclaimBond}. */
function reclaimBond(IHATClaimsManager _vault, bytes32 _claimId) external {
if (!bondClaimable[msg.sender][_vault][_claimId]) {
// the bond is claimable if either
// the bond is claimable if the claim wasn't dismissed and either
// (a) it is not related to the current active claim
// (b) it is about the current active claim but the claim has already expired

if (claimDisputesDismissed[_vault][_claimId]) {
revert ClaimDisputesDismissed();
}

IHATClaimsManager.Claim memory claim = _vault.getActiveClaim();

if (
Expand Down Expand Up @@ -482,6 +488,7 @@ contract HATArbitrator is IHATArbitrator, Ownable {
];

if (
submitClaimRequest.submittedAt == 0 ||
block.timestamp <=
submitClaimRequest.submittedAt + submitClaimRequestReviewPeriod
) {
Expand All @@ -491,7 +498,7 @@ contract HATArbitrator is IHATArbitrator, Ownable {
delete submitClaimRequests[_internalClaimId];
token.safeTransfer(
submitClaimRequest.submitter,
bondsNeededToStartDispute
submitClaimRequest.bond
);

emit SubmitClaimRequestExpired(_internalClaimId);
Expand Down
16 changes: 11 additions & 5 deletions contracts/HATKlerosConnector.sol
Original file line number Diff line number Diff line change
Expand Up @@ -164,8 +164,10 @@ contract HATKlerosConnector is IDisputeResolver, IHATKlerosConnector, Ownable {
dispute.externalDisputeId = externalDisputeId;
externalIDtoLocalID[externalDisputeId] = localDisputeId;

if (msg.value > arbitrationCost)
payable(_disputer).transfer(msg.value - arbitrationCost);
if (msg.value > arbitrationCost) {
(bool success,) = payable(_disputer).call{value: msg.value - arbitrationCost}("");
require(success, "Failed to send ETH");
}

emit Challenged(_claimId);
emit Dispute(
Expand Down Expand Up @@ -318,8 +320,11 @@ contract HATKlerosConnector is IDisputeResolver, IHATKlerosConnector, Ownable {
);
}

if (msg.value > contribution)
payable(msg.sender).transfer(msg.value - contribution); // Sending extra value back to contributor. It is the user's responsibility to accept ETH.
if (msg.value > contribution) {
(bool success,) = payable(msg.sender).call{value: msg.value - contribution}("");
require(success, "Failed to send ETH"); // Sending extra value back to contributor. It is the user's responsibility to accept ETH.
}

return round.hasPaid[_side];
}

Expand Down Expand Up @@ -362,7 +367,8 @@ contract HATKlerosConnector is IDisputeResolver, IHATKlerosConnector, Ownable {

if (reward != 0) {
round.contributions[_beneficiary][_side] = 0;
_beneficiary.transfer(reward); // It is the user's responsibility to accept ETH.
(bool success,) = payable(_beneficiary).call{value: reward}("");
require(success, "Failed to send ETH"); // It is the user's responsibility to accept ETH.
emit Withdrawal(
_localDisputeId,
_round,
Expand Down
5 changes: 4 additions & 1 deletion contracts/HATKlerosV2Connector.sol
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,10 @@ contract HATKlerosV2Connector is IArbitrable, IHATKlerosConnector {
dispute.externalDisputeId = externalDisputeId;
externalIDtoLocalID[externalDisputeId] = localDisputeId;

if (msg.value > arbitrationCost) payable(_disputer).transfer(msg.value - arbitrationCost);
if (msg.value > arbitrationCost) {
(bool success,) = payable(_disputer).call{value: msg.value - arbitrationCost}("");
require(success, "Failed to send ETH");
}

emit Challenged(_claimId);
// TODO: add new IEvidence events once they're established.
Expand Down
17 changes: 17 additions & 0 deletions contracts/HATPaymentSplitterFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ contract HATPaymentSplitterFactory {
address public immutable implementation;
event HATPaymentSplitterCreated(address indexed _hatPaymentSplitter);

error ArrayLengthMismatch();
error NoPayees();
error ZeroAddress();
error ZeroShares();
error DuplicatedPayee();

constructor (address _implementation) {
implementation = _implementation;
}
Expand All @@ -21,6 +27,17 @@ contract HATPaymentSplitterFactory {
}

function predictSplitterAddress(address[] memory _payees, uint256[] memory _shares) public view returns (address) {
if (_payees.length != _shares.length) revert ArrayLengthMismatch();
if (_payees.length == 0) revert NoPayees();

for (uint256 i = 0; i < _payees.length; i++) {
if (_payees[i] == address(0)) revert ZeroAddress();
if (_shares[i] == 0) revert ZeroShares();
for (uint256 j = i + 1; j < _payees.length; j++) {
if (_payees[i] == _payees[j]) revert DuplicatedPayee();
}
}

return Clones.predictDeterministicAddress(implementation, keccak256(abi.encodePacked(_payees, _shares)));
}
}
1 change: 1 addition & 0 deletions contracts/interfaces/IHATArbitrator.sol
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ interface IHATArbitrator {
error AlreadyChallenged();
error CourtCannotBeZero();
error CannontChangeCourtAddress();
error ClaimDisputesDismissed();

struct Resolution {
address beneficiary;
Expand Down
2 changes: 1 addition & 1 deletion contracts/interfaces/IHATClaimsManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@
error NotEnoughUserBalance();
// Only arbitrator or registry owner
error OnlyArbitratorOrRegistryOwner();
// Unchalleged claim can only be approved if challenge period is over
// Unchallenged claim can only be approved if challenge period is over
error UnchallengedClaimCanOnlyBeApprovedAfterChallengePeriod();
// Challenged claim can only be approved by arbitrator before the challenge timeout period
error ChallengedClaimCanOnlyBeApprovedByArbitratorUntilChallengeTimeoutPeriod();
Expand Down Expand Up @@ -488,5 +488,5 @@
* @notice Returns the claims manager's version
* @return The claims manager's version
*/
function VERSION() external view returns(string calldata);

Check warning on line 491 in contracts/interfaces/IHATClaimsManager.sol

View workflow job for this annotation

GitHub Actions / build (14.x)

Function name must be in mixedCase
}
38 changes: 38 additions & 0 deletions contracts/mocks/BadKlerosConnectorEthReceiver.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;

import "../interfaces/IHATArbitrator.sol";
import "../HATKlerosConnector.sol";
import "../interfaces/IHATClaimsManager.sol";

contract BadKlerosConnectorEthReceiver {
bool public shouldFail = true;

function challengeResolution(
IHATArbitrator _arbitrator,
IHATClaimsManager _vault,
bytes32 _claimId,
string calldata _evidence
) external payable {
_arbitrator.challengeResolution{value: msg.value}(_vault, _claimId, _evidence);
}

function fundAppeal(
HATKlerosConnector _connector,
uint256 _localDisputeId,
uint256 _side
) external payable returns (bool) {
return _connector.fundAppeal{value: msg.value}(_localDisputeId, _side);
}

function setShouldFail(bool _shouldFail) external {
shouldFail = _shouldFail;
}

receive() external payable {
if (shouldFail) {
revert("cannot accept transfer");
}
}

}
17 changes: 14 additions & 3 deletions contracts/tokenlock/TokenLock.sol
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ abstract contract TokenLock is Ownable, ITokenLock {
error AmountCannotBeZero();
error AmountRequestedBiggerThanSurplus();
error LockIsNonRevocable();
error LockIsAlreadyRevoked();
error NoAvailableUnvestedAmount();
error OnlySweeper();
error CannotSweepVestedToken();
Expand Down Expand Up @@ -190,17 +191,27 @@ abstract contract TokenLock is Ownable, ITokenLock {
if (!revocable)
revert LockIsNonRevocable();

uint256 unvestedAmount = managedAmount - vestedAmount();
if (isRevoked)
revert LockIsAlreadyRevoked();

uint256 vestedAmount = vestedAmount();

uint256 unvestedAmount = managedAmount - vestedAmount;
if (unvestedAmount == 0)
revert NoAvailableUnvestedAmount();

isRevoked = true;

managedAmount = vestedAmount;

// solhint-disable-next-line not-rely-on-time
endTime = block.timestamp;

token.safeTransfer(owner(), unvestedAmount);

emit TokensRevoked(beneficiary, unvestedAmount);

selfdestruct(payable(msg.sender));
trySelfDestruct();
}

/**
Expand Down Expand Up @@ -445,7 +456,7 @@ abstract contract TokenLock is Ownable, ITokenLock {
}

function trySelfDestruct() private {
if (currentTime() > endTime && currentBalance() == 0) {
if (currentTime() >= endTime && currentBalance() == 0) {
selfdestruct(payable(msg.sender));
}
}
Expand Down
34 changes: 34 additions & 0 deletions docs/dodoc/HATArbitrator.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,29 @@ See {IHATArbitrator-challengeResolution}.
| _claimId | bytes32 | undefined |
| _evidence | string | undefined |

### claimDisputesDismissed

```solidity
function claimDisputesDismissed(contract IHATClaimsManager, bytes32) external view returns (bool)
```





#### Parameters

| Name | Type | Description |
|---|---|---|
| _0 | contract IHATClaimsManager | undefined |
| _1 | bytes32 | undefined |

#### Returns

| Name | Type | Description |
|---|---|---|
| _0 | bool | undefined |

### confiscateDisputers

```solidity
Expand Down Expand Up @@ -951,6 +974,17 @@ error ChallengePeriodPassed()



### ClaimDisputesDismissed

```solidity
error ClaimDisputesDismissed()
```






### ClaimExpired

```solidity
Expand Down
58 changes: 58 additions & 0 deletions docs/dodoc/HATPaymentSplitterFactory.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,3 +95,61 @@ event HATPaymentSplitterCreated(address indexed _hatPaymentSplitter)



## Errors

### ArrayLengthMismatch

```solidity
error ArrayLengthMismatch()
```






### DuplicatedPayee

```solidity
error DuplicatedPayee()
```






### NoPayees

```solidity
error NoPayees()
```






### ZeroAddress

```solidity
error ZeroAddress()
```






### ZeroShares

```solidity
error ZeroShares()
```







12 changes: 0 additions & 12 deletions docs/dodoc/elin/contracts/utils/StorageSlot.md

This file was deleted.

12 changes: 0 additions & 12 deletions docs/dodoc/elin/contracts/utils/math/SignedMath.md

This file was deleted.

11 changes: 11 additions & 0 deletions docs/dodoc/interfaces/IHATArbitrator.md
Original file line number Diff line number Diff line change
Expand Up @@ -627,6 +627,17 @@ error ChallengePeriodPassed()



### ClaimDisputesDismissed

```solidity
error ClaimDisputesDismissed()
```






### ClaimExpired

```solidity
Expand Down
Loading
Loading