Introducing Sequester’s Donations Pallet

Sequester Chain
6 min readJun 21, 2022

--

Overview

Since Polkadot-based chains are fee-optional, transaction fees currently being used as an anti-spam mechanism can be leveraged to make every transaction on Polkadot carbon negative, without requiring any changes to the user experience. To enable this future, we are building Sequester — a package that automates the functionality of aggregating transaction fees, exchanging them into carbon-backed tokens, and retiring underlying carbon offsets that meet the community’s specifications.

Sequester’s Technical Approach

For the duration of its lease on Polkadot or Kusama, a parachain has unlimited computing capacity and therefore does not need to pay any extra gas fees for the network to process its transactions. Thus, parachains on Polkadot have the unique quality of being fee-optional. However, while fees are technically optional, most existing parachains are still choosing to charge transaction fees to reduce spam and prevent denial-of-service attacks while simultaneously bolstering their protocol treasuries. These “unnecessary but still collected” transaction fees are unique to Polkadot and will power Sequester’s traction, usage, and impact.

In order to collect these fees and properly handle their conversion into carbon credits, Sequester will need to handle:

  1. Receiving transaction fees sent from other chains
  2. Exchanging those tokens into carbon-backed tokens, and
  3. Initiating retirement of the underlying assets for the carbon-backed tokens

As outlined in our white paper, the implementation will consist of a common good chain and a pallet, called the “donations” pallet. This pallet will sum the transaction fees on a Substrate chain over a period of blocks and send a percentage of them to the Sequester Common Good chain, where they will be used to purchase carbon credits. These carbon credits will then be permanently retired and removed from circulation.

We visualize and explain this process in Figure 1 below:

This article is a technical deep-dive into our approach for step 1, which will allow Substrate chains to track transaction fees on their network and send them to the Sequester Common Good chain, including integration and implementation details.

Technical Design of the Donations Pallet

In order to accomplish the aforementioned task, our pallet performs the following multi-step process:

  1. Each block an offchain worker will iterate through the events from that block and call the FeeCalculator logic passed into the pallet (see code snippet below), where the transaction fees are parsed. At the end of the block, the sum of the transaction fees calculated is added to an off-chain variable that stores cumulative transaction fees over a period of time.
  2. Every OnChainUpdateInterval blocks, the offchain worker will submit an unsigned transaction to record the sum of pending transaction fees in on-chain storage, reset the off-chain cumulative fee variable, and send a TxnFeeQueued event with the summed amount.
  3. Every SpendPeriod blocks (a configurable variable in pallet_treasury), the treasury will call the SpendFunds trait, which will check the on-chain storage for queued transaction fees. If there are valid transaction fees, they will be subsumed into a special Sequester account, and an XCM call will be constructed that will send the queued funds to the Sequester chain. Once on Sequester’s chain, these funds will be used to purchase and retire carbon credits.

Integration of the Pallet To Your Chain

We’ve set up an example chain that adds the donations pallet into its runtime. Let’s dive into this integration, starting with the example Runtime Config below.

Note that the parameter_types section will be completely configurable by each chain. For example, a chain can set the percentage of their transaction fees to send to Sequester via the TxnFeePercentage type. The purposes of each type are documented inline below.

The next step is to implement the calculate_fees_from_events function. Since fees are customizable on Substrate chains, and each chain has control over where its fees are sent via the pallet_transaction_payment pallet, each chain will be required to implement its own custom logic regarding summing the transaction fees.

In our example implementation, we provide the logic for a chain that deposits 100% of its funds into its treasury:

Finally, we need to configure the Treasury to call the SpendFunds hook in pallet_donations. You can do this by passing the donations pallet into the Treasury SpendFunds variable:

Once implemented, you are ready to start testing!

Testing

As a first step, install the Substrate front-end template. We’ll use this to validate that the donations pallet is working properly.

Next, build your chain locally, by running:

cargo +nightly build —-release && ./target/release/node-template —-dev

Please note that for the specific implementation of calculate_fees_from_events used in sequester-example-node, it will have to be built with the nightly branch of Rust.

Once your chain is running, navigate to your local directory of the Substrate front-end template and start it by running yarn start.

Feel free to modify the Substrate front-end template as needed for your chain or use an alternative front-end with transfer functionality.

The template should appear as follows.

Next, send a transaction, by choosing an account from the above list, and any amount from the available balance.

The sequester-example-node, as used in the image below, deposits 100% of transaction fees into its treasury and is configured to donate 10% of transaction fees via Sequester. As can be seen in the screenshot, the chain deposited 125,000,144 units of the native token into the Treasury from the transaction fee (this can be confirmed via the treasury:Deposit event).

Next, let’s check that the donation pallet properly indexed these fees. Every OnChainUpdateInterval blocks, the donations pallet will queue the transaction fees that have been summed via off-chain workers, to be indexed by the spend_funds hook in pallet_treasury.

Success of this functionality can be confirmed via the donations::TxnFeeQueued event.

Next, we need to ensure that the queued funds are properly withdrawn from the treasury and sent via XCM to Sequester.

The donations::TxnFeeSubsumed event is emitted when the funds are withdrawn from the Treasury into Sequester’s local account, as seen below:

Finally, the donations::SequesterTransferSuccess event is seen when the XCM message has been sent (this functionality is currently mocked and will come in the coming months when the Sequester common good chain goes live). We can see from the treasury::Rollover event that the treasury account has decreased from 125,000,144 units of the local currency to 112,500,130.

This difference should match the amount emitted in the TxnFeeSubsumed event.

With that, you’ve successfully validated that the donations pallet is live on your chain and operating functionally (with XCM soon on the way). Congrats!

Next Steps

Once the Sequester common-good chain goes live on Polkadot and Kusama, we will follow up with validation options to ensure that these funds are sent to the correct location. Stay tuned for next steps!

--

--