// File: contracts/helper/RevenueAggregatorV2.sol



// SPDX-License-Identifier: SPWPL

pragma solidity 0.8.15;
import "@opengsn/contracts/src/ERC2771Recipient.sol";

contract RevenueAggregatorV2 is ERC2771Recipient{
    /** @notice Emits when a withdrawal takes place
     * @param path The address of the revenue path
     * @param status Whether the withdrawal suceeded
     */
    event WithdrawStatus(address indexed path, bool indexed status, bytes result);
    error ZeroAddressProvided();

    constructor (address _forwarder){

        _setTrustedForwarder(_forwarder);
    }

    /** @notice Batch withdrawal request for tokens across revenue paths
     * @param paths List of revenue paths
     * @param targetWallet The wallet for which the withdrawal is being made
     */
    function withdrawPathToken(address[] calldata paths, address targetWallet, address tokenAddress) external {
        uint256 pathLength = paths.length;

        for (uint256 i; i < pathLength; ) {
            if(paths[i] == address(0)){
                revert ZeroAddressProvided();
            }
            (bool status, bytes memory result) = address(paths[i]).call(
                abi.encodeWithSignature("release(address,address)",tokenAddress,targetWallet)
            );
            
            emit WithdrawStatus(paths[i], status, result);
            unchecked{++i;}
        }
    }

        function distributePathToken(address[] calldata paths, address tokenAddress) external {
        uint256 pathLength = paths.length;

        for (uint256 i; i < pathLength; ) {

            (bool status, bytes memory result) = address(paths[i]).call(
                abi.encodeWithSignature("distributePendingTokens(address)",tokenAddress)
            );

            unchecked{++i;}
        }
    }

   
}

// File: @opengsn/contracts/src/ERC2771Recipient.sol



// SPDX-License-Identifier: MIT
// solhint-disable no-inline-assembly
pragma solidity >=0.6.9;

import "./interfaces/IERC2771Recipient.sol";

/**
 * @title The ERC-2771 Recipient Base Abstract Class - Implementation
 *
 * @notice Note that this contract was called `BaseRelayRecipient` in the previous revision of the GSN.
 *
 * @notice A base contract to be inherited by any contract that want to receive relayed transactions.
 *
 * @notice A subclass must use `_msgSender()` instead of `msg.sender`.
 */
abstract contract ERC2771Recipient is IERC2771Recipient {

    /*
     * Forwarder singleton we accept calls from
     */
    address private _trustedForwarder;

    /**
     * :warning: **Warning** :warning: The Forwarder can have a full control over your Recipient. Only trust verified Forwarder.
     * @notice Method is not a required method to allow Recipients to trust multiple Forwarders. Not recommended yet.
     * @return forwarder The address of the Forwarder contract that is being used.
     */
    function getTrustedForwarder() public virtual view returns (address forwarder){
        return _trustedForwarder;
    }

    function _setTrustedForwarder(address _forwarder) internal {
        _trustedForwarder = _forwarder;
    }

    /// @inheritdoc IERC2771Recipient
    function isTrustedForwarder(address forwarder) public virtual override view returns(bool) {
        return forwarder == _trustedForwarder;
    }

    /// @inheritdoc IERC2771Recipient
    function _msgSender() internal override virtual view returns (address ret) {
        if (msg.data.length >= 20 && isTrustedForwarder(msg.sender)) {
            // At this point we know that the sender is a trusted forwarder,
            // so we trust that the last bytes of msg.data are the verified sender address.
            // extract sender address from the end of msg.data
            assembly {
                ret := shr(96,calldataload(sub(calldatasize(),20)))
            }
        } else {
            ret = msg.sender;
        }
    }

    /// @inheritdoc IERC2771Recipient
    function _msgData() internal override virtual view returns (bytes calldata ret) {
        if (msg.data.length >= 20 && isTrustedForwarder(msg.sender)) {
            return msg.data[0:msg.data.length-20];
        } else {
            return msg.data;
        }
    }
}

// File: @opengsn/contracts/src/interfaces/IERC2771Recipient.sol



// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0;

/**
 * @title The ERC-2771 Recipient Base Abstract Class - Declarations
 *
 * @notice A contract must implement this interface in order to support relayed transaction.
 *
 * @notice It is recommended that your contract inherits from the ERC2771Recipient contract.
 */
abstract contract IERC2771Recipient {

    /**
     * :warning: **Warning** :warning: The Forwarder can have a full control over your Recipient. Only trust verified Forwarder.
     * @param forwarder The address of the Forwarder contract that is being used.
     * @return isTrustedForwarder `true` if the Forwarder is trusted to forward relayed transactions by this Recipient.
     */
    function isTrustedForwarder(address forwarder) public virtual view returns(bool);

    /**
     * @notice Use this method the contract anywhere instead of msg.sender to support relayed transactions.
     * @return sender The real sender of this call.
     * For a call that came through the Forwarder the real sender is extracted from the last 20 bytes of the `msg.data`.
     * Otherwise simply returns `msg.sender`.
     */
    function _msgSender() internal virtual view returns (address);

    /**
     * @notice Use this method in the contract instead of `msg.data` when difference matters (hashing, signature, etc.)
     * @return data The real `msg.data` of this call.
     * For a call that came through the Forwarder, the real sender address was appended as the last 20 bytes
     * of the `msg.data` - so this method will strip those 20 bytes off.
     * Otherwise (if the call was made directly and not through the forwarder) simply returns `msg.data`.
     */
    function _msgData() internal virtual view returns (bytes calldata);
}