abstract contract PurchaseLifeCycles {
    /**
     * Wrapper for the purchase data passed as argument to the life cycle functions and down to their step functions.
     */
    struct PurchaseData {
        address payable purchaser;
        address payable recipient;
        address token;
        bytes32 sku;
        uint256 quantity;
        bytes userData;
        uint256 totalPrice;
        bytes32[] pricingData;
        bytes32[] paymentData;
        bytes32[] deliveryData;
    }

    /*                               Internal Life Cycle Functions                               */

    /**
     * `estimatePurchase` lifecycle.
     * @param purchase The purchase conditions.
     */
    function _estimatePurchase(PurchaseData memory purchase) internal view virtual returns (uint256 totalPrice, bytes32[] memory pricingData) {
        _validation(purchase);
        _pricing(purchase);

        totalPrice = purchase.totalPrice;
        pricingData = purchase.pricingData;
    }

    /**
     * `purchaseFor` lifecycle.
     * @param purchase The purchase conditions.
     */
    function _purchaseFor(PurchaseData memory purchase) internal virtual {
        _validation(purchase);
        _pricing(purchase);
        _payment(purchase);
        _delivery(purchase);
        _notification(purchase);
    }

    /*                            Internal Life Cycle Step Functions                             */

    /**
     * Lifecycle step which validates the purchase pre-conditions.
     * @dev Responsibilities:
     *  - Ensure that the purchase pre-conditions are met and revert if not.
     * @param purchase The purchase conditions.
     */
    function _validation(PurchaseData memory purchase) internal view virtual;

    /**
     * Lifecycle step which computes the purchase price.
     * @dev Responsibilities:
     *  - Computes the pricing formula, including any discount logic and price conversion;
     *  - Set the value of `purchase.totalPrice`;
     *  - Add any relevant extra data related to pricing in `purchase.pricingData` and document how to interpret it.
     * @param purchase The purchase conditions.
     */
    function _pricing(PurchaseData memory purchase) internal view virtual;

    /**
     * Lifecycle step which manages the transfer of funds from the purchaser.
     * @dev Responsibilities:
     *  - Ensure the payment reaches destination in the expected output token;
     *  - Handle any token swap logic;
     *  - Add any relevant extra data related to payment in `purchase.paymentData` and document how to interpret it.
     * @param purchase The purchase conditions.
     */
    function _payment(PurchaseData memory purchase) internal virtual;

    /**
     * Lifecycle step which delivers the purchased SKUs to the recipient.
     * @dev Responsibilities:
     *  - Ensure the product is delivered to the recipient, if that is the contract's responsibility.
     *  - Handle any internal logic related to the delivery, including the remaining supply update;
     *  - Add any relevant extra data related to delivery in `purchase.deliveryData` and document how to interpret it.
     * @param purchase The purchase conditions.
     */
    function _delivery(PurchaseData memory purchase) internal virtual;

    /**
     * Lifecycle step which notifies of the purchase.
     * @dev Responsibilities:
     *  - Manage after-purchase event(s) emission.
     *  - Handle calls to the notifications receiver contract's `onPurchaseNotificationReceived` function, if applicable.
     * @param purchase The purchase conditions.
     */
    function _notification(PurchaseData memory purchase) internal virtual;
}
/**
 * @title PurchaseLifeCycles
 * An abstract contract which define the life cycles for a purchase implementer.
 */
function _purchaseFor(PurchaseData memory purchase) internal virtual {
    _validation(purchase);
    _pricing(purchase);
    _payment(purchase);
    _delivery(purchase);
    _notification(purchase);
}

/**
 * `purchaseFor` lifecycle.
 * @param purchase The purchase conditions.
 */