4

I came across different versions of delegatecall via assembly and I tried all of them - no different result so far. How do they differ and which is the best version to use?

OpenZeppelin version:

assembly {
    let ptr := mload(0x40)
    calldatacopy(ptr, 0, calldatasize)
    let result := delegatecall(gas, _impl, ptr, calldatasize, 0, 0)
    let size := returndatasize
    returndatacopy(ptr, 0, size)

    switch result
    case 0 { revert(ptr, size) }
    default { return(ptr, size) }
}

MakerDAO version:

assembly {
    let succeeded := delegatecall(sub(gas, 5000), _target, add(_calldata, 0x20), mload(_calldata), 0, 0)
    let size := returndatasize

    response := mload(0x40)
    mstore(0x40, add(response, and(add(add(size, 0x20), 0x1f), not(0x1f))))
    mstore(response, size)
    returndatacopy(add(response, 0x20), 0, size)

    switch iszero(succeeded)
    case 1 {
        revert(add(response, 0x20), size)
    }
}

Simple version:

assembly {
    let succeeded := delegatecall(sub(gas, 5000), _target, add(_calldata, 0x20), mload(_calldata), 0, 32)
    response := mload(0)
    switch iszero(succeeded)
    case 1 {
        revert(0, 0)
    }
}

1 Answer 1

7

OpenZeppelin's one is the most generic and addresses contract upgrade scenario. It forwards msg.data as is to called contracts, and returns what called contract returned.

MakerDAO's is also generic but it allows passing arbitrary bytes as parameters and packs returned value into bytes as well.

Simple version allows arbitrary bytes as parameters but only returns first 32 bytes of returned value. It also ignores any data returned by failed delegate call.

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.