Signing - Ethereum

Pre-Requisite: You have generated the transaction and have it in the txn variable (see prior pages).

You have two options (EIP-712 and JSON), but EIP-712 is limited in terms of message size.

JSON

You can simply sign the JSON, similar to the signatures for other chains.

Wallet Connect / WAGMI

import {
    TransactionPayload,
    TxContext,
    createTxBroadcastBody,
} from 'bitbadgesjs-sdk';
import { signMessage } from '@wagmi/core';

const signTxn = async (
    context: TxContext,
    payload: TransactionPayload,
    simulate: boolean
) => {
    if (!account) throw new Error('Account not found.');

    let sig = '';
    if (!simulate) {
        const message = payload.jsonToSign;
        sig = await signMessage({
            message: message,
        });
    }

    const txBody = createTxBroadcastBody(context, payload, sig);
    return txBody;
};

Standard

https://docs.metamask.io/wallet/reference/personal_sign/

const sig = await window.ethereum.request({
    method: 'personal_sign', //May be eth_sign on some wallets
    params: [address, payload.jsonToSign],
});

EIP-712

Important: EIP-712 is limited in message size. Due to its poor performance, it greatly slows down the blockchain, so we only allow it to be used for small messages.

payload.jsonToSign.length > 1000

Signing with Wallet Connect / WAGMI

import {
    TransactionPayload,
    TxContext,
    createTxBroadcastBodyEthereum,
} from 'bitbadgesjs-sdk';
import { signTypedData } from '@wagmi/core';

const signTxn = async (
    context: TxContext,
    payload: TransactionPayload,
    simulate: boolean
) => {
    if (!account) throw new Error('Account not found.');

    let sig = '';
    if (!simulate) {
        sig = await signTypedData({
            message: payload.eipToSign.message as any,
            types: payload.eipToSign.types as any,
            domain: payload.eipToSign.domain,
            primaryType: payload.eipToSign.primaryType,
        });
    }

    const txBody = createTxBroadcastBodyEthereum(context, payload, sig);
    return txBody;
};

Signing with Metamask

To sign with Metamask, replace the signature logic in the snipper above with the code below.

//Add necessary imports
import { _TypedDataEncoder } from 'ethers/lib/utils.js';

// Init Metamask
await window.ethereum.enable();

const ethAddress = '...';

//Option 1: window.ethereum
const eip = _TypedDataEncoder.getPayload(
    payload.eipToSign.domain,
    types_,
    payload.eipToSign.message
);
const sig = await window.ethereum.request({
    method: 'eth_signTypedData_v4',
    params: [ethAddress, JSON.stringify(eip)],
});

//Option 2: Use the signer._signTypedData from ethers directly (https://docs.ethers.org/v5/api/signer/#Signer-signTypedData)
//It will give an error with an unused EIP712Domain type, so you have to remove that before calling it as seen below.
//It adds this type automatically.

//From https://github.com/wagmi-dev/wagmi/blob/main/packages/core/src/actions/accounts/signTypedData.ts#L41
const types_ = Object.entries(payload.eipToSign.types)
    .filter(([key]) => key !== 'EIP712Domain')
    .reduce((types, [key, attributes]: [string, TypedDataField[]]) => {
        types[key] = attributes.filter((attr) => attr.type !== 'EIP712Domain');
        return types;
    }, {} as Record<string, TypedDataField[]>);

// Method name may be changed in the future, see https://docs.ethers.io/v5/api/signer/#Signer-signTypedData
return await signer._signTypedData(
    payload.eipToSign.domain,
    types_,
    payload.eipToSign.message
);

Output

This will leave you with a variable which is to be submitted to a running blockchain node. See Broadcast to a Node.

Full Snippet

Last updated