Skip to main content

Signing messages

Immutable Passport supports signing the following message standards:

Sign Messages

import { passport } from '@imtbl/sdk';
import { providers } from 'ethers';

async function sign(passportInstance: passport.Passport) {

const provider = passportInstance.connectEvm();
const web3Provider = new providers.Web3Provider(provider);
const signer = web3Provider.getSigner();
const chainId = 13371; // zkEVM mainnet
const address = await signer.getAddress();

// Define our "domain separator" to ensure user signatures are unique across apps/chains
const domain = {
name: 'Ether Mail',
version: '1',
chainId,
verifyingContract: address,
};

const types = {
Person: [
{ name: 'name', type: 'string' },
{ name: 'wallet', type: 'address' },
],
Mail: [
{ name: 'from', type: 'Person' },
{ name: 'to', type: 'Person' },
{ name: 'contents', type: 'string' },
]
};

const message = {
from: {
name: 'Cow',
wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
},
to: {
name: 'Bob',
wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
},
contents: 'Hello, Bob!',
};

let signature: string;
try {
signature = await signer._signTypedData(domain, types, message);
} catch (error: any) {
// Handle user denying signature
if (error.code === 4001){

}
}

}

Verify Signatures

💡Note
To verify a signature, the users smart contract wallet must have been deployed previously. This occurs when the user submits their first transaction.

Verifying the authenticity of a signature can be done by calling the isSignatureValid method on the user's smart contract.

import { ethers, providers } from 'ethers';

// https://eips.ethereum.org/EIPS/eip-1271#specification
// EIP-1271 states that `isValidSignature` must return the following value if the signature is valid
const ERC_1271_MAGIC_VALUE = '0x1626ba7e';

export const isSignatureValid = async (
address: string, // The Passport wallet address returned from eth_requestAccounts
payload: any,
signature: string,
zkEvmProvider: providers.Provider // can be any provider, Passport or not
) => {
const types = { ...payload.types };
// Ethers auto-generates the EIP712Domain type in the TypedDataEncoder, and so it needs to be removed
delete types.EIP712Domain;

const hash = ethers.utils._TypedDataEncoder.hash(
payload.domain,
types,
payload.message
);
const contract = new ethers.Contract(
address,
['function isValidSignature(bytes32, bytes) public view returns (bytes4)'],
zkEvmProvider
);

const isValidSignatureHex = await contract.isValidSignature(hash, signature);
return isValidSignatureHex === ERC_1271_MAGIC_VALUE;
};