Deploy a Contract
This guide walks through deploying a Solidity contract to Xenea with Foundry, then verifying the source code on XENEA Scan.
Xenea currently provides the Ubusuna Testnet. Additional networks will follow the same workflow. Look up the chain ID, RPC URL, and explorer URL in Network Resources. Get testnet tokens from Claim Ubusuna Testnet XENE. This guide uses the xenea_ubusuna alias in its examples.
Prerequisites
Foundry installed
Native token balance in your deployer wallet on the target network (testnets provide a faucet — see Claim Ubusuna Testnet XENE)
Scaffold a project
Initialize a new Foundry project:
forge init xenea-dapp-sandbox
cd xenea-dapp-sandboxThis generates a sample src/Counter.sol, script/Counter.s.sol, and test/Counter.t.sol. This guide uses the generated Counter contract as the deployment target.
Configure Foundry
Edit foundry.toml to add a Xenea profile and one or more RPC endpoints:
[profile.default]
src = "src"
out = "out"
libs = ["lib"]
evm_version = "paris"
[rpc_endpoints]
xenea_ubusuna = "https://rpc-ubusuna.xeneascan.com/"
# xenea_mainnet = "<RPC_URL>"Throughout the rest of this guide, xenea_ubusuna is used as the example alias. Replace it with whichever entry you want to deploy to.
⚠️ Set
evm_version = "paris". Xenea runs the Paris EVM. Without this setting, Solidity 0.8.20+ defaults to Shanghai and emits thePUSH0opcode, and your deployment will revert.
Prepare a deployer wallet
Import your private key into a Foundry keystore (encrypted on disk):
You'll be prompted for the private key (a 0x-prefixed 64-char hex string) and a password to encrypt the keystore. The keystore is saved to ~/.foundry/keystores/xenea-deployer.
Get the address:
Check the balance on your target network:
Build and test
Deploy
Deploy Counter with forge create:
⚠️ Always pass
--legacyon Xenea. Xenea uses legacy (Type 0) transactions. Forge commands that broadcast transactions —forge create,forge script,cast send— need this flag.
You'll be prompted for the keystore password. On success you'll see:
Save the Deployed to address — you'll need it for the next steps.
Using forge script instead
forge script insteadIf your deployment involves multiple contracts or post-deploy calls, a Script contract is the standard Foundry approach. On Xenea, pass --legacy and --slow so broadcasts wait for each receipt before moving on:
Confirm deployment
Check that bytecode exists at the deployed address:
A long 0x… blob confirms the contract is on-chain. A bare 0x usually means the contract is not present at that address on the selected network.
Interact with the contract
Use cast call for read-only functions and cast send for state-changing ones:
💡 If
cast sendhangs while waiting for a receipt, add--asyncto return immediately with the tx hash, then confirm later withcast receipt <hash> --rpc-url xenea_ubusuna.
Verify the contract
XENEA Scan accepts verification through the web UI using Standard JSON Input generated by Foundry.
1. Generate Standard JSON Input
--show-standard-json-input writes the solc Standard JSON Input to stdout without making a network request.
2. Look up the compiler version
Open out/Counter.sol/Counter.json in your editor and search for compiler.version.
Copy the value exactly. For example:
You will enter this on the explorer as v0.8.31+commit.f0907708.
3. Submit on XENEA Scan
Open the dedicated Verify Contract page for Ubusuna Testnet:
https://ubusuna.xeneascan.com/verify-contract
Choose Via Standard Input JSON and fill in:
Contract Address
<DEPLOYED_ADDRESS>
Contract Name
Counter
Compiler
the version from step 2 (e.g. v0.8.31+commit.f0907708)
Standard Input JSON
upload counter-standard-input.json
Click Verify & Publish. After success, the contract page on XENEA Scan will show the source code, ABI, and Read/Write Contract UI.
Use src/Counter.sol:Counter only in the Foundry command. On the explorer form, enter Counter.
Troubleshooting
cast code returns 0x
cast code returns 0xThe contract is not present at that address on the selected network. Check these first:
You passed
--legacyon broadcast commandsYour deployer has enough native tokens
Your RPC alias points to the intended network
You are checking the correct deployed address
Deployment reverts with opcode errors
Set evm_version = "paris" in foundry.toml. Solidity 0.8.20+ otherwise emits PUSH0, which Xenea does not support.
Verification fails on the explorer
Check that these values match your build exactly:
Contract name, such as
CounterCompiler version from
out/Counter.sol/Counter.jsonStandard JSON Input generated from the same build
If the compiler version does not match the build you want to verify, rebuild the project with the intended compiler version and generate the Standard JSON Input again.
Appendix: Command cheatsheet
Replace xenea_ubusuna with whichever [rpc_endpoints] alias you registered for your target network.
forge build
Compile contracts
forge test
Run local tests
forge create <path:Contract> --rpc-url xenea_ubusuna --account <name> --legacy --broadcast
Deploy a single contract
forge script <path>:<Script> --rpc-url xenea_ubusuna --account <name> --legacy --broadcast --slow
Run a deployment script
forge verify-contract <addr> <path:Contract> --show-standard-json-input > out.json
Generate Standard JSON Input for manual verification
cast call <addr> "fn()(ret)" --rpc-url xenea_ubusuna
Read a view/pure function
cast send <addr> "fn(args)" <values> --rpc-url xenea_ubusuna --account <name> --legacy
Send a state-changing tx
cast receipt <txhash> --rpc-url xenea_ubusuna
Fetch a transaction receipt
cast code <addr> --rpc-url xenea_ubusuna
Check deployed bytecode
cast balance <addr> --rpc-url xenea_ubusuna --ether
Check balance
Last updated