Typed Message Signing

Prerequisites

Overview

Typed Message is a popular activity within the Ethereum ecosystem. This basically lets you sign any arbitrary message you would like. You can read more about ERC-712 (Typed Structure Data Hashing & Signing) here.

Transaction Authorization Policy (TAP) Requirements

In order to execute Typed Message transactions from Fireblocks, the issuer must be authorized to do so via a "Contract Call" TAP rule, that explicitly allows for typed messages, as shown here:

2322

Typed message example

See below the use of typed message signing API for Ethereum message signing.

async function signArbitraryMessage(fireblocks: FireblocksSDK, vaultAccountId: string, message: string, addressIndex = 0) { 
    
    const { status, id } = await fireblocks.createTransaction({
        operation: TransactionOperation.TYPED_MESSAGE,
        assetId: "ETH",
        source: { 
            type: PeerType.VAULT_ACCOUNT,
            id: vaultAccountId
        },
        note: `Test Message`,
        extraParameters: {
            rawMessageData: {
                messages: [{
                    content: Buffer.from(message).toString("hex"),
                    index: addressIndex,
                    type: "ETH_MESSAGE"
                }]
            }
        }
    });
    let currentStatus = status;
    let txInfo:any;

    while (currentStatus != TransactionStatus.COMPLETED && currentStatus != TransactionStatus.FAILED) { 
        console.log("keep polling for tx " + id + "; status: " + currentStatus);
        txInfo = await fireblocks.getTransactionById(id);
        currentStatus = txInfo.status; 
        await new Promise(r => setTimeout(r, 1000));
    };
   
    const walletAddresses = await fireblocks.getDepositAddresses(vaultAccountId, "ETH");

    console.log(walletAddresses);
        
    console.log("Address: ", walletAddresses[0].address); 
    console.log("Message: ", message);
        
    const signature = txInfo.signedMessages[0].signature;

    const v = 27 + signature.v;
    console.log("Signature: ", "0x" + signature.r + signature.s + v.toString(16));
}

signArbitraryMessage(fireblocks, "0", "INSERT TEXT HERE");
def sign_arbitrary_message(fireblocks: FireblocksSDK, vault_id: str, message: str, address_index: int = 0):
    status, id = fireblocks.create_transaction(
        tx_type="TYPED_MESSAGE",
        asset_id="ETH",
        source=TransferPeerPath(VAULT_ACCOUNT, vault_id),
        note="ETH Test Message",
        extra_parameters={
            "rawMessageData":
                RawMessage([UnsignedMessage(
                    content=bytes(message).hex(),
                    bip44addressIndex=address_index
                )])
        }
    ).values()

    wallet_address = fireblocks.get_deposit_addresses(vault_id, "ETH")
    print(wallet_address)

    print(f"Address: {wallet_address[0]['address']}\nMessage: {message}")
    
    while status != TRANSACTION_STATUS_COMPLETED and status != TRANSACTION_STATUS_FAILED:
        tx_info = fireblocks.get_transaction_by_id(id)
        status = tx_info['status']
        
    signature = tx_info["signedMessages"][0]["signature"]
    
    v = 27 + int(signature["v"])
    
    print(f"Signature: 0x{signature['r']}{signature['s']}{v}")
    
sign_arbitrary_message(fireblocks, "0", "INSERT TEXT HERE")