xanoutas/solidity-security-findings huggingface dataset:
A user can lose money if his ```rageQuit``` call is frontrun (intentionally or not) by the ```distribute``` call.
Audit: 2023-10-party-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-10-party/blob/b23c65d62a20921c709582b0b76b387f2bb9ebb5/contracts/party/PartyGovernance.sol#L487-L542
https://github.com/code-423n4/2023-10-party/blob/b23c65d62a20921c709582b0b76b387f2bb9ebb5/contracts/party/PartyGovernanceNFT.sol#L378-L395
https://github.com/code-423n4/2023-10-party/blob/b23c65d62a20921c709582b0b76b387f2bb9ebb5/contracts/party/PartyGovernanceNFT.sol#L408-L441


# Vulnerability details

## Impact
A user can lose money if his ```rageQuit``` call is frontrun (intentionally or not) by the ```distribute``` call.
## Proof of Concept
- Alice doesn't want to be a member of a party anymore so she decides to rage quit.
- She does this by calling the ```rageQuit``` with ```withdrawTokens = [USDC];``` (let's suppose the party has USDC tokens so she can withdraw a proportion of the tokens)
- A malicious actor front runs her call with a ```distribute``` call and ```token``` set to USDC. (this call can also happen completely by accident and doesn't have to be a malicious call targeting a tx from Alice)
- A distribute function checks if distributions are enabled and transfers the ```amount``` of ```token``` to the global ```TokenDistributor```.
```solidity
function distribute(
    uint256 amount,
    ITokenDistributor.TokenType tokenType,
    address token,
    uint256 tokenId
) external returns (ITokenDistributor.DistributionInfo memory distInfo) {
    _assertNotGloballyDisabled();
    if (msg.sender != address(this)) {
        if (_getSharedProposalStorage().opts.distributionsRequireVote) {
            revert DistributionsRequireVoteError();
        }
        // Must be an active member.
        VotingPowerSnapshot memory snap = _getLastVotingPowerSnapshotForVoter(msg.sender);
        if (snap.intrinsicVotingPower == 0 && snap.delegatedVotingPower == 0) {
            revert NotAuthorized();
        }
    }
    // Prevent creating a distribution if the party has not started.
    if (_getSharedProposalStorage().governanceValues.totalVotingPower == 0) {
        revert PartyNotStartedError();
    }
    // Get the address of the token distributor.
    ITokenDistributor distributor = ITokenDistributor(
        _GLOBALS.getAddress(LibGlobals.GLOBAL_TOKEN_DISTRIBUTOR)
    );
    ...
    if (tokenType == ITokenDistributor.TokenType.Native) {
        ...
    }
    // Otherwise must be an ERC20 token distribution.
    assert(tokenType == ITokenDistributor.TokenType.Erc20);
    IERC20(token).compatTransfer(address(distributor), amount);
    return
        distributor.createErc20Distribution(
            IERC20(token),
            Party(payable(address(this))),
            feeRecipient_,
            feeBps_
        );
}
```
- Now let's suppose the caller of ```distribute``` sets ```amount = USDC.balanceOf(address(party))``` and transfers all of the USDC tokens from the party to the distributor.
- Right after that the ```tx``` from Alice is executed.
- The first part of the ```rageQuit``` call calculates t
The execute function at the PartyGovernance contract does not enforce an order of execution for approved proposals
Audit: 2023-10-party-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-10-party/blob/main/contracts/party/PartyGovernance.sol#L706-L715
https://github.com/code-423n4/2023-10-party/blob/main/contracts/party/PartyGovernance.sol#L724-L738


# Vulnerability details

## Impact
Approving a proposal changes it's status at the PartyGovernance contract so it can be later executed. 
When there are no proposals under execution, any member can call execute with the intended proposal Id and, if it is already approved, it gets executed.
However the system has no mechanism to grant proposal execution order, and any member could MEV to push through the proposals that most interest them and to ensure a non-desired proposal reaches it's expiry timestamp.[1]

This also poses an important issue to the business logic: governance systems are created to coordinate complex group interactions that would not be possible without certain deterministic nature. Parties are likely to encounter use cases that involve time-based executions and step-by-step-based flows. If a malicious member can interfere with the intended behaviour, the possibilities for loss are endless such as:
A party may not be able to close it's lending position fast enough, even though the proposal to do so was approved, and end up liquidated because certain member may front-run other members execute a proposal that leaves the party in a proposal in-progress state.[2]

## Proof of Concept
When calling execute at the PartyGovernance contract, the function only ensures the Proposal is ready for execution and has not reached it's maxExecutableTime yet:
```solidity
function execute(
        uint256 proposalId,
        Proposal memory proposal,
        IERC721[] memory preciousTokens,
        uint256[] memory preciousTokenIds,
        bytes calldata progressData,
        bytes calldata extraData
    ) external payable {
...
if (status != ProposalStatus.Ready && status != ProposalStatus.InProgress) {
            revert BadProposalStatusError(status);
        }
        if (status == ProposalStatus.Ready) {
            // If the proposal has not been executed yet, make sure it hasn't
            // expired. Note that proposals that have been executed
            // (but still have more steps) ignore `maxExecutableTime`.
            if (proposal.maxExecutableTime < block.timestamp) {
                revert ExecutionTimeExceededError(
                    proposal.maxExecutableTime,
                    uint40(block.timestamp)
                );
            }
            proposalState.values.executedTime = uint40(block.timestamp);
        }
...
}
```

There are no checks whatsoever in regards to the passed proposalId nor past executed proposalIds.


As the function is external and only checks if the PartyGovernance is not globally checked and the caller is a member, there are multiple different parties that could MEV by calling execute:
```solidity
 function execute(
        uint256 proposalId,
        Proposal memory proposal,
Users may be unable to claim a refund.
Audit: 2023-10-party-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-10-party/blob/b23c65d62a20921c709582b0b76b387f2bb9ebb5/contracts/crowdfund/InitialETHCrowdfund.sol#L318-L343


# Vulnerability details

## Impact
Users may be unable to claim a refund.
## Proof of Concept
A ```refund``` call can ```fail``` if the contributor cannot receive eth. Eg. smart contracts without ```fallback``` and ```receive``` functions.
```solidity
function refund(uint256 tokenId) external returns (uint96 amount) {
    // Check crowdfund lifecycle.
    {
        CrowdfundLifecycle lc = getCrowdfundLifecycle();
        if (lc != CrowdfundLifecycle.Lost) {
            revert WrongLifecycleError(lc);
        }
    }

    // Get amount to refund.
    uint96 votingPower = party.votingPowerByTokenId(tokenId).safeCastUint256ToUint96();
    amount = convertVotingPowerToContribution(votingPower);

    if (amount > 0) {
        // Get contributor to refund.
        address payable contributor = payable(party.ownerOf(tokenId));

        // Burn contributor's party card.
        party.burn(tokenId);

        // Refund contributor.
        contributor.transferEth(amount);

        emit Refunded(contributor, tokenId, amount);
    }
}
```
## Tools Used
VS Code
## Recommended Mitigation Steps
Add a ```recipient``` parameter as a backup address to which the funds can be refunded.


## Assessed type

ETH-Transfer
Users can overpay for the credited ```votingPower``` and lose ```ETH```.
Audit: 2023-10-party-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-10-party/blob/b23c65d62a20921c709582b0b76b387f2bb9ebb5/contracts/crowdfund/InitialETHCrowdfund.sol#L164-L176
https://github.com/code-423n4/2023-10-party/blob/b23c65d62a20921c709582b0b76b387f2bb9ebb5/contracts/crowdfund/InitialETHCrowdfund.sol#L305-L307
https://github.com/code-423n4/2023-10-party/blob/b23c65d62a20921c709582b0b76b387f2bb9ebb5/contracts/party/PartyGovernanceNFT.sol#L216-L220
https://github.com/code-423n4/2023-10-party/blob/b23c65d62a20921c709582b0b76b387f2bb9ebb5/contracts/party/PartyGovernanceNFT.sol#L179-L183


# Vulnerability details

## Impact
Users can overpay for the credited ```votingPower``` and lose ```ETH```.
## Proof of Concept
- A new party is created with the initial ```totalVotingPower``` set as ```10000``` (can be any non-zero value, keep in mind that party can be initialized with ```totalVotingPower > 0```... The ```InitialETHCrowdfund``` in scope has ```totalVotingPower``` set as 0 by default but other crowdfunds can have non-zero ```totalVotingPower```).
- Alice contributes 1 ETH to the crowdfund calling ```contribute``` which invokes ```_contribute```
```solidity
function _contribute(
    address payable contributor,
    address delegate,
    uint96 amount,
    uint256 tokenId,
    bytes memory gateData
) private returns (uint96 votingPower) {
    ...

    votingPower = _processContribution(contributor, delegate, amount);

    // OK to contribute with zero just to update delegate.
    if (amount == 0) return 0;

    if (tokenId == 0) {
        ...
    } else if (disableContributingForExistingCard) {
        revert ContributingForExistingCardDisabledError();
    } else if (party.ownerOf(tokenId) == contributor) {
        // Increase voting power of contributor's existing party card.
        party.increaseVotingPower(tokenId, votingPower);
    } else {
        revert NotOwnerError(tokenId);
    }
}
```
- She passes the ```tokenId = 3```. This is the token she owns from a previous contribution. She wants to increase the ```votingPower``` of the token by contributing more ETH (the same bug goes for when Alice tries to mint a new token invoking the  ```mint``` function).
- Since the token already exists the ```increaseVotingPower``` is called on a party
```solidity
else if (party.ownerOf(tokenId) == contributor) {
    // Increase voting power of contributor's existing party card.
    party.increaseVotingPower(tokenId, votingPower);
}
```
- If the ```totalVotingPower - mintedVotingPower_ < votingPower``` her votingPower is decreased.
 For example the ```totalVotingPower = 10000``` and the current ```mintedVotingPower_  = 9990```. The ```votingPower``` she was supposed to receive for her 1 ETH contribution would be for example 1000, but since this would mint more ```votingPower``` than ```totalVotingPower```, the ```votingPower``` of Alice is reduced to ```10000 - 9990 = 10```. 
- Doing simple math if she receives ```1000 votingPower for  1 ETH``` contribution then she
`_hostsAccepted()` can return true even without all hosts' votes, which can be exploited by a malicious host to execute any proposal immediately
Audit: 2023-10-party-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-10-party/blob/b23c65d62a20921c709582b0b76b387f2bb9ebb5/contracts/party/PartyGovernance.sol#L457-L472
https://github.com/code-423n4/2023-10-party/blob/b23c65d62a20921c709582b0b76b387f2bb9ebb5/contracts/party/PartyGovernance.sol#L637


# Vulnerability details

In the Party Governance system, a proposal cannot be executed until it reaches the [`READY`](https://github.com/code-423n4/2023-10-party/blob/b23c65d62a20921c709582b0b76b387f2bb9ebb5/contracts/party/PartyGovernance.sol#L53) state. And the `READY` state can be reached only if one of the following conditions is met:
1. The votes threshold is met, and the execution delay has [passed](https://github.com/code-423n4/2023-10-party/blob/b23c65d62a20921c709582b0b76b387f2bb9ebb5/contracts/party/PartyGovernance.sol#L1090) 
2. All party members have unanimously [accepted](https://github.com/code-423n4/2023-10-party/blob/b23c65d62a20921c709582b0b76b387f2bb9ebb5/contracts/party/PartyGovernance.sol#L1094) the proposal. 
3. All hosts in the party have [accepted](https://github.com/code-423n4/2023-10-party/blob/b23c65d62a20921c709582b0b76b387f2bb9ebb5/contracts/party/PartyGovernance.sol#L1098) the proposal. 

We will focus on the third condition, it is a new addition and currently has a flaw.

When a party members initiates a proposal by calling [`propose()`](https://github.com/code-423n4/2023-10-party/blob/b23c65d62a20921c709582b0b76b387f2bb9ebb5/contracts/party/PartyGovernance.sol#L553),  two values, `numHosts` and `numHostsAccepted`, are recorded. `numHosts` represents the number of hosts at the time the proposal is created, and `numHostsAccepted` starts at zero. `numHostsAccepted` serves as a counter to keep track of how many hosts have accepted the proposal. When a host [accept](https://github.com/code-423n4/2023-10-party/blob/b23c65d62a20921c709582b0b76b387f2bb9ebb5/contracts/party/PartyGovernance.sol#L595) a proposal, this counter gets increased:
```solidity
        if (isHost[msg.sender]) {
            ++values.numHostsAccepted;
        }
```
This mechanism ensures that when `numHostsAccepted` becomes equal to `numHosts`, the proposal can skip the veto period and become `READY` for immediate execution, meeting the third condition mentioned above.

There is another functionality: [`abdicateHost()`](https://github.com/code-423n4/2023-10-party/blob/b23c65d62a20921c709582b0b76b387f2bb9ebb5/contracts/party/PartyGovernance.sol#L457C14-L457C26)
Which allows current hosts to abdicate their host position. Either to burn it or to transfer it to another address. 
```solidity
    function abdicateHost(address newPartyHost) external {
        _assertHost();
        if (newPartyHost != address(0)) {
            if (isHost[newPartyHost]) {
                revert InvalidNewHostError();
            }
        ///@audit-issue doesn't reset ProposalStateValues.numHostsAccepted for the new host!
        ///@audit-issue 1 host can manipulate other hosts and whole party! -
totalVotingPower is close to the maximum, users who overpay tokens will not be refunded.
Audit: 2023-10-party-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-10-party/blob/b23c65d62a20921c709582b0b76b387f2bb9ebb5/contracts/crowdfund/InitialETHCrowdfund.sol#L172
https://github.com/code-423n4/2023-10-party/blob/b23c65d62a20921c709582b0b76b387f2bb9ebb5/contracts/party/PartyGovernanceNFT.sol#L181


# Vulnerability details

## Impact
totalVotingPower is close to the maximum, users who overpay tokens will not be refunded.
Cause the loss of user funds.

## Proof of Concept

In InitialETHCrowdfund, the value of `votingPower` when `party.mint` is determined according to msg.value:

```solidity
    function contribute(
        address delegate,
        bytes memory gateData
    ) public payable onlyDelegateCall returns (uint96 votingPower) {
        return
            _contribute(
                payable(msg.sender),
                delegate,
@>              msg.value.safeCastUint256ToUint96(),
                0, // Mint a new party card for the contributor.
                gateData
            );
    }
    
    function _contribute(
        address payable contributor,
        address delegate,
        uint96 amount,
        uint256 tokenId,
        bytes memory gateData
    ) private returns (uint96 votingPower) {
        // Require a non-null delegate.
        if (delegate == address(0)) {
            revert InvalidDelegateError();
        }
        ....
        if (tokenId == 0) {
            // Mint contributor a new party card.
@>          party.mint(contributor, votingPower, delegate);
        } else if (disableContributingForExistingCard) {
            revert ContributingForExistingCardDisabledError();
        } else if (party.ownerOf(tokenId) == contributor) {
            // Increase voting power of contributor's existing party card.
            party.increaseVotingPower(tokenId, votingPower);
        } else {
            revert NotOwnerError(tokenId);
        }
    }
```

If totalVotingPower is close to the maximum value in `party.mint`, the amount of votingPower will be reduced, but the ETH overpaid by the user will not be returned, which is unfair to the user who contributes at the end, resulting in the loss of funds.

```solidity
    function mint(
        address owner,
        uint256 votingPower,
        address delegate
    ) external returns (uint256 tokenId) {
        _assertAuthority();
        uint96 mintedVotingPower_ = mintedVotingPower;
        uint96 totalVotingPower = _getSharedProposalStorage().governanceValues.totalVotingPower;

        // Cap voting power to remaining unminted voting power supply.
        uint96 votingPower_ = votingPower.safeCastUint256ToUint96();
        // Allow minting past total voting power if minting party cards for
        // initial crowdfund when there is no total voting power.
        if (totalVotingPower != 0 && totalVotingPower - mintedVotingPower_ < votingPower_) {
            unchecked {
@>              votingPower_ = totalVotingPower - mintedVotingPower_;
            }
        }
        .....
```

T
OffChainSignatureValidator.isValidSignature function results in unintended collisions
Audit: 2023-10-party-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-10-party/blob/b23c65d62a20921c709582b0b76b387f2bb9ebb5/contracts/signature-validators/OffChainSignatureValidator.sol#L28-L80
https://github.com/code-423n4/2023-10-party/blob/b23c65d62a20921c709582b0b76b387f2bb9ebb5/contracts/signature-validators/OffChainSignatureValidator.sol#L48-L52


# Vulnerability details

## Impact
Unintended collisions can lead to data integrity issues, where different sets of input data produce the same packed representation. This can result in unexpected behavior when decoding the data.

If the packed data is used in security-critical operations such as access control or cryptographic functions, collisions could introduce vulnerabilities and compromise the security of the contract.

Collisions may lead to unintended behavior when the packed data is used in conditional statements, calculations, or other parts of the contract logic.

If the contract interacts with other contracts or systems, collisions can create interoperability problems, especially if the encoding format is relied upon for communication.

## Proof of Concept
OffChainSignatureValidator.isValidSignature(bytes32,bytes) (contracts/signature-validators/OffChainSignatureValidator.sol#28-80) calls abi.encodePacked() with multiple dynamic arguments:
- encodedPacket = abi.encodePacked(Ethereum Signed Message:
,Strings.toString(message.length),message) (contracts/signature-validators/OffChainSignatureValidator.sol#48-52)

## Tools Used
Slither, Manual Review

## Recommended Mitigation Steps
Detect collision due to dynamic type usages in `abi.encodePacked`.
Do not use more than one dynamic type in `abi.encodePacked()`. Use `abi.encode()`, preferably.


## Assessed type

Error
User can frontrun / backrun total voting power update to withdraw more fund from party
Audit: 2023-10-party-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-10-party/blob/b23c65d62a20921c709582b0b76b387f2bb9ebb5/contracts/party/PartyGovernanceNFT.sol#L236
https://github.com/code-423n4/2023-10-party/blob/b23c65d62a20921c709582b0b76b387f2bb9ebb5/contracts/party/PartyGovernanceNFT.sol#L393


# Vulnerability details

## Impact

Update total voting power can impact live proposal

## Proof of Concept

in the current implementation

the authority address can call increaseTotalVotingPower or [decreaseTotalVotingPower](https://github.com/code-423n4/2023-10-party/blob/b23c65d62a20921c709582b0b76b387f2bb9ebb5/contracts/party/PartyGovernanceNFT.sol#L236)

```solidity
/// @notice Increase the total voting power of the party. Only callable by
///         an authority.
/// @param votingPower The new total voting power to add.
function increaseTotalVotingPower(uint96 votingPower) external {
	_assertAuthority();
	_getSharedProposalStorage().governanceValues.totalVotingPower += votingPower;
}

/// @notice Decrease the total voting power of the party. Only callable by
///         an authority.
/// @param votingPower The new total voting power to add.
function decreaseTotalVotingPower(uint96 votingPower) external {
	_assertAuthority();
	_getSharedProposalStorage().governanceValues.totalVotingPower -= votingPower;
}
```

but calling such function can have unintended side effects

the codebase that use the state totalVotingPower is this function when comparing the voting power share of

```solidity
/// @notice Return the voting power share of a token. Denominated
///         fractions of 1e18. I.e., 1e18 = 100%.
/// @param tokenId The token ID to query.
/// @return share The voting power percentage of `tokenId`.
function getVotingPowerShareOf(uint256 tokenId) public view returns (uint256) {
	uint256 totalVotingPower = _getSharedProposalStorage().governanceValues.totalVotingPower;
	return
		totalVotingPower == 0 ? 0 : (votingPowerByTokenId[tokenId] * 1e18) / totalVotingPower;
}
```

suppose the totalVotingPower is reduced, the getVotingPowerShareOf return a large number and 

can this function is used to calculate how much fund user can withdraw [when rageQuit](https://github.com/code-423n4/2023-10-party/blob/b23c65d62a20921c709582b0b76b387f2bb9ebb5/contracts/party/PartyGovernanceNFT.sol#L393) on party NFT, 

```solidity
// Check token's balance.
uint256 balance = address(withdrawTokens[i]) == ETH_ADDRESS
	? address(this).balance
	: withdrawTokens[i].balanceOf(address(this));

// Add fair share of tokens from the party to total.
for (uint256 j; j < tokenIds.length; ++j) {
	// Must be retrieved before burning the token.
	withdrawAmounts[i] += (balance * getVotingPowerShareOf(tokenIds[j])) / 1e18;
}
```

in case when  getVotingPowerShareOf return a large amount when total voting power is reduced, user can rage quit to suddenly withdraw more fund by backrun the total voting power reduction

or in case when the total voting power, they can frontrun to avoid loss

the POC belo