Dry run OpenGov Referenda in Chopsticks - Simplified Guide

@xlc created a guide to dry run OpenGov referenda in Chopsticks. It is simple, but it assumes a bit higher technical level of competency than many OpenGov participants that need it have.

Jeeper and I simplified the language around it a bit and wrote a guide with step-by-step guide with images: Simulate OpenGov Referenda in Chopsticks

And a short video: https://www.youtube.com/watch?v=K6xccd1jJLw

Enjoy

5 Likes

Chopsticks Web is another tool I created that could make things simpler
Please submit feedbacks/bug reports to Issues · xlc/chopsticks-web · GitHub

3 Likes

With the transition of Governance to AssetHub, the old guidance is no longer up-to-date. On AH, we still have to get relay chain blocks for the scheduler. So we need to extend the sample a bit.

A minimal example that should work on AH currently looks like this:

const validationData = await api.query.parachainSystem.validationData();
const relayBlock = validationData.unwrap().relayParentNumber.toNumber();

const encodedCall = '0x00003048656c6c6f20576f726c6421' // system.remark("Hello World!")

await api.rpc('dev_setStorage', {
 scheduler: {
   agenda: [
     [
       [relayBlock], [
         {
           call: { Inline: encodedCall },
           origin: { system: 'Root' }
         }
       ]
     ]
   ]
 }
})


await api.rpc('dev_newBlock')

As a side note: this currently does not work with the Chopsticks version that PJS comes with, since its not the latest and it seems PJS is currently not maintained. It works if you run Chopsticks yourself and point PJS towards it.

To run with Chopsticks/PAPI, you can run this code:

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

const WS_ENDPOINT = 'ws://localhost:8000';

async function main() {
  const provider = new WsProvider(WS_ENDPOINT);
  const api = await ApiPromise.create({ provider });

  // Get current relay block number (scheduler uses relay blocks, not parachain!)
  const validationData = await api.query.parachainSystem.validationData();
  const relayBlock = validationData.unwrap().relayParentNumber.toNumber();
  console.log('Relay block:', relayBlock);

  // Example call
  const encodedCall = '0x00003048656c6c6f20576f726c6421'; // system.remark("Hello World!")
  console.log('Call:', encodedCall);

  // Set scheduler agenda with Root origin
  await provider.send('dev_setStorage', [{
    scheduler: {
      agenda: [[[relayBlock], [{
        call: { Inline: encodedCall },
        origin: { system: 'Root' }
      }]]]
    }
  }]);

  // Build block to execute
  await provider.send('dev_newBlock', []);

  // Check result from Dispatched event
  const events = await api.query.system.events();
  const dispatched = events.find(e =>
    e.event.section === 'scheduler' && e.event.method === 'Dispatched'
  );

  if (dispatched) {
    const result = dispatched.event.data[2].toHuman(); // 3rd field is result
    console.log('\nResult:', result);
  } else {
    console.log('\nNo Dispatched event - call may have failed');
  }

  await api.disconnect();
}

main().catch(console.error);

1 Like