4

I'm looking to make low-level delegatecall to a library that can be changed via a setter on the contract(see code below). Within the library, I am looking to make state changes to the calling contract. I have two issues.

First, I am unable to pass a storage struct to the delagatecall function correctly. The call below to updateStruct fails. I am aware of abi encoding difference between libraries vs contracts (https://docs.soliditylang.org/en/v0.8.14/contracts.html#function-signatures-and-selectors-in-libraries). From the docs I have applied "Other storage pointer types use the type identifier of their corresponding non-storage type, but append a single space followed by storage to it." So in the code below I am doing exactly that abi.encodeWithSignature("updateStruct(Test.A storage)", refType). Why is this not correct?

Second, I am trying to update the state of the value type like uint in the updateUint function. Is that possible via a delegatecall to lib? The code below does not fail when calling updateUint but it does not update the valueType state variable of the calling contract.

Any help appreciated

library Test{

    struct A {
        uint256 a;
    }
    function updateStruct(A storage refType)external {
        refType.a=5;
    }

    function updateUint(uint256 valueType)external {
        valueType=5;
    }
}

contract TestContract {
    address public adapterLib;
    struct A {
        uint256 a;
    }
    A public refType;
    uint public valueType;

    function setLib(address lib)public{
        adapterLib = lib;
    }
    

    function updateStruct()public {
        (bool success, bytes memory result)=adapterLib.delegatecall(abi.encodeWithSignature("updateStruct(Test.A storage)", refType));
        require(success);
    }

    function updateUint()public {
        (bool success, bytes memory result)=adapterLib.delegatecall(abi.encodeWithSignature("updateUint(uint256)", valueType));
        require(success);
    }
}
1

1 Answer 1

3
+50

I think the best approach is to have a Library function that modifies your contract's storage. (By using assembly{ })

Basically, instead of sending a structure by delegatecall and then receiving it in the Library, you rather send the storage slot of the struct and appropriately modify the data in that slot.

See the code below for reference.

//SPDX-License-Identifier: UNLICENCED
pragma solidity 0.8.3;  

    struct A {
        uint256 a;
    }


library TestLibrary {

    function updateStruct(A storage refType) external {
        refType.a = 5;
    }

    function updateOverDelegateCall(uint256 slotNumber) external {

        assembly {
        sstore(slotNumber, 9)
        }

    }

}

contract TestContract {

    using TestLibrary for A; 

    A public refType;

    address public adapterLib;

    function setLib(address lib)public{
        adapterLib = lib;
    }


    function updateStruct() public {
        refType.updateStruct();
    }

    function updateOverDelegateCall() public {

        uint256 slotNumber;

        // Slot number of the struct we want to change
        assembly{
            slotNumber:=refType.slot
        }
        
        (bool success, bytes memory result)=adapterLib.delegatecall(abi.encodeWithSignature("updateOverDelegateCall(uint256)", slotNumber));
        require(success);
    }

}

The same approach can be done for any unit, string or any other type of value.

3
  • Hey cheers for you answer! I guess in order to update a value type like uint one has indeed no choice but to use assembly. However one should be ably to encode structs as pointers via encodeWithSignature while making a delegatecall without any assembly to input the slot explictly. Any idea why the above in my example does not work? I am referring to updateStruct()
    – FreddyC
    Nov 17, 2022 at 9:27
  • I did try to solve it using Struct, but everything I tried (Sending Tupple), simply didn't work. And I can't figure out what the trick is.
    – Sky
    Nov 17, 2022 at 11:43
  • 1
    Yeah me neither, will leave this question as open for now
    – FreddyC
    Nov 17, 2022 at 12:10

Your Answer

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

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