In the case of blocklisting occurs for immutable addresses that are used in transfer functions, funds will stuck in Proxy contract.
In order to prove points that I will state later, I am starting with explaining how some variables set during life-cycle of one contest:
First, contest start with owner's call to the setContest()
and during this call salt which is used in creating proxy is called with "implementation" parameter as shown below:
Then sponsors send tokens to the proxy contract before its deployment.
During deployment we are again using same "implementation" parameter in _deployProxy()
as shown below:
So we know that "implementation" parameter can not change after setContest()
call.
Inside our proxy(where we hold our tokens) we have an immutable _implementation
that is used for distributing process which again can not change:
And inside our implementation (distributor) we have again an immutable addresses FACTORY_ADDRESS
which will call to distribute function (only FACTORY_ADDRESS can call it) and STADIUM_ADDRESS
which is the address to receive fees that set in the constructor and they can not change after deployment as shown below:
Sponsor mentioned that stadium address is the same as ProxyFactory's owner:
auditor: so STADIUM_ADDRESS will be set by the protocol. correct me if I'm wrong
sponsor: Nope the STADIUM_ADDRESS is the owner of the protocol.
Now here comes the vulnerability:
Expected tokens to use in contract is mentioned in nat-spec as:
@notice General ERC20 stable coin tokens, e.g. JPYC, USDC, USDT, DAI, etc, are suppsoed to be used in SPARKN.
The problem is JPYC,USDC and USDT are tokens with blocklist feature!
Let's look at JPYC'S transfer function:
So in order for transfers to occur in JPYC, both the "msg.sender" and "to" address must not be blacklisted.
Coming back to our SPARKN, we know that after contest end, prices will send via _distribute()
function called inside ProxyFactory and distribute()
that is inside Distributor.sol have two transfers:
So what are the risks in here?
1 - if implementation contract is blocklisted, distribute will fail. Since msg.sender for transfer function is Distributor.sol's deployed address (implementation), and there is no way to change this address after deployment(it is immutable in proxy and it is used in salt while creating proxy) in the case of blocklisted Distributor.sol, funds will stuck at proxy contract without a way to withdraw.
2 - if one of the winners is blocklisted, distribute will fail. This is not a problem since winners are passed as a data to function, in case this happens it can be solved off-chain (Winner can provide another not blocklisted address or winner gets deleted from winners).
3 - if STADIUM_ADDRESS
is blocklisted, distribute will fail. This address is protocol's owner as mentioned by sponsor, and if that address get blocklisted by token, since there is no way to change this address (it is immutable), funds will stuck at proxy contract without a way to withdraw.
Funds get stuck in a proxy contract without a way to withdraw. Hence this issue describes a high severity vulnerability.
Manual Review
If protocol wants to use tokens with blocklists, they have to reconsider implementations of immutables.
To be specific:
1- STADIUM_ADDRESS
in Distributor.sol should be changeable in case of blocklist.
2- _implementation
in Proxy.sol should be changeable (which actually effects proxy's salt calculation, hence salt calculation should also be changed to a one that don't have implementation address inside).
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.