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"
]
}
}
}
}}
Submitted on: 2025-09-28 15:02:25
Comments
Log in to comment.
No comments yet.