DeliveryVersusPaymentV1HelperV1

Description:

Smart contract deployed on Ethereum with Factory features.

Blockchain: Ethereum

Source Code: View Code On The Blockchain

Solidity Source Code:

{{
  "language": "Solidity",
  "sources": {
    "src/dvp/V1/DeliveryVersusPaymentV1HelperV1.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity 0.8.30;

/**
 * ██████╗░██╗░░░██╗██████╗░███████╗░█████╗░░██████╗██╗░░░██╗░░░██╗░░██╗██╗░░░██╗███████╗
 * ██╔══██╗██║░░░██║██╔══██╗██╔════╝██╔══██╗██╔════╝╚██╗░██╔╝░░░╚██╗██╔╝╚██╗░██╔╝╚════██║
 * ██║░░██║╚██╗░██╔╝██████╔╝█████╗░░███████║╚█████╗░░╚████╔╝░░░░░╚███╔╝░░╚████╔╝░░░███╔═╝
 * ██║░░██║░╚████╔╝░██╔═══╝░██╔══╝░░██╔══██║░╚═══██╗░░╚██╔╝░░░░░░██╔██╗░░░╚██╔╝░░██╔══╝░░
 * ██████╔╝░░╚██╔╝░░██║░░░░░███████╗██║░░██║██████╔╝░░░██║░░░██╗██╔╝╚██╗░░░██║░░░███████╗
 * ╚═════╝░░░░╚═╝░░░╚═╝░░░░░╚══════╝╚═╝░░╚═╝╚═════╝░░░░╚═╝░░░╚═╝╚═╝░░╚═╝░░░╚═╝░░░╚══════╝
 */
import {IDeliveryVersusPaymentV1} from "./IDeliveryVersusPaymentV1.sol";

/**
 * @title DeliveryVersusPaymentV1HelperV1
 * @dev Provides view helper functions to page through settlements using a cursor-based approach.
 * Created by https://pv0.one. UI implemented at https://dvpeasy.xyz.
 * It allows filtering by token address, by involved party, or by token type (Ether, ERC20, or NFT).
 * Each function accepts a DVP contract, a starting cursor and a pageSize and returns matching settlement
 * IDs along with a nextCursor (which is the settlement ID to use as the starting cursor in the next call).
 * These functions are not intended to be used in state-changing transactions, they are intended for
 * use by clients as read-only views of the DeliveryVersusPaymentV1 contract.
 * It is clients resposibility to ensure that the DVP contract is valid.
 */
contract DeliveryVersusPaymentV1HelperV1 {
  error InvalidPageSize();

  modifier validPageSize(uint256 pageSize) {
    if (pageSize < 2 || pageSize > 200) revert InvalidPageSize();
    _;
  }

  enum TokenType {
    Ether, // Settlements containing any flow with Ether (token == address(0))
    ERC20, // Settlements containing any flow with an ERC20 token (token != address(0) && isNFT == false)
    NFT // Settlements containing any flow with an NFT (token != address(0) && isNFT == true)
  }

  // A struct for returning token type information.
  struct TokenTypeInfo {
    uint8 id;
    string name;
  }

  //------------------------------------------------------------------------------
  // External
  //------------------------------------------------------------------------------
  /**
   * @dev Returns a list of token types as (id, name) pairs.
   */
  function getTokenTypes() external pure returns (TokenTypeInfo[] memory) {
    TokenTypeInfo[] memory types = new TokenTypeInfo[](3);
    types[0] = TokenTypeInfo(uint8(TokenType.Ether), "Ether");
    types[1] = TokenTypeInfo(uint8(TokenType.ERC20), "ERC20");
    types[2] = TokenTypeInfo(uint8(TokenType.NFT), "NFT");
    return types;
  }

  /**
   * @dev Returns a page of settlement IDs that include at least one flow with the given token address.
   * @param dvpAddress The address of the Delivery verus Payment contract.
   * @param token The token address used to filter settlements.
   * @param startCursor The settlement ID to start from (0 means start at the latest settlement).
   * @param pageSize The number of matching settlement IDs to return, valid values 2 to 200.
   * @return settlementIds An array of matching settlement IDs (up to pageSize in length).
   * @return nextCursor The settlement ID to use as the startCursor on the next call (or 0 if finished).
   */
  function getSettlementsByToken(address dvpAddress, address token, uint256 startCursor, uint256 pageSize)
    external
    view
    validPageSize(pageSize)
    returns (uint256[] memory settlementIds, uint256 nextCursor)
  {
    // true indicates filtering on flows' token field.
    return _getPagedSettlementIds(dvpAddress, startCursor, pageSize, true, token);
  }

  /**
   * @dev Returns a page of settlement IDs that involve the given party (as sender or receiver).
   * @param dvpAddress The address of the Delivery verus Payment contract.
   * @param involvedParty The address to filter settlements by.
   * @param startCursor The settlement ID to start from (0 means start at the latest settlement).
   * @param pageSize The number of matching settlement IDs to return, valid values 2 to 200.
   * @return settlementIds An array of matching settlement IDs (up to pageSize in length).
   * @return nextCursor The settlement ID to use as the startCursor on the next call (or 0 if finished).
   */
  function getSettlementsByInvolvedParty(
    address dvpAddress,
    address involvedParty,
    uint256 startCursor,
    uint256 pageSize
  ) external view validPageSize(pageSize) returns (uint256[] memory settlementIds, uint256 nextCursor) {
    // false indicates filtering on flows' from/to fields.
    return _getPagedSettlementIds(dvpAddress, startCursor, pageSize, false, involvedParty);
  }

  /**
   * @dev Returns a page of settlement IDs that include at least one flow matching the specified token type.
   * Token type can be Ether, ERC20, or NFT.
   * @param dvpAddress The address of the Delivery verus Payment contract.
   * @param tokenType The token type to filter settlements by.
   * @param startCursor The settlement ID to start from (0 means start at the latest settlement).
   * @param pageSize The number of matching settlement IDs to return, valid values 2 to 200.
   * @return settlementIds An array of matching settlement IDs (up to pageSize in length).
   * @return nextCursor The settlement ID to use as the startCursor on the next call (or 0 if finished).
   */
  function getSettlementsByTokenType(address dvpAddress, TokenType tokenType, uint256 startCursor, uint256 pageSize)
    external
    view
    validPageSize(pageSize)
    returns (uint256[] memory settlementIds, uint256 nextCursor)
  {
    return _getPagedSettlementIdsByType(dvpAddress, startCursor, pageSize, tokenType);
  }

  //------------------------------------------------------------------------------
  // Internal
  //------------------------------------------------------------------------------
  /**
   * @dev Internal helper that iterates backwards over settlement IDs to accumulate matching ones for address-based filters.
   * @param dvpAddress The address of the Delivery verus Payment contract.
   * @param startCursor The settlement ID to start from (0 means use dvp.settlementIdCounter()).
   * @param pageSize The number of matching settlement IDs to accumulate.
   * @param isTokenFilter. If true, filtering is done on flows' token field (comparing to filterAddress).
   * If false, filtering is done on flows' from/to fields (comparing to filterAddress).
   * @param filterAddress The address to filter by.
   * @return matchingIds An array of matching settlement IDs (of length <= pageSize).
   * @return nextCursor The settlement ID from which to continue in the next call (or 0 if there are no more).
   */
  function _getPagedSettlementIds(
    address dvpAddress,
    uint256 startCursor,
    uint256 pageSize,
    bool isTokenFilter,
    address filterAddress
  ) internal view returns (uint256[] memory matchingIds, uint256 nextCursor) {
    IDeliveryVersusPaymentV1 dvp = IDeliveryVersusPaymentV1(dvpAddress);
    uint256 current = startCursor == 0 ? dvp.settlementIdCounter() : startCursor;
    uint256[] memory temp = new uint256[](pageSize);
    uint256 count = 0;

    while (current > 0 && count < pageSize) {
      try dvp.getSettlement(current) returns (
        string memory, uint256, IDeliveryVersusPaymentV1.Flow[] memory flows, bool, bool
      ) {
        bool found = false;
        uint256 lengthFlows = flows.length;
        for (uint256 i = 0; i < lengthFlows; i++) {
          if (isTokenFilter) {
            if (flows[i].token == filterAddress) {
              found = true;
              break;
            }
          } else {
            if (flows[i].from == filterAddress || flows[i].to == filterAddress) {
              found = true;
              break;
            }
          }
        }
        if (found) {
          temp[count] = current;
          count++;
        }
      } catch {
        // settlement cannot be retrieved, skip it.
      }
      current--;
    }
    nextCursor = current;
    matchingIds = new uint256[](count);
    for (uint256 j = 0; j < count; j++) {
      matchingIds[j] = temp[j];
    }
  }

  /**
   * @dev Internal helper that iterates backwards over settlement IDs to accumulate matching ones based on token type.
   * @param dvpAddress The address of the Delivery verus Payment contract.
   * @param startCursor The settlement ID to start from (0 means use dvp.settlementIdCounter()).
   * @param pageSize The number of matching settlement IDs to accumulate.
   * @param tokenType The token type filter (Ether, ERC20, or NFT).
   * @return matchingIds An array of matching settlement IDs (of length <= pageSize).
   * @return nextCursor The settlement ID from which to continue in the next call (or 0 if there are no more).
   */
  function _getPagedSettlementIdsByType(address dvpAddress, uint256 startCursor, uint256 pageSize, TokenType tokenType)
    internal
    view
    returns (uint256[] memory matchingIds, uint256 nextCursor)
  {
    IDeliveryVersusPaymentV1 dvp = IDeliveryVersusPaymentV1(dvpAddress);
    uint256 current = startCursor == 0 ? dvp.settlementIdCounter() : startCursor;
    uint256[] memory temp = new uint256[](pageSize);
    uint256 count = 0;

    while (current > 0 && count < pageSize) {
      try dvp.getSettlement(current) returns (
        string memory, uint256, IDeliveryVersusPaymentV1.Flow[] memory flows, bool, bool
      ) {
        if (_matchesTokenType(flows, tokenType)) {
          temp[count] = current;
          count++;
        }
      } catch {
        // settlement cannot be retrieved, skip it.
      }
      current--;
    }
    nextCursor = current;
    matchingIds = new uint256[](count);
    for (uint256 j = 0; j < count; j++) {
      matchingIds[j] = temp[j];
    }
  }

  /**
   * @dev Internal pure function to determine if any flow in the provided array matches the specified token type.
   * @param flows An array of flows to check.
   * @param tokenType The token type filter.
   * @return True if at least one flow matches the token type, false otherwise.
   */
  function _matchesTokenType(IDeliveryVersusPaymentV1.Flow[] memory flows, TokenType tokenType)
    internal
    pure
    returns (bool)
  {
    uint256 lengthFlows = flows.length;
    for (uint256 i = 0; i < lengthFlows; i++) {
      // For Ether, the token address must be zero.
      if (tokenType == TokenType.Ether && flows[i].token == address(0)) {
        return true;
      }
      // For ERC20, the token address must be non-zero and isNFT must be false.
      if (tokenType == TokenType.ERC20 && flows[i].token != address(0) && !flows[i].isNFT) {
        return true;
      }
      // For NFT, the token address must be non-zero and isNFT must be true.
      if (tokenType == TokenType.NFT && flows[i].token != address(0) && flows[i].isNFT) {
        return true;
      }
    }
    return false;
  }
}
"
    },
    "src/dvp/V1/IDeliveryVersusPaymentV1.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity 0.8.30;

/**
 * ██████╗░██╗░░░██╗██████╗░███████╗░█████╗░░██████╗██╗░░░██╗░░░██╗░░██╗██╗░░░██╗███████╗
 * ██╔══██╗██║░░░██║██╔══██╗██╔════╝██╔══██╗██╔════╝╚██╗░██╔╝░░░╚██╗██╔╝╚██╗░██╔╝╚════██║
 * ██║░░██║╚██╗░██╔╝██████╔╝█████╗░░███████║╚█████╗░░╚████╔╝░░░░░╚███╔╝░░╚████╔╝░░░███╔═╝
 * ██║░░██║░╚████╔╝░██╔═══╝░██╔══╝░░██╔══██║░╚═══██╗░░╚██╔╝░░░░░░██╔██╗░░░╚██╔╝░░██╔══╝░░
 * ██████╔╝░░╚██╔╝░░██║░░░░░███████╗██║░░██║██████╔╝░░░██║░░░██╗██╔╝╚██╗░░░██║░░░███████╗
 * ╚═════╝░░░░╚═╝░░░╚═╝░░░░░╚══════╝╚═╝░░╚═╝╚═════╝░░░░╚═╝░░░╚═╝╚═╝░░╚═╝░░░╚═╝░░░╚══════╝
 */

/**
 * @title IDeliveryVersusPaymentV1
 * @dev Interface sufficient for DVP Helper contract to interact with a DVP contract.
 * Created by https://pv0.one. UI implemented at https://dvpeasy.xyz.
 */
interface IDeliveryVersusPaymentV1 {
  /// @dev A Flow is a single transfer from one address to another
  struct Flow {
    /// @dev address of ERC-20, ERC-721 or zero address for ETH
    address token;
    /// @dev flag of token is NFT
    bool isNFT;
    /// @dev party from address
    address from;
    /// @dev party to address
    address to;
    /// @dev Stores amount for ERC-20, ETH or tokenId for ERC-721
    uint256 amountOrId;
  }

  /**
   * @dev Returns the last settlement id used.
   */
  function settlementIdCounter() external view returns (uint256);

  /**
   * @dev Retrieves settlement details.
   * @param settlementId The settlement ID.
   * @return settlementReference A free-text reference.
   * @return cutoffDate The settlement's cutoff date.
   * @return flows An array of flows contained in the settlement.
   * @return isSettled True if the settlement has been executed.
   * @return isAutoSettled True if the settlement is set for auto-settlement.
   */
  function getSettlement(uint256 settlementId)
    external
    view
    returns (
      string memory settlementReference,
      uint256 cutoffDate,
      Flow[] memory flows,
      bool isSettled,
      bool isAutoSettled
    );
}
"
    }
  },
  "settings": {
    "remappings": [
      "@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
      "@openzeppelin/contracts-upgradeable-v5-2-0/=lib/openzeppelin-contracts-upgradeable/contracts/",
      "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
      "@openzeppelin/contracts-v5-2-0/=lib/openzeppelin-contracts/contracts/",
      "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
      "forge-std/=lib/forge-std/src/",
      "halmos-cheatcodes/=lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/",
      "openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
      "openzeppelin-contracts/=lib/openzeppelin-contracts/"
    ],
    "optimizer": {
      "enabled": true,
      "runs": 200
    },
    "metadata": {
      "useLiteralContent": false,
      "bytecodeHash": "ipfs",
      "appendCBOR": true
    },
    "outputSelection": {
      "*": {
        "*": [
          "evm.bytecode",
          "evm.deployedBytecode",
          "devdoc",
          "userdoc",
          "metadata",
          "abi"
        ]
      }
    },
    "evmVersion": "prague",
    "viaIR": true
  }
}}

Tags:
Factory|addr:0xe1e2e50918bf18207ee87b7618888128d19d8a44|verified:true|block:23632751|tx:0x67178df2150f733dcba0bb077749cd30f68f471246ca2c7fd004338979301560|first_check:1761242128

Submitted on: 2025-10-23 19:55:30

Comments

Log in to comment.

No comments yet.