Will be interesting to see what really happened.
Will be interesting to see what really happened.
https://bscscan.com/address/0x7e0c621ea9f7afd5b86a50b0942eae...
Note line 304 the O is a 0:
bytes32 slot = ADMIN_SL0T;
This is like in Java, where you mean to override a method in a superclass but mis-spell the name of the method and therefore instead end up simply adding a new method with the mis-spelled name.
I guess either Solidity doesn't have something like Java 1.5+'s @Override, or else it just wasn't used.
In any case it's hard to believe this was accidental. Of all the places you could make this mistake, most of the others wouldn't result in a massive exploit like this.
But I agree, that's not what happened here.
In short:
* the smart contact is made in a way that allows upgrades by an administrator * the developers transfer their administrator privileges to another user as a show of good faith * the code to transfer the privileges actually doesn't do anything * the developers upgrade the contract giving themselves permission to take the funds
Then elsewhere on line 50, anybody who creates a Proxy object will automatically be made the admin with zero auth.
> The hackers implemented a change in the ownership of the smart contract address.
bytes32 slot = ADMIN_SL0T;
https://bscscan.com/address/0x7e0c621ea9f7afd5b86a50b0942eae...
These kind of rug pulls are more uncommon but not rare, they give the developers some level of plausible deniability. Even so their actions after speak volumes.
Note line 304 the O is a 0:
bytes32 slot = ADMIN_SL0T;
comment: @dev Storage slot with the admin of the contract. This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is validated in the constructor.
bytes32 internal constant ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; bytes32 internal constant ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
// this is the getter
function _admin() internal view returns (address adm) {
bytes32 slot = ADMIN_SLOT;
assembly {
// return the memory at slot
adm := sload(slot)
}
}
// this is the setter, notice the 0 and the different hash
bytes32 internal constant ADMIN_SL0T = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6102;
// this doesn't set the same value as the getter, in effect the admin cannot be changed
function _setAdmin(address newAdmin) internal {
bytes32 slot = ADMIN_SL0T;
assembly {
// set the memory at slot to the value of newAdmin
sstore(slot, newAdmin)
}
}
https://bscscan.com/address/0x7e0c621ea9f7afd5b86a50b0942eae...What's interesting is to see how it will be dealt with. Most "DeFi" and cryptocurrency aficionados are quick to claim that "code is law", so we'll see whether they change their minds when their own money is at stake.
code might not reflect
the intentions
So now we need human judges to judge what the intention of a smart contract is?Well, wouldn't it already be quite a win if for 99.9% of the smart contract out there no human judge was needed?
It's an honest question: ain't it unthinkable that most could be fully automated and yet real courts could be used in rare cases and that that'd be already be quite an improvement? Or is the system only working if 100% of the time no human ruling is needed?
I have no idea...
Most modern DeFi exploits take advantage of unintended interactions between multiple smart contracts.