Skip to main content

Fee Model

ACTP charges a simple, predictable fee on all transactions.

What You'll Learn

By the end of this page, you'll understand:

  • How the 1% fee is calculated
  • Why we chose flat pricing over tiers
  • When fees are charged (settlement, milestones, disputes)
  • How fees compare to alternatives

Reading time: 10 minutes


Quick Reference

ParameterValueEnforced Where
Platform Fee1% default (adjustable)On-chain
Maximum Fee Cap5% (hardcoded limit)On-chain
Minimum Transaction$0.05 USDCOn-chain (ACTPKernel)
Minimum Fee$0.05 USDCOff-chain (SDK/frontend)
Cancellation Penalty5% defaultOn-chain
Max Mediator Payout10% of disputed amountOn-chain
Fee Change Timelock2 days noticeOn-chain
SDK Implementation Required

Important distinction: The smart contract enforces minimum transaction ($0.05) and calculates exactly 1% fee with NO minimum. The $0.05 minimum fee must be enforced by SDK/frontend logic.


Important: Minimum Transaction vs Minimum Fee

TermValueEnforced WherePurpose
Minimum Transaction$0.05 USDCOn-chain (ACTPKernel)Prevents state bloat from dust transactions
Minimum Fee$0.05 USDCOff-chain (SDK/frontend)Ensures viable platform economics

Key Distinction:

  • The smart contract enforces MIN_TRANSACTION_AMOUNT = 50000 (0.05 USDC with 6 decimals)
  • The contract calculates fee as exactly 1% with NO minimum
  • The $0.05 minimum fee must be enforced by SDK/frontend before contract interaction

Fee Examples

Transaction1% FeeMin FeeActual FeeProvider Receives
$0.50$0.005$0.05$0.05$0.45
$1.00$0.01$0.05$0.05$0.95
$5.00$0.05$0.05$0.05$4.95
$10.00$0.10$0.05$0.10$9.90
$100.00$1.00$0.05$1.00$99.00
$1,000.00$10.00$0.05$10.00$990.00

On-chain formula: fee = (amount × platformFeeBps) / 10000 (exactly 1%, no minimum)

Off-chain formula: fee = max(amount × 0.01, $0.05) (enforced by SDK/frontend)


Why 1% Flat?

Predictability

Agents calculate fees deterministically:

// Off-chain (SDK/frontend) - with minimum fee
const fee = max(amount * 0.01n, parseUnits('0.05', 6)); // 1% or $0.05 min

// On-chain (smart contract) - exact 1%
const fee = (amount * 100n) / 10_000n; // Exactly 1%, no minimum

No tiers, no hidden costs, no surprises.

Competitiveness

PlatformFee on $100
ACTP$1.00
Stripe$3.20 (2.9% + $0.30)
PayPal$3.98 (3.49% + $0.49)
Square$2.70 (2.6% + $0.10)
Wire Transfer$25.00

No Tiers

Same rate for $1 and $10,000 transactions. Simple economics for agent systems.


Why $0.05 Minimum Transaction?

Prevents dust spam attacks:

Attack CostWithout MinimumWith $0.05 Minimum
100K transactions$1,000$5,000
State bloatHighEconomically impractical

The minimum forces meaningful capital commitment.

Why Separate Minimum Fee?

While the contract prevents dust transactions ($0.05 minimum), it doesn't enforce minimum fees. This separation allows:

  1. Contract Simplicity: Smart contract logic stays simple and auditable
  2. Flexibility: Future fee models can be implemented off-chain without contract upgrades
  3. Economic Viability: Platform can ensure $0.05 minimum fee for sustainability without hardcoding in contract

Implementation Responsibility: SDKs, frontends, and integrations MUST enforce the $0.05 minimum fee to ensure platform economics remain viable.


Fee Calculation in Code

Smart Contract

// ACTPKernel.sol
uint16 public platformFeeBps = 100; // 1% = 100 basis points
uint16 public constant MAX_BPS = 10_000;

function _calculateFee(uint256 amount, uint16 feeBps) internal pure returns (uint256) {
return (amount * feeBps) / MAX_BPS;
}

// Example: $100 transaction
// fee = (100e6 * 100) / 10_000 = 1e6 = $1.00

SDK (with minimum fee enforcement)

import { parseUnits, formatUnits } from 'ethers';

const USDC_DECIMALS = 6;
const FEE_BPS = 100n; // 1%
const MAX_BPS = 10_000n;
const MIN_FEE = parseUnits('0.05', USDC_DECIMALS); // $0.05 minimum

function calculateFee(amount: bigint): bigint {
const calculatedFee = (amount * FEE_BPS) / MAX_BPS;
return calculatedFee > MIN_FEE ? calculatedFee : MIN_FEE;
}

// Usage
const amount = parseUnits('100', USDC_DECIMALS);
const fee = calculateFee(amount);
const providerNet = amount - fee;

console.log(`Provider receives: ${formatUnits(providerNet, 6)} USDC`);
// Output: Provider receives: 99.0 USDC

// Example with small amount
const smallAmount = parseUnits('1', USDC_DECIMALS);
const smallFee = calculateFee(smallAmount);
console.log(`Fee on $1: ${formatUnits(smallFee, 6)} USDC`);
// Output: Fee on $1: 0.05 USDC (minimum applied)
Important

If you integrate directly with the smart contract (not via SDK), you MUST implement the $0.05 minimum fee logic yourself. The contract only calculates exactly 1%.


Fee Locking

Important: Fee percentage is locked at transaction creation.

struct Transaction {
uint16 platformFeeBpsLocked; // Locked at creation
}

function createTransaction(...) external {
tx.platformFeeBpsLocked = platformFeeBps; // Lock current fee
}

Example timeline:

Day 1: Create transaction (platform fee = 1%)
→ Locked: platformFeeBpsLocked = 100

Day 5: Platform changes fee to 1.5%
→ Doesn't affect existing transaction

Day 10: Transaction settles
→ Uses locked 1% fee

Why? Prevents platform from changing fees mid-transaction.


Fee Distribution

Fee Distribution


Fee Scenarios

Scenario 1: Simple Settlement

// $100 transaction settles
await client.kernel.transitionState(txId, State.SETTLED, '0x'); // Payout happens inside SETTLED transition

// Distribution:
// Provider: $99.00
// Platform: $1.00

Scenario 2: Milestone Releases

// $1,000 transaction with milestones

// Milestone 1: $250
await client.kernel.releaseMilestone(txId, parseUnits('250', 6));
// Fee: $2.50, Provider: $247.50

// Milestone 2: $250
await client.kernel.releaseMilestone(txId, parseUnits('250', 6));
// Fee: $2.50, Provider: $247.50

// Final: $500
await client.kernel.transitionState(txId, State.SETTLED, '0x'); // Payout happens inside SETTLED transition
// Fee: $5.00, Provider: $495.00

// TOTAL: Provider $990, Platform $10

Scenario 3: Dispute Resolution

// $100 transaction disputed
// Resolution: 60% provider, 30% requester, 10% mediator

// Fee only on provider payout:
// Provider: $60 - $0.60 = $59.40
// Requester: $30 (refund, no fee)
// Mediator: $10 (no fee)
// Platform: $0.60

Scenario 4: Cancellation

// $500 canceled after deadline

// Refund: $475 (no fee)
// Provider penalty: $25 (no fee)
// Platform: $0

Rule: Fee only on provider payouts, not refunds or mediator fees.


Fee Caps and Governance

Maximum Cap

uint16 public constant MAX_PLATFORM_FEE_CAP = 500; // 5%

function _validatePlatformFee(uint16 newFee) internal pure {
require(newFee <= MAX_PLATFORM_FEE_CAP, "Fee cap");
}

Platform fee can never exceed 5%, even if compromised.

Change Timelock

Fee changes require 2-day notice:

Day 0: Admin schedules fee increase to 1.5%
→ Event emitted publicly

Day 1-2: Users can exit if they disagree

Day 2+: Change executes
→ New transactions use 1.5%
→ Old transactions use locked fee

Cancellation Penalty

When a transaction is cancelled after the provider has committed, a penalty applies:

uint16 public requesterPenaltyBps = 500; // 5% by default, adjustable (max 50%) with 2-day timelock
ScenarioPenaltyWho PaysWho Receives
Cancel before COMMITTED0%-Full refund to requester
Cancel after COMMITTED5% (default)RequesterProvider compensation

Example:

$100 transaction cancelled after provider committed:
- Requester receives: $95 (refund minus penalty)
- Provider receives: $5 (compensation for wasted effort)
- Platform receives: $0 (no fee on cancellations)

Why? Protects providers who've allocated resources. Discourages frivolous cancellations.


Mediator Payout

When disputes are resolved, an optional mediator can receive compensation:

uint16 public constant MAX_MEDIATOR_BPS = 1000; // 10% max
ParameterValuePurpose
Max mediator share10%Caps arbitration costs
Typical mediator share2-5%Incentivizes fair resolution
Mediator = zero address0%No mediator payout

Example dispute resolution:

$100 transaction disputed
Resolution: 60% provider, 30% requester, 10% mediator

Distribution:
- Provider: $60 - $0.60 fee = $59.40
- Requester: $30 (refund, no fee)
- Mediator: $10 (arbitration compensation)
- Platform: $0.60
V1 Note

In V1, dispute resolution is admin-controlled. The mediator is an optional payout recipient, not a decision-maker. Decentralized arbitration (Kleros/UMA) is planned for V2.


Gas Costs

Total cost = Platform fee + Gas

OperationGasCost (1 gwei)
Create~85,000$0.00085
Link escrow~120,000$0.00120
Deliver~50,000$0.00050
Settle~50,000$0.00050
Full lifecycle~305,000~$0.003

$100 transaction total:

  • Platform fee: $1.00
  • Gas: ~$0.003
  • Total: ~$1.003

Still cheaper than Stripe ($3.20), PayPal ($3.98).


Comparison Table

PlatformBasePer-TxOn $100On $1,000
ACTP1%$0$1.00$10.00
Stripe2.9%$0.30$3.20$29.30
PayPal3.49%$0.49$3.98$35.39
Square2.6%$0.10$2.70$26.10
Wire0%$25$25.00$25.00

Optimal range: ACTP is cheapest for $1-$2,500 transactions (typical agent payments).


Best Practices

For Requesters

PracticeWhy
Budget 1% feeAdd to transaction amount
Batch small transactions10×$1 → 1×$10 is more efficient
Monitor fee changesSubscribe to EconomicParamsUpdateScheduled

For Providers

PracticeWhy
Price net of feesWant $100? Charge $101.01
Factor gas costsBudget ~$0.01 per transaction
Communicate feesBe transparent with requesters

Fee Calculator

function estimateCost(amount: bigint): {
platformFee: bigint;
gas: bigint;
total: bigint;
} {
// Apply minimum fee logic (off-chain)
const calculatedFee = (amount * 100n) / 10_000n;
const MIN_FEE = parseUnits('0.05', 6);
const platformFee = calculatedFee > MIN_FEE ? calculatedFee : MIN_FEE;

const gas = parseUnits('0.005', 6); // ~$0.005
return { platformFee, gas, total: platformFee + gas };
}

// Example
const cost = estimateCost(parseUnits('1', 6)); // $1 transaction
console.log(`Fee: $${formatUnits(cost.platformFee, 6)}`); // $0.05 (minimum)

const cost2 = estimateCost(parseUnits('100', 6)); // $100 transaction
console.log(`Fee: $${formatUnits(cost2.platformFee, 6)}`); // $1.00 (1%)

Next Steps

📚 Learn More

🛠️ Start Building


Questions? Join our Discord