Vulnerability: Prefer using abi.encode in TokenDistributor
Severity: medium

Description:
The method `_hashLeaf` is called when a user claims their airdrop.\\n```\\n// can we repoduce leaf hash included in the claim?\\nrequire(\\_hashLeaf(user\\_id, user\\_amount, leaf), 'TokenDistributor: Leaf Hash Mismatch.');\\n```\\n\\nThis method receives the `user_id` and the `user_amount` as arguments.\\n```\\n/\\*\\*\\n\\* @notice hash user\\_id + claim amount together & compare results to leaf hash \\n\\* @return boolean true on match\\n\\*/\\nfunction \\_hashLeaf(uint32 user\\_id, uint256 user\\_amount, bytes32 leaf) private returns (bool) {\\n```\\n\\nThese arguments are abi encoded and hashed together to produce a unique hash.\\n```\\nbytes32 leaf\\_hash = keccak256(abi.encodePacked(keccak256(abi.encodePacked(user\\_id, user\\_amount))));\\n```\\n\\nThis hash is checked against the third argument for equality.\\n```\\nreturn leaf == leaf\\_hash;\\n```\\n\\nIf the hash matches the third argument, it returns true and considers the provided `user_id` and `user_amount` are correct.\\nHowever, packing differently sized arguments may produce collisions.\\nThe Solidity documentation states that packing dynamic types will produce collisions, but this is also the case if packing `uint32` and `uint256`.\\nBelow there's an example showing that packing `uint32` and `uint256` in both orders can produce collisions with carefully picked values.\\n```\\nlibrary Encode {\\n    function encode32Plus256(uint32 \\_a, uint256 \\_b) public pure returns (bytes memory) {\\n        return abi.encodePacked(\\_a, \\_b);\\n    }\\n   \\n    function encode256Plus32(uint256 \\_a, uint32 \\_b) public pure returns (bytes memory) {\\n        return abi.encodePacked(\\_a, \\_b);\\n    }\\n}\\n\\ncontract Hash {\\n    function checkEqual() public pure returns (bytes32, bytes32) {\\n        // Pack 1\\n        uint32  a1 = 0x12345678;\\n        uint256 b1 = 0x99999999999999999999999999999999999999999999999999999999FFFFFFFF;\\n       \\n        // Pack 2\\n        uint256 a2 = 0x1234567899999999999999999999999999999999999999999999999999999999;\\n        uint32  b2 = 0xFFFFFFFF;\\n       \\n        // Encode these 2 different values\\n        bytes memory packed1 = Encode.encode32Plus256(a1, b1);\\n        bytes memory packed2 = Encode.encode256Plus32(a2, b2);\\n       \\n        // Check if the packed encodings match\\n        require(keccak256(packed1) == keccak256(packed2), "Hash of representation should match");\\n       \\n        // The hashes are the same\\n        // 0x9e46e582607c5c6e05587dacf66d311c4ced0819378a41d4b4c5adf99d72408e\\n        return (\\n            keccak256(packed1),\\n            keccak256(packed2)\\n        );\\n    }\\n}\\n```\\n\\nChanging `abi.encodePacked` to `abi.encode` in the library will make the transaction fail with error message `Hash of representation should match`.

Impact:

Recommended mitigation:
Resolution\\nFixed in gitcoinco/governance#7\\nUnless there's a specific use case to use `abi.encodePacked`, you should always use `abi.encode`. You might need a few more bytes in the transaction data, but it prevents collisions. Similar fix can be achieved by using `unit256` for both values to be packed to prevent any possible collisions.