Skip to main content

payMultiple Function

Function Type: external
Function Signature: payMultiple((address,address,string,address,uint256,uint256,uint256,bool,address,bytes)[]) Returns: (uint256 successfulTransactions, uint256 failedTransactions)

Executes a batch of individual payment instructions within a single transaction. Each payment instruction (PayData) can originate from a different sender (from) and specifies its own recipient, token, amount, fee, nonce, and authorization signature. This allows an executor to efficiently process multiple unrelated payments together.

Parameters

ParameterTypeDescription
payDataPayData[]An array of structs, each defining a single payment operation

PayData Struct

Defines the complete set of parameters for a single, independent payment within the batch.

struct PayData {
address from;
address to_address;
string to_identity;
address token;
uint256 amount;
uint256 priorityFee;
uint256 nonce;
bool priority;
address executor;
bytes signature;
}
FieldTypeDescription
fromaddressThe address whose funds are being sent and whose signature/nonce are validated for this payment.
to_addressaddresshe recipient's direct address. Used if to_identity is empty.
to_identitystringAn alternative identifier for the recipient. If provided, the contract will attempt to resolve it to an address.
tokenaddressThe specific token address for this individual transfer.
amountuint256The quantity of token to transfer from from to the recipient.
priorityFeeuint256An additional fee, paid in token from the from address to the msg.sender (executor).
nonceuint256Nonce associated with the from address. Must match the expected sync or async nonce.
priorityboolDetermines execution mode: true for asynchronous (uses async nonce), false for synchronous (uses sync nonce).
executoraddressThe address authorized to submit this transaction to the contract. Can be address(0) for unrestricted execution.
signaturebytesA cryptographic signature (EIP-191) from the from address, authorizing this specific payment's details.
info

If you want to know more about the signature structure, refer to the Payment Signature Structure section.

Execution Methods

The function can be executed in two ways:

Fisher Execution

  • An fisher collects multiple authorized PayData structures (with valid signatures) from various users from the fishing spot.
  • The fisher aggregates these into the payData array.
  • The fisher submits the transaction calling payMultiple.

Direct Execution

  • A user or service constructs the payData array (potentially containing just one payment request or multiple from the same/different users for whom they have authorization).
  • They directly call payMultiple.
tip

If using a service as the direct executor, we recommend specifying the service's address as the executor parameter.

Workflow

  1. Iterate through each payment (PayData struct) in the payData array (i from 0 to length-1):

    a. Signature & Sync Nonce Verification: Validates the provided payData[i].signature against the reconstructed message. If priority is false (synchronous), this verification also implicitly checks the nonce against the expected synchronous nonce as part of the signed message. Reverts if the signature is invalid.

    b. Executor Validation: Checks if the payData[i].executor parameter matches the transaction sender (msg.sender). If payData[i].executor is address(0), this check is bypassed, allowing anyone to submit the transaction (provided the signature is valid). If payData[i].executor is non-zero and doesn't match msg.sender increments failedTransactions and skips to the next iteration.

    c. Nonce Verification & Update: Checks nonce validity based on the payData[i].priority flag

    • If invalid, increments failedTransactions and continues to the next iteration
    • If valid, updates the appropriate nonce mapping:
      • nextSyncUsedNonce for synchronized nonces
      • nextAsyncUsedNonce for asynchronized nonces

    d. Resolve Recipient Address:

    • If to_identity is provided (not empty), it attempts to resolve the identity to an owner address using verifyStrictAndGetOwnerOfIdentity from the MateNameService contract.
    • If to_identity is empty, it uses the provided to_address.

    e. Checks sender balance: Verifies the sender has sufficient funds for both the payment and priority fee. If insufficient, increments failedTransactions and moves to the next iteration

    f. Executes the payment: Processes the transfer using the pay function (which calls _updateBalance). If payment fails, increments failedTransactions and continues to next iteration

    g. Processes priority fee (optional): If the executor holds sMATE and a priority fee is provided, the function calls _updateBalance to process the priority fee and distribute it to the executor in the payData[i].token.

    h. Records success: For successful payments, increments the successfulTransactions counter

  2. After the loop finishes, if the msg.sender (executor) holds sMATE tokens:

    • Calculate the total reward: reward = getReward() * successfulTransactions.
    • Distribute the reward to the msg.sender using _giveMateReward.
  3. The function returns two values:

    • failedTransactions: Count of failed payment attempts
    • successfulTransactions: Count of successful payments

payMultiple with Fisher

payMultiple Direct