HIGH severity: `NativeTokenStreamingEnforcer` and `ERTokenStreamingEnforcer` gas optimizations. **Description:**
1. Cache the amount spent to avoid multiple storage reads:

2. Avoid overriding storage data when spent is 0 and data is already set

3. Total spent is impossible to be greater than the amount unlocked, hence checking if the amount spent is greater than or equal to the amount...

Vulnerable code:
function _validateAndConsumeAllowance(
        bytes calldata _terms,
        bytes calldata _executionCallData,
        bytes32 _delegationHash,
        address _redeemer
    )
        private
    {
        (, uint256 value_,) = _executionCallData.decodeSingle();
        (uint256 initialAmount_, uint256 maxAmount_, uint256 amountPerSecond_, uint256 startTime_) = getTermsInfo(_terms);
        require(maxAmount_ >= initialAmount_, "NativeTokenStreamingEnforcer:invalid-max-amount");
        require(startTime_ > 0, "NativeTokenStreamingEnforcer:invalid-zero-start-time");
        StreamingAllowance storage allowance_ = streamingAllowances[msg.sender][_delegationHash];
++      uint256 currentAmountSpent = allowance_.spent;
--      if (allowance_.spent == 0) {
++      if (currentAmountSpent == 0) {
            // First use of this delegation
            allowance_.initialAmount = initialAmount_;
            allowance_.maxAmount = maxAmount_;
            allowance_.amountPerSecond = amountPerSecond_;
            allowance_.startTime = startTime_;
        }
        require(value_ <= _getAvailableAmount(allowance_), "NativeTokenStreamingEnforcer:allowance-exceeded");
--      allowance_.spent += value_;
++      allowance_.spent = value_ + currentAmountSpent;
        emit IncreasedSpentMap(
            msg.sender,
            _redeemer,
            _delegationHash,
            initialAmount_,
            maxAmount_,
            amountPerSecond_,
            startTime_,
--          allowance_.spent,
++          value_ + currentAmountSpent,
            block.timestamp
        );
    }

function _validateAndConsumeAllowance(
        bytes calldata _terms,
        bytes calldata _executionCallData,
        bytes32 _delegationHash,
        address _redeemer
    )
        private
    {
        ...
        StreamingAllowance storage allowance_ = streamingAllowances[msg.sender][_delegationHash];
--      if (allowance_.spent == 0) {
++      if (allowance_.spent == 0 && allowance_.startTime == 0) {
            // First use of this delegation
            allowance_.initialAmount = initialAmount_;
            allowance_.maxAmount = maxAmount_;
            allowance_.amountPerSecond = amountPerSecond_;
            allowance_.startTime = startTime_;
        }
        ...
    }

function _getAvailableAmount(StreamingAllowance memory _allowance) private view returns (uint256) {
        if (block.timestamp < _allowance.startTime) return 0;
        uint256 elapsed_ = block.timestamp - _allowance.startTime;
        uint256 unlocked_ = _allowance.initialAmount + (_allowance.amountPerSecond * elapsed_);
        if (unlocked_ > _allowance.maxAmount) {
            unlocked_ = _allowance.maxAmount;
        }
--      if (_allowance.spent >= unlocked_) return 0;
++      if (_allowance.spent == unlocked_) return 0;
        return unlocked_ - _allowance.spent;
    }