Skip to content

Instantly share code, notes, and snippets.

@Aboudjem
Last active February 26, 2026 21:52
Show Gist options
  • Select an option

  • Save Aboudjem/d3e2e833123aee05a105557ce2f059b0 to your computer and use it in GitHub Desktop.

Select an option

Save Aboudjem/d3e2e833123aee05a105557ce2f059b0 to your computer and use it in GitHub Desktop.
Integra Testnet Deployment Report — February 26, 2026

Integra Testnet Deployment Report — February 26, 2026

Integra Testnet Deployment Report

Date: February 26, 2026 Chain ID: integra-testnet-1 EVM Chain ID: 26218 (hex: 0x666a) Deployer: Adam Boudjemaa Genesis Hash: 1dd8856029d8b5a90a995c53e028bd4e89d2c5e654a81e5d808b2dfacb1fcde2


Servers

Server Moniker IP Provider Location
Testnet-Gateway Integra-Helsinki 46.225.231.81 Hetzner Helsinki, Finland
Signer-1 Integra-Amsterdam 45.77.139.208 Vultr Amsterdam, Netherlands
Signer-2 Integra-NewYork 159.223.206.94 DigitalOcean New York, USA

SSH: ssh -i ~/.ssh/integra root@<IP>


Phase 1: Build Binary

Cross-compiling from macOS ARM to Linux AMD64 failed due to secp256k1 C bindings requiring CGO. Built natively on the Gateway server instead.

# On local machine — upload source
cd /Users/adamboudj/projects/integra-chain
tar czf /tmp/integra-chain.tar.gz --exclude='.git' --exclude='build' .
scp -i ~/.ssh/integra /tmp/integra-chain.tar.gz root@46.225.231.81:/root/

# On Gateway — install Go 1.23.8
ssh -i ~/.ssh/integra root@46.225.231.81
wget https://go.dev/dl/go1.23.8.linux-amd64.tar.gz
rm -rf /usr/local/go && tar -C /usr/local -xzf go1.23.8.linux-amd64.tar.gz
export PATH=$PATH:/usr/local/go/bin
go version
# go version go1.23.8 linux/amd64

# Build
mkdir -p /root/integra-chain && cd /root/integra-chain
tar xzf /root/integra-chain.tar.gz
cd integra
CGO_ENABLED=1 go build -o /root/integra-chain/build/intgd ./cmd/intgd

file /root/integra-chain/build/intgd
# ELF 64-bit LSB executable, x86-64

Gotcha: GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build fails with undefined: secp256k1.RecoverPubkey. The Cosmos EVM SDK uses C bindings for secp256k1 — you MUST build on Linux with CGO_ENABLED=1.


Phase 2: Deploy Binary

# From Gateway, copy to all 3 nodes
cp /root/integra-chain/build/intgd /usr/local/bin/intgd

scp /usr/local/bin/intgd root@45.77.139.208:/usr/local/bin/intgd
scp /usr/local/bin/intgd root@159.223.206.94:/usr/local/bin/intgd

# Verify on each
intgd help  # Should show Integra Daemon commands

Phase 3: Genesis Ceremony

3.1 Initialize all nodes

# On Gateway
intgd init Integra-Helsinki --chain-id integra-testnet-1

# On Signer-1
intgd init Integra-Amsterdam --chain-id integra-testnet-1

# On Signer-2
intgd init Integra-NewYork --chain-id integra-testnet-1

3.2 Generate keys (all nodes use --keyring-backend file)

# On each node
intgd keys add validator --keyring-backend file --algo eth_secp256k1

# On Gateway only — treasury key
intgd keys add testnet-treasury --keyring-backend file --algo eth_secp256k1

Addresses Generated

Key Address
Gateway validator integra1wry6d9njdpacwnj2mpt82wwln7hcagy93smkwx
Signer-1 validator integra15uyrkdtw2rlpfm2wfq4rmrcycgl2e5k536z60y
Signer-2 validator integra1gn3arhpev8sw9pp96hevsv0t8mj9cd5wwpqrhe
Treasury integra1y2v26vmd0juqtqz9er0nqmywt226e698ldu4kw

Valoper Addresses

Validator Valoper
Helsinki integravaloper1wry6d9njdpacwnj2mpt82wwln7hcagy9hwue3t
Amsterdam integravaloper15uyrkdtw2rlpfm2wfq4rmrcycgl2e5k5hy94sf
NewYork integravaloper1gn3arhpev8sw9pp96hevsv0t8mj9cd5wgl8vg5

Node IDs

Node ID
Gateway 10d16647b0476d5405ceeb20347437a70da0c0b1
Signer-1 1d215b882540caf56adf5d4279f377b57dfecac5
Signer-2 bee94426ebd65dd3ee7ab56b8fcebf7f1b1585e7

Mnemonics: Saved offline. Handed to Piyush.

3.3 Add genesis accounts (on Gateway)

# Treasury: 99,999,997,000 IRL = 99999997000 * 10^18 airl
intgd genesis add-genesis-account integra1y2v26vmd0juqtqz9er0nqmywt226e698ldu4kw \
  99999997000000000000000000000airl

# Validators: 1,000 IRL each
intgd genesis add-genesis-account integra1wry6d9njdpacwnj2mpt82wwln7hcagy93smkwx \
  1000000000000000000000airl
intgd genesis add-genesis-account integra15uyrkdtw2rlpfm2wfq4rmrcycgl2e5k536z60y \
  1000000000000000000000airl
intgd genesis add-genesis-account integra1gn3arhpev8sw9pp96hevsv0t8mj9cd5wwpqrhe \
  1000000000000000000000airl

3.4 Customize genesis parameters (on Gateway)

Applied via jq to ~/.intgd/config/genesis.json:

GENESIS=$HOME/.intgd/config/genesis.json

# Denom metadata
jq '.app_state.bank.denom_metadata = [{
  "description": "The native staking and governance token of Integra Layer",
  "denom_units": [
    {"denom": "airl", "exponent": 0, "aliases": ["attoirl"]},
    {"denom": "irl", "exponent": 18}
  ],
  "base": "airl",
  "display": "irl",
  "name": "Integra",
  "symbol": "IRL"
}]' $GENESIS > tmp.json && mv tmp.json $GENESIS

# EVM
jq '.app_state.vm.params.evm_denom = "airl"' $GENESIS > tmp.json && mv tmp.json $GENESIS

# FeeMarket — CRITICAL: base_fee MUST be "0" for gentx to work
jq '.app_state.feemarket.params.no_base_fee = false' $GENESIS > tmp.json && mv tmp.json $GENESIS
jq '.app_state.feemarket.params.base_fee_change_denominator = 8' $GENESIS > tmp.json && mv tmp.json $GENESIS
jq '.app_state.feemarket.params.elasticity_multiplier = 2' $GENESIS > tmp.json && mv tmp.json $GENESIS
jq '.app_state.feemarket.params.base_fee = "0"' $GENESIS > tmp.json && mv tmp.json $GENESIS
jq '.app_state.feemarket.params.min_gas_price = "0.000000000000000000"' $GENESIS > tmp.json && mv tmp.json $GENESIS
jq '.app_state.feemarket.params.min_gas_multiplier = "0.500000000000000000"' $GENESIS > tmp.json && mv tmp.json $GENESIS

# Mint — 3% fixed inflation
jq '.app_state.mint.params.mint_denom = "airl"' $GENESIS > tmp.json && mv tmp.json $GENESIS
jq '.app_state.mint.params.inflation_rate_change = "0.000000000000000000"' $GENESIS > tmp.json && mv tmp.json $GENESIS
jq '.app_state.mint.params.inflation_max = "0.030000000000000000"' $GENESIS > tmp.json && mv tmp.json $GENESIS
jq '.app_state.mint.params.inflation_min = "0.030000000000000000"' $GENESIS > tmp.json && mv tmp.json $GENESIS
jq '.app_state.mint.params.goal_bonded = "0.010000000000000000"' $GENESIS > tmp.json && mv tmp.json $GENESIS
jq '.app_state.mint.params.blocks_per_year = "6311520"' $GENESIS > tmp.json && mv tmp.json $GENESIS
jq '.app_state.mint.minter.inflation = "0.030000000000000000"' $GENESIS > tmp.json && mv tmp.json $GENESIS

# Staking
jq '.app_state.staking.params.bond_denom = "airl"' $GENESIS > tmp.json && mv tmp.json $GENESIS
jq '.app_state.staking.params.unbonding_time = "1814400s"' $GENESIS > tmp.json && mv tmp.json $GENESIS
jq '.app_state.staking.params.max_validators = 100' $GENESIS > tmp.json && mv tmp.json $GENESIS
jq '.app_state.staking.params.max_entries = 7' $GENESIS > tmp.json && mv tmp.json $GENESIS
jq '.app_state.staking.params.historical_entries = 10000' $GENESIS > tmp.json && mv tmp.json $GENESIS
jq '.app_state.staking.params.min_commission_rate = "0.000000000000000000"' $GENESIS > tmp.json && mv tmp.json $GENESIS

# Governance
jq '.app_state.gov.params.min_deposit = [{"denom":"airl","amount":"1000000000000000000000000"}]' $GENESIS > tmp.json && mv tmp.json $GENESIS
jq '.app_state.gov.params.expedited_min_deposit = [{"denom":"airl","amount":"5000000000000000000000000"}]' $GENESIS > tmp.json && mv tmp.json $GENESIS
jq '.app_state.gov.params.max_deposit_period = "604800s"' $GENESIS > tmp.json && mv tmp.json $GENESIS
jq '.app_state.gov.params.voting_period = "432000s"' $GENESIS > tmp.json && mv tmp.json $GENESIS
jq '.app_state.gov.params.expedited_voting_period = "86400s"' $GENESIS > tmp.json && mv tmp.json $GENESIS
jq '.app_state.gov.params.quorum = "0.334000000000000000"' $GENESIS > tmp.json && mv tmp.json $GENESIS
jq '.app_state.gov.params.threshold = "0.500000000000000000"' $GENESIS > tmp.json && mv tmp.json $GENESIS
jq '.app_state.gov.params.veto_threshold = "0.334000000000000000"' $GENESIS > tmp.json && mv tmp.json $GENESIS
jq '.app_state.gov.params.min_initial_deposit_ratio = "0.250000000000000000"' $GENESIS > tmp.json && mv tmp.json $GENESIS
jq '.app_state.gov.params.burn_vote_veto = true' $GENESIS > tmp.json && mv tmp.json $GENESIS

# Slashing
jq '.app_state.slashing.params.signed_blocks_window = "10000"' $GENESIS > tmp.json && mv tmp.json $GENESIS
jq '.app_state.slashing.params.min_signed_per_window = "0.050000000000000000"' $GENESIS > tmp.json && mv tmp.json $GENESIS
jq '.app_state.slashing.params.downtime_jail_duration = "600s"' $GENESIS > tmp.json && mv tmp.json $GENESIS
jq '.app_state.slashing.params.slash_fraction_double_sign = "0.050000000000000000"' $GENESIS > tmp.json && mv tmp.json $GENESIS
jq '.app_state.slashing.params.slash_fraction_downtime = "0.000100000000000000"' $GENESIS > tmp.json && mv tmp.json $GENESIS

# Distribution
jq '.app_state.distribution.params.community_tax = "0.000000000000000000"' $GENESIS > tmp.json && mv tmp.json $GENESIS
jq '.app_state.distribution.params.withdraw_addr_enabled = true' $GENESIS > tmp.json && mv tmp.json $GENESIS

3.5 Distribute pre-gentx genesis to signer nodes

scp $GENESIS root@45.77.139.208:/root/.intgd/config/genesis.json
scp $GENESIS root@159.223.206.94:/root/.intgd/config/genesis.json

3.6 Create gentx on each node

# On each node (replace moniker)
intgd genesis gentx validator 1000000000000000000000airl \
  --chain-id integra-testnet-1 \
  --moniker "Integra-Helsinki" \
  --commission-rate 0.05 \
  --commission-max-rate 0.20 \
  --commission-max-change-rate 0.01 \
  --keyring-backend file

3.7 Collect gentxs on Gateway

# Download gentxs from signer nodes
scp root@45.77.139.208:/root/.intgd/config/gentx/*.json /tmp/gentx-signer1.json
scp root@159.223.206.94:/root/.intgd/config/gentx/*.json /tmp/gentx-signer2.json

# Copy to Gateway gentx folder
cp /tmp/gentx-signer1.json /root/.intgd/config/gentx/
cp /tmp/gentx-signer2.json /root/.intgd/config/gentx/

# Collect and validate
intgd genesis collect-gentxs
intgd genesis validate

3.8 Distribute final genesis

scp /root/.intgd/config/genesis.json root@45.77.139.208:/root/.intgd/config/genesis.json
scp /root/.intgd/config/genesis.json root@159.223.206.94:/root/.intgd/config/genesis.json

# Verify sha256 matches on all 3
sha256sum /root/.intgd/config/genesis.json
# 1dd8856029d8b5a90a995c53e028bd4e89d2c5e654a81e5d808b2dfacb1fcde2

Phase 4: Configure Nodes

All nodes — config.toml

[p2p]
persistent_peers = "10d16647b0476d5405ceeb20347437a70da0c0b1@46.225.231.81:26656,1d215b882540caf56adf5d4279f377b57dfecac5@45.77.139.208:26656,bee94426ebd65dd3ee7ab56b8fcebf7f1b1585e7@159.223.206.94:26656"

All nodes — app.toml

minimum-gas-prices = "5000000000000airl"

[json-rpc]
# Gateway only:
enable = true
address = "0.0.0.0:8545"
ws-address = "0.0.0.0:8546"

# Signer nodes:
# enable = false
[evm]
chain-id = "26218"

All nodes — client.toml

chain-id = "integra-testnet-1"

Gateway only — additional app.toml

[api]
enable = true
address = "tcp://0.0.0.0:1317"

[state-sync]
snapshot-interval = 1000

Signer nodes only — app.toml

pruning = "everything"

[tx_index]
indexer = "null"

Phase 5: Systemd Services

# /etc/systemd/system/intgd.service (all 3 nodes)
[Unit]
Description=Integra Testnet Node
After=network-online.target
Wants=network-online.target

[Service]
User=root
ExecStart=/usr/local/bin/intgd start
Restart=always
RestartSec=3
LimitNOFILE=65535

[Install]
WantedBy=multi-user.target
systemctl daemon-reload
systemctl enable intgd

Phase 6: Launch

# Start all 3 within 60 seconds
systemctl start intgd                                          # Gateway
ssh root@45.77.139.208 "systemctl start intgd"                # Signer-1
ssh root@159.223.206.94 "systemctl start intgd"               # Signer-2

Result: Chain producing blocks within 15 seconds. All 3 validators bonded.


Phase 7: Delegation

Delegated 200,000,000 IRL from treasury to each validator.

AMOUNT="200000000000000000000000000airl"

intgd tx staking delegate integravaloper1wry6d9njdpacwnj2mpt82wwln7hcagy9hwue3t $AMOUNT \
  --from testnet-treasury --keyring-backend file \
  --gas auto --gas-adjustment 1.5 --gas-prices 5000000000000airl \
  --chain-id integra-testnet-1 -y

intgd tx staking delegate integravaloper15uyrkdtw2rlpfm2wfq4rmrcycgl2e5k5hy94sf $AMOUNT \
  --from testnet-treasury --keyring-backend file \
  --gas auto --gas-adjustment 1.5 --gas-prices 5000000000000airl \
  --chain-id integra-testnet-1 -y

intgd tx staking delegate integravaloper1gn3arhpev8sw9pp96hevsv0t8mj9cd5wgl8vg5 $AMOUNT \
  --from testnet-treasury --keyring-backend file \
  --gas auto --gas-adjustment 1.5 --gas-prices 5000000000000airl \
  --chain-id integra-testnet-1 -y

Delegation TX hashes:

Validator TX Hash
Helsinki F082FEE07C704A20F25A3379A7F1B78C2F389E7CEFF6849F053B2ACAB05B92C2
Amsterdam C4A0B4FEAF938BB6FBC4E31A4666A959FE9CBFC0857B414E02B456FAA09031AC
NewYork 7CE10D3E9BB6AE1D30D31710D52072A8FCAB5C2FDCAB71E0D6278EF82C2A60A1

Final stake: ~200,001,000 IRL each (~33.3% VP each).


Phase 8: DNS + Caddy

DNS (Route53)

Updated A records in zone Z07594511H8QLFFDPQYUJ (integralayer.com):

Subdomain IP
testnet-rpc.integralayer.com 46.225.231.81
testnet-api.integralayer.com 46.225.231.81
testnet-evm.integralayer.com 46.225.231.81

Caddy — /etc/caddy/Caddyfile

testnet-rpc.integralayer.com {
    reverse_proxy localhost:26657
}

testnet-api.integralayer.com {
    reverse_proxy localhost:1317
}

testnet-evm.integralayer.com {
    handle_path /rpc {
        reverse_proxy localhost:8545
    }
    handle_path /rpc/* {
        reverse_proxy localhost:8545
    }
    handle /ws {
        reverse_proxy localhost:8546
    }
    handle {
        reverse_proxy localhost:8545
    }
}

Gotcha: UFW firewall must have ports 80 and 443 open for Let's Encrypt ACME challenge. Also open 1317, 8545, 8546.

ufw allow 80/tcp && ufw allow 443/tcp && ufw allow 1317/tcp && ufw allow 8545/tcp && ufw allow 8546/tcp && ufw reload

Phase 9: Key Backups

All keys backed up to ~/.integra-backups-testnet/{gateway,signer1,signer2}/ including priv_validator_key.json, node_key.json, and keyring-file/. Mnemonics saved to ~/.integra-backups-testnet/mnemonics.txt (chmod 600).


Issues Encountered & Resolutions

Issue 1: CGO Cross-Compilation Failure

Error: undefined: secp256k1.RecoverPubkey when building with CGO_ENABLED=0 Root cause: Cosmos EVM uses C bindings for secp256k1 cryptography Fix: Build natively on Linux with CGO_ENABLED=1 Mainnet impact: Must build on a Linux machine or use Docker

Issue 2: goal_bonded Must Be Positive

Error: goal bonded must be positive: 0.000000000000000000 during gentx Root cause: Cosmos SDK mint module validation rejects zero goal_bonded Fix: Set goal_bonded = "0.010000000000000000" (1%) Mainnet impact: Use 0.010000000000000000 for goal_bonded in genesis

Issue 3: Feemarket Base Fee Blocks Gentx

Error: fee not provided. The minimum global fee for this tx is: 1000000000000000000airl: insufficient fee Root cause: Genesis feemarket base_fee was set to 5000 gwei. Gentx transactions are created without fees, but DeliverTx enforces the fee floor during genesis. Fix: Set base_fee = "0" and min_gas_price = "0.000000000000000000" in feemarket genesis params. The actual fee floor is enforced post-launch by minimum-gas-prices in app.toml. Mainnet impact: CRITICAL — feemarket genesis base_fee MUST be "0". EIP-1559 base fee adjusts upward organically after block 1.

Issue 4: UFW Blocking Let's Encrypt

Error: Caddy ACME challenge timeout — "Timeout during connect (likely firewall problem)" Root cause: UFW only had ports 22 and 26656 open. Fix: ufw allow 80/tcp && ufw allow 443/tcp && ufw reload Mainnet impact: Always open 80/443 on any node running Caddy

Issue 5: SCP Glob Expansion Over SSH

Error: scp root@host:/path/*.json failed — zsh doesn't expand remote globs Fix: List files via SSH first, then SCP exact filenames Mainnet impact: Minor inconvenience


Final Verification

Block height:  163+ (and counting)
Genesis hash:  1dd8856029d8b5a90a995c53e028bd4e89d2c5e654a81e5d808b2dfacb1fcde2

Validators:
  Integra-Helsinki   — BONDED — 200,001,000 IRL — 33.3% VP
  Integra-Amsterdam  — BONDED — 200,001,000 IRL — 33.3% VP
  Integra-NewYork    — BONDED — 200,001,000 IRL — 33.3% VP

Endpoints:
  RPC:  https://testnet-rpc.integralayer.com  (TLS, block production confirmed)
  REST: https://testnet-api.integralayer.com  (TLS, validators query working)
  EVM:  https://testnet-evm.integralayer.com  (TLS, eth_chainId = 0x666a)

EVM Chain ID: 26218 (0x666a)
MetaMask RPC URL: https://testnet-evm.integralayer.com

Addendum: Post-Deployment Updates (Feb 26, 2026)

Validator Moniker Rename

  • Integra-NewYorkIntegra-SantaClara (reflects actual DigitalOcean datacenter in Santa Clara, CA)
  • On-chain tx: edit-validator --new-moniker "Integra-SantaClara"

DNS Consolidation

Old 3-subdomain approach replaced with single-domain path routing:

Old New
https://testnet-rpc.integralayer.com https://testnet.integralayer.com/rpc
https://testnet-api.integralayer.com https://testnet.integralayer.com/api
https://testnet-evm.integralayer.com https://testnet.integralayer.com/evm
(none) wss://testnet.integralayer.com/ws

Old subdomain DNS records deleted.

MetaMask / Wallet Config

RPC URL:  https://testnet.integralayer.com/evm
Chain ID: 26218
Symbol:   IRL
Explorer: https://testnet.blockscout.integralayer.com

Blockscout EVM Explorer

  • Deployed on gateway (46.225.231.81) at /opt/blockscout/
  • URL: https://testnet.blockscout.integralayer.com
  • Backend: blockscout/blockscout:7.0.2, Frontend: ghcr.io/blockscout/frontend:latest
  • Indexing Chain ID 26218, connected to local EVM node via host.docker.internal:8545

Current Validator Set

Integra-Helsinki    — BONDED — 200,001,000 IRL — 33.3% VP
Integra-Amsterdam   — BONDED — 200,001,000 IRL — 33.3% VP
Integra-SantaClara  — BONDED — 200,001,000 IRL — 33.3% VP
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment