Skip to content

EIP-712 typed data

Every signed operation in Sail is EIP-712 typed data. This page lists the exact type strings the kernel verifies (from SailKernel), plus the template Configure type from BaseSharedPermission. All type hashes are keccak256 of the type string shown.

EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)
name = "SailKernel"
version = "1"
chainId = <the chain>
verifyingContract = <the SailKernel address>

kernel.hashTypedDataV4(structHash) applies this domain on-chain; equivalently keccak256("\x19\x01" ++ domainSeparator ++ structHash).

Dispatch(address account,address permission,address target,uint256 value,bytes32 dataHash,uint256 nonce,uint256 deadline)
DispatchBatch(address account,address permission,bytes32 callsHash,uint256 nonce,uint256 deadline)
  • dataHash = keccak256(data); nonce = managerNonces[account].
  • callsHash = keccak256(abi.encode(calls)); nonce = batchNonces[account].

Permission-signer operations (signed by permissionSigner)

Section titled “Permission-signer operations (signed by permissionSigner)”
RegisterPermission(address account,address permission,uint256 nonce,uint256 deadline)
RevokePermission(address account,address permission,uint256 nonce,uint256 deadline)
ReplacePermission(address account,address oldPermission,address newPermission,uint256 nonce,uint256 deadline)
RegisterPermissions(address account,address[] permissions,uint256 nonce,uint256 deadline)
RevokePermissions(address account,address[] permissions,uint256 nonce,uint256 deadline)
ReplacePermissions(address account,address[] oldPermissions,address[] newPermissions,uint256 nonce,uint256 deadline)
RevokeSession(address account,uint256 nonce,uint256 deadline)
ActivateSession(address account,uint256 nonce,uint256 deadline)
SetFeePolicy(address account,address newFeePolicy,address feeAsset,uint256 nonce,uint256 deadline)

All use nonce = signerNonces[account].

Template configuration (signed by permissionSigner, verified by the template)

Section titled “Template configuration (signed by permissionSigner, verified by the template)”
Configure(address account,bytes32 paramsHash,uint256 nonce,uint256 deadline)
SetAgentIdentity(address account,bytes32 identityHash,uint256 nonce,uint256 deadline)
  • paramsHash = keccak256(params); nonce = template.configNonces(account).
  • Verified against the EIP-712 domain of the template (each shared template is its own EIP712 domain, e.g. name = "SharedBoundedSwapPermission", version = "1"), not the kernel.

For RegisterPermissions / RevokePermissions / ReplacePermissions, an address[] field is encoded per EIP-712 §4 as the keccak256 of the ABI-encoded, zero-padded addresses:

bytes32 arrHash = keccak256(abi.encodePacked(/* each address as bytes32 */));

(The kernel’s _hashAddressArray builds a bytes32[] of zero-padded addresses and hashes the packed result.)

bytes32 structHash = keccak256(abi.encode(
kernel.DISPATCH_TYPEHASH(),
account, permission, target, value,
keccak256(data),
kernel.managerNonces(account),
deadline
));
bytes32 digest = kernel.hashTypedDataV4(structHash);
// sign `digest` with the manager key (ECDSA), or have an ERC-1271 signer attest it

Signatures are verified with _recoverOrERC1271: ECDSA first, then ERC-1271 fallback for contract signers — so managers and permission signers may be EOAs, multisigs, or smart accounts.