diff --git a/etc/EXAMPLE.json b/etc/EXAMPLE.json index 35ef9e6..c765e09 100644 --- a/etc/EXAMPLE.json +++ b/etc/EXAMPLE.json @@ -1,7 +1,7 @@ { "network": { - "name": "testnet", - "url": "https://alpha4.starknet.io", + "name": "devnet", + "url": "http://127.0.0.1", "accounts": { "deployer": { "address": "", diff --git a/package.json b/package.json index c220b66..569e541 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,10 @@ "starknet": "^5.19.5" }, "scripts": { - "declare": "node scripts/deploy_zklink.js declareZklink", - "deploy": "node scripts/deploy_zklink.js deployZklink" + "build": "node scripts/build.js build", + "declareZklink": "node scripts/deploy_zklink.js declareZklink", + "deployZklink": "node scripts/deploy_zklink.js deployZklink", + "deployFaucetToken": "node scripts/deploy_faucet.js deployFaucetToken", + "addToken": "node scripts/interact.js addToken" } } diff --git a/scripts/build.js b/scripts/build.js new file mode 100644 index 0000000..0905889 --- /dev/null +++ b/scripts/build.js @@ -0,0 +1,102 @@ +import { program } from "commander"; +import fs from "fs"; +import { executeCommand } from "./utils.js"; +import { command, contractPath } from "./constants.js"; + +program + .command("build") + .description("replace zklink contract constants and compile") + .action(async () => { + await build(); + }); + +program.parse(); + +function parseBlockPeriod(blockPeriod) { + const regex = /^(\d+)\s+seconds?$/i; + const match = blockPeriod.match(regex); + + if (match) { + return parseInt(match[1], 10); + } else { + throw new Error(`Invalid block period: ${blockPeriod}`); + } +} + +function writeZklinkConstants(configs) { + fs.readFile(contractPath.ZKLINK_CONSTANTS_PATH, 'utf8', (err, data) => { + if (err) { + console.error(err); + return; + } + + // BLOCK_PERIOD + let result = data.replace(/(const BLOCK_PERIOD: u64 = )(\d+)(;)/, `$1${configs.blockPeriod}$3`); + // PRIORITY_EXPIRATION + result = result.replace(/(const PRIORITY_EXPIRATION: u64 = )(\d+)(;)/, `$1${configs.priorityExpiration}$3`); + // UPGRADE_NOTICE_PERIOD + result = result.replace(/(const UPGRADE_NOTICE_PERIOD: u64 = )(\d+)(;)/, `$1${configs.upgradeNoticePeriod}$3`); + // CHAIN_ID + result = result.replace(/(const CHAIN_ID: u8 = )(\d+)(;)/, `$1${configs.chainId}$3`); + // MIN_CHAIN_ID + result = result.replace(/(const MIN_CHAIN_ID: u8 = )(\d+)(;)/, `$1${configs.minChainId}$3`); + // MAX_CHAIN_ID + result = result.replace(/(const MAX_CHAIN_ID: u8 = )(\d+)(;)/, `$1${configs.maxChainId}$3`); + // ALL_CHAAINS + result = result.replace(/(const ALL_CHAINS: u256 = )(\d+)(;)/, `$1${configs.allChains}$3`); + // CHAIN_INDEX + result = result.replace(/(const CHAIN_INDEX: u256 = )(\d+)(;)/, `$1${configs.chainIndex}$3`); + // ENABLE_COMMIT_COMPRESSED_BLOCK + result = result.replace(/(const ENABLE_COMMIT_COMPRESSED_BLOCK: felt252 = )(\d+)(;)/, `$1${configs.enableCommitCompressedBlock}$3`); + + fs.writeFile(contractPath.ZKLINK_CONSTANTS_PATH, result, 'utf8', (err) => { + if (err) { + console.error(err); + return; + } + }); + }); +} + +async function build() { + // read config json file + const netName = process.env.NET === undefined ? "EXAMPLE" : process.env.NET; + let netConfig = await fs.promises.readFile(`./etc/${netName}.json`, "utf-8"); + netConfig = JSON.parse(netConfig); + + const blockPeriod = parseBlockPeriod(netConfig.macro.BLOCK_PERIOD); + const upgradeNoticePeriod = netConfig.macro.UPGRADE_NOTICE_PERIOD; + const priorityExpiration = netConfig.macro.PRIORITY_EXPIRATION; + const chainId = netConfig.macro.CHAIN_ID; + const enableCommitCompressedBlock = netConfig.macro.ENABLE_COMMIT_COMPRESSED_BLOCK ? 1 : 0; + const minChainId = netConfig.macro.MIN_CHAIN_ID; + const maxChainId = netConfig.macro.MAX_CHAIN_ID; + const allChains = netConfig.macro.ALL_CHAINS; + const chainIndex = (1 << chainId) - 1; + + const configs = { + blockPeriod, + upgradeNoticePeriod, + priorityExpiration, + chainId, + enableCommitCompressedBlock, + minChainId, + maxChainId, + allChains, + chainIndex + } + + console.log("🔥 Reading and replace zklink constants..."); + console.log("configs:", configs); + writeZklinkConstants(configs); + console.log("✅ Replace zklink constants success"); + + console.log("Building zklink contract..."); + await executeCommand(command.COMMAND_BUILD) + .then((stdout) => { + console.log(stdout) + }).catch((error) => { + console.log(error) + }); + console.log("✅ Build zklink contract success"); +} \ No newline at end of file diff --git a/scripts/deploy_log_name.js b/scripts/constants.js similarity index 85% rename from scripts/deploy_log_name.js rename to scripts/constants.js index df9d9d0..2077af9 100644 --- a/scripts/deploy_log_name.js +++ b/scripts/constants.js @@ -27,6 +27,16 @@ const VERIFIER_SIERRA_PATH = "./target/release/zklink_Verifier.sierra.json"; const VERIFIER_CASM_PATH = "./target/release/zklink_Verifier.casm.json"; const ZKLINK_SIERRA_PATH = "./target/release/zklink_Zklink.sierra.json"; const ZKLINK_CASM_PATH = "./target/release/zklink_Zklink.casm.json"; +const FAUCET_TOKEN_SIERRA_PATH = "./target/release/zklink_FaucetToken.sierra.json"; +const FAUCET_TOKEN_CASM_PATH = "./target/release/zklink_FaucetToken.casm.json"; +const ZKLINK_CONSTANTS_PATH = "./src/utils/constants.cairo"; + +// command +const COMMAND_BUILD = "scarb --release build"; + +export var command = { + COMMAND_BUILD +} export var contractPath = { GATEKEEPER_SIERRA_PATH, @@ -34,7 +44,10 @@ export var contractPath = { VERIFIER_SIERRA_PATH, VERIFIER_CASM_PATH, ZKLINK_SIERRA_PATH, - ZKLINK_CASM_PATH + ZKLINK_CASM_PATH, + ZKLINK_CONSTANTS_PATH, + FAUCET_TOKEN_SIERRA_PATH, + FAUCET_TOKEN_CASM_PATH } export var logName = { diff --git a/scripts/deploy_faucet.js b/scripts/deploy_faucet.js new file mode 100644 index 0000000..2e0747d --- /dev/null +++ b/scripts/deploy_faucet.js @@ -0,0 +1,65 @@ +import { program } from "commander"; +import fs from "fs"; +import { contractPath } from "./constants.js"; +import { connectStarknet, buildFaucetTokenConstructorArgs, getClassHashFromError } from "./utils.js"; +import { json } from "starknet"; + +program + .command("deployFaucetToken") + .description("deploy faucet token") + .requiredOption('--name ', 'The token name') + .requiredOption('--symbol ', 'The token symbol') + .option('--decimals ', 'The token decimals', 18) + .option('--from-transfer-fee-ratio', 'The fee ratio taken of from address when transfer', 0) + .option('--to-transfer-fee-ratio', 'The fee ratio taken of to address when transfer', 0) + .action(async function (options) { + await deploy_faucet_token(options); + }); + +program.parse(); + +async function deploy_faucet_token(options) { + const name = options.name; + const symbol = options.symbol; + const decimals = options.decimals; + const fromTransferFeeRatio = options.fromTransferFeeRatio; + const toTransferFeeRatio = options.toTransferFeeRatio; + + console.log("name:", name); + console.log("symbol:", symbol); + console.log("decimals:", decimals); + console.log("fromTransferFeeRatio:", fromTransferFeeRatio); + console.log("toTransferFeeRatio:", toTransferFeeRatio); + + let { provider, deployer, governor, netConfig} = await connectStarknet(); + + // declare faucet token + const ContractSierra = json.parse(fs.readFileSync(contractPath.FAUCET_TOKEN_SIERRA_PATH).toString("ascii")); + const contractCasm = json.parse(fs.readFileSync(contractPath.FAUCET_TOKEN_CASM_PATH).toString("ascii")); + let classHash; + try { + const declareResponse = await deployer.declare({ contract: ContractSierra, casm: contractCasm }); + await provider.waitForTransaction(declareResponse.transaction_hash); + classHash = declareResponse.class_hash; + console.log('✅ Faucet Token Contract declared with classHash = ', classHash); + } catch (error) { + if (error.errorCode !== 'StarknetErrorCode.CLASS_ALREADY_DECLARED') { + throw error; + } + + classHash = getClassHashFromError(error); + if (classHash === undefined) { + console.log('❌ Cannot declare gatekeeper contract class hash:', error); + return; + } else { + console.log('✅ Faucet Token Contract already declared with classHash =', classHash); + } + } + + // deploy faucet token + const constructorArgs = buildFaucetTokenConstructorArgs(ContractSierra.abi, name, symbol, decimals, fromTransferFeeRatio, toTransferFeeRatio); + const deployResponse = await deployer.deployContract({ classHash: classHash, constructorCalldata: constructorArgs }); + await provider.waitForTransaction(deployResponse.transaction_hash); + + console.log('✅ Faucet Token Contract deployed at =', deployResponse.contract_address); +} \ No newline at end of file diff --git a/scripts/deploy_zklink.js b/scripts/deploy_zklink.js index 4bb6088..0b8eee6 100644 --- a/scripts/deploy_zklink.js +++ b/scripts/deploy_zklink.js @@ -1,7 +1,7 @@ import { Contract, json, cairo } from "starknet"; import fs from "fs"; import { program } from "commander"; -import { logName, contractPath } from "./deploy_log_name.js" +import { logName, contractPath } from "./constants.js" import { connectStarknet, getDeployLog, buildVerifierConstructorArgs, buildZklinkConstructorArgs, buildGateKeeperConstructorArgs, getClassHashFromError } from "./utils.js"; @@ -9,7 +9,7 @@ program .command("declareZklink") .description("Declare zklink and verifier contract") .action(async () => { - declare_zklink(); + await declare_zklink(); }); program @@ -26,7 +26,7 @@ program .option('--skip-verify', 'Skip verification', false) .option('--force', 'Force redeploy', false) .action(async (options) => { - deploy_zklink(options); + await deploy_zklink(options); }); async function declare_zklink() { diff --git a/scripts/interact.js b/scripts/interact.js new file mode 100644 index 0000000..a5fcca0 --- /dev/null +++ b/scripts/interact.js @@ -0,0 +1,47 @@ +import { program } from "commander"; +import fs from "fs"; +import { Contract, json } from "starknet"; +import { contractPath, logName } from "./constants.js"; +import { connectStarknet, getDeployLog } from "./utils.js"; + +program + .command("addToken") + .description("Adds a new token with a given address for testnet") + .option('--zklink ', 'The zkLink contract address (default get from deploy log)', undefined) + .requiredOption('--token-id ', 'The token id') + .requiredOption('--token-address ', 'The token address') + .option('--token-decimals ', 'The token decimals', 18) + .option('--standard ', 'The token is a standard ERC20 token', true) + .action(async (options) => { + await add_token(options); + }); + +program.parse(); + +async function add_token(options) { + let { provider, deployer, governor, netConfig} = await connectStarknet(); + const { deployLogPath, deployLog } = getDeployLog(logName.DEPLOY_ZKLINK_LOG_PREFIX); + + const zklinkAddress = options.zklink === undefined ? deployLog[logName.DEPLOY_LOG_ZKLINK] : options.zklink; + const tokenId = options.tokenId; + const tokenAddress = options.tokenAddress; + const tokenDecimals = options.tokenDecimals; + const standard = options.standard; + + console.log("zklink:", zklinkAddress); + console.log("governor:", governor.address); + console.log("tokenId:", tokenId); + console.log("tokenAddress:", tokenAddress); + console.log("tokenDecimals:", tokenDecimals); + console.log("standard:", standard); + console.log("Adding new ERC20 token to zklink"); + + const zklinkContractSierra = json.parse(fs.readFileSync(contractPath.ZKLINK_SIERRA_PATH).toString("ascii")); + const zklink = new Contract(zklinkContractSierra.abi, zklinkAddress, provider); + + zklink.connect(governor); + const call = zklink.populate("addToken", [tokenId, tokenAddress, tokenDecimals, standard]); + const tx = await zklink.addToken(call.calldata); + await provider.waitForTransaction(tx.transaction_hash); + console.log('✅ zklink add new ERC20 token success, tx:', tx.transaction_hash); +} \ No newline at end of file diff --git a/scripts/utils.js b/scripts/utils.js index 91bdc5b..9ede6ee 100644 --- a/scripts/utils.js +++ b/scripts/utils.js @@ -1,5 +1,7 @@ import fs from "fs"; import { Provider, CallData, Account, constants } from "starknet"; +import { exec } from "child_process"; +import { stdout } from "process"; function buildProvider(networkConfig) { @@ -21,7 +23,7 @@ function buildProvider(networkConfig) { export async function connectStarknet() { // read config json file - const netName = process.env.NET === undefined ? "devnet" : process.env.NET; + const netName = process.env.NET === undefined ? "EXAMPLE" : process.env.NET; let netConfig = await fs.promises.readFile(`./etc/${netName}.json`, "utf-8"); netConfig = JSON.parse(netConfig); @@ -37,6 +39,12 @@ export async function connectStarknet() { return { provider, deployer, governor, netConfig}; } +export function buildFaucetTokenConstructorArgs(abi, name, symbol, decimals, fromTransferFeeRatio, toTransferFeeRatio) { + const contractCallData = new CallData(abi); + const constructorArgs = contractCallData.compile("constructor", [name, symbol, decimals, fromTransferFeeRatio, toTransferFeeRatio]) + return constructorArgs; +} + export function buildGateKeeperConstructorArgs(abi, master, mainContract) { const contractCallData = new CallData(abi); const constructorArgs = contractCallData.compile("constructor", [master, mainContract]) @@ -90,4 +98,19 @@ export function getClassHashFromError(error) { } else { return undefined; } +} + +export function executeCommand(command) { + return new Promise((resolve, reject) => { + exec(command, (error, stdout, stderr) => { + if (error) { + console.error(`Error executing command: ${error.message}`); + console.error(`Command error: ${stderr}`); + console.error(`Command output: ${stdout}`); + resolve(''); + } else { + resolve(stdout); + } + }); + }); } \ No newline at end of file diff --git a/src/contracts/zklink.cairo b/src/contracts/zklink.cairo index 39e40f7..874498a 100644 --- a/src/contracts/zklink.cairo +++ b/src/contracts/zklink.cairo @@ -504,8 +504,6 @@ mod Zklink { #[external(v0)] impl Zklink of super::IZklink { - // TODO: upgrade interface - // Deposit ERC20 token to Layer 2 - transfer ERC20 tokens from user into contract, validate it, register deposit // it MUST be ok to call other external functions within from this function // when the token(eg. erc777) is not a pure erc20 token diff --git a/src/dev.cairo b/src/dev.cairo new file mode 100644 index 0000000..ee27d9b --- /dev/null +++ b/src/dev.cairo @@ -0,0 +1 @@ +mod faucet_token; diff --git a/src/dev/faucet_token.cairo b/src/dev/faucet_token.cairo new file mode 100644 index 0000000..0f05e59 --- /dev/null +++ b/src/dev/faucet_token.cairo @@ -0,0 +1,194 @@ +use starknet::ContractAddress; + +#[starknet::interface] +trait IFaucetToken { + fn name(self: @TContractState) -> felt252; + fn symbol(self: @TContractState) -> felt252; + fn decimals(self: @TContractState) -> u8; + fn total_supply(self: @TContractState) -> u256; + fn balance_of(self: @TContractState, account: ContractAddress) -> u256; + fn allowance(self: @TContractState, owner: ContractAddress, spender: ContractAddress) -> u256; + fn transfer(ref self: TContractState, recipient: ContractAddress, amount: u256) -> bool; + fn transfer_from( + ref self: TContractState, sender: ContractAddress, recipient: ContractAddress, amount: u256 + ) -> bool; + fn approve(ref self: TContractState, spender: ContractAddress, amount: u256) -> bool; + fn mint_to(ref self: TContractState, to: ContractAddress, amount: u256) -> bool; +} + +#[starknet::contract] +mod FaucetToken { + use integer::BoundedInt; + use openzeppelin::token::erc20::interface::IERC20; + use openzeppelin::token::erc20::interface::IERC20CamelOnly; + use starknet::ContractAddress; + use starknet::get_caller_address; + use zeroable::Zeroable; + + #[storage] + struct Storage { + _name: felt252, + _symbol: felt252, + _decimals: u8, + _from_transfer_fee_ratio: u8, + _to_transfer_fee_ratio: u8, + _total_supply: u256, + _balances: LegacyMap, + _allowances: LegacyMap<(ContractAddress, ContractAddress), u256>, + } + + #[event] + #[derive(Drop, starknet::Event)] + enum Event { + Transfer: Transfer, + Approval: Approval, + } + + #[derive(Drop, starknet::Event)] + struct Transfer { + from: ContractAddress, + to: ContractAddress, + value: u256 + } + + #[derive(Drop, starknet::Event)] + struct Approval { + owner: ContractAddress, + spender: ContractAddress, + value: u256 + } + + #[constructor] + fn constructor( + ref self: ContractState, + name: felt252, + symbol: felt252, + decimals: u8, + from_transfer_fee_ratio: u8, + to_transfer_fee_ratio: u8 + ) { + self._name.write(name); + self._symbol.write(symbol); + self._decimals.write(decimals); + self._from_transfer_fee_ratio.write(from_transfer_fee_ratio); + self._to_transfer_fee_ratio.write(to_transfer_fee_ratio); + } + + #[external(v0)] + impl FaucetTokenImpl of super::IFaucetToken { + fn name(self: @ContractState) -> felt252 { + self._name.read() + } + + fn symbol(self: @ContractState) -> felt252 { + self._symbol.read() + } + + fn decimals(self: @ContractState) -> u8 { + self._decimals.read() + } + + fn total_supply(self: @ContractState) -> u256 { + self._total_supply.read() + } + + fn balance_of(self: @ContractState, account: ContractAddress) -> u256 { + self._balances.read(account) + } + + fn allowance( + self: @ContractState, owner: ContractAddress, spender: ContractAddress + ) -> u256 { + self._allowances.read((owner, spender)) + } + + fn transfer(ref self: ContractState, recipient: ContractAddress, amount: u256) -> bool { + let sender = get_caller_address(); + self._transfer(sender, recipient, amount); + true + } + + fn transfer_from( + ref self: ContractState, + sender: ContractAddress, + recipient: ContractAddress, + amount: u256 + ) -> bool { + let caller = get_caller_address(); + self._spend_allowance(sender, caller, amount); + self._transfer(sender, recipient, amount); + true + } + + fn approve(ref self: ContractState, spender: ContractAddress, amount: u256) -> bool { + let caller = get_caller_address(); + self._approve(caller, spender, amount); + true + } + + fn mint_to(ref self: ContractState, to: ContractAddress, amount: u256) -> bool { + self._mint(to, amount); + true + } + } + + // + // Internal + // + + #[generate_trait] + impl InternalImpl of InternalTrait { + fn _mint(ref self: ContractState, recipient: ContractAddress, amount: u256) { + assert(!recipient.is_zero(), 'mint1'); + self._total_supply.write(self._total_supply.read() + amount); + self._balances.write(recipient, self._balances.read(recipient) + amount); + self.emit(Transfer { from: Zeroable::zero(), to: recipient, value: amount }); + } + + fn _burn(ref self: ContractState, account: ContractAddress, amount: u256) { + assert(!account.is_zero(), 'burn0'); + self._total_supply.write(self._total_supply.read() - amount); + self._balances.write(account, self._balances.read(account) - amount); + self.emit(Transfer { from: account, to: Zeroable::zero(), value: amount }); + } + + fn _approve( + ref self: ContractState, owner: ContractAddress, spender: ContractAddress, amount: u256 + ) { + assert(!owner.is_zero(), 'apr1'); + assert(!spender.is_zero(), 'apr2'); + self._allowances.write((owner, spender), amount); + self.emit(Approval { owner, spender, value: amount }); + } + + fn _transfer( + ref self: ContractState, + sender: ContractAddress, + recipient: ContractAddress, + amount: u256 + ) { + assert(!sender.is_zero(), 'tsf1'); + assert(!recipient.is_zero(), 'tsf2'); + self._balances.write(sender, self._balances.read(sender) - amount); + self._balances.write(recipient, self._balances.read(recipient) + amount); + self.emit(Transfer { from: sender, to: recipient, value: amount }); + + if sender.is_non_zero() && self._from_transfer_fee_ratio.read() > 0 { + self._burn(sender, amount / self._from_transfer_fee_ratio.read().into()); + } + + if recipient.is_non_zero() && self._to_transfer_fee_ratio.read() > 0 { + self._burn(recipient, amount / self._to_transfer_fee_ratio.read().into()); + } + } + + fn _spend_allowance( + ref self: ContractState, owner: ContractAddress, spender: ContractAddress, amount: u256 + ) { + let current_allowance = self._allowances.read((owner, spender)); + if current_allowance != BoundedInt::max() { + self._approve(owner, spender, current_allowance - amount); + } + } + } +} diff --git a/src/lib.cairo b/src/lib.cairo index 5eaea10..1f4ab96 100644 --- a/src/lib.cairo +++ b/src/lib.cairo @@ -1,4 +1,5 @@ mod contracts; mod utils; +mod dev; #[cfg(test)] mod tests; diff --git a/src/utils/constants.cairo b/src/utils/constants.cairo index 9af9ae1..08b9a3e 100644 --- a/src/utils/constants.cairo +++ b/src/utils/constants.cairo @@ -1,4 +1,16 @@ // zkLink configuration constants +// Do not change those value as below, otherwise unit test will fail. +// And this value will be automatically modified by the automated +// deployment script based on the configuration file in the ./etc directory before deployment +// - BLOCK_PERIOD +// - PRIORITY_EXPIRATION +// - UPGRADE_NOTICE_PERIOD +// - CHAIN_ID +// - MIN_CHAIN_ID +// - MAX_CHAIN_ID +// - ALL_CHAINS +// - CHAIN_INDEX +// - ENABLE_COMMIT_COMPRESSED_BLOCK const EMPTY_STRING_KECCAK: u256 = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470; @@ -24,7 +36,6 @@ const MAX_SUB_ACCOUNT_ID: u8 = 31; // Expected average period of block creation, default 15s // In starknet, block_number and block_timestamp type is u64 -// TODO: replace before deploy const BLOCK_PERIOD: u64 = 15; // Operation chunks: @@ -41,13 +52,11 @@ const CHANGE_PUBKEY_BYTES: usize = 69; // Expiration delta for priority request to be satisfied (in ETH blocks) // PRIORITY_EXPIRATION(default 80640) = PRIORITY_EXPIRATION_PERIOD / BLOCK_PERIOD, -// TODO: replace before deploy const PRIORITY_EXPIRATION: u64 = 0; // Notice period before activation preparation status of upgrade mode (in seconds) // NOTE: we must reserve for users enough time to send full exit operation, wait maximum time for processing this operation and withdraw funds from it. // UPGRADE_NOTICE_PERIOD(default 1814400) = MASS_FULL_EXIT_PERIOD(432000, 5 days) + PRIORITY_EXPIRATION_PERIOD + TIME_TO_WITHDRAW_FUNDS_FROM_FULL_EXIT(172800, 2 days) -// TODO: replace before deploy const UPGRADE_NOTICE_PERIOD: u64 = 0; // Max commitment produced in zk proof where highest 3 bits is 0 @@ -65,27 +74,21 @@ const AUTH_FACT_RESET_TIMELOCK: u64 = 86400; const MAX_DEPOSIT_AMOUNT: u128 = 20282409603651670423947251286015; // Chain id defined by ZkLink -// TODO: check before deploy const CHAIN_ID: u8 = 1; // Min chain id defined by ZkLink -// TODO: check before deploy const MIN_CHAIN_ID: u8 = 1; // Max chain id defined by ZkLink -// TODO: check before deploy const MAX_CHAIN_ID: u8 = 4; // All chain index, for example [1, 2, 3, 4] => 1 << 0 | 1 << 1 | 1 << 2 | 1 << 3 = 15 -// TODO: check before deploy const ALL_CHAINS: u256 = 15; // Chain index, CHAIN_ID is non-zero value -// TODO: check before deploy const CHAIN_INDEX: u256 = 1; // Enable commit a compressed block -// TODO: check before deploy // Now, in cairo only literal constants are currently supported. // It should be 1 if true, be 0 if false. const ENABLE_COMMIT_COMPRESSED_BLOCK: felt252 = 1;