Skip to content

The Preimage Pallet

Introduction

The Preimage Pallet allows users and the runtime to store the preimage of some encoded call data on chain. Furthermore, other pallets can use preimage hashes to store and manage large byte-blobs. For example, token holders can submit a governance proposal through the Referenda Pallet using a preimage hash of the action to be carried out.

Governance-related functionality is based on three new pallets and precompiles: the Preimage Pallet and Preimage Precompile, the Referenda Pallet and Referenda Precompile, and the Conviction Voting Pallet and Conviction Voting Precompile. The aforementioned precompiles are Solidity interfaces that enable you to perform governance functions using the Ethereum API.

This guide will provide an overview of the extrinsics, storage methods, and getters for the pallet constants available in the Preimage Pallet on Moonbeam. This guide assumes you are familiar with governance-related terminology; if not, please check out the governance overview page for more information.

Preimage Pallet Interface

Extrinsics

The Preimage Pallet provides the following extrinsics (functions):

notePreimage(encodedProposal) - registers a preimage for an upcoming proposal, given the encoded preimage of a proposal. If the preimage was previously requested, no fees or deposits are taken for providing the preimage. Otherwise, a deposit is taken proportional to the size of the preimage. Emits a Noted event
import { ApiPromise, WsProvider } from '@polkadot/api';

const encodedProposal = INSERT_ENCODED_PROPOSAL;

const main = async () => {
  const api = await ApiPromise.create({
    provider: new WsProvider('INSERT_WSS_ENDPOINT'),
  });

  const tx = api.tx.preimage.notePreimage(encodedProposal);
  const txHash = await tx.signAndSend('INSERT_ACCOUNT_OR_KEYRING');

  api.disconnect();
};

main();
requestPreimage(bytes) - requests a preimage to be uploaded to the chain without paying any fees or deposits. Once the preimage request has been submitted on-chain, the user who submitted the preimage and deposit will get their deposit back, and they will no longer control the preimage. Must be executed by the Root Origin. Emits a Requested event
  • bytes - the hash of a preimage
import { ApiPromise, WsProvider } from '@polkadot/api';

const bytes = INSERT_PREIMAGE_HASH;

const main = async () => {
  const api = await ApiPromise.create({
    provider: new WsProvider('INSERT_WSS_ENDPOINT'),
  });

  const tx = api.tx.preimage.requestPreimage(bytes);
  const txHash = await tx.signAndSend('INSERT_ACCOUNT_OR_KEYRING');

  api.disconnect();
};

main();
unnotePreimage(hash) - clears an unrequested preimage from the runtime storage, given the hash of the preimage to be removed. Emits a Cleared event
  • hash - the hash of a preimage
import { ApiPromise, WsProvider } from '@polkadot/api';

const hash = INSERT_PREIMAGE_HASH;

const main = async () => {
  const api = await ApiPromise.create({
    provider: new WsProvider('INSERT_WSS_ENDPOINT'),
  });

  const tx = api.tx.preimage.unnotePreimage(hash);
  const txHash = await tx.signAndSend('INSERT_ACCOUNT_OR_KEYRING');

  api.disconnect();
};

main();
unrequestPreimage(hash) - clears a previously made request for a preimage. Must be executed by the Root Origin. Emits a Cleared event
  • hash - the hash of a preimage
import { ApiPromise, WsProvider } from '@polkadot/api';

const hash = INSERT_PREIMAGE_HASH;

const main = async () => {
  const api = await ApiPromise.create({
    provider: new WsProvider('INSERT_WSS_ENDPOINT'),
  });

  const tx = api.tx.preimage.unrequestPreimage(hash);
  const txHash = await tx.signAndSend('INSERT_ACCOUNT_OR_KEYRING');

  api.disconnect();
};

main();

Storage Methods

The Preimage Pallet includes the following read-only storage methods to obtain chain state data:

palletVersion() - returns the current pallet version

None.

A number representing the current version of the pallet.

// If using Polkadot.js API and calling toJSON() on the query results
0
import { ApiPromise, WsProvider } from '@polkadot/api';

const main = async () => {
  const api = await ApiPromise.create({
    provider: new WsProvider('INSERT_WSS_ENDPOINT'),
  });
  const palletVersion = await api.query.preimage.palletVersion();
};

main();
preimageFor([hash, length]) - returns the encoded proposal for a preimage, given the hash and length of the preimage
  • [hash, length] - the hash and length of the preimage

The encoded call data of the proposal.

// If using Polkadot.js API and calling toJSON() on the query results
0x00002c68656c6c6f5f776f726c64
import { ApiPromise, WsProvider } from '@polkadot/api';

const preimageInfo = [INSERT_PREIMAGE_HASH, INSERT_PREIMAGE_LENGTH];

const main = async () => {
  const api = await ApiPromise.create({
    provider: new WsProvider('INSERT_WSS_ENDPOINT'),
  });

  const preimageFor = await api.query.preimage.preimageFor(preimageInfo);
};

main();
statusFor(hash) - returns the request status for a given preimage hash
  • hash - the preimage hash to get the request status for

Status information for the preimage, which includes the status, the preimage deposit information, and the length of the preimage. The status can be either unrequested or requested.

{
  unrequested: { // Request status
    deposit: [
      '0x3B939FeaD1557C741Ff06492FD0127bd287A421e', // Depositor
      '0x00000000000000004569f6996d8c8000' // Amount deposited
    ],
    len: 18 // Length of the preimage
  }
}
import { ApiPromise, WsProvider } from '@polkadot/api';

const hash = INSERT_PREIMAGE_HASH;

const main = async () => {
  const api = await ApiPromise.create({
    provider: new WsProvider('INSERT_WSS_ENDPOINT'),
  });

  const statusFor = await api.query.preimage.statusFor(hash);
};

main();

How to Generate an Encoded Proposal

To generate an encoded proposal, you must first create the extrinsic that will be run if the proposal passes the governance process. Instead of attempting to send the extrinsic, you'll obtain the SCALE-encoded hash of the extrinsic, which you'll use to submit the preimage.

For example, if you wanted to set an on-chain remark that said "Hello World," you could generate the encoded call data using the following snippet:

import { ApiPromise, WsProvider } from '@polkadot/api';

const main = async () => {
  const api = await ApiPromise.create({
    provider: new WsProvider('ws://127.0.0.1:9944'),
  });

  const encodedProposal = api.tx.system.remark('Hello World').method.toHex();

  api.disconnect();
};

main();

Then, you can use the encoded call data to submit the preimage for the proposal:

import { ApiPromise, WsProvider } from '@polkadot/api';

const main = async () => {
  const api = await ApiPromise.create({
    provider: new WsProvider('INSERT_WSS_ENDPOINT'),
  });

  const encodedProposal = api.tx.system.remark('Hello World').method.toHex();

  const tx = api.tx.preimage.notePreimage(encodedProposal);
  const txHash = await tx.signAndSend('INSERT_ACCOUNT_OR_KEYRING');

  api.disconnect();
};

main();
Last update: November 22, 2024
| Created: January 17, 2023