Files
aitbc/contracts/AITBCPaymentProcessor.sol
oib 7bb2905cca Update database paths and fix foreign key references across coordinator API
- Change SQLite database path from `/home/oib/windsurf/aitbc/data/` to `/opt/data/`
- Fix foreign key references to use correct table names (users, wallets, gpu_registry)
- Replace governance router with new governance and community routers
- Add multi-modal RL router to main application
- Simplify DEPLOYMENT_READINESS_REPORT.md to focus on production deployment status
- Update governance router with decentralized DAO voting
2026-02-26 19:32:06 +01:00

697 lines
20 KiB
Solidity

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/security/Pausable.sol";
import "./AIPowerRental.sol";
/**
* @title AITBC Payment Processor
* @dev Advanced payment processing contract with escrow, automated releases, and dispute resolution
* @notice Handles AITBC token payments for AI power rental services
*/
contract AITBCPaymentProcessor is Ownable, ReentrancyGuard, Pausable {
// State variables
IERC20 public aitbcToken;
AIPowerRental public aiPowerRental;
uint256 public paymentCounter;
uint256 public platformFeePercentage = 250; // 2.5% in basis points
uint256 public disputeResolutionFee = 100; // 1% in basis points
uint256 public minPaymentAmount = 1e15; // 0.001 AITBC minimum
uint256 public maxPaymentAmount = 1e22; // 10,000 AITBC maximum
// Structs
struct Payment {
uint256 paymentId;
address from;
address to;
uint256 amount;
uint256 platformFee;
uint256 disputeFee;
PaymentStatus status;
uint256 releaseTime;
uint256 createdTime;
uint256 confirmedTime;
bytes32 agreementId;
string paymentPurpose;
ReleaseCondition releaseCondition;
bytes32 conditionHash;
}
struct EscrowAccount {
uint256 escrowId;
address depositor;
address beneficiary;
uint256 amount;
uint256 releaseTime;
bool isReleased;
bool isRefunded;
bytes32 releaseCondition;
uint256 createdTime;
EscrowType escrowType;
}
struct ScheduledPayment {
uint256 scheduleId;
uint256 paymentId;
uint256 nextReleaseTime;
uint256 releaseInterval;
uint256 totalReleases;
uint256 releasedCount;
bool isActive;
}
// Enums
enum PaymentStatus {
Created,
Confirmed,
HeldInEscrow,
Released,
Refunded,
Disputed,
Cancelled
}
enum EscrowType {
Standard,
PerformanceBased,
TimeBased,
Conditional
}
enum ReleaseCondition {
Immediate,
Manual,
Performance,
TimeBased,
DisputeResolution
}
// Mappings
mapping(uint256 => Payment) public payments;
mapping(uint256 => EscrowAccount) public escrowAccounts;
mapping(uint256 => ScheduledPayment) public scheduledPayments;
mapping(address => uint256[]) public senderPayments;
mapping(address => uint256[]) public recipientPayments;
mapping(bytes32 => uint256) public agreementPayments;
mapping(address => uint256) public userEscrowBalance;
mapping(address => bool) public authorizedPayees;
mapping(address => bool) public authorizedPayers;
// Events
event PaymentCreated(
uint256 indexed paymentId,
address indexed from,
address indexed to,
uint256 amount,
bytes32 agreementId,
string paymentPurpose
);
event PaymentConfirmed(
uint256 indexed paymentId,
uint256 confirmedTime,
bytes32 transactionHash
);
event PaymentReleased(
uint256 indexed paymentId,
address indexed to,
uint256 amount,
uint256 platformFee
);
event PaymentRefunded(
uint256 indexed paymentId,
address indexed to,
uint256 amount,
string reason
);
event EscrowCreated(
uint256 indexed escrowId,
address indexed depositor,
address indexed beneficiary,
uint256 amount,
EscrowType escrowType
);
event EscrowReleased(
uint256 indexed escrowId,
uint256 amount,
bytes32 conditionHash
);
event EscrowRefunded(
uint256 indexed escrowId,
address indexed depositor,
uint256 amount,
string reason
);
event ScheduledPaymentCreated(
uint256 indexed scheduleId,
uint256 indexed paymentId,
uint256 nextReleaseTime,
uint256 releaseInterval
);
event ScheduledPaymentReleased(
uint256 indexed scheduleId,
uint256 indexed paymentId,
uint256 releaseCount
);
event DisputeInitiated(
uint256 indexed paymentId,
address indexed initiator,
string reason
);
event DisputeResolved(
uint256 indexed paymentId,
uint256 resolutionAmount,
bool resolvedInFavorOfPayer
);
event PlatformFeeCollected(
uint256 indexed paymentId,
uint256 feeAmount,
address indexed collector
);
// Modifiers
modifier onlyAuthorizedPayer() {
require(authorizedPayers[msg.sender], "Not authorized payer");
_;
}
modifier onlyAuthorizedPayee() {
require(authorizedPayees[msg.sender], "Not authorized payee");
_;
}
modifier paymentExists(uint256 _paymentId) {
require(_paymentId < paymentCounter, "Payment does not exist");
_;
}
modifier validStatus(uint256 _paymentId, PaymentStatus _requiredStatus) {
require(payments[_paymentId].status == _requiredStatus, "Invalid payment status");
_;
}
modifier sufficientBalance(address _user, uint256 _amount) {
require(aitbcToken.balanceOf(_user) >= _amount, "Insufficient balance");
_;
}
modifier sufficientAllowance(address _user, uint256 _amount) {
require(aitbcToken.allowance(_user, address(this)) >= _amount, "Insufficient allowance");
_;
}
// Constructor
constructor(address _aitbcToken, address _aiPowerRental) {
aitbcToken = IERC20(_aitbcToken);
aiPowerRental = AIPowerRental(_aiPowerRental);
paymentCounter = 0;
}
/**
* @dev Creates a new payment
* @param _to Recipient address
* @param _amount Payment amount
* @param _agreementId Associated agreement ID
* @param _paymentPurpose Purpose of the payment
* @param _releaseCondition Release condition
*/
function createPayment(
address _to,
uint256 _amount,
bytes32 _agreementId,
string memory _paymentPurpose,
ReleaseCondition _releaseCondition
) external onlyAuthorizedPayer sufficientBalance(msg.sender, _amount) sufficientAllowance(msg.sender, _amount) nonReentrant whenNotPaused returns (uint256) {
require(_amount >= minPaymentAmount, "Amount below minimum");
require(_amount <= maxPaymentAmount, "Amount above maximum");
require(_to != address(0), "Invalid recipient");
require(authorizedPayees[_to], "Recipient not authorized");
uint256 paymentId = paymentCounter++;
uint256 platformFee = (_amount * platformFeePercentage) / 10000;
uint256 disputeFee = (_amount * disputeResolutionFee) / 10000;
uint256 totalAmount = _amount + platformFee + disputeFee;
payments[paymentId] = Payment({
paymentId: paymentId,
from: msg.sender,
to: _to,
amount: _amount,
platformFee: platformFee,
disputeFee: disputeFee,
status: PaymentStatus.Created,
releaseTime: 0,
createdTime: block.timestamp,
confirmedTime: 0,
agreementId: _agreementId,
paymentPurpose: _paymentPurpose,
releaseCondition: _releaseCondition,
conditionHash: bytes32(0)
});
senderPayments[msg.sender].push(paymentId);
recipientPayments[_to].push(paymentId);
if (_agreementId != bytes32(0)) {
agreementPayments[_agreementId] = paymentId;
}
// Transfer tokens to contract
require(
aitbcToken.transferFrom(msg.sender, address(this), totalAmount),
"Payment transfer failed"
);
emit PaymentCreated(paymentId, msg.sender, _to, _amount, _agreementId, _paymentPurpose);
return paymentId;
}
/**
* @dev Confirms a payment with transaction hash
* @param _paymentId ID of the payment
* @param _transactionHash Blockchain transaction hash
*/
function confirmPayment(uint256 _paymentId, bytes32 _transactionHash)
external
paymentExists(_paymentId)
validStatus(_paymentId, PaymentStatus.Created)
nonReentrant
{
Payment storage payment = payments[_paymentId];
require(msg.sender == payment.from, "Only payer can confirm");
payment.status = PaymentStatus.Confirmed;
payment.confirmedTime = block.timestamp;
payment.conditionHash = _transactionHash;
// Handle immediate release
if (payment.releaseCondition == ReleaseCondition.Immediate) {
_releasePayment(_paymentId);
} else if (payment.releaseCondition == ReleaseCondition.TimeBased) {
payment.status = PaymentStatus.HeldInEscrow;
payment.releaseTime = block.timestamp + 1 hours; // Default 1 hour hold
} else {
payment.status = PaymentStatus.HeldInEscrow;
}
emit PaymentConfirmed(_paymentId, block.timestamp, _transactionHash);
}
/**
* @dev Releases a payment to the recipient
* @param _paymentId ID of the payment
*/
function releasePayment(uint256 _paymentId)
external
paymentExists(_paymentId)
nonReentrant
{
Payment storage payment = payments[_paymentId];
require(
payment.status == PaymentStatus.Confirmed ||
payment.status == PaymentStatus.HeldInEscrow,
"Payment not ready for release"
);
if (payment.releaseCondition == ReleaseCondition.Manual) {
require(msg.sender == payment.from, "Only payer can release manually");
} else if (payment.releaseCondition == ReleaseCondition.TimeBased) {
require(block.timestamp >= payment.releaseTime, "Release time not reached");
}
_releasePayment(_paymentId);
}
/**
* @dev Creates an escrow account
* @param _beneficiary Beneficiary address
* @param _amount Amount to lock in escrow
* @param _releaseTime Release time (0 for no time limit)
* @param _escrowType Type of escrow
* @param _releaseCondition Release condition hash
*/
function createEscrow(
address _beneficiary,
uint256 _amount,
uint256 _releaseTime,
EscrowType _escrowType,
bytes32 _releaseCondition
) external onlyAuthorizedPayer sufficientBalance(msg.sender, _amount) sufficientAllowance(msg.sender, _amount) nonReentrant whenNotPaused returns (uint256) {
require(_beneficiary != address(0), "Invalid beneficiary");
require(_amount >= minPaymentAmount, "Amount below minimum");
uint256 escrowId = paymentCounter++;
escrowAccounts[escrowId] = EscrowAccount({
escrowId: escrowId,
depositor: msg.sender,
beneficiary: _beneficiary,
amount: _amount,
releaseTime: _releaseTime,
isReleased: false,
isRefunded: false,
releaseCondition: _releaseCondition,
createdTime: block.timestamp,
escrowType: _escrowType
});
// Transfer tokens to contract
require(
aitbcToken.transferFrom(msg.sender, address(this), _amount),
"Escrow transfer failed"
);
userEscrowBalance[msg.sender] += _amount;
emit EscrowCreated(escrowId, msg.sender, _beneficiary, _amount, _escrowType);
return escrowId;
}
/**
* @dev Releases escrow to beneficiary
* @param _escrowId ID of the escrow account
*/
function releaseEscrow(uint256 _escrowId)
external
nonReentrant
{
EscrowAccount storage escrow = escrowAccounts[_escrowId];
require(!escrow.isReleased, "Escrow already released");
require(!escrow.isRefunded, "Escrow already refunded");
require(
escrow.releaseTime == 0 || block.timestamp >= escrow.releaseTime,
"Release time not reached"
);
escrow.isReleased = true;
userEscrowBalance[escrow.depositor] -= escrow.amount;
require(
aitbcToken.transfer(escrow.beneficiary, escrow.amount),
"Escrow release failed"
);
emit EscrowReleased(_escrowId, escrow.amount, escrow.releaseCondition);
}
/**
* @dev Refunds escrow to depositor
* @param _escrowId ID of the escrow account
* @param _reason Reason for refund
*/
function refundEscrow(uint256 _escrowId, string memory _reason)
external
nonReentrant
{
EscrowAccount storage escrow = escrowAccounts[_escrowId];
require(!escrow.isReleased, "Escrow already released");
require(!escrow.isRefunded, "Escrow already refunded");
require(
msg.sender == escrow.depositor || msg.sender == owner(),
"Only depositor or owner can refund"
);
escrow.isRefunded = true;
userEscrowBalance[escrow.depositor] -= escrow.amount;
require(
aitbcToken.transfer(escrow.depositor, escrow.amount),
"Escrow refund failed"
);
emit EscrowRefunded(_escrowId, escrow.depositor, escrow.amount, _reason);
}
/**
* @dev Initiates a dispute for a payment
* @param _paymentId ID of the payment
* @param _reason Reason for dispute
*/
function initiateDispute(uint256 _paymentId, string memory _reason)
external
paymentExists(_paymentId)
nonReentrant
{
Payment storage payment = payments[_paymentId];
require(
payment.status == PaymentStatus.Confirmed ||
payment.status == PaymentStatus.HeldInEscrow,
"Cannot dispute this payment"
);
require(
msg.sender == payment.from || msg.sender == payment.to,
"Only payment participants can dispute"
);
payment.status = PaymentStatus.Disputed;
emit DisputeInitiated(_paymentId, msg.sender, _reason);
}
/**
* @dev Resolves a dispute
* @param _paymentId ID of the disputed payment
* @param _resolutionAmount Amount to award to the winner
* @param _resolveInFavorOfPayer True if resolving in favor of payer
*/
function resolveDispute(
uint256 _paymentId,
uint256 _resolutionAmount,
bool _resolveInFavorOfPayer
) external onlyOwner paymentExists(_paymentId) nonReentrant {
Payment storage payment = payments[_paymentId];
require(payment.status == PaymentStatus.Disputed, "Payment not disputed");
require(_resolutionAmount <= payment.amount, "Resolution amount too high");
address winner = _resolveInFavorOfPayer ? payment.from : payment.to;
address loser = _resolveInFavorOfPayer ? payment.to : payment.from;
// Calculate refund for loser
uint256 refundAmount = payment.amount - _resolutionAmount;
// Transfer resolution amount to winner
if (_resolutionAmount > 0) {
require(
aitbcToken.transfer(winner, _resolutionAmount),
"Resolution payment failed"
);
}
// Refund remaining amount to loser
if (refundAmount > 0) {
require(
aitbcToken.transfer(loser, refundAmount),
"Refund payment failed"
);
}
payment.status = PaymentStatus.Released;
emit DisputeResolved(_paymentId, _resolutionAmount, _resolveInFavorOfPayer);
}
/**
* @dev Claims platform fees
* @param _paymentId ID of the payment
*/
function claimPlatformFee(uint256 _paymentId)
external
onlyOwner
paymentExists(_paymentId)
nonReentrant
{
Payment storage payment = payments[_paymentId];
require(payment.status == PaymentStatus.Released, "Payment not released");
require(payment.platformFee > 0, "No platform fee to claim");
uint256 feeAmount = payment.platformFee;
payment.platformFee = 0;
require(
aitbcToken.transfer(owner(), feeAmount),
"Platform fee transfer failed"
);
emit PlatformFeeCollected(_paymentId, feeAmount, owner());
}
/**
* @dev Authorizes a payee
* @param _payee Address to authorize
*/
function authorizePayee(address _payee) external onlyOwner {
authorizedPayees[_payee] = true;
}
/**
* @dev Revokes payee authorization
* @param _payee Address to revoke
*/
function revokePayee(address _payee) external onlyOwner {
authorizedPayees[_payee] = false;
}
/**
* @dev Authorizes a payer
* @param _payer Address to authorize
*/
function authorizePayer(address _payer) external onlyOwner {
authorizedPayers[_payer] = true;
}
/**
* @dev Revokes payer authorization
* @param _payer Address to revoke
*/
function revokePayer(address _payer) external onlyOwner {
authorizedPayers[_payer] = false;
}
/**
* @dev Updates platform fee percentage
* @param _newFee New fee percentage in basis points
*/
function updatePlatformFee(uint256 _newFee) external onlyOwner {
require(_newFee <= 1000, "Fee too high"); // Max 10%
platformFeePercentage = _newFee;
}
/**
* @dev Emergency pause function
*/
function pause() external onlyOwner {
_pause();
}
/**
* @dev Unpause function
*/
function unpause() external onlyOwner {
_unpause();
}
// Internal functions
function _releasePayment(uint256 _paymentId) internal {
Payment storage payment = payments[_paymentId];
payment.status = PaymentStatus.Released;
// Transfer amount to recipient
require(
aitbcToken.transfer(payment.to, payment.amount),
"Payment transfer failed"
);
// Transfer platform fee to owner
if (payment.platformFee > 0) {
require(
aitbcToken.transfer(owner(), payment.platformFee),
"Platform fee transfer failed"
);
}
emit PaymentReleased(_paymentId, payment.to, payment.amount, payment.platformFee);
}
// View functions
/**
* @dev Gets payment details
* @param _paymentId ID of the payment
*/
function getPayment(uint256 _paymentId)
external
view
paymentExists(_paymentId)
returns (Payment memory)
{
return payments[_paymentId];
}
/**
* @dev Gets escrow account details
* @param _escrowId ID of the escrow account
*/
function getEscrowAccount(uint256 _escrowId)
external
view
returns (EscrowAccount memory)
{
return escrowAccounts[_escrowId];
}
/**
* @dev Gets all payments for a sender
* @param _sender Address of the sender
*/
function getSenderPayments(address _sender)
external
view
returns (uint256[] memory)
{
return senderPayments[_sender];
}
/**
* @dev Gets all payments for a recipient
* @param _recipient Address of the recipient
*/
function getRecipientPayments(address _recipient)
external
view
returns (uint256[] memory)
{
return recipientPayments[_recipient];
}
/**
* @dev Gets payment associated with an agreement
* @param _agreementId ID of the agreement
*/
function getAgreementPayment(bytes32 _agreementId)
external
view
returns (uint256)
{
return agreementPayments[_agreementId];
}
/**
* @dev Gets user's escrow balance
* @param _user Address of the user
*/
function getUserEscrowBalance(address _user)
external
view
returns (uint256)
{
return userEscrowBalance[_user];
}
}