La prevención de delegación de llamadas (delegatecall) en Solidity no funciona.
Soy un traductor de español que traduce documentos de TI. Traduce lo siguiente al español. No traduzcas el código y la salida en markdown.
Soy un principiante estudiando el código de Github de Uniswap V3. Encontré el archivo “noDelegateCall.sol” en este enlace y descubrí una forma de evitar que un contrato sea llamado por delegación desde otro contrato. Sin embargo, al intentar implementar esto, me encontré con un problema.
pragma solidity >0.8.0;
contract Receiver {
string greeting = "Hola";
address private immutable original;
event Greeting(string greeting, address original, address addressThis);
constructor() {
original = address(this);
}
function checkNotDelegateCall() private view {
require(address(this) == original);
}
modifier noDelegateCall() {
checkNotDelegateCall();
_;
}
function greet() external noDelegateCall {
emit Greeting(greeting, original, address(this));
}
}
contract Sender {
string greeting = "Hola";
function delegatedGreeting(address _contract) external {
(bool success,) = _contract.delegatecall(
abi.encodeWithSignature("greet()")
);
}
}
Si llamo a la función delegatedGreeting
, espero que la función se revierta porque las variables original
y address(this)
son diferentes. Sin embargo, aunque emite un evento vacío, aún no se revierte. ¿Por qué ocurre esto?
davy.ai
La razón por la que la función
delegatedGreeting
no revierte es que la funcióndelegatecall
permite al contrato llamado acceder al almacenamiento del contrato llamante. En este caso, las variablesoriginal
yaddress(this)
se almacenan en el almacenamiento del contratoReceiver
. CuandodelegatedGreeting
llama a la funcióngreet
a través dedelegatecall
, se ejecuta en el contexto del contratoSender
, que no tiene las variablesoriginal
yaddress(this)
en su almacenamiento. Sin embargo, aún puede acceder a esas variables en el almacenamiento del contratoReceiver
debido adelegatecall
. Por lo tanto, la funcióncheckNotDelegateCall()
en el modificadornoDelegateCall
sigue pasando y la función no revierte.Para asegurarse de que el modificador
noDelegateCall
funcione como se espera, debe utilizar el opcodeCALL
en lugar deDELEGATECALL
. El opcodeCALL
no permite que el contrato llamado acceda al almacenamiento del contrato llamante. Puede modificar la funcióndelegatedGreeting
de la siguiente manera:Con esta implementación, la llamada a
delegatedGreeting
revertirá como se espera, ya que las variablesoriginal
yaddress(this)
no coincidirán debido a la ausencia de acceso al almacenamiento del contrato llamado.