Sparkn

CodeFox Inc.
DeFiFoundryProxy
15,000 USDC
View results
Submission Details
Severity: high

Organizer is unable to distribute multi-token rewards

Summary

If sponsors provide rewards in different tokens (e.g. USDC, USDT and JPYC), the organizer will be able to distribute only one of the tokens.

Vulnerability Details

Both deployProxyAndDistribute and deployProxyAndDistributeBySignature, intended for reward distribution, attempt to deploy the proxy before sending the rewards. This makes it impossible for the organizer to distribute different tokens for the same contest, because the subsequent calls would try to deploy a contract to an address with already existing bytecode, which will throw an error.

The organizer will have to contact the owner, so they will distribute the remaining tokens via distributeByOwner - the only function that doesn't deploy the proxy.

Proof of Concept

Add to ProxyTest.t.sol

function testSecondTokenFails() public {
// contest set up from the testing suite
vm.startPrank(factoryAdmin);
bytes32 randomId = keccak256(abi.encode("James", "001"));
proxyFactory.setContest(organizer, randomId, block.timestamp, address(distributor));
bytes32 salt = keccak256(abi.encode(organizer, randomId, address(distributor)));
address proxyAddress = proxyFactory.getProxyAddress(salt, address(distributor));
// sponsor provides rewards in two tokens
vm.startPrank(sponsor);
MockERC20(jpycv1Address).transfer(proxyAddress, 100_000 ether);
MockERC20(jpycv2Address).transfer(proxyAddress, 100_000 ether);
// distribution data from the testing suite
address[] memory winners = new address[](1);
winners[0] = user1;
uint256[] memory percentages_ = new uint256[](1);
percentages_[0] = 9500;
bytes memory data1 =
abi.encodeWithSelector(Distributor.distribute.selector, jpycv1Address, winners, percentages_, "");
bytes memory data2 =
abi.encodeWithSelector(Distributor.distribute.selector, jpycv2Address, winners, percentages_, "");
// organizer attempts to distribute two tokens
vm.startPrank(organizer);
proxyFactory.deployProxyAndDistribute(randomId, address(distributor), data1);
assertEq(MockERC20(jpycv1Address).balanceOf(user1), 95_000 ether);
vm.expectRevert();
proxyFactory.deployProxyAndDistribute(randomId, address(distributor), data2);
}

Impact

Organizers are unable to distribute multi-token rewards.

Tools Used

Manual review

Recommendations

Deploy the proxy only if it doesn't already exist, so the subsequent distributions will succeed:

function _deployProxy(address organizer, bytes32 contestId, address implementation) internal returns (address) {
bytes32 salt = _calculateSalt(organizer, contestId, implementation);
- address proxy = address(new Proxy{salt: salt}(implementation));
+ address proxy = getProxyAddress(salt, implementation);
+ if (proxy.code.length == 0) {
+ new Proxy{salt: salt}(implementation);
+ }
return proxy;
}

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.