contract DelegateProxy {
    /**
    * @dev Performs a delegatecall and returns whatever the delegatecall returned (entire context execution will return!)
    * @param _dst Destination address to perform the delegatecall
    * @param _calldata Calldata for the delegatecall
    */
    function delegatedFwd(address _dst, bytes _calldata) internal {
        require(isContract(_dst));
        assembly {
            let result := delegatecall(sub(gas, 10000), _dst, add(_calldata, 0x20), mload(_calldata), 0, 0)
            let size := returndatasize

            let ptr := mload(0x40)
            returndatacopy(ptr, 0, size)

            // revert instead of invalid() bc if the underlying call failed with invalid() it already wasted gas.
            // if the call returned error data, forward it
            switch result case 0 { revert(ptr, size) }
            default { return(ptr, size) }
        }
    }

    function isContract(address _target) internal view returns (bool) {
        uint256 size;
        assembly { size := extcodesize(_target) }
        return size > 0;
    }
}
function delegatedFwd(address _dst, bytes _calldata) internal {
    require(isContract(_dst));
    assembly {
        let result := delegatecall(sub(gas, 10000), _dst, add(_calldata, 0x20), mload(_calldata), 0, 0)
        let size := returndatasize

        let ptr := mload(0x40)
        returndatacopy(ptr, 0, size)

        // revert instead of invalid() bc if the underlying call failed with invalid() it already wasted gas.
        // if the call returned error data, forward it
        switch result case 0 { revert(ptr, size) }
        default { return(ptr, size) }
    }
}

/**
 * @dev Performs a delegatecall and returns whatever the delegatecall returned (entire context execution will return!)
 * @param _dst Destination address to perform the delegatecall
 * @param _calldata Calldata for the delegatecall
 */