Signing messages
Immutable Passport supports signing the following message standards:
Sign Messages
- Web
- ethers.js
- EIP-712
- ERC-191
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){
}
}
}
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();
// Please note there is a 500 character limit for the message
const message = "this is a personal sign message";
let signature: string;
try {
signature = await signer.signMessage(message);
} catch (error: any) {
// Handle user denying signature
if (error.code === -32003) {
console.log('User denied signature');
}
}
}
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.
- Verify EIP-712 signature
- Verify ERC-191 signature
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;
};
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: string,
signature: string,
zkEvmProvider: providers.Provider, // can be any provider, Passport or not
) => {
const digest = ethers.utils.hashMessage(payload);
const contract = new ethers.Contract(
address,
['function isValidSignature(bytes32, bytes) public view returns (bytes4)'],
zkEvmProvider,
);
const isValidSignatureHex = await contract.isValidSignature(digest, signature);
return isValidSignatureHex === ERC_1271_MAGIC_VALUE;
};