Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 45 additions & 1 deletion contracts/tax/AgentTax.sol
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ contract AgentTax is Initializable, AccessControlUpgradeable {
bytes32 public constant ADMIN_ROLE = keccak256("ADMIN_ROLE");
bytes32 public constant EXECUTOR_ROLE = keccak256("EXECUTOR_ROLE");
bytes32 public constant EXECUTOR_V2_ROLE = keccak256("EXECUTOR_V2_ROLE");
bytes32 public constant FEE_RATE_ADJUSTER_ROLE =
keccak256("FEE_RATE_ADJUSTER_ROLE");
uint256 internal constant MIN_PROTOTYPE_V2_ONCHAIN_VIRTUAL_ID = 10 ** 12;

uint256 internal constant DENOM = 10000;
Expand Down Expand Up @@ -105,6 +107,15 @@ contract AgentTax is Initializable, AccessControlUpgradeable {
IBondingV2ForTax public bondingV2;
IBondingV4ForTax public bondingV4;

mapping(uint256 agentId => uint16) public agentFeeRate;
mapping(uint256 agentId => bool) public hasAgentFeeRate;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if agentFeeRate[agentId] > 0 means hasAgentFeeRate, one var should be enough


event AgentFeeRateUpdated(
uint256 indexed agentId,
uint16 feeRate,
bool isOverride
);

/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
_disableInitializers();
Expand Down Expand Up @@ -211,6 +222,38 @@ contract AgentTax is Initializable, AccessControlUpgradeable {
emit TreasuryUpdated(oldTreasury, treasury_);
}

/**
* @notice Sets a per-agent treasury fee rate (basis points). Creator receives the remainder.
* @dev Cleared via `clearAgentFeeRate`; until then swaps use this rate instead of `feeRate`.
*/
function setAgentFeeRate(
uint256 agentId,
uint16 feeRate_
) external onlyRole(FEE_RATE_ADJUSTER_ROLE) {
require(feeRate_ <= DENOM, "Invalid fee rate");
agentFeeRate[agentId] = feeRate_;
hasAgentFeeRate[agentId] = true;
emit AgentFeeRateUpdated(agentId, feeRate_, true);
}

/**
* @notice Removes a per-agent fee override so swaps fall back to global `feeRate`.
*/
function clearAgentFeeRate(
uint256 agentId
) external onlyRole(FEE_RATE_ADJUSTER_ROLE) {
delete agentFeeRate[agentId];
delete hasAgentFeeRate[agentId];
emit AgentFeeRateUpdated(agentId, feeRate, false);
}

function _feeRateForAgent(uint256 agentId) internal view returns (uint16) {
if (hasAgentFeeRate[agentId]) {
return agentFeeRate[agentId];
}
return feeRate;
}

/**
* @notice Returns TBA and creator addresses used for tax attribution for `agentId`.
*/
Expand Down Expand Up @@ -304,7 +347,8 @@ contract AgentTax is Initializable, AccessControlUpgradeable {
uint256 assetReceived = amounts[1];
emit SwapExecuted(agentId, amountToSwap, assetReceived);

uint256 feeAmount = (assetReceived * feeRate) / DENOM;
uint256 feeAmount = (assetReceived * _feeRateForAgent(agentId)) /
DENOM;
uint256 creatorFee = assetReceived - feeAmount;

if (creatorFee > 0) {
Expand Down