Skip to main content

Customize Appchain gas token

Overview

This guide helps you change your Appchain's gas token.

An Appchain's gas token is used to pay for transaction fees. Madara Appchains support both the traditional Eth gas token and the newer STRK gas token. This guide focuses on switching the used STRK token.

Changing the used gas token helps you customize the Appchain to suit your needs. It's one of the available configuration options when starting an Appchain.

Circular dependency challenges

To change the gas token, you first need a token to change to. But deploying that token requires a running Appchain. This creates a challenge: if the Appchain is already running, how can its gas token be changed?

The workaround is to temporarily start the Appchain to calculate the deployment address of the new token, then stop it, wipe its state, and configure the Appchain to use that address. Since Starknet deployments are deterministic, the token can be re-deployed to the same address after the reset.

Continuing an Appchain after a reset from a previous state is not yet supported.

Two approaches

The Appchain's gas token can be changed in two ways.

Option 1: Change directly in the Appchain

Changing the gas token directly in the Appchain consists of the following steps:

  1. Deploy a new, custom ERC20 token in the Appchain. Note its address.
  2. Stop the Appchain and remove its data. Change the Appchain config to use the token address as gas token (even if the address doesn't have anything yet).
  3. Deploy the token the same way again. This should result in the same address, making the gas token usable.

With this option, the settlement layer's gas token functionality remains unchanged.

Use this option if you want your Appchain to have custom functionality related to the gas token. Some possible use cases include:

  1. Implementing custom minting logic.
  2. Introducing deflationary mechanics or other supply adjustments.
  3. Integrating with external contracts—for example, supporting new interfaces.
  4. Adding compliance-related features.
  5. Or simply changing the token’s name or symbol for branding purposes.

Option 2: Change through the settlement layer

Changing the gas token through the settlement layer consists of the following steps:

  1. Deploy a new, custom ERC20 token in the Appchain's settlement layer.
  2. Add the token to the used bridge (StarkGate). This gives you a new token address in the Appchain side.
  3. Stop the Appchain and remove its data. Change the Appchain config to use the token address as gas token (even if the address doesn't have anything yet).
  4. Deploy the token the same way in the settlement layer again and add to the bridge. This should result in the same address in the Appchain, making the gas token usable.

With this option, the Appchain's gas token functionality remains unchanged.

Use this option if you want to have custom settlement layer functionality for the gas token. However, this is not a typical approach.

Prerequisites

Before starting, please make sure you have all of the required tools installed.

Remember to also check the hardware requirements to make sure you can run an Appchain properly.

Change the token in the Appchain

This section helps you change the token through the Appchain directly. The settlement layer's respective token does not change.

Step 1: Run the Appchain

You should start by installing the Madara CLI and running your Appchain with the CLI:

git clone https://github.com/madara-alliance/madara-cli.git
cd madara-cli
cargo run create app-chain

Step 2: Wait for the Appchain to be configured

It will require about 55 blocks (about 10 minutes) for the Appchain to be configured properly - you should wait for that before interacting with it.

Appchain is ready

Once the Appchain is ready, open a new terminal for interaction.

Step 3: Prepare an account

An account needs to be prepared before it can be deployed.

The required parameters for the command are:

  • Account type
    • Used value: oz
    • Use a generic OpenZeppelin account type
  • Appchain RPC URL
    • Used value: http://localhost:9945
    • This is the default URL.
  • Class hash for the account
    • Used value: 0x5c478ee27f2112411f86f207605b2e2c58cdb647bac0df27f660ef2252359c6
    • This is a class hash for an OpenZeppelin account. This hash is already declared in the Appchain.
  • Account name
    • Used value: account-for-guide
    • This is the name we will use in this guide for our account.

The full command is:

sncast account create --type oz \
--url http://127.0.0.1:9945 \
--class-hash 0x5c478ee27f2112411f86f207605b2e2c58cdb647bac0df27f660ef2252359c6 \
--name account-for-guide --silent

Account created

Note the returned account address. You should store this address as a variable for the current session - this will be used in subsequent interactions. You can store the address with (remember to change the actual value):

export MADARA_GUIDE_ACCOUNT="0xabc"

Step 4: Bridge assets

You now need to bridge some Eth to the account. We need Eth to pay for transactions, since the Appchain doesn't (yet) have STRK for gas fees.

First, you need to prepare parameters for the bridging transaction. Here are the ones used in the command:

  • Settlement layer bridge address.
    • Used value: 0x8a791620dd6260079bf849dc5567adc3f2fdc318
    • This is the default bridge address.
  • A settlement layer RPC URL.
    • Used value: http://127.0.0.1:8545
    • This is the default URL.
  • A private key to the wallet with the assets.
    • Used value: 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
    • This is the private key for a settlement layer wallet with Eth, provided by Anvil.
  • The bridge function's signature.
    • Used value: deposit(uint256,uint256)
    • This is static and doesn't change.
  • The amount to be bridged.
    • Used value: 345000000
    • This denotes 345000000 weis.
  • An account on the Appchain to receive the assets.
    • Used value: $MADARA_GUIDE_ACCOUNT
    • This is the address that should receive the assets. This references the variable you set earlier.
  • Assets to send to the bridge.
    • Used value: 345000001wei
    • This has to be larger than the amount we want to send for the receiver to cover bridging fees. Using value 345000001 is enough in our setup.

The full command is:

cast send 0x8a791620dd6260079bf849dc5567adc3f2fdc318 \
--rpc-url http://127.0.0.1:8545 \
--private-key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 \
--value 345000001wei \
"deposit(uint256,uint256)" \
345000000 \
$MADARA_GUIDE_ACCOUNT

Sending assets

The assets should get bridged within about 10 seconds - the time it takes to form a new block.

Step 5: Deploy the account

Once the account has been created and it has assets, it still needs to be deployed to the Appchain.

The required parameters for the command are:

  • Appchain RPC URL
    • Used value: http://localhost:9945
    • This is the default URL.
  • Account name
    • Used value: account-for-guide
    • This is the same name used above. The underlying address is not relevant.
  • Fee token
    • Used value: eth
    • Use Appchain version of Eth to pay for transaction fees.

The full command is:

sncast account deploy --url http://127.0.0.1:9945 --name account-for-guide --fee-token eth

Account deployed

Step 6: Prepare your new token

Since you're changing the gas token, you need a new one to replace it. If you already have your implementation ready, feel free to use that. Otherwise, you can use a simple example ERC20 token shown here. This example utilizes OpenZeppelin's ERC20 implementation.

warning

The token used in this example is highly insecure since it allows anyone to mint any amount of tokens. This is meant only for educational purposes.

Initialize a Scarb project

You should initialize a new Scarb project with default settings in a new folder:

mkdir madara_token
cd madara_token
scarb init --no-vcs --test-runner cairo-test

Save the token contract locally

Replace the contents of src/lib.cairo with:

#[starknet::contract]
mod NewStrk {
use openzeppelin::token::erc20::{ERC20Component, ERC20HooksEmptyImpl};
use starknet::ContractAddress;

component!(path: ERC20Component, storage: erc20, event: ERC20Event);

// External
#[abi(embed_v0)]
impl ERC20MixinImpl = ERC20Component::ERC20MixinImpl<ContractState>;

// Internal
impl ERC20InternalImpl = ERC20Component::InternalImpl<ContractState>;

#[storage]
struct Storage {
#[substorage(v0)]
erc20: ERC20Component::Storage,
}

#[event]
#[derive(Drop, starknet::Event)]
enum Event {
#[flat]
ERC20Event: ERC20Component::Event,
}

#[constructor]
fn constructor(ref self: ContractState) {
self.erc20.initializer("NewStrk", "NSTRK");
}

#[generate_trait]
#[abi(per_item)]
impl ExternalImpl of ExternalTrait {
#[external(v0)]
fn mint(ref self: ContractState, recipient: ContractAddress, amount: u256) {
self.erc20.mint(recipient, amount);
}
}
}

Next, replace the contents of Scarb.toml in the root of the project with:

[package]
name = "madara_token"
version = "0.1.0"
edition = "2024_07"

[dependencies]
starknet = ">=2.9.4"
openzeppelin = "1.0.0"

[[target.starknet-contract]]

Compile the example contract

Compile the contract with:

scarb build

Step 7: Declare the token

You now have a ready token to declare to the network.

The required parameters for the command are:

  • Account name
    • Used value: account-for-guide
    • This is the same name used above. The underlying address is not relevant.
  • Appchain RPC URL
    • Used value: http://localhost:9945
    • This is the default URL.
  • Fee token
    • Used value: eth
    • Use Appchain version of Eth to pay for transaction fees.
  • Contract name
    • Used value: NewStrk
    • Name of our token contract

The full command is:

sncast --account account-for-guide declare --url http://localhost:9945 --fee-token eth --contract-name NewStrk

Gas token declared

Note the declared class hash. It may take up to a minute for the declaration to be available in the Appchain.

Step 8: Deploy the token

You are now ready to deploy the token itself.

The required parameters for the command are:

  • Account name
    • Used value: account-for-guide
    • This is the same name used above. The underlying address is not relevant.
  • Salt for contract deployment
    • Used value: 1
    • Use a hardcoded salt value so the deployment address is deterministic.
  • Appchain RPC URL
    • Used value: http://localhost:9945
    • This is the default URL.
  • Fee token
    • Used value: eth
    • Use Appchain version of Eth to pay for transaction fees.
  • Class hash
    • Used value: 0x02132f1600bbdb005de58f45719a8e65ea1ae418176484eadfac70f9e8b65c75
    • The class hash declared earlier. Adjust if needed.

The full command is:

sncast --account account-for-guide deploy --salt 1 \
--url http://localhost:9945 \
--fee-token eth \
--class-hash 0x02132f1600bbdb005de58f45719a8e65ea1ae418176484eadfac70f9e8b65c75

Gas token deployed

Note the deployed contract's address. You should store this address as a variable for the current session - this will be used in subsequent interactions. You can store the address with (remember to change the actual value if needed):

export MADARA_GUIDE_TOKEN_CONTRACT="0x0626a0f65b77b24472ea339b7c754be50c7f86685d8d9805bf7f1472bb04a2da"

Step 9: Stop and reset the Appchain

You now have the token address for your new gas token. At this point, the Appchain has to be stopped and reset so the new gas token can be taken into use.

To stop the Appchain, go back to its terminal and press ctrl+c. Once all of the containers have stopped gracefully, remove the Appchain data with:

sudo rm -rf deps/data
sudo rm -rf data

The data removal is required because Appchains do not yet support continuation from the previous state upon a restart.

Step 10: Generate a config file

Once the Appchain has fully stopped, you can generate a configuration file for it by running:

cargo run init --default

This will generate a default configuration file in folder deps/data called my_custom_config.toml.

Step 11: Change the default gas token in config

Next, you should change the default gas token value in the config. Check the new token address deployed earlier. Unfortunately, we can't use the variable set earlier since we're in a different terminal session, so you'll have to modify the value (0xabc) by hand in the following command:

sed -i 's/^\(native_fee_token_address\s*=\s*\).*/\1"0xabc"/' deps/data/my_custom_config.toml

The above command uses sed to modify the config file's native_fee_token_address entry.

Step 12: Start the Appchain with the config file

It's now time to start the Appchain with a custom gas token. Note that the token is not actually deployed in the Appchain yet since we removed its state - only the gas token address is changed.

Start the appchain with the config file:

cargo run create app-chain --config-file deps/data/my_custom_config.toml

Step 13: Wait for the Appchain to be configured

Wait until the Appchain is ready. Check step 2 for more information.

Once it's ready, you should switch back to the earlier terminal session where you have your token project.

Step 14: Repeat steps 4 and 5

To get your account set up, repeat steps 4 and 5 in this guide.

Once those steps are done, continue from here.

Step 15: Repeat steps 7 and 8

To get your token deployed again, repeat steps 7 and 8 in this guide. Note that the steps should result in the same contract class hash and address as earlier.

Once those steps are done, continue from here.

Step 16: Mint yourself some tokens

The new gas token has now been deployed and is in use. But you still need to get these tokens somehow. Because we left an insecure minting function in the contract, you can simply mint yourself some tokens now.

The required parameters for the command are:

  • Account name
    • Used value: account-for-guide
    • This is the same name as was used above.
  • Appchain RPC URL
    • Used value: http://localhost:9945
    • This is the default URL.
  • Fee token
    • Used value: eth
    • Use Appchain version of Eth to pay for transaction fees.
  • Contract address
    • Used value: $MADARA_GUIDE_TOKEN_CONTRACT
    • The target contract address. ts. This references the variable you set earlier.
  • Function name
    • Used value: mint
    • This is the name of the function we are calling inside the token smart contract.
  • Function arguments
    • Used value: "$MADARA_GUIDE_ACCOUNT, 567000000"
    • These are the arguments we want to pass to the used function. The first denotes the address who should receive the tokens, the second is the minted token amount.
sncast --account account-for-guide invoke \
--url http://localhost:9945 \
--fee-token eth \
--contract-address $MADARA_GUIDE_TOKEN_CONTRACT \
--function mint --arguments "$MADARA_GUIDE_ACCOUNT, 567000000"

Minted some tokens

Step 17: Check your balance

You can now check your balance to make sure you have the right amount of gas tokens.

The required parameters for the command are:

  • Appchain RPC URL
    • Used value: http://localhost:9945
    • This is the default URL.
  • Contract address
    • Used value: $MADARA_GUIDE_TOKEN_CONTRACT
    • The target contract address. ts. This references the variable you set earlier.
  • Function name
    • Used value: balance_of
    • This is the name of the function we are calling inside the token smart contract.
  • Function arguments
    • Used value: "$MADARA_GUIDE_ACCOUNT"
    • This is the argument we want to pass to the used function. Since we want to check our own balance, we input our address.
sncast call \
--url http://localhost:9945 \
--contract-address $MADARA_GUIDE_TOKEN_CONTRACT \
--function balance_of --arguments "$MADARA_GUIDE_ACCOUNT"

Token balance

The result should be the same balance you minted earlier, in hexadecimal format.

Step 18: Use new gas token to pay for transactions

Since you now have some of the new gas tokens, you can use it to interact with the Appchain. The following is an example transaction that mints tokens to an arbitrary address - this helps verify that the new gas token is working as expected.

The required parameters for the command are:

  • Account name
    • Used value: account-for-guide
    • This is the same name as was used above.
  • Appchain RPC URL
    • Used value: http://localhost:9945
    • This is the default URL.
  • Fee token
    • Used value: strk
    • Use the Appchain's gas token to pay for transaction fees.
  • Contract address
    • Used value: $MADARA_GUIDE_TOKEN_CONTRACT
    • The target contract address. ts. This references the variable you set earlier.
  • Function name
    • Used value: mint
    • This is the name of the function we are calling inside the token smart contract.
  • Function arguments
    • Used value: "$0x1, 123"
    • These are the arguments we want to pass to the used function. The first denotes the address who should receive the tokens, the second is the minted token amount.
sncast --account account-for-guide invoke \
--url http://localhost:9945 \
--fee-token strk \
--contract-address $MADARA_GUIDE_TOKEN_CONTRACT \
--function mint --arguments "0x1, 123"

Minted some more tokens

You can now check your gas token balance again, from the previous step, and see it has gone down, since you paid for the gas fees.

New token balance

Congratulations, you have now successfully changed your Appchain's gas token!

Change the token through the settlement layer

This option will be documented later.