GOAT Network
Sequencers

Running a Sequencer Node

In this guide, “sequencer node” and “validator” refer to the same operational role from different perspectives.

Ensure the host has persistent volumes for /data/goat and /data/geth, or update your compose file to match your preferred paths.

System Requirements

AreaRequirement
CPUEquivalent to c5.2xlarge or better
Storage40 GiB root disk plus a 100 GiB gp3 volume mounted to /data
NetworkIPv4 Elastic IP or another stable public IPv4 address
OSLinux, such as Ubuntu LTS
ToolingDocker, Docker Compose, and cast

Open Ports

PortProtocolSource
30303UDP0.0.0.0/0
30303TCP0.0.0.0/0
26656TCP0.0.0.0/0

Deployment

Fetch the compose file

Retrieve the correct docker-compose.yml from the GOAT Network release repository for your target network.

Start the services

Start sequencer services
docker compose up -d

Verify sync

Check node sync
docker compose exec goat goatd status | jq

Wait until "catching_up": false.

Back up /data/goat/config/priv_validator_key.json before continuing. Losing this key can block node recovery.

Validator Registration

There is no public website for validator registration yet. Continue only if you are comfortable with Solidity contract calls and Linux operations.

Generate the creation proof

Generate validator creation proof
GOAT_VALIDATOR_OWNER=0xYOUR_OWNER_ADDRESS
GOAT_GETH_CHAIN_ID=$(docker compose exec geth geth attach --exec 'Number(eth.chainId())')
docker compose exec goat goatd modgen locking sign \
  --owner "$GOAT_VALIDATOR_OWNER" \
  --eth-chain-id "$GOAT_GETH_CHAIN_ID"

GOAT_VALIDATOR_OWNER is the node administrator's EVM address. This owner is responsible for locking, redemption, and related validator operations.

Review the generated values

The output includes the validator address, owner address, public key, and signature required for registration.

Example creation proof output
{
  "owner": "0x",
  "pubkey": "0x2b4a44d655b6d5882f58997417320f98b9fcb9b9fb563ce089d462928a1bd0569359880e97221e5a8a1a5c1b4f012e61f4f75fc0937189600671532bcdb7cf0e",
  "signature": "0xe8d37ae31e755021b8dd63d1723730057998204d29a9f36b9464d82d3e47830051bca27cae8dd0ecd23e724ed74b031d0e14d1be3b9995f5a984dba947b2c3ee00",
  "validator": "0x3d2cc0ff49145113a46d576a269d291898c5138a"
}

Confirm the minimum locking threshold

Call creationThreshold() on the Locking contract to get the minimum locking amounts and confirm the owner wallet holds enough assets.

Read the locking threshold
cast call \
  --json \
  --rpc-url https://rpc.goat.network \
  0xbC10000000000000000000000000000000000004 \
  'creationThreshold()((address,uint256)[])'

Example mainnet response:

creationThreshold response
[
  "[(0x0000000000000000000000000000000000000000, 500000000000000000)]"
]

0xbC10000000000000000000000000000000000004 is the official Locking contract. In the response, the zero address represents the native token, Bitcoin. 500000000000000000 is the minimum amount required to create a validator. If the token address is not the zero address, approve the Locking contract before registration so it can spend the required token.

Coordinate final approval

If your target environment still requires whitelisting, complete the approval step with the GOAT Network team before broadcasting the creation transaction.

Register your validator

Call create() on the Locking contract to register the validator. The example below targets mainnet; change ETH_RPC_URL if you are working on another network.

Register validator on mainnet
ETH_RPC_URL=https://rpc.goat.network

VALIDATOR_PUBKEY=0x2b4a44d655b6d5882f58997417320f98b9fcb9b9fb563ce089d462928a1bd0569359880e97221e5a8a1a5c1b4f012e61f4f75fc0937189600671532bcdb7cf0e
VALIDATOR_SIGNATURE=0xe8d37ae31e755021b8dd63d1723730057998204d29a9f36b9464d82d3e47830051bca27cae8dd0ecd23e724ed74b031d0e14d1be3b9995f5a984dba947b2c3ee00
GOAT_LOCKING_CONTRACT=0xbC10000000000000000000000000000000000004
SIG_V=${VALIDATOR_SIGNATURE: -2}
SIG_V=$((16#$SIG_V + 27))
SIG_V=$(printf "0x%02X" "$SIG_V")

BITCOIN_LOCKING_VALUE=$(cast call --json $GOAT_LOCKING_CONTRACT 'tokens(address)(bool,uint64,uint256,uint256)' '0x0000000000000000000000000000000000000000' | jq -r '.[3]')

cast send -v --interactive --value $BITCOIN_LOCKING_VALUE $GOAT_LOCKING_CONTRACT 'create(bytes32[2],bytes32,bytes32,uint8)' \
  "[0x${VALIDATOR_PUBKEY:2:64},0x${VALIDATOR_PUBKEY:66:64}]" "0x${VALIDATOR_SIGNATURE:2:64}" "0x${VALIDATOR_SIGNATURE:66:64}" "${SIG_V}"

Use the VALIDATOR_PUBKEY and VALIDATOR_SIGNATURE generated in the creation proof step. The same operation is also available in the Hardhat locking task for teams that prefer scripted contract calls.

Next References

On this page