contract DelegateProxy is ERCProxy, IsContract {
  uint256 internal constant FWD_GAS_LIMIT = 10000;

  /**
   * @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 memory _calldata) internal {
    require(isContract(_dst));
    uint256 fwdGasLimit = FWD_GAS_LIMIT;

    assembly {
      let result := delegatecall(sub(gas, fwdGasLimit), _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) }
    }
  }
}
// https://github.com/aragon/aragonOS/blob/07d309f5e81c768269dfc49373d41fac4528ebd2/contracts/common/DelegateProxy.sol
function delegatedFwd(address _dst, bytes memory _calldata) internal {
  require(isContract(_dst));
  uint256 fwdGasLimit = FWD_GAS_LIMIT;

  assembly {
    let result := delegatecall(sub(gas, fwdGasLimit), _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
 */