Disperse Payment Signature Structure
To authorize disperse payment operations the user must generate a cryptographic signature compliant with the EIP-191 standard.
The signature is created by signing a precisely formatted string message derived from the payment details, including a hash of the recipient data array.
Signed Message Format
The message is constructed by concatenating the following components as strings, separated by commas (,
):
string.concat(
"ef83c1d6",
",",
AdvancedStrings.bytes32ToString(hashList),
",",
AdvancedStrings.addressToString(_token),
",",
Strings.toString(_amount),
",",
Strings.toString(_priorityFee),
",",
Strings.toString(_nonce),
",",
_priorityFlag ? "true" : "false",
",",
AdvancedStrings.addressToString(_executor)
);
Message Components
1. Function Selector (Hex String):
ef83c1d6
: Identifies thedispersePay
function
2. Hash List (String):
- The result of
AdvancedStrings.bytes32ToString(hashList)
- Where
hashList = sha256(abi.encode(toData))
- Purpose: Ensures signature covers the specific recipient list and amounts
3. Token Address (String):
- The result of
AdvancedStrings.addressToString(_token)
- Purpose: Identifies the token being distributed
4. Total Amount (String):
- The result of
Strings.toString(_amount)
- Purpose: Specifies the total amount being distributed across all recipients
5. Priority Fee (String):
- The result of
Strings.toString(_priorityFee)
- Purpose: Specifies the fee paid to fishers
6. Nonce (String):
- The result of
Strings.toString(_nonce)
- Purpose: Provides replay protection for the transaction
7. Priority Flag (String):
"true"
: If_priorityFlag
istrue
(asynchronous)"false"
: If_priorityFlag
isfalse
(synchronous)- Purpose: Explicitly includes the execution mode in the signed message
8. Executor Address (String):
- The result of
AdvancedStrings.addressToString(_executor)
- Purpose: Specifies the address authorized to submit this payment request
addressToString
converts an address to a lowercase stringStrings.toString
converts a number to a string_priority_boolean
indicates whether the payment will be executed asynchronously (true
) or synchronously (false
)
Hash List Structure
The hashList
component within the signature message is derived by ABI-encoding the entire toData
array and then computing its sha256
hash:
bytes32 hashList = sha256(abi.encode(toData));
This ensures that the signature covers the specific recipient list and amounts.
Example
Here's a practical example of constructing a signature message for distributing 0.1 ETH to multiple recipients:
Scenario: User wants to distribute 0.1 ETH to three recipients using synchronous processing
Recipients (toData
array):
DispersePayMetadata[] memory toData = new DispersePayMetadata[](3);
toData[0] = DispersePayMetadata({
amount: 30000000000000000, // 0.03 ETH
to_address: 0x742c7b6b472c8f4bd58e6f9f6c82e8e6e7c82d8c,
to_identity: ""
});
toData[1] = DispersePayMetadata({
amount: 50000000000000000, // 0.05 ETH
to_address: address(0),
to_identity: "alice"
});
toData[2] = DispersePayMetadata({
amount: 20000000000000000, // 0.02 ETH
to_address: 0x8e3f2b4c5d6a7f8e9c1b2a3d4e5f6c7d8e9f0a1b,
to_identity: ""
});
Parameters:
hashList
:sha256(abi.encode(toData))
=0x1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b
_token
:address(0)
(ETH)_amount
:100000000000000000
(0.1 ETH total)_priorityFee
:5000000000000000
(0.005 ETH)_nonce
:25
_priorityFlag
:false
(synchronous)_executor
:address(0)
(unrestricted)
Resulting message string:
ef83c1d6,0x1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b,0x0000000000000000000000000000000000000000,100000000000000000,5000000000000000,25,false,0x0000000000000000000000000000000000000000
Message breakdown:
ef83c1d6
- Function selector for dispersePay0x1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b
- Hash of recipient data0x0000000000000000000000000000000000000000
- Token address (ETH)100000000000000000
- Total amount in wei (0.1 ETH)5000000000000000
- Priority fee in wei (0.005 ETH)25
- Noncefalse
- Priority flag (synchronous)0x0000000000000000000000000000000000000000
- Executor (unrestricted)
AdvancedStrings.addressToString
converts an address to a lowercase hexadecimal string with "0x" prefixAdvancedStrings.bytes32ToString
converts a bytes32 hash to a hexadecimal string with "0x" prefixStrings.toString
converts a number to a string_priorityFlag
indicates whether the payment will be executed asynchronously (true
) or synchronously (false
)- The
hashList
must be calculated assha256(abi.encode(toData))
to ensure signature integrity - Total
_amount
should equal the sum of all individual amounts in thetoData
array
DispersePayMetadata
Struct
Defines the payment details for a single recipient within the toData
array.
struct DispersePayMetadata {
uint256 amount;
address to_address;
string to_identity;
}
- amount: The amount to send to this specific recipient
- to_address: Direct address (use
address(0)
if using identity) - to_identity: Username/identity string (empty if using address)