feat: recreate AgentWallet.sol based on docs

This commit is contained in:
oib
2026-02-27 22:54:37 +01:00
parent d152044c6f
commit 501676ff93

View File

@@ -0,0 +1,191 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
/**
* @title AgentWallet
* @dev Isolated agent-specific wallet for micro-transactions, funded by user allowances.
*/
contract AgentWallet is Ownable, ReentrancyGuard {
using SafeERC20 for IERC20;
IERC20 public aitbcToken;
// Structs
struct Agent {
address owner;
uint256 balance;
uint256 spendingLimit;
uint256 totalSpent;
bool isActive;
}
struct Transaction {
uint256 txId;
address agent;
address recipient;
uint256 amount;
uint256 timestamp;
string purpose;
}
// State Variables
uint256 public txCounter;
mapping(address => Agent) public agents;
mapping(uint256 => Transaction) public transactions;
mapping(address => uint256[]) public agentTransactions;
// Events
event AgentRegistered(address indexed agent, address indexed owner);
event AgentDeactivated(address indexed agent);
event FundsDeposited(address indexed agent, uint256 amount);
event FundsWithdrawn(address indexed agent, uint256 amount);
event SpendingLimitUpdated(address indexed agent, uint256 newLimit);
event MicroTransactionExecuted(uint256 indexed txId, address indexed agent, address indexed recipient, uint256 amount, string purpose);
// Modifiers
modifier onlyAgentOwner(address _agent) {
require(agents[_agent].owner == msg.sender, "Not agent owner");
_;
}
modifier onlyActiveAgent(address _agent) {
require(agents[_agent].isActive, "Agent is not active");
_;
}
constructor(address _aitbcToken) {
require(_aitbcToken != address(0), "Invalid token address");
aitbcToken = IERC20(_aitbcToken);
}
/**
* @dev Register a new agent wallet
* @param _agent The address of the agent
* @param _initialSpendingLimit The max the agent can spend
*/
function registerAgent(address _agent, uint256 _initialSpendingLimit) external {
require(_agent != address(0), "Invalid agent address");
require(agents[_agent].owner == address(0), "Agent already registered");
agents[_agent] = Agent({
owner: msg.sender,
balance: 0,
spendingLimit: _initialSpendingLimit,
totalSpent: 0,
isActive: true
});
emit AgentRegistered(_agent, msg.sender);
}
/**
* @dev Deactivate an agent
* @param _agent The address of the agent
*/
function deactivateAgent(address _agent) external onlyAgentOwner(_agent) {
agents[_agent].isActive = false;
emit AgentDeactivated(_agent);
}
/**
* @dev Update the spending limit for an agent
* @param _agent The address of the agent
* @param _newLimit The new spending limit
*/
function updateSpendingLimit(address _agent, uint256 _newLimit) external onlyAgentOwner(_agent) {
agents[_agent].spendingLimit = _newLimit;
emit SpendingLimitUpdated(_agent, _newLimit);
}
/**
* @dev Deposit AITBC tokens into an agent's wallet
* @param _agent The address of the agent
* @param _amount The amount to deposit
*/
function deposit(address _agent, uint256 _amount) external onlyActiveAgent(_agent) nonReentrant {
require(_amount > 0, "Amount must be greater than 0");
// Transfer tokens from the caller to this contract
aitbcToken.safeTransferFrom(msg.sender, address(this), _amount);
// Update agent balance
agents[_agent].balance += _amount;
emit FundsDeposited(_agent, _amount);
}
/**
* @dev Withdraw AITBC tokens from an agent's wallet back to the owner
* @param _agent The address of the agent
* @param _amount The amount to withdraw
*/
function withdraw(address _agent, uint256 _amount) external onlyAgentOwner(_agent) nonReentrant {
require(_amount > 0, "Amount must be greater than 0");
require(agents[_agent].balance >= _amount, "Insufficient balance");
// Update agent balance
agents[_agent].balance -= _amount;
// Transfer tokens back to the owner
aitbcToken.safeTransfer(msg.sender, _amount);
emit FundsWithdrawn(_agent, _amount);
}
/**
* @dev Execute a micro-transaction from the agent to a recipient
* @param _recipient The address of the recipient
* @param _amount The amount to send
* @param _purpose The purpose of the transaction
*/
function executeMicroTransaction(
address _recipient,
uint256 _amount,
string calldata _purpose
) external onlyActiveAgent(msg.sender) nonReentrant returns (uint256) {
require(_recipient != address(0), "Invalid recipient");
require(_amount > 0, "Amount must be greater than 0");
Agent storage agent = agents[msg.sender];
require(agent.balance >= _amount, "Insufficient balance");
require(agent.totalSpent + _amount <= agent.spendingLimit, "Spending limit exceeded");
// Update agent balances
agent.balance -= _amount;
agent.totalSpent += _amount;
// Create transaction record
uint256 txId = txCounter++;
transactions[txId] = Transaction({
txId: txId,
agent: msg.sender,
recipient: _recipient,
amount: _amount,
timestamp: block.timestamp,
purpose: _purpose
});
agentTransactions[msg.sender].push(txId);
// Transfer tokens to the recipient
aitbcToken.safeTransfer(_recipient, _amount);
emit MicroTransactionExecuted(txId, msg.sender, _recipient, _amount, _purpose);
return txId;
}
/**
* @dev Get transaction history for an agent
* @param _agent The address of the agent
*/
function getAgentTransactions(address _agent) external view returns (uint256[] memory) {
return agentTransactions[_agent];
}
}