dispersePay Function
Function Type: external
Function Signature: dispersePay(address,(uint256,address,string)[],address,uint256,uint256,address,uint256,bool,bytes)
Distributes tokens from a single sender to multiple recipients with efficient single-source multi-recipient payment distribution. This function uses a single signature to authorize distribution to multiple recipients, supports both direct addresses and identity-based recipients, and includes integrated priority fee and staker reward systems.
The signature structure for these payments is detailed in the Disperse Payment Signature Structure section.
Parameters
| Parameter | Type | Description |
|---|---|---|
from | address | The address of the payment sender whose funds will be distributed. |
toData | DispersePayMetadata[] | An array detailing each recipient's address/identity and the amount they should receive. See struct below. |
token | address | The token address to be distributed. |
amount | uint256 | The total amount of tokens to distribute across all recipients. Must equal the sum of individual amounts in toData. |
priorityFee | uint256 | Fee amount for the transaction executor (distributed to stakers as reward). |
senderExecutor | address | Address authorized to execute this transaction. Use address(0) to allow any address to execute. |
nonce | uint256 | Transaction nonce for replay protection managed by Core.sol. Usage depends on isAsyncExec. |
isAsyncExec | bool | Determines nonce type: true for asynchronous (parallel), false for synchronous (sequential). |
signature | bytes | Cryptographic signature (EIP-191) from the from address authorizing the distribution. |
If you want to know more about the signature structure, refer to the Disperse Payment Signature Structure section.
DispersePayMetadata Struct
Defines the payment details for a single recipient within the toData array.
struct DispersePayMetadata {
uint256 amount;
address to_address;
string to_identity;
}
| Field | Type | Description |
|---|---|---|
amount | uint256 | The amount of tokens to be sent to this recipient. |
to_address | address | Direct recipient address. Used when to_identity is an empty string (""). |
to_identity | string | Username/identity of the recipient. If provided, the contract resolves it to an address via the NameService. |
If to_identity is an empty string (""), the to_address field will be used as the recipient's destination address. Otherwise, the contract attempts to resolve the to_identity to its owner address using the NameService.
Execution Methods
This function can be executed by any address, with different behavior depending on whether the executor is a staker:
Fisher Execution
- A fisher collects multiple disperse payment requests with valid signatures from users through fishing spots.
- The fisher submits the transaction and receives priority fees and principal token rewards if they are a staker.
Direct Execution
- A user or service directly calls
dispersePaywith appropriate authorization. - Staker executors receive priority fees and principal token rewards for processing.
When using a service as the executor, we recommend specifying the service's address in the senderExecutor parameter for additional security.
Workflow
-
Signature Verification: Validates the
signatureusing Core.sol's centralized signature verification:- Constructs signature payload:
buildSignaturePayload(evvmId, address(this), hashPayload, senderExecutor, nonce, isAsyncExec) hashPayloadis generated viaCoreHashUtils.hashDataForDispersePay(toData, token, amount, priorityFee)- Recovers signer and compares with
fromaddress. Reverts withInvalidSignatureon failure.
- Constructs signature payload:
-
User Validation: Checks if the user is allowed to execute transactions using
canExecuteUserTransaction(from). Reverts withUserCannotExecuteTransactionif not allowed. -
Nonce Management: Core.sol handles nonce verification and updates based on
isAsyncExec:- Async (isAsyncExec = true): Checks if the nonce hasn't been used via
asyncNonceStatus(from, nonce), then marks it as used. Reverts withAsyncNonceAlreadyUsedif already used, orAsyncNonceIsReservedByAnotherServiceif reserved by another service. - Sync (isAsyncExec = false): Verifies the nonce matches
nextSyncNonce[from], then increments it. Reverts withSyncNonceMismatchon mismatch.
- Async (isAsyncExec = true): Checks if the nonce hasn't been used via
-
Executor Validation: If
senderExecutoris notaddress(0), checks thatmsg.sendermatches thesenderExecutoraddress. Reverts withSenderIsNotTheSenderExecutorif they don't match. -
Staker Check: Determines if the executor (
msg.sender) is a registered staker usingisAddressStaker. -
Balance Verification: Checks that the
fromaddress has sufficient balance. The required balance depends on staker status:- If executor is a staker:
amount + priorityFee - If executor is not a staker:
amountonly (priorityFee is not collected)
Reverts with
InsufficientBalanceif insufficient. - If executor is a staker:
-
Balance Deduction: Subtracts the required amount from the sender's balance upfront:
- If executor is a staker: deducts
amount + priorityFee - If executor is not a staker: deducts
amountonly
- If executor is a staker: deducts
-
Distribution Loop: Iterates through each recipient in the
toDataarray:- Amount Tracking: Maintains a running total (
accumulatedAmount) of distributed amounts - Recipient Resolution:
- If
to_identityis provided, verifies the identity exists usingstrictVerifyIfIdentityExistand resolves it to an owner address usinggetOwnerOfIdentity - If
to_identityis empty, usesto_address
- If
- Token Distribution: Adds the specified amount to the recipient's balance
- Amount Tracking: Maintains a running total (
-
Amount Validation: Verifies that the total distributed amount (
accumulatedAmount) exactly matches the specifiedamountparameter. Reverts withInvalidAmountif mismatch. -
Staker Benefits: If the executor is a staker (
isAddressStaker(msg.sender)):- Grants 1 principal token reward using
_giveReward - Transfers the
priorityFeeto the executor's balance
- Grants 1 principal token reward using
-
Nonce Update: Marks the nonce as used to prevent replay attacks:
- Async (priorityFlag = true): Marks the custom nonce as used in
asyncUsedNonce - Sync (priorityFlag = false): Increments the sequential nonce in
nextSyncUsedNonce
- Async (priorityFlag = true): Marks the custom nonce as used in