Files
asle/contracts/src/core/facets/RWAFacet.sol
defiQUG 507d9a35b1 Add initial project structure and documentation files
- Created .gitignore to exclude sensitive files and directories.
- Added API documentation in API_DOCUMENTATION.md.
- Included deployment instructions in DEPLOYMENT.md.
- Established project structure documentation in PROJECT_STRUCTURE.md.
- Updated README.md with project status and team information.
- Added recommendations and status tracking documents.
- Introduced testing guidelines in TESTING.md.
- Set up CI workflow in .github/workflows/ci.yml.
- Created Dockerfile for backend and frontend setups.
- Added various service and utility files for backend functionality.
- Implemented frontend components and pages for user interface.
- Included mobile app structure and services.
- Established scripts for deployment across multiple chains.
2025-12-03 21:22:31 -08:00

190 lines
6.9 KiB
Solidity

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import {IRWAFacet} from "../../interfaces/IRWAFacet.sol";
import {IERC1404} from "../../interfaces/IERC1404.sol";
import {IComplianceFacet} from "../../interfaces/IComplianceFacet.sol";
import {IOracle} from "../../interfaces/IOracle.sol";
import {LibAccessControl} from "../../libraries/LibAccessControl.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
contract RWAFacet is IRWAFacet, IERC1404 {
using SafeERC20 for IERC20;
struct RWAStorage {
mapping(uint256 => RWA) rwas;
mapping(uint256 => address) valueOracles; // tokenId => oracle address
mapping(uint256 => bool) transferRestricted; // tokenId => restricted
mapping(uint256 => uint256) lastValueUpdate; // tokenId => timestamp
uint256 rwaCount;
}
// ERC-1404 restriction codes
uint8 private constant SUCCESS = 0;
uint8 private constant COMPLIANCE_FAILURE = 1;
uint8 private constant HOLDER_NOT_VERIFIED = 2;
uint8 private constant TRANSFER_RESTRICTED = 3;
bytes32 private constant RWA_STORAGE_POSITION = keccak256("asle.rwa.storage");
function rwaStorage() internal pure returns (RWAStorage storage rs) {
bytes32 position = RWA_STORAGE_POSITION;
assembly {
rs.slot := position
}
}
function tokenizeRWA(
address assetContract,
string calldata assetType,
uint256 totalValue,
bytes calldata complianceData
) external override returns (uint256 tokenId) {
// Check compliance - RWA tokenization typically requires Regulated mode
IComplianceFacet complianceFacet = IComplianceFacet(address(this));
require(
complianceFacet.canAccess(msg.sender, IComplianceFacet.ComplianceMode.Regulated),
"RWAFacet: Regulated compliance required"
);
RWAStorage storage rs = rwaStorage();
tokenId = rs.rwaCount;
rs.rwaCount++;
RWA storage rwa = rs.rwas[tokenId];
rwa.tokenId = tokenId;
rwa.assetContract = assetContract;
rwa.assetType = assetType;
rwa.totalValue = totalValue;
rwa.fractionalizedAmount = 0;
rwa.active = true;
rs.lastValueUpdate[tokenId] = block.timestamp;
emit RWATokenized(tokenId, assetContract, assetType, totalValue);
}
function fractionalizeRWA(
uint256 tokenId,
uint256 amount,
address recipient
) external override returns (uint256 shares) {
RWAStorage storage rs = rwaStorage();
RWA storage rwa = rs.rwas[tokenId];
require(rwa.active, "RWAFacet: RWA not active");
require(amount > 0, "RWAFacet: Amount must be > 0");
require(rwa.fractionalizedAmount + amount <= rwa.totalValue, "RWAFacet: Exceeds total value");
// Verify recipient compliance
IComplianceFacet complianceFacet = IComplianceFacet(address(this));
require(
complianceFacet.canAccess(recipient, IComplianceFacet.ComplianceMode.Regulated),
"RWAFacet: Recipient must have regulated compliance"
);
require(
complianceFacet.validateTransaction(msg.sender, recipient, amount),
"RWAFacet: Compliance validation failed"
);
rwa.fractionalizedAmount += amount;
rwa.verifiedHolders[recipient] = true;
shares = amount; // 1:1 for simplicity, could use different ratio
emit RWAFractionalized(tokenId, recipient, amount);
}
function getRWA(uint256 tokenId) external view override returns (
address assetContract,
string memory assetType,
uint256 totalValue,
uint256 fractionalizedAmount,
bool active
) {
RWA storage rwa = rwaStorage().rwas[tokenId];
return (
rwa.assetContract,
rwa.assetType,
rwa.totalValue,
rwa.fractionalizedAmount,
rwa.active
);
}
function verifyHolder(uint256 tokenId, address holder) external view override returns (bool) {
return rwaStorage().rwas[tokenId].verifiedHolders[holder];
}
// ============ ERC-1404 Transfer Restrictions ============
function detectTransferRestriction(address from, address to, uint256 amount) external view override returns (uint8) {
// Find which RWA token this relates to (simplified - in production would need token mapping)
RWAStorage storage rs = rwaStorage();
// Check compliance
IComplianceFacet complianceFacet = IComplianceFacet(address(this));
if (!complianceFacet.validateTransaction(from, to, amount)) {
return COMPLIANCE_FAILURE;
}
// Check holder verification for all RWAs
// In production, would check specific token
for (uint256 i = 0; i < rs.rwaCount; i++) {
if (rs.transferRestricted[i]) {
if (!rs.rwas[i].verifiedHolders[to]) {
return HOLDER_NOT_VERIFIED;
}
}
}
return SUCCESS;
}
function messageForTransferRestriction(uint8 restrictionCode) external pure override returns (string memory) {
if (restrictionCode == COMPLIANCE_FAILURE) return "Transfer failed compliance check";
if (restrictionCode == HOLDER_NOT_VERIFIED) return "Recipient not verified holder";
if (restrictionCode == TRANSFER_RESTRICTED) return "Transfer restricted for this token";
return "Transfer allowed";
}
// ============ Asset Value Management ============
function updateAssetValue(uint256 tokenId, address oracle) external {
LibAccessControl.requireRole(LibAccessControl.DEFAULT_ADMIN_ROLE, msg.sender);
RWAStorage storage rs = rwaStorage();
rs.valueOracles[tokenId] = oracle;
rs.lastValueUpdate[tokenId] = block.timestamp;
}
function getAssetValue(uint256 tokenId) external view returns (uint256) {
RWAStorage storage rs = rwaStorage();
address oracle = rs.valueOracles[tokenId];
if (oracle == address(0)) {
return rs.rwas[tokenId].totalValue;
}
try IOracle(oracle).latestRoundData() returns (
uint80,
int256 price,
uint256,
uint256 updatedAt,
uint80
) {
require(price > 0, "RWAFacet: Invalid oracle price");
require(updatedAt > 0, "RWAFacet: Stale oracle data");
return uint256(price);
} catch {
return rs.rwas[tokenId].totalValue; // Fallback to stored value
}
}
function setTransferRestricted(uint256 tokenId, bool restricted) external {
LibAccessControl.requireRole(LibAccessControl.DEFAULT_ADMIN_ROLE, msg.sender);
rwaStorage().transferRestricted[tokenId] = restricted;
}
}