ShukaIntegratedEscrow

Description:

Smart contract deployed on Ethereum with Factory features.

Blockchain: Ethereum

Source Code: View Code On The Blockchain

Solidity Source Code:

{{
  "language": "Solidity",
  "sources": {
    "contracts/ShukaIntegratedEscrow.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

/**
 * @title ShukaIntegratedEscrow
 * @dev Escrow system for Shuka licenses with revenue sharing
 * Integrates with LicenseAnchor for license verification and fee structure
 */
contract ShukaIntegratedEscrow {
    
    // Admin address (Shuka's admin wallet)
    address public admin;
    
    // Reference to deployed LicenseAnchor contract
    address public licenseAnchor;
    
    // Escrow structure for transactions
    struct Escrow {
        string licenseId;
        address buyer;
        address seller;
        uint256 amount;
        uint256 platformFee;
        uint256 royaltyFee;
        bool released;
        bool refunded;
        uint256 createdAt;
        uint256 releasedAt;
    }
    
    // License fee configuration
    struct LicenseFees {
        uint256 royaltyPercentage;  // Basis points (100 = 1%)
        uint256 platformFeePercentage;  // Basis points
        uint256 minimumFee;  // Minimum fee in wei
        bool escrowRequired;
        bool autoRelease;
        uint256 autoReleaseDelay;  // Delay in seconds for auto-release
    }
    
    // Mappings
    mapping(bytes32 => Escrow) public escrows;
    mapping(string => LicenseFees) public licenseFees;
    mapping(address => uint256) public balances;
    
    // Events
    event EscrowCreated(
        bytes32 indexed escrowId,
        string indexed licenseId,
        address indexed buyer,
        address seller,
        uint256 amount
    );
    
    event EscrowReleased(
        bytes32 indexed escrowId,
        address indexed seller,
        uint256 amount,
        uint256 platformFee,
        uint256 royaltyFee
    );
    
    event EscrowRefunded(
        bytes32 indexed escrowId,
        address indexed buyer,
        uint256 amount
    );
    
    event LicenseFeesUpdated(
        string indexed licenseId,
        uint256 royaltyPercentage,
        uint256 platformFeePercentage
    );
    
    // Modifiers
    modifier onlyAdmin() {
        require(msg.sender == admin, "Only admin can perform this action");
        _;
    }
    
    modifier escrowExists(bytes32 escrowId) {
        require(escrows[escrowId].createdAt > 0, "Escrow does not exist");
        _;
    }
    
    /**
     * @dev Constructor
     * @param _licenseAnchor Address of the deployed LicenseAnchor contract
     */
    constructor(address _licenseAnchor) {
        admin = msg.sender;
        licenseAnchor = _licenseAnchor;
    }
    
    /**
     * @dev Set license fee structure
     * @param licenseId The license UUID
     * @param royaltyBps Royalty percentage in basis points
     * @param platformBps Platform fee percentage in basis points
     * @param minFee Minimum fee amount
     * @param requireEscrow Whether escrow is required for this license
     * @param autoRelease Whether to auto-release after delay
     * @param releaseDelay Auto-release delay in seconds
     */
    function setLicenseFees(
        string memory licenseId,
        uint256 royaltyBps,
        uint256 platformBps,
        uint256 minFee,
        bool requireEscrow,
        bool autoRelease,
        uint256 releaseDelay
    ) external onlyAdmin {
        require(royaltyBps <= 10000, "Royalty percentage too high");
        require(platformBps <= 10000, "Platform fee percentage too high");
        
        licenseFees[licenseId] = LicenseFees({
            royaltyPercentage: royaltyBps,
            platformFeePercentage: platformBps,
            minimumFee: minFee,
            escrowRequired: requireEscrow,
            autoRelease: autoRelease,
            autoReleaseDelay: releaseDelay
        });
        
        emit LicenseFeesUpdated(licenseId, royaltyBps, platformBps);
    }
    
    /**
     * @dev Create an escrow for a license transaction
     * @param licenseId The license UUID
     * @param seller The seller's address
     * @return escrowId The unique escrow identifier
     */
    function createEscrow(
        string memory licenseId,
        address seller
    ) external payable returns (bytes32) {
        require(msg.value > 0, "Escrow amount must be greater than zero");
        require(seller != address(0), "Invalid seller address");
        require(seller != msg.sender, "Cannot escrow to yourself");
        
        LicenseFees memory fees = licenseFees[licenseId];
        require(fees.escrowRequired || fees.royaltyPercentage > 0, "License does not require escrow");
        
        // Calculate fees
        uint256 platformFee = (msg.value * fees.platformFeePercentage) / 10000;
        uint256 royaltyFee = (msg.value * fees.royaltyPercentage) / 10000;
        
        // Ensure minimum fee is met
        uint256 totalFees = platformFee + royaltyFee;
        require(totalFees >= fees.minimumFee || fees.minimumFee == 0, "Total fees below minimum");
        
        // Generate escrow ID
        bytes32 escrowId = keccak256(
            abi.encodePacked(
                licenseId,
                msg.sender,
                seller,
                msg.value,
                block.timestamp
            )
        );
        
        // Create escrow
        escrows[escrowId] = Escrow({
            licenseId: licenseId,
            buyer: msg.sender,
            seller: seller,
            amount: msg.value,
            platformFee: platformFee,
            royaltyFee: royaltyFee,
            released: false,
            refunded: false,
            createdAt: block.timestamp,
            releasedAt: 0
        });
        
        emit EscrowCreated(escrowId, licenseId, msg.sender, seller, msg.value);
        
        // Auto-release if configured
        if (fees.autoRelease && fees.autoReleaseDelay == 0) {
            _releaseEscrow(escrowId);
        }
        
        return escrowId;
    }
    
    /**
     * @dev Release escrow funds to seller
     * @param escrowId The escrow identifier
     */
    function releaseEscrow(bytes32 escrowId) external {
        Escrow storage escrow = escrows[escrowId];
        require(escrow.createdAt > 0, "Escrow does not exist");
        require(!escrow.released && !escrow.refunded, "Escrow already processed");
        
        // Check if caller is authorized
        require(
            msg.sender == admin || 
            msg.sender == escrow.buyer ||
            (licenseFees[escrow.licenseId].autoRelease && 
             block.timestamp >= escrow.createdAt + licenseFees[escrow.licenseId].autoReleaseDelay),
            "Not authorized to release"
        );
        
        _releaseEscrow(escrowId);
    }
    
    /**
     * @dev Internal function to release escrow
     * @param escrowId The escrow identifier
     */
    function _releaseEscrow(bytes32 escrowId) internal {
        Escrow storage escrow = escrows[escrowId];
        
        escrow.released = true;
        escrow.releasedAt = block.timestamp;
        
        uint256 sellerAmount = escrow.amount - escrow.platformFee - escrow.royaltyFee;
        
        // Transfer funds
        if (sellerAmount > 0) {
            payable(escrow.seller).transfer(sellerAmount);
        }
        
        // Platform fees go to admin
        if (escrow.platformFee > 0) {
            payable(admin).transfer(escrow.platformFee);
        }
        
        // For now, royalties also go to admin (can be changed to rights holder)
        if (escrow.royaltyFee > 0) {
            payable(admin).transfer(escrow.royaltyFee);
        }
        
        emit EscrowReleased(
            escrowId,
            escrow.seller,
            sellerAmount,
            escrow.platformFee,
            escrow.royaltyFee
        );
    }
    
    /**
     * @dev Refund escrow to buyer (only admin or seller can refund)
     * @param escrowId The escrow identifier
     */
    function refundEscrow(bytes32 escrowId) external escrowExists(escrowId) {
        Escrow storage escrow = escrows[escrowId];
        require(!escrow.released && !escrow.refunded, "Escrow already processed");
        require(
            msg.sender == admin || msg.sender == escrow.seller,
            "Only admin or seller can refund"
        );
        
        escrow.refunded = true;
        
        // Refund full amount to buyer
        payable(escrow.buyer).transfer(escrow.amount);
        
        emit EscrowRefunded(escrowId, escrow.buyer, escrow.amount);
    }
    
    /**
     * @dev Get escrow details
     * @param escrowId The escrow identifier
     * @return The escrow details
     */
    function getEscrow(bytes32 escrowId) external view returns (Escrow memory) {
        return escrows[escrowId];
    }
    
    /**
     * @dev Calculate fees for a license transaction
     * @param licenseId The license UUID
     * @param amount The transaction amount
     * @return platformFee The platform fee
     * @return royaltyFee The royalty fee
     * @return sellerAmount The amount seller will receive
     */
    function calculateFees(
        string memory licenseId,
        uint256 amount
    ) external view returns (
        uint256 platformFee,
        uint256 royaltyFee,
        uint256 sellerAmount
    ) {
        LicenseFees memory fees = licenseFees[licenseId];
        
        platformFee = (amount * fees.platformFeePercentage) / 10000;
        royaltyFee = (amount * fees.royaltyPercentage) / 10000;
        sellerAmount = amount - platformFee - royaltyFee;
        
        return (platformFee, royaltyFee, sellerAmount);
    }
    
    /**
     * @dev Check if escrow can be released
     * @param escrowId The escrow identifier
     * @return canRelease Whether the escrow can be released
     * @return reason The reason if it cannot be released
     */
    function canReleaseEscrow(bytes32 escrowId) external view returns (bool canRelease, string memory reason) {
        Escrow memory escrow = escrows[escrowId];
        
        if (escrow.createdAt == 0) {
            return (false, "Escrow does not exist");
        }
        
        if (escrow.released) {
            return (false, "Escrow already released");
        }
        
        if (escrow.refunded) {
            return (false, "Escrow already refunded");
        }
        
        LicenseFees memory fees = licenseFees[escrow.licenseId];
        
        if (fees.autoRelease && block.timestamp >= escrow.createdAt + fees.autoReleaseDelay) {
            return (true, "Auto-release period passed");
        }
        
        return (true, "Can be released by authorized party");
    }
    
    /**
     * @dev Withdraw accumulated balance (admin only)
     */
    function withdrawBalance() external onlyAdmin {
        uint256 balance = address(this).balance;
        require(balance > 0, "No balance to withdraw");
        payable(admin).transfer(balance);
    }
    
    /**
     * @dev Update admin address
     * @param newAdmin The new admin address
     */
    function updateAdmin(address newAdmin) external onlyAdmin {
        require(newAdmin != address(0), "Invalid admin address");
        admin = newAdmin;
    }
    
    /**
     * @dev Receive function to accept ETH
     */
    receive() external payable {}
}"
    }
  },
  "settings": {
    "optimizer": {
      "enabled": true,
      "runs": 200
    },
    "viaIR": true,
    "evmVersion": "paris",
    "outputSelection": {
      "*": {
        "*": [
          "evm.bytecode",
          "evm.deployedBytecode",
          "devdoc",
          "userdoc",
          "metadata",
          "abi"
        ]
      }
    }
  }
}}

Tags:
Factory|addr:0xbe6b6fa19d3c1ae6430a90e6b63bf56ae2cb77b8|verified:true|block:23461347|tx:0xf1677035261d8591120142a6a38dd8541cbd2576beef3c1b5005950f1bb713c7|first_check:1759064545

Submitted on: 2025-09-28 15:02:25

Comments

Log in to comment.

No comments yet.