assertOffchainMessageV1Equal

function assertOffchainMessageV1Equal(
    receivedMessage,
    expectedMessage,
): void;

Asserts that a version 1 offchain message you received from an untrusted source is the message that you expected it to be.

A signer (eg. a wallet) returns the message bytes it signed alongside its signature. Verifying that signature proves only that the signer produced it over those bytes; it says nothing about whether those bytes represent the message you asked for. Use this function to establish that they do, then verify the signature separately with verifyOffchainMessageEnvelope.

Perform this assertion before verifying signatures. A signer that signed the wrong message will otherwise surface as a signature verification failure, which misattributes the problem to the cryptography rather than to the content.

This function compares version 1 messages only. Decoding produces an OffchainMessage of indeterminate version, so narrow it to a OffchainMessageV1 before calling this — see the example below. Deciding what to do about a message of some other version is a matter of policy that belongs to you rather than to this function.

Parameters

ParameterTypeDescription
receivedMessageOffchainMessageV1The message you decoded from the bytes the signer reports having signed.
expectedMessageOffchainMessageV1The message you expected the signer to sign.

Returns

void

Throws

A SolanaError with code SOLANA_ERROR__OFFCHAIN_MESSAGE__CONTENT_DOES_NOT_MATCH_EXPECTED if the two messages' contents differ.

Throws

A SolanaError with code SOLANA_ERROR__OFFCHAIN_MESSAGE__REQUIRED_SIGNATORIES_DO_NOT_MATCH_EXPECTED if the two messages require signatures from different addresses.

Example

import { getOffchainMessageDecoder, assertOffchainMessageV1Equal } from '@solana/offchain-messages';
 
const receivedMessage = getOffchainMessageDecoder().decode(signedOffchainMessage);
switch (receivedMessage.version) {
    case 1:
        assertOffchainMessageV1Equal(receivedMessage, expectedMessage);
        break;
    default:
        throw new Error(`Expected a version 1 message; got version ${receivedMessage.version}`);
}

Remarks

Required signatories are compared without regard to order. The offchain message specification mandates that they be serialized in lexicographic order, so a decoded message always lists them in that order while expectedMessage may list them in whatever order you built it with. Both lists are sorted before they are compared, and they are reported in sorted order in the error context so that they can be compared by eye.

Order is the only thing ignored. The lists are otherwise compared element by element, so listing an address twice in expectedMessage is a mismatch rather than a no-op. A decoded message can never contain a duplicate — the codec rejects one — so this only arises from a malformed expectedMessage, and reporting it surfaces the mistake instead of hiding it.

Message content is not included in the error context, because it can carry data you would rather not have written to logs or forwarded to an error reporting service. Its length in UTF-8 bytes — the encoding in which version 1 content is serialized — is reported instead.

See

verifyOffchainMessageEnvelope to verify the signatures themselves once you know the message is the one you expected.

On this page