Skip to main content

dispatchOrder_fillPropotionalFee

Signature Verification

dispatchOrder_fillPropotionalFee uses Core.sol's centralized verification via validateAndConsumeNonce() with P2PSwapHashUtils.hashDataForDispatchOrder(). Includes dual-executor parameters.

Function Signature:

function dispatchOrder_fillPropotionalFee(
address user,
address tokenA,
address tokenB,
uint256 orderId,
uint256 amountOfTokenBToFill,
address senderExecutor,
address originExecutor,
uint256 nonce,
bytes memory signature,
uint256 priorityFeePay,
uint256 noncePay,
bytes memory signaturePay
) external

Fills an existing order using a proportional fee model where fee = (amountB × percentageFee) / 10,000. Transfers tokenA to buyer, pays seller with tokenB + fee share, distributes remaining fees.

Parameters

ParameterTypeDescription
useraddressBuyer address filling the order
tokenAaddressToken buyer will receive
tokenBaddressToken buyer will pay
orderIduint256Order ID to fill
amountOfTokenBToFilluint256Amount to pay (must be >= amountB + fee)
senderExecutoraddressRestricts which address can execute this operation via msg.sender (address(0) = anyone can execute)
originExecutoraddressEOA that will initiate the transaction, verified via tx.origin (address(0) = anyone can initiate)
nonceuint256User's nonce for P2PSwap service operations
signaturebytesUser's authorization signature
priorityFeePayuint256Optional MATE priority fee for faster execution
noncePayuint256Nonce for Core payment transaction (collects tokenB + fee)
signaturePaybytesSignature for Core payment authorization

Signature Requirements

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

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

Signature Format:

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

Where:

  • evvmId: Chain ID from block.chainid
  • senderExecutor: Address that can execute via msg.sender
  • hashPayload: Result from P2PSwapHashUtils.hashDataForDispatchOrder(...)
  • originExecutor: EOA that will initiate the transaction
  • nonce: User's nonce for P2PSwap service
  • true: Always async execution

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

Fee Model

Calculation

fee = (orderAmountB × percentageFee) / 10,000

// Default: percentageFee = 500 (5%)
// Example: 100 USDC order → 5 USDC fee

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

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

Total to Buyer: Must pay amountB + fee
Seller Receives: amountB + (fee × 50%)
Example (100 USDC order, 5 USDC fee):

  • Buyer pays: 105 USDC
  • Seller gets: 100 USDC (order) + 2.5 USDC (50% of fee) = 102.5 USDC
  • Treasury: 2 USDC (40% of fee)
  • Stakers: 0.5 USDC (10% of fee)

Execution Flow

1. Centralized Verification

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

Validates:

  • Signature authenticity via EIP-191
  • Nonce hasn't been consumed
  • Executor restrictions (if specified)

On Failure:

  • Core__InvalidSignature() - Invalid signature
  • Core__NonceAlreadyUsed() - Nonce consumed
  • Core__InvalidExecutor() - Executor restrictions not met

2. Market & Order Lookup

uint256 market = findMarket(tokenA, tokenB);

Order storage order = _validateMarketAndOrder(market, orderId);

Validation:

  • Market exists
  • Order exists (seller != address(0))
  • Order is active

On Failure: Internal revert if invalid

3. Fee Calculation & Validation

uint256 fee = calculateFillPropotionalFee(order.amountB);
// fee = (order.amountB * percentageFee) / 10_000

uint256 requiredAmount = order.amountB + fee;

if (amountOfTokenBToFill < requiredAmount) {
revert("Insuficient amountOfTokenToFill");
}

Required: Buyer must provide at least amountB + fee

4. Collect Payment

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

Action: Transfers amountOfTokenBToFill from buyer to Core.sol

5. Overpayment Refund

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

If overpaid: Refunds amountOfTokenBToFill - requiredAmount via makeCaPay()
Benefit: Allows UI flexibility, user won't lose excess

6. Fee Distribution

_distributePayments(
metadata.tokenB,
order.amountB,
fee,
order.seller,
msg.sender,
priorityFeeEvvm
);

Internal Distribution:

// Calculate portions
uint256 sellerFee = (fee × rewardPercentage.seller) / 10000;
uint256 serviceFee = (fee × rewardPercentage.service) / 10000;
uint256 stakerFee = (fee × rewardPercentage.mateStaker) / 10000;

// Seller payment
makeDisperseCaPay([{
recipient: seller,
token: tokenB,
amount: amountB + sellerFee
}, {
recipient: executor,
token: MATE,
amount: priorityFee + stakerFee
}]);

// Service treasury (accumulated)
balancesOfContract[tokenB] += serviceFee;

7. Transfer TokenA to Buyer

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

Action: Releases original locked tokenA from seller to buyer

8. Staker Rewards

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

Rewards (MATE tokens):

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

9. Clear Order

_clearOrderAndUpdateMarket(market, metadata.orderId);

State Changes:

  • Order deleted (seller = address(0))
  • Market ordersAvailable decremented

Complete Usage Example

// Scenario: Buy 1000 USDC for 0.5 ETH (with 5% fee)
address buyer = 0x123...;
address usdc = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48;
address eth = 0x0000000000000000000000000000000000000000;
address executor = 0x456...;
uint256 orderId = 7;

// Order details: seller offers 1000 USDC, wants 0.5 ETH
// Fee: 0.5 ETH × 5% = 0.025 ETH
// Required: 0.5 + 0.025 = 0.525 ETH

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

// 2. Generate hash
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
MetadataDispatchOrder memory metadata = MetadataDispatchOrder({
tokenA: usdc,
tokenB: eth,
orderId: orderId,
amountOfTokenBToFill: 0.525 ether, // 0.5 + 0.025 fee
originExecutor: executor,
nonce: nonce,
signature: signature
});

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

// 6. Execute dispatch
p2pSwap.dispatchOrder_fillPropotionalFee(
buyer,
metadata,
0.5 ether, // Priority fee
nonceEvvm,
signatureEvvm
);

// Result:
// - Buyer pays: 0.525 ETH
// - Buyer receives: 1000 USDC
// - Seller receives: 0.5 ETH (order) + 0.0125 ETH (50% fee) = 0.5125 ETH
// - Treasury accumulates: 0.01 ETH (40% fee)
// - Stakers share: 0.0025 ETH (10% fee)
// - Executor receives: 0.5 MATE (priority) + 4-5x MATE (reward)

Gas Costs

ScenarioGas CostNotes
Standard Fill~280,000 gasNo overpayment
With Refund~320,000 gasOverpayment handled
With Priority~300,000 gasIncludes MATE distribution

Economic Model

Buyer Costs

  • Order Amount: amountB (what seller requested)
  • Protocol Fee: amountB × 5% (default)
  • Total: amountB × 1.05

Seller Revenue

  • Base: amountB (100% of requested amount)
  • Fee Bonus: fee × 50% (liquidity provider reward)
  • Total: amountB × 1.025

Staker Revenue

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

Example Profitability (100 USDC order, 5% fee):

  • Executor receives: ~0.5 USDC (10% of 5 USDC) + priority + 4x MATE
  • Very profitable for large orders

Error Handling

Core.sol Errors

  • Core__InvalidSignature() - Signature failed
  • Core__NonceAlreadyUsed() - Nonce consumed
  • Core__InvalidExecutor() - Wrong executor
  • Core__InsufficientBalance() - Buyer lacks tokenB

P2PSwap Errors

  • "Insuficient amountOfTokenToFill" - Payment < required amount
  • Internal validation failures for market/order

License: EVVM-NONCOMMERCIAL-1.0
Gas Estimate: 280k-320k gas
Staker Reward: 4-5x MATE + fee share + priority
Fee: 5% proportional (default)