gleeth/eip712
EIP-712 typed structured data hashing and signing.
Implements the encoding rules from the EIP-712 specification for signing structured data with domain separation. Used for ERC-2612 permits, DEX order signing, meta-transactions, and other off-chain authorization.
Examples
let domain = eip712.domain()
|> eip712.domain_name("MyDapp")
|> eip712.domain_version("1")
|> eip712.domain_chain_id(1)
let types = dict.from_list([
#("Mail", [
eip712.field("from", "address"),
eip712.field("to", "address"),
eip712.field("contents", "string"),
]),
])
let message = dict.from_list([
#("from", eip712.address_val("0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826")),
#("to", eip712.address_val("0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB")),
#("contents", eip712.string_val("Hello, Bob!")),
])
let data = eip712.typed_data(types, "Mail", domain, message)
let assert Ok(sig) = eip712.sign_typed_data(data, wallet)
Types
EIP-712 domain separator fields. All fields are optional - include only those relevant to your application.
pub type Domain {
Domain(
name: option.Option(String),
version: option.Option(String),
chain_id: option.Option(Int),
verifying_contract: option.Option(String),
salt: option.Option(String),
)
}
Constructors
-
Domain( name: option.Option(String), version: option.Option(String), chain_id: option.Option(Int), verifying_contract: option.Option(String), salt: option.Option(String), )
Complete EIP-712 typed data structure ready for hashing or signing.
pub type TypedData {
TypedData(
types: dict.Dict(String, List(TypedField)),
primary_type: String,
domain: Domain,
message: dict.Dict(String, TypedValue),
)
}
Constructors
-
TypedData( types: dict.Dict(String, List(TypedField)), primary_type: String, domain: Domain, message: dict.Dict(String, TypedValue), )
A field in a typed struct definition.
pub type TypedField {
TypedField(name: String, type_name: String)
}
Constructors
-
TypedField(name: String, type_name: String)
A value in a typed data message. Matches the EIP-712 encoding rules.
pub type TypedValue {
StringVal(String)
IntVal(Int)
BoolVal(Bool)
AddressVal(String)
Bytes32Val(BitArray)
BytesVal(BitArray)
ArrayVal(List(TypedValue))
StructVal(dict.Dict(String, TypedValue))
}
Constructors
-
StringVal(String) -
IntVal(Int) -
BoolVal(Bool) -
AddressVal(String) -
Bytes32Val(BitArray) -
BytesVal(BitArray) -
ArrayVal(List(TypedValue)) -
StructVal(dict.Dict(String, TypedValue))
Values
pub fn address_val(addr: String) -> TypedValue
Wrap an Ethereum address as a typed value.
pub fn array_val(items: List(TypedValue)) -> TypedValue
Wrap a list of typed values as an array value.
pub fn bytes32_val(b: BitArray) -> TypedValue
Wrap a fixed 32-byte value as a typed value.
pub fn domain() -> Domain
Create an empty domain. Use domain_name, domain_version, etc. to set fields.
pub fn domain_salt(d: Domain, salt: String) -> Domain
Set the domain salt field (hex-encoded bytes32).
pub fn domain_verifying_contract(
d: Domain,
address: String,
) -> Domain
Set the domain verifying contract address.
pub fn encode_type(
type_name: String,
types: dict.Dict(String, List(TypedField)),
) -> String
Build the canonical type encoding string. Example: “Mail(address from,address to,string contents)” Referenced structs are collected, sorted, and appended.
pub fn field(name: String, type_name: String) -> TypedField
Create a typed field definition.
pub fn hash_domain(
d: Domain,
custom_types: dict.Dict(String, List(TypedField)),
) -> Result(BitArray, String)
Compute the domain separator hash.
pub fn hash_struct(
type_name: String,
data: dict.Dict(String, TypedValue),
types: dict.Dict(String, List(TypedField)),
) -> Result(BitArray, String)
Compute hashStruct: keccak256(typeHash || encodeData(s)).
pub fn hash_type(
type_name: String,
types: dict.Dict(String, List(TypedField)),
) -> BitArray
Compute typeHash: keccak256(encodeType(typeName)).
pub fn hash_typed_data(
data: TypedData,
) -> Result(BitArray, String)
Compute the EIP-712 digest: keccak256(“\x19\x01” || domainSeparator || hashStruct(message)). This is the hash that gets signed.
pub fn int_val(n: Int) -> TypedValue
Wrap an integer as a typed value (for uint256, int256, etc.).
pub fn recover_typed_data(
data: TypedData,
signature_hex: String,
) -> Result(String, String)
Recover the signer address from a typed data signature.
pub fn sign_typed_data(
data: TypedData,
w: wallet.Wallet,
) -> Result(secp256k1.Signature, String)
Sign typed data with a wallet. Returns the signature.
pub fn string_val(s: String) -> TypedValue
Convenience constructors for typed values.
pub fn struct_val(
fields: dict.Dict(String, TypedValue),
) -> TypedValue
Wrap a dict of named fields as a struct value.
pub fn typed_data(
types: dict.Dict(String, List(TypedField)),
primary_type: String,
d: Domain,
message: dict.Dict(String, TypedValue),
) -> TypedData
Create a complete typed data structure.