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:
- Deploy a new, custom ERC20 token in the Appchain. Note its address.
- 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).
- 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:
- Implementing custom minting logic.
- Introducing deflationary mechanics or other supply adjustments.
- Integrating with external contracts—for example, supporting new interfaces.
- Adding compliance-related features.
- 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:
- Deploy a new, custom ERC20 token in the Appchain's settlement layer.
- Add the token to the used bridge (StarkGate). This gives you a new token address in the Appchain side.
- 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).
- 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.
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
- Used value:
- Appchain RPC URL
- Used value:
http://localhost:9945
- This is the default URL.
- Used value:
- 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.
- Used value:
- Account name
- Used value:
account-for-guide
- This is the name we will use in this guide for our account.
- Used value:
The full command is:
sncast account create --type oz \
--url http://127.0.0.1:9945 \
--class-hash 0x5c478ee27f2112411f86f207605b2e2c58cdb647bac0df27f660ef2252359c6 \
--name account-for-guide --silent
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.
- Used value:
- A settlement layer RPC URL.
- Used value:
http://127.0.0.1:8545
- This is the default URL.
- Used value:
- 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.
- Used value:
- The bridge function's signature.
- Used value:
deposit(uint256,uint256)
- This is static and doesn't change.
- Used value:
- The amount to be bridged.
- Used value:
345000000
- This denotes 345000000 weis.
- Used value:
- 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.
- Used value:
- 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.
- Used value:
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
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.
- Used value:
- Account name
- Used value:
account-for-guide
- This is the same name used above. The underlying address is not relevant.
- Used value:
- Fee token
- Used value:
eth
- Use Appchain version of Eth to pay for transaction fees.
- Used value:
The full command is:
sncast account deploy --url http://127.0.0.1:9945 --name account-for-guide --fee-token eth
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.
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.
- Used value:
- Appchain RPC URL
- Used value:
http://localhost:9945
- This is the default URL.
- Used value:
- Fee token
- Used value:
eth
- Use Appchain version of Eth to pay for transaction fees.
- Used value:
- Contract name
- Used value:
NewStrk
- Name of our token contract
- Used value:
The full command is:
sncast --account account-for-guide declare --url http://localhost:9945 --fee-token eth --contract-name NewStrk
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.
- Used value:
- Salt for contract deployment
- Used value:
1
- Use a hardcoded salt value so the deployment address is deterministic.
- Used value:
- Appchain RPC URL
- Used value:
http://localhost:9945
- This is the default URL.
- Used value:
- Fee token
- Used value:
eth
- Use Appchain version of Eth to pay for transaction fees.
- Used value:
- Class hash
- Used value:
0x02132f1600bbdb005de58f45719a8e65ea1ae418176484eadfac70f9e8b65c75
- The class hash declared earlier. Adjust if needed.
- Used value:
The full command is:
sncast --account account-for-guide deploy --salt 1 \
--url http://localhost:9945 \
--fee-token eth \
--class-hash 0x02132f1600bbdb005de58f45719a8e65ea1ae418176484eadfac70f9e8b65c75
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.
- Used value:
- Appchain RPC URL
- Used value:
http://localhost:9945
- This is the default URL.
- Used value:
- Fee token
- Used value:
eth
- Use Appchain version of Eth to pay for transaction fees.
- Used value:
- Contract address
- Used value:
$MADARA_GUIDE_TOKEN_CONTRACT
- The target contract address. ts. This references the variable you set earlier.
- Used value:
- Function name
- Used value:
mint
- This is the name of the function we are calling inside the token smart contract.
- Used value:
- 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.
- Used value:
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"
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.
- Used value:
- Contract address
- Used value:
$MADARA_GUIDE_TOKEN_CONTRACT
- The target contract address. ts. This references the variable you set earlier.
- Used value:
- Function name
- Used value:
balance_of
- This is the name of the function we are calling inside the token smart contract.
- Used value:
- 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.
- Used value:
sncast call \
--url http://localhost:9945 \
--contract-address $MADARA_GUIDE_TOKEN_CONTRACT \
--function balance_of --arguments "$MADARA_GUIDE_ACCOUNT"
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.
- Used value:
- Appchain RPC URL
- Used value:
http://localhost:9945
- This is the default URL.
- Used value:
- Fee token
- Used value:
strk
- Use the Appchain's gas token to pay for transaction fees.
- Used value:
- Contract address
- Used value:
$MADARA_GUIDE_TOKEN_CONTRACT
- The target contract address. ts. This references the variable you set earlier.
- Used value:
- Function name
- Used value:
mint
- This is the name of the function we are calling inside the token smart contract.
- Used value:
- 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.
- Used value:
sncast --account account-for-guide invoke \
--url http://localhost:9945 \
--fee-token strk \
--contract-address $MADARA_GUIDE_TOKEN_CONTRACT \
--function mint --arguments "0x1, 123"
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.
Congratulations, you have now successfully changed your Appchain's gas token!
Change the token through the settlement layer
This option will be documented later.