Skip to main content

dispatchOrder_fillFixedFee

Signature Verification

dispatchOrder_fillFixedFee uses Core.sol's centralized verification via validateAndConsumeNonce() with P2PSwapHashUtils.hashDataForDispatchOrder(). Includes originExecutor parameter (EOA executor verified with tx.origin).

Function Signature:

function dispatchOrder_fillFixedFee(
address user,
MetadataDispatchOrder memory metadata,
uint256 priorityFeeEvvm,
uint256 nonceEvvm,
bytes memory signatureEvvm,
uint256 maxFillFixedFee
) external

Fills an existing order using a fixed/capped fee model with 10% tolerance. Fee = min(proportionalFee, maxFillFixedFee), allowing buyers to pay anywhere in the range [amountB + 90% fee, amountB + 100% fee].

Parameters

ParameterTypeDescription
useraddressBuyer address filling the order
metadataMetadataDispatchOrderDispatch details including originExecutor, nonce, and signature
priorityFeeEvvmuint256Optional MATE priority fee for faster execution
nonceEvvmuint256Nonce for Core payment transaction (collects tokenB + fee)
signatureEvvmbytesSignature for Core payment authorization
maxFillFixedFeeuint256Fee cap for this execution (default: 0.001 ETH)

MetadataDispatchOrder Structure

struct MetadataDispatchOrder {
address tokenA; // Token buyer will receive
address tokenB; // Token buyer will pay
uint256 orderId; // Order ID to fill
uint256 amountOfTokenBToFill; // Amount to pay (flexible within tolerance)
address originExecutor; // EOA that will execute (verified with tx.origin)
uint256 nonce; // Core nonce for P2PSwap service
bytes signature; // User's authorization signature
}

Signature Requirements

Operation Hash
bytes32 hashPayload = P2PSwapHashUtils.hashDataForDispatchOrder(
metadata.tokenA,
metadata.tokenB,
metadata.orderId
);

Note: Both proportional and fixed fee variants use the same hash function.

Signature Format:

{evvmId},{p2pSwapAddress},{hashPayload},{originExecutor},{nonce},true

Payment Signature: Separate signature required for paying tokenB + fee via Core.pay().

Fee Model

Calculation with Cap

proportionalFee = (orderAmountB × percentageFee) / 10,000
fee = min(proportionalFee, maxFillFixedFee)

// Default cap: 0.001 ETH
// Example: 100 ETH order × 5% = 5 ETH, capped at 0.001 ETH

10% Tolerance Range

fee10 = (fee × 1000) / 10,000  // 10% of fee
minRequired = amountB + fee - fee10
maxRequired = amountB + fee

// Buyer can pay anywhere in: [minRequired, maxRequired]

Purpose:

  • Protects buyers from excessive fees on large orders
  • Allows UI flexibility (can display range)
  • Avoids exact rounding issues

Fee Calculation Based on Payment

if (amountPaid >= minRequired && amountPaid < maxRequired) {
finalFee = amountPaid - amountB // Use actual amount paid
} else {
finalFee = fee // Full fee if paying maximum
}

Distribution (Default: seller 50%, service 40%, staker 10%)

Same as proportional model but with capped fee:

RecipientSharePurpose
Seller50%amountB + (finalFee × 50%)
Service Treasury40%finalFee × 40% (accumulated)
MATE Stakers10%finalFee × 10% (distributed)

Example (10 ETH order, 5% = 0.5 ETH but capped at 0.001 ETH):

  • Buyer pays: 10.001 ETH or within [10.0009, 10.001]
  • Fee used: 0.001 ETH
  • Seller gets: 10 ETH (order) + 0.0005 ETH (50% of fee) = 10.0005 ETH
  • Treasury: 0.0004 ETH (40% of fee)
  • Stakers: 0.0001 ETH (10% of fee)

Execution Flow

1. Centralized Verification

core.validateAndConsumeNonce(
user,
P2PSwapHashUtils.hashDataForDispatchOrder(
metadata.tokenA,
metadata.tokenB,
metadata.orderId
),
metadata.originExecutor,
metadata.nonce,
true, // Always async execution
metadata.signature
);

Validates:

  • Signature authenticity via EIP-191
  • Nonce hasn't been consumed
  • Executor is the specified EOA (via tx.origin)

On Failure:

  • Core__InvalidSignature() - Invalid signature
  • Core__NonceAlreadyUsed() - Nonce consumed
  • Core__InvalidExecutor() - Executing EOA doesn't match originExecutor

2. Market & Order Lookup

uint256 market = findMarket(metadata.tokenA, metadata.tokenB);

Order storage order = _validateMarketAndOrder(market, metadata.orderId);

Validation: Market and order exist, order is active

3. Fee Calculation with Cap & Tolerance

(uint256 fee, uint256 fee10) = calculateFillFixedFee(
order.amountB,
maxFillFixedFee
);

// Internal calculation:
// proportionalFee = (amountB * percentageFee) / 10_000
// if (proportionalFee > maxFillFixedFee) {
// fee = maxFillFixedFee
// fee10 = (fee * 1000) / 10_000
// } else {
// fee = proportionalFee
// fee10 = 0 // No tolerance if under cap
// }

uint256 minRequired = order.amountB + fee - fee10;
uint256 fullRequired = order.amountB + fee;

if (metadata.amountOfTokenBToFill < minRequired) {
revert("Insuficient amountOfTokenBToFill");
}

Tolerance Benefit: Buyer can pay 90%-100% of fee, not forced to exact amount

4. Collect Payment

requestPay(
user,
metadata.tokenB,
metadata.amountOfTokenBToFill,
priorityFeeEvvm,
nonceEvvm,
true, // Always async
signatureEvvm
);

Action: Transfers amountOfTokenBToFill from buyer to Core.sol

5. Calculate Final Fee

uint256 finalFee = _calculateFinalFee(
metadata.amountOfTokenBToFill,
order.amountB,
fee,
fee10
);

// Internal logic:
// if (amountPaid >= minRequired && amountPaid < fullRequired) {
// finalFee = amountPaid - order.amountB
// } else {
// finalFee = fee
// }

6. Overpayment Refund

bool didRefund = _handleOverpaymentRefund(
user,
metadata.tokenB,
metadata.amountOfTokenBToFill,
fullRequired
);

If overpaid beyond maxRequired: Refunds excess via makeCaPay()

7. Fee Distribution

_distributePayments(
metadata.tokenB,
order.amountB,
finalFee, // Uses calculated final fee
order.seller,
msg.sender,
priorityFeeEvvm
);

Distribution based on finalFee (not original fee):

  • Seller: amountB + (finalFee × 50%)
  • Executor: priorityFee + (finalFee × 10%)
  • Service: finalFee × 40%

8. Transfer TokenA to Buyer

makeCaPay(user, metadata.tokenA, order.amountA);

Action: Releases tokenA to buyer

9. Staker Rewards

_rewardExecutor(msg.sender, didRefund ? 5 : 4);

Rewards (MATE tokens):

  • 4x: Standard fill
  • 5x: Fill + handled refund

10. Clear Order

_clearOrderAndUpdateMarket(market, metadata.orderId);

Complete Usage Example

// Scenario: Buy 1000 USDC for 20 ETH (large order)
// Proportional fee: 20 ETH × 5% = 1 ETH
// Capped fee: min(1 ETH, 0.001 ETH) = 0.001 ETH
// 10% tolerance: 0.0001 ETH
// Range: [20.0009 ETH, 20.001 ETH]

address buyer = 0x123...;
address usdc = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48;
address eth = 0x0000000000000000000000000000000000000000;
address executor = 0x456...;
uint256 orderId = 7;

// 1. Get nonce
uint256 nonce = core.getNonce(buyer, address(p2pSwap));

// 2. Generate hash (same as proportional!)
bytes32 hashPayload = P2PSwapHashUtils.hashDataForDispatchOrder(
usdc,
eth,
orderId
);

// 3. Create signature
string memory message = string.concat(
Strings.toString(block.chainid), ",",
Strings.toHexString(address(p2pSwap)), ",",
Strings.toHexString(uint256(hashPayload)), ",",
Strings.toHexString(executor), ",",
Strings.toString(nonce), ",true"
);
bytes memory signature = signMessage(message, buyerPrivateKey);

// 4. Create metadata
// User can choose to pay anywhere in [20.0009, 20.001]
MetadataDispatchOrder memory metadata = MetadataDispatchOrder({
tokenA: usdc,
tokenB: eth,
orderId: orderId,
amountOfTokenBToFill: 20.00095 ether, // Within tolerance
originExecutor: executor,
nonce: nonce,
signature: signature
});

// 5. Generate payment signature
uint256 nonceEvvm = core.getNonce(buyer, address(core));
bytes memory signatureEvvm = generatePaymentSignature(
buyer,
eth,
20.00095 ether,
0.5 ether, // 0.5 MATE priority fee
nonceEvvm,
true
);

// 6. Execute dispatch with fee cap
p2pSwap.dispatchOrder_fillFixedFee(
buyer,
metadata,
0.5 ether, // Priority fee
nonceEvvm,
signatureEvvm,
0.001 ether // maxFillFixedFee cap
);

// Result:
// - Buyer pays: 20.00095 ETH
// - Buyer receives: 1000 USDC
// - finalFee calculated: 0.00095 ETH (actual paid - 20 ETH)
// - Seller receives: 20 ETH + 0.000475 ETH (50% of 0.00095) = 20.000475 ETH
// - Treasury: 0.00038 ETH (40% of 0.00095)
// - Stakers: 0.000095 ETH (10% of 0.00095)
// - Executor: 0.5 MATE (priority) + 4x MATE (reward)

Gas Costs

ScenarioGas CostNotes
Standard Fill~290,000 gasWithin tolerance
With Refund~330,000 gasOverpayment beyond max
Min Payment~280,000 gas90% fee (minRequired)
Max Payment~300,000 gas100% fee (fullRequired)

Economic Model

Buyer Benefits

  • Fee Protection: Large orders capped at maxFillFixedFee
  • Flexibility: Can pay 90%-100% of fee
  • Predictability: Known maximum fee upfront

Examples:

Order Size5% FeeCapped AtBuyer Saves
1 ETH0.05 ETH0.05 ETH0 (under cap)
5 ETH0.25 ETH0.25 ETH0 (under cap)
10 ETH0.5 ETH0.001 ETH0.499 ETH
100 ETH5 ETH0.001 ETH4.999 ETH

Seller Impact

  • Receives 50% of actualFee, not proportional fee
  • Large orders = lower fee bonus
  • Incentivizes smaller orders or higher base prices

Staker Revenue

ComponentAmountCondition
Priority FeeUser-defined MATEIf > 0
Fee SharefinalFee × 10%Distributed to executor
Base Reward4-5x MATEStandard execution

Profitability: Better for small-medium orders. Large orders capped.

Comparison: Proportional vs Fixed

AspectProportionalFixed (Capped)
Fee FormulaamountB × 5%min(amountB × 5%, 0.001 ETH)
ToleranceNone±10% of fee
Buyer FlexibilityMust pay exactRange accepted
Large OrdersExpensiveProtected by cap
Seller RevenueHigher on largeLower on large
Best ForSmall-medium ordersLarge orders

Error Handling

Core.sol Errors

  • Core__InvalidSignature() - Signature failed
  • Core__NonceAlreadyUsed() - Nonce consumed
  • Core__InvalidExecutor() - Executing EOA doesn't match originExecutor
  • Core__InsufficientBalance() - Buyer lacks tokenB

P2PSwap Errors

  • "Insuficient amountOfTokenBToFill" - Payment < minRequired
  • Internal validation failures for market/order

Use Cases

When to Use Fixed Fee

  • Large Orders: 10+ ETH where 5% would be excessive
  • Predictable Costs: Need to know max fee upfront
  • Price Sensitivity: Buyers want fee protection
  • UI Ranges: Display min-max payment options

When to Use Proportional

  • Small Orders: < 0.02 ETH where cap doesn't apply
  • Simplicity: Exact fee calculation
  • Seller Incentive: Higher fee bonus
  • Standard Trading: Most common use case

License: EVVM-NONCOMMERCIAL-1.0
Gas Estimate: 280k-330k gas
Staker Reward: 4-5x MATE + capped fee share + priority
Fee Cap: 0.001 ETH (default) with 10% tolerance