Offchain messages
Build, compile, sign, and verify messages offchain
Introduction
Any time you want one or more parties to approve of something that is not governed by an onchain program, you can prepare a message for them to sign offchain. Such messages can contain arbitrary contents, like the text of a plain-language contract, or some data encoded as text. Each offchain message contains a list of one or more signers that must provide a signature over that encoded message. Only when all of the required signers provide an authentic signature over the message are its contents considered to be ratified. You can use Kit to create, sign, verify, encode, and decode offchain messages.
Installation
Offchain message utilities are included within the @solana/kit library but you may also install them using their standalone packages.
To install the offchain message utilities:
What is an offchain message?
An offchain message consists of some UTF-8 message text, and a list of one or more required signers. The message is considered ratified when all of the signers provide a signature over the encoded message.
Here is an example of a contract being proposed by one person as an offchain message, and ratified by another.
Building offchain messages
Use the OffchainMessage type to help you create an offchain message.
Specifying the version
Specify the version property to select the schema and capabilities of the message. The latest version is version 1 which corresponds to the specification found in sRFC 3.
The format and construction of v0 messages is beyond the scope of this guide. You can read the v0 specification here.
Required signatories
Each message must specify a list of addresses belonging to accounts that must sign the message in order for it to be considered valid.
Using a signer
You can declare one or more required signatories using a MessageSigner.
When you do so, the message will have the capability to self-sign using the signOffchainMessageWithSigners method. Follow the instructions for signing offchain message envelopes with CryptoKeyPairs to sign it.
Using an address
You can declare one or more required signatories for whom you don't control the private key using the addresses of their accounts.
Defining the message content
Each message must contain some non-empty UTF-8 text the signatories must agree upon.
Using text
The content can be a string of UTF-8 text.
Using data
You can also encode arbitrary data as text using an encoding such as base-64.
Signing offchain messages
In order to be considered ratified an offchain message must be signed by all of the private keys belonging to accounts that are required signatories of the message.
FullySignedOffchainMessageEnvelope: An offchain message that is signed by all of its required signatories.OffchainMessageEnvelope: A compiled offchain message encoded as bytes, paired with a map between its required signatory addresses and their provided signatures, if any.
Offchain messages whose signers are specified using MessageSigner objects have the ability to self-sign. This is because signers encapsulate both the address of the signing account as well as an implementation of the signing algorithm for the private key associated with that account.
The signOffchainMessageWithSigners method will return a new signed offchain message envelope of type FullySignedOffchainMessageEnvelope.
This function will throw if the offchain message does not carry a MessageSigner implementation
for every required signer. To partially sign a message that you know to carry a strict subset of
the required MessageSigners, use the
partiallySignOffchainMessageWithSigners
method.
Building offchain messages using MessageSigners is the recommended way to create self-signable offchain messages. To sign with a CryptoKey directly, you first have to compile the offchain message.
This produces an unsigned offchain message envelope. Follow the instructions for signing offchain message envelopes with CryptoKeyPairs to sign it.
If the version of the offchain message is known, use the compile function specific to that
version, such as
compileOffchainMessageV1Envelope. This will
prevent you from bundling compilers you don't need, saving space in your JavaScript bundle.
Signing offchain message envelopes
Wherever you have a OffchainMessageEnvelope instead of an OffchainMessage you can add or replace a signature using the signOffchainMessageEnvelope method and one or more CryptoKeyPairs.
This function will throw if the resultant offchain message envelope is missing a signature for
one of the offchain message's required signers. To partially sign an offchain message envelope,
use the
partiallySignOffchainMessageEnvelope
method.
Verifying an offchain message
Given an offchain message envelope, you can verify that it has been signed by all of its required signatories using the verifyOffchainMessageEnvelope method.
Verifying an offchain message will tell you if its content has been signed by all required
signatories, but it will not ensure that the content of the message nor its list of required
signatories is what you expect it to be. Take special care to inspect the content of the message
before accepting it. If you have the original bytes of the message, you can compare them to the
content of the envelope you are verifying. Otherwise, see deserializing offchain
messages for instructions on how to decode the envelope's
content for inspection.
Serializing offchain messages
If you would like to share an offchain message envelope with someone, you can serialize it to bytes using an encoder.
Deserializing offchain messages
Decoding the bytes of an encoded offchain message envelope yields an OffchainMessageEnvelope object. This takes the form of a compiled offchain message encoded as OffchainMessageBytes, paired with a map between its required signatory addresses and their provided signatures, if any.
Decoding the bytes of the offchain message envelope will yield an object containing an offchain message in its compiled form – a message in a form suitable for signing and transmitting over a network. Decompiling a compiled message will yield an OffchainMessage object. This is the most common form of offchain message that you will encounter when using Kit to build an application.