Home

Signing and Verifying Messages

note

This guide is for custodial smart accounts. If you are using non-custodial smart accounts, you should use the Sign Messages with Openfort's embedded signer.

Signing and verifying messages for smart accounts is different than with EOAs. There are a few reasons why:

  • With an EOA, the address is effectively the public key of the private key used for signing. Therefore, verifying a EOA signature is as simple as recovering the signature and compare the recovered public key with the address.

    • With a smart account, the address is the address of a smart contract that has no cryptographic link to the signing private key. Therefore, you must use ERC-1271 to validate the message.
  • With an EOA, you don't have to deploy the account. It just exists.

    • Since smart accounts need to be deployed, it may not be clear how you can validate messages against a smart account not yet deployed.

Signing messages#

To sign messages:

server.ts

_42
// Set your secret key. Remember to switch to your live secret key in production.
_42
// See your keys here: https://dashboard.openfort.xyz/apikeys
_42
const Openfort = require('@openfort/openfort-node').default;
_42
const openfort = new Openfort(YOUR_SECRET_KEY);
_42
_42
const _domain = {
_42
name: "Openfort",
_42
version: "0.5",
_42
chainId: 13337,
_42
verifyingContract: "0x9b5AB198e042fCF795E4a0Fa4269764A4E8037D2",
_42
};
_42
const types = {
_42
Mail: [
_42
{ name: "from", type: "Person" },
_42
{ name: "to", type: "Person" },
_42
{ name: "content", type: "string" },
_42
],
_42
Person: [
_42
{ name: "name", type: "string" },
_42
{ name: "wallet", type: "address" },
_42
],
_42
};
_42
const mail = {
_42
from: {
_42
name: "Alice",
_42
wallet: "0x2111111111111111111111111111111111111111",
_42
},
_42
to: {
_42
name: "Bob",
_42
wallet: "0x3111111111111111111111111111111111111111",
_42
},
_42
content: "Hello!",
_42
};
_42
const structHash = ethers.utils._TypedDataEncoder.hash(domain, types, mail);
_42
_42
const signature = await openfort.accounts.signPayload({
_42
id: "acc_4194ad24-c818-4e5c-b003-9cc2aa7df53b",
_42
hash: structHash,
_42
domain: domain
_42
value: mail,
_42
types: types,
_42
});

Validating signatures#

You can validate signatures with ERC-1271. Here's an example with ethers:

client.ts

_40
const ethers = require("ethers");
_40
_40
async function verifySignature(hash, signature, address) {
_40
let provider = new ethers.providers.JsonRpcProvider(providerUrl);
_40
const ABI = {
_40
inputs: [
_40
{
_40
internalType: "bytes32",
_40
name: "_hash",
_40
type: "bytes32",
_40
},
_40
{
_40
internalType: "bytes",
_40
name: "_signature",
_40
type: "bytes",
_40
},
_40
],
_40
name: "isValidSignature",
_40
outputs: [
_40
{
_40
internalType: "bytes4",
_40
name: "",
_40
type: "bytes4",
_40
},
_40
],
_40
stateMutability: "view",
_40
type: "function",
_40
};
_40
const iface = new ethers.utils.Interface(ABI);
_40
const encodedDataDeposit = iface.encodeFunctionData("isValidSignature", [
_40
hash,
_40
signature,
_40
]);
_40
_40
const tx = {
_40
to: address,
_40
data: encodedDataDeposit,
_40
};
_40
return await provider.call(tx);
_40
}