pay Function
Function Type: external
Function Signature: pay(address,address,string,address,uint256,uint256,address,uint256,bool,bytes)
The pay function executes a payment from one address to a single recipient address or identity. This is EVVM Core's primary single payment function with intelligent staker detection and centralized signature verification.
Key features:
- Single Payment: Transfers tokens from one sender to one recipient (address or username)
- Staker Detection: Automatically detects if the executor is a staker and distributes rewards accordingly
- Centralized Nonce Management: Uses Core.sol's unified nonce system for enhanced security
- Identity Resolution: Can send payments to usernames which are resolved to addresses via NameService
- Signature Verification: Validated through Core.sol's centralized signature system
The function supports both synchronous and asynchronous nonce management through the isAsyncExec parameter, making it flexible for various execution patterns and use cases. For details on nonce types, see Nonce Types in EVVM. For signature details, see Payment Signature Structure.
Parameters
| Field | Type | Description |
|---|---|---|
from | address | The address of the payment sender whose funds are being transferred and whose signature/nonce are validated. |
to_address | address | Direct recipient address. Used when to_identity is empty. |
to_identity | string | Username/identity of the recipient. If provided, the contract resolves it to an address via the NameService. |
token | address | The token contract address for the transfer. |
amount | uint256 | The quantity of tokens to transfer from from to the recipient. |
priorityFee | uint256 | Additional fee for transaction priority. If the executor is a staker, they receive this fee as a reward. |
senderExecutor | address | Address authorized to execute this transaction. Use address(0) to allow any address to execute. |
nonce | uint256 | Transaction nonce value managed by Core.sol. Usage depends on isAsyncExec: if false (sync), must equal the expected synchronous nonce; if true (async), can be any unused nonce. |
isAsyncExec | bool | Execution type flag: false = synchronous nonce (sequential), true = asynchronous nonce (parallel). |
signature | bytes | Cryptographic signature (EIP-191) from the from address authorizing this payment. Validated by Core.sol's centralized signature system. |
The nonce parameter is managed centrally by Core.sol. When isAsyncExec is false (synchronous), the provided nonce must equal Core.getNextCurrentSyncNonce(from). When true (asynchronous), the nonce can be any value not yet used, checked via Core.getIfUsedAsyncNonce(from, nonce).
Execution Methods
The function can be executed in multiple ways:
Fisher Execution
- A user signs the payment details and sends the request (parameters + signature) to a fishing spot.
- A fisher (preferably a staker for rewards) captures the transaction and validates the request.
- The fisher submits the transaction to the function for processing and receives rewards if they are a staker.
Direct Execution
- The user or any authorized service directly calls the
payfunction. - If a
senderExecutoraddress is specified, only that address can submit the transaction. - If
senderExecutoris set toaddress(0), anyone can execute the transaction with a valid signature.
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 system:- Constructs signature payload:
buildSignaturePayload(evvmId, address(this), hashPayload, senderExecutor, nonce, isAsyncExec) hashPayloadis generated viaCoreHashUtils.hashDataForPay(to_address, to_identity, 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. -
Resolve Recipient Address: Determines the final recipient address:
- If
to_identityis provided (not empty), resolves the identity to an owner address usingverifyStrictAndGetOwnerOfIdentityfrom the NameService contract. - If
to_identityis empty, uses the providedto_address.
- If
-
Balance Update: Executes the payment transfer using the
_updateBalancefunction, sendingamountoftokenfrom thefromaddress to the resolved recipient address. -
Staker Benefits Distribution: If the executor (
msg.sender) is a registered staker:- Priority Fee Transfer: If
priorityFee > 0, transfers thepriorityFeeamount oftokenfrom thefromaddress to themsg.sender(executor) as a staker reward. - Principal Token Reward: Grants 1x reward amount in principal tokens to the
msg.sender(executor) using the_giveRewardfunction.
- Priority Fee Transfer: If
For more information about the signature structure, refer to the Payment Signature Structure section.
Need to send from one user to multiple recipients?
Use dispersePay to send tokens from a single sender to multiple different addresses or identities in one transaction.
Need to execute multiple separate payments?
Use batchPay to process several individual pay operations within a single transaction, each with their own sender, recipient, and parameters.