1

I want to create a modifier to dynamically forward parameters to a validator lets say I have a contract

contract Foo {
    address validatorAddress;

    modifier validate() {
        assembly {
            // Forward the call to the target contract and get the return data
            let result := delegatecall(gas(), validatorAddress, add(calldatasize(), 0x20), calldatasize(), 0, 0)

            // Check if the call was successful
            if iszero(result) {
                // Revert execution if the call failed
                revert(0, 0)
            }
        }
        _;
    }

    function bar(uint256 dependent) external validate {
        // Function body
    }
}

Now I would like to implement a validator like so:

function Validator {
    function bar(uint256 dependent, address originalSender) external validate {
    }
}

I know the encoding in solidity is not optimal, but is there any simple trick I can use to forward the original sender. I would think I can just overwrite the calldata buffer to append the msg sender, i just dont know if i need to modify padding or something or how gas efficient it would be:

let sender := caller()
let senderSize := 32

EDIT attempt:

let result := delegatecall(gas(), validatorAddress, add(calldatasize() + senderSize, 0x20), calldatasize() + sender, 0, 0)

How can I forward the original msg sender to the validator?

Not really sure how the delegatecall operates, does it just take in a memoryPointer, and the memory size for the calldata? If i append the sender to the call data, it wont be continuous memory if another variable was stored inbetween the calls would I need to deep copy and abi encode?

1
  • 1
    To get the original sender, you could also use tx.origin. Can you please add the minimum reproducible code where you’re trying to pass the original sender in the function call ? Commented Apr 29 at 5:05

1 Answer 1

0

You can just work around the issue by, passing the original context, and calling a validation function manually.

struct Context {
    uint256 msgValue;
    address msgSender;
    bytes4 msgSig;
}

interface IValidator {
    function validate(Context memory context) external;
}


contract ValidatorConsumerBase {

    constructor() {
        // validator = IValidator(address(this));
    }

    modifier isAuthorizedPayable() {
        _executeValidate(msg.value, msg.sender, msg.sig);
        _;
    }

    // Access to msg.Value causes complier errors
    // for not payable functions which consume this modifer
    modifier isAuthorized() {
        _executeValidate(0, msg.sender, msg.sig);
        _;
    }

    event V(address sender, bytes4 sig);
    function validate(Context memory context) external {
    }

    function _executeValidate(uint256 msgValue, address msgSender, bytes4 msgSig) private {
        Context memory context;
        context.msgValue = msgValue;
        context.msgSender = msgSender;
        context.msgSig = msgSig;

        emit V(context.msgSender, context.msgSig);

    }

    function bar(uint256) external isAuthorized returns (bytes4) {
        return msg.sig;
    }

    function barHash(uint256) external pure returns (bytes4) {
        return bytes4(keccak256("bar(uint256)"));
    }
}

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.