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 "Typed Message" TAP rule, that explicitly allows for typed messages, as shown here:
Typed message EIP-712 example
See below the use of typed message in the EIP-712 standard:
const { FireblocksSDK, PeerType, TransactionOperation, TransactionStatus } = require("fireblocks-sdk");
const fs = require('fs');
const path = require('path');
const apiSecret = fs.readFileSync(path.resolve(__dirname, "fireblocks_secret.key"), "utf8");
const apiKey = "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"; // Your API Key
const fireblocks = new FireblocksSDK(apiSecret, apiKey);
async function signEIP712Message(vaultAccountId, exampleSignRequest) {
const { status, id } = await fireblocks.createTransaction({
operation: TransactionOperation.TYPED_MESSAGE,
assetId: "ETH",
source: {
type: PeerType.VAULT_ACCOUNT,
id: vaultAccountId
},
amount: "0",
note: "Test EIP-712 Message",
extraParameters: {
rawMessageData: {
messages: [exampleSignRequest],
},
},
});
let currentStatus = status;
let txInfo;
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 exampleSignRequest = {
type: "EIP712",
index: 0,
content: {
types: {
EIP712Domain: [
{
name: "name",
type: "string"
},
{
name: "version",
type: "string"
},
{
name: "chainId",
type: "uint256"
},
{
name: "verifyingContract",
type: "address"
}
],
Permit: [
{
name: "owner",
type: "address"
},
{
name: "spender",
type: "address"
},
{
name: "value",
type: "uint256"
},
{
name: "nonce",
type: "uint256"
},
{
name: "deadline",
type: "uint256"
}
]
},
primaryType: "Permit",
domain: {
name: "USDC",
version: "1",
chainId: 9,
verifyingContract: "0x6e11530D05DF9BcA475Ba23eA26AcCCab9122d4c"
},
message: {
owner: "0x74ehEb032057CF42bDA226F132AF771ADc415D32",
spender: "0x7a6E1C5cBe4F7B1f863b2251Cb801b4dEE905c2c",
value: 2,
nonce: 0,
deadline: 1923318233
}
}
};
signEIP712Message("0", exampleSignRequest);
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")
Updated 5 months ago