diff --git a/package.json b/package.json
index d256d69a..04eea2a7 100644
--- a/package.json
+++ b/package.json
@@ -124,7 +124,7 @@
         "_dist-stats": "gzip -k9f -S '.gz' ./dist/quais.min.js && gzip -k9f -S '.gz' ./dist/quais.umd.min.js && gzip -k9f -S '.gz' ./dist/wordlists-extra.min.js && du -hs ./dist/*.gz && echo '' && du -hs ./dist/*.js",
         "auto-build": "npm run build -- -w",
         "lint": "eslint src/**/*.ts --fix",
-        "build": "tsc --project tsconfig.esm.json",
+        "build": "tsc --project tsconfig.esm.json && cp ./misc/basedirs/lib.esm/package.json ./lib/esm",
         "build-all": "npm run build && npm run build-commonjs",
         "build-clean": "npm run clean && npm run build && npm run build-all && npm run _build-dist && npm run _dist-stats",
         "build-commonjs": "tsc --project tsconfig.commonjs.json",
diff --git a/src/_tests/test-providers-data.ts b/src/_tests/test-providers-data.ts
index fee4f365..467eff56 100644
--- a/src/_tests/test-providers-data.ts
+++ b/src/_tests/test-providers-data.ts
@@ -8,8 +8,9 @@ import assert from 'assert';
 //import type { Provider } from "../index.js";
 import { getTxType, quais } from '../index.js';
 import axios from 'axios';
-import { stall } from "./utils.js";
-import dotenv from "dotenv";
+import { stall } from './utils.js';
+import dotenv from 'dotenv';
+import { Shard } from '../constants/index.js';
 dotenv.config();
 // import {
 //     networkFeatureAtBlock, networkNames,
@@ -20,13 +21,12 @@ dotenv.config();
 
 //setupProviders();
 
-
 const providerC1 = new quais.JsonRpcProvider(process.env.CYPRUS1URL);
 const privateKey = process.env.CYPRUS1PK;
-console.log(privateKey)
+console.log(privateKey);
 const wallet = new quais.Wallet(process.env.CYPRUS1PK || '', providerC1);
-const destinationC1 = '0x0047f9CEa7662C567188D58640ffC48901cde02a'
-const destinationC2 = '0x011ae0a1Bd5B71b4F16F8FdD3AEF278C3D042449'
+const destinationC1 = '0x0047f9CEa7662C567188D58640ffC48901cde02a';
+const destinationC2 = '0x011ae0a1Bd5B71b4F16F8FdD3AEF278C3D042449';
 
 function equals(name: string, actual: any, expected: any): void {
     if (expected && expected.eq) {
@@ -100,43 +100,43 @@ async function getRPCGasPrice(url: string | undefined) {
 async function sendTransaction(to: string) {
     let txResponse;
     let typeValue;
-    try{
-        console.log("Nonce: ", await providerC1.getTransactionCount(wallet.address, 'latest'),)
-        do{
-        typeValue = getTxType(wallet.address, to);
-        const gas = await getRPCGasPrice(process.env.CYPRUS1URL);
-        let tx: {
-            from: string;
-            to: string;
-            value: any;  
-            gasPrice: any;
-            maxFeePerGas: any;
-            maxPriorityFeePerGas:any;
-            nonce: number;
-            data: string;
-            type: number;
-            gasLimit: number;
-            chainId: number;
-            etxGasLimit?: any;
-            etxGasTip?: any;
-            etxGasPrice?: any;
-        } = {
-            from: wallet.address,
-            to,
-            value: quais.parseEther("0.1"),  // Sending 0.1 ether
-            gasPrice: gas*2,
-            maxFeePerGas: quais.parseUnits('20', 'gwei'),
-            maxPriorityFeePerGas: quais.parseUnits('20', 'gwei'),
-            nonce: await providerC1.getTransactionCount(wallet.address, 'latest'),
-            data: '',
-            type: typeValue,
-            gasLimit: typeValue == 0 ? 21000 : 42000,
-            chainId: Number(process.env.CHAIN_ID || 1337),
-        };
-        txResponse = await wallet.sendTransaction(tx);
-        console.log(txResponse)
-        await stall(15000);
-    } while (txResponse.hash == null);
+    try {
+        console.log('Nonce: ', await providerC1.getTransactionCount(wallet.address, 'latest'));
+        do {
+            typeValue = getTxType(wallet.address, to);
+            const gas = await getRPCGasPrice(process.env.CYPRUS1URL);
+            const tx: {
+                from: string;
+                to: string;
+                value: any;
+                gasPrice: any;
+                maxFeePerGas: any;
+                maxPriorityFeePerGas: any;
+                nonce: number;
+                data: string;
+                type: number;
+                gasLimit: number;
+                chainId: number;
+                etxGasLimit?: any;
+                etxGasTip?: any;
+                etxGasPrice?: any;
+            } = {
+                from: wallet.address,
+                to,
+                value: quais.parseEther('0.1'), // Sending 0.1 ether
+                gasPrice: gas * 2,
+                maxFeePerGas: quais.parseUnits('20', 'gwei'),
+                maxPriorityFeePerGas: quais.parseUnits('20', 'gwei'),
+                nonce: await providerC1.getTransactionCount(wallet.address, 'latest'),
+                data: '',
+                type: typeValue,
+                gasLimit: typeValue == 0 ? 21000 : 42000,
+                chainId: Number(process.env.CHAIN_ID || 1337),
+            };
+            txResponse = await wallet.sendTransaction(tx);
+            console.log(txResponse);
+            await stall(15000);
+        } while (txResponse.hash == null);
 
         console.log(`Transaction hash for type ${typeValue}: `, txResponse.hash);
         return txResponse;
@@ -152,16 +152,13 @@ async function fetchRPCBlock(blockNumber: string | null) {
     try {
         let response;
         do {
-        response = await axios.post(process.env.CYPRUS1URL || "http://localhost:8610", {
-        jsonrpc: "2.0",
-        method: "quai_getBlockByNumber",
-        params: [
-            blockNumber || '0xA',
-            false
-        ],
-        id: 1
-        });
-    }while (response?.data?.result?.woHeader?.headerHash == null)
+            response = await axios.post(process.env.CYPRUS1URL || 'http://localhost:8610', {
+                jsonrpc: '2.0',
+                method: 'quai_getBlockByNumber',
+                params: [blockNumber || '0xA', false],
+                id: 1,
+            });
+        } while (response?.data?.result?.woHeader?.headerHash == null);
         return response.data.result;
     } catch (error: any) {
         throw error;
@@ -242,7 +239,7 @@ describe('Test Provider Block operations', function () {
     });
 
     it('should fetch block by number', async function () {
-        const responseBlock = (await providerC1.getBlock('0,0', '0xA')) as quais.Block;
+        const responseBlock = (await providerC1.getBlock(Shard.Cyprus1, '0xA')) as quais.Block;
         assert.ok(responseBlock != null, 'block != null');
         // TODO: `provider` is not used, remove?
         // eslint-disable-next-line @typescript-eslint/no-unused-vars
@@ -256,7 +253,7 @@ describe('Test Provider Block operations', function () {
 
     it('should fetch block by hash', async function () {
         assert.ok(block.hash != null, 'block.hash != null');
-        const responseBlock = (await providerC1.getBlock('0,0', block.hash)) as quais.Block;
+        const responseBlock = (await providerC1.getBlock(Shard.Paxos2, block.hash)) as quais.Block;
         assert.ok(responseBlock != null, 'block != null');
         // TODO: `provider` is not used, remove?
         // eslint-disable-next-line @typescript-eslint/no-unused-vars
@@ -274,8 +271,8 @@ describe('Test Transaction operations', function () {
     let internalToExternalTx: any;
 
     it('should fetch balance after internal tx', async function () {
-        this.timeout(60000)
-        const oldBal = await fetchRPCBalance(destinationC1, process.env.CYPRUS1URL || "http://localhost:8610");
+        this.timeout(60000);
+        const oldBal = await fetchRPCBalance(destinationC1, process.env.CYPRUS1URL || 'http://localhost:8610');
         internalTx = await sendTransaction(destinationC1);
         await stall(30000);
         const expectedBal = BigInt(internalTx.value);
@@ -283,11 +280,13 @@ describe('Test Transaction operations', function () {
         const actualBal = Number(balance) - Number(oldBal);
         const tolerance = 1e-6; // Define a small tolerance level
 
-        const withinTolerance = Math.abs((actualBal - Number(expectedBal)) * 100 / Number(expectedBal)) <= tolerance;
-        assert(withinTolerance, `Actual balance ${actualBal} is not within the acceptable range of expected balance ${Number(expectedBal)}`);
+        const withinTolerance = Math.abs(((actualBal - Number(expectedBal)) * 100) / Number(expectedBal)) <= tolerance;
+        assert(
+            withinTolerance,
+            `Actual balance ${actualBal} is not within the acceptable range of expected balance ${Number(expectedBal)}`,
+        );
 
-
-        const receipt = await fetchRPCTxReceipt(internalTx.hash, process.env.CYPRUS1URL || "http://localhost:8610");
+        const receipt = await fetchRPCTxReceipt(internalTx.hash, process.env.CYPRUS1URL || 'http://localhost:8610');
         const expectedReceipt = {
             blockHash: receipt.blockHash,
             contractAddress: receipt.contractAddress || null,
@@ -312,16 +311,18 @@ describe('Test Transaction operations', function () {
             ...receiptResponse,
             logs: receiptResponse?.logs,
         };
-        console.log(receiptResult.blockHash)
-        equals("Internal Tx Receipt", receiptResult, expectedReceipt);
-
+        console.log(receiptResult.blockHash);
+        equals('Internal Tx Receipt', receiptResult, expectedReceipt);
     });
 
     it('should fetch transaction receipt for internal to external tx', async function () {
         this.timeout(120000);
         internalToExternalTx = await sendTransaction(destinationC2);
         await stall(60000);
-        const receipt = await fetchRPCTxReceipt(internalToExternalTx.hash, process.env.CYPRUS1URL || "http://localhost:8610");
+        const receipt = await fetchRPCTxReceipt(
+            internalToExternalTx.hash,
+            process.env.CYPRUS1URL || 'http://localhost:8610',
+        );
         await stall(30000);
         const etx = receipt.etxs[0];
         const expectedReceipt = {
diff --git a/src/constants/index.ts b/src/constants/index.ts
index dc26531b..438634af 100644
--- a/src/constants/index.ts
+++ b/src/constants/index.ts
@@ -4,15 +4,10 @@
  * @_section: api/constants: Constants  [about-constants]
  */
 
-export { ZeroAddress } from "./addresses.js";
-export { ZeroHash } from "./hashes.js";
-export {
-    N,
-    WeiPerEther,
-    MaxUint256,
-    MinInt256,
-    MaxInt256
-} from "./numbers.js";
-export { quaisymbol, MessagePrefix } from "./strings.js";
-export { ShardData } from "./shards.js";
-export { QI_COIN_TYPE, QUAI_COIN_TYPE } from "./coins.js";
+export { ZeroAddress } from './addresses.js';
+export { ZeroHash } from './hashes.js';
+export { N, WeiPerEther, MaxUint256, MinInt256, MaxInt256 } from './numbers.js';
+export { quaisymbol, MessagePrefix } from './strings.js';
+export { toShard, Shard, ShardData } from './shards.js';
+export { toZone, Zone, ZoneData } from './zones.js';
+export { QI_COIN_TYPE, QUAI_COIN_TYPE } from './coins.js';
diff --git a/src/constants/shards.ts b/src/constants/shards.ts
index 63c84ec3..bc7da889 100644
--- a/src/constants/shards.ts
+++ b/src/constants/shards.ts
@@ -1,72 +1,72 @@
+import { ZoneData } from './zones.js';
+
+export enum Shard {
+    Cyprus = '0x0',
+    Cyprus1 = '0x00',
+    Cyprus2 = '0x01',
+    Cyprus3 = '0x02',
+    Paxos = '0x1',
+    Paxos1 = '0x10',
+    Paxos2 = '0x11',
+    Paxos3 = '0x12',
+    Hydra = '0x2',
+    Hydra1 = '0x20',
+    Hydra2 = '0x21',
+    Hydra3 = '0x22',
+    Prime = '0x',
+}
+
+function shardFromBytes(shard: string): Shard {
+    switch (shard) {
+        case '0x00':
+            return Shard.Cyprus1;
+        case '0x01':
+            return Shard.Cyprus2;
+        case '0x02':
+            return Shard.Cyprus3;
+        case '0x10':
+            return Shard.Paxos1;
+        case '0x11':
+            return Shard.Paxos2;
+        case '0x12':
+            return Shard.Paxos3;
+        case '0x20':
+            return Shard.Hydra1;
+        case '0x21':
+            return Shard.Hydra2;
+        case '0x22':
+            return Shard.Hydra3;
+        default:
+            throw new Error('Invalid shard');
+    }
+}
 /**
  * Constant data that defines each shard within the network.
  *
  * @category Constants
  */
-
 export const ShardData = [
+    ...ZoneData,
     {
-        name: 'Cyprus One',
-        nickname: 'cyprus1',
-        shard: 'zone-0-0',
-        context: 2,
-        byte: '0x00', //0000 0000 region-0 zone-0
-    },
-    {
-        name: 'Cyprus Two',
-        nickname: 'cyprus2',
-        shard: 'zone-0-1',
-        context: 2,
-        byte: '0x01', // 0000 0001 region-0 zone-1
-    },
-    {
-        name: 'Cyprus Three',
-        nickname: 'cyprus3',
-        shard: 'zone-0-2',
-        context: 2,
-        byte: '0x02', // 0000 0010 region-0 zone-2
-    },
-    {
-        name: 'Paxos One',
-        nickname: 'paxos1',
-        shard: 'zone-1-0',
-        context: 2,
-        byte: '0x10', // 0001 0000 region-1 zone-0
-    },
-    {
-        name: 'Paxos Two',
-        nickname: 'paxos2',
-        shard: 'zone-1-1',
+        name: 'Cyprus',
+        nickname: 'cyprus',
+        shard: 'region-0',
         context: 2,
-        byte: '0x11', // 0001 0001 region-1 zone-1
+        byte: '0x0',
     },
     {
-        name: 'Paxos Three',
-        nickname: 'paxos3',
-        shard: 'zone-1-2',
+        name: 'Paxos',
+        nickname: 'paxos',
+        shard: 'region-1',
         context: 2,
-        byte: '0x12', // 0001 0010 region-1 zone-2
+        byte: '0x1',
     },
     {
-        name: 'Hydra One',
-        nickname: 'hydra1',
-        shard: 'zone-2-0',
+        name: 'Hydra',
+        nickname: 'hydra',
+        shard: 'region-2',
         context: 2,
-        byte: '0x20', // 0010 0000 region-2 zone-0
-    },
-    {
-        name: 'Hydra Two',
-        nickname: 'hydra2',
-        shard: 'zone-2-1',
-        context: 2,
-        byte: '0x21', // 0010 0001 region-2 zone-1
-    },
-    {
-        name: 'Hydra Three',
-        nickname: 'hydra3',
-        shard: 'zone-2-2',
-        context: 2,
-        byte: '0x22', // 0010 0010 region-2 zone-2
+        byte: '0x2',
     },
     {
         name: 'Prime',
@@ -76,3 +76,10 @@ export const ShardData = [
         byte: '0x',
     },
 ];
+
+export function toShard(shard: string): Shard {
+    return shardFromBytes(
+        ShardData.find((it) => it.name == shard || it.byte == shard || it.nickname == shard || it.shard == shard)
+            ?.byte || '',
+    );
+}
diff --git a/src/constants/zones.ts b/src/constants/zones.ts
new file mode 100644
index 00000000..0599c62e
--- /dev/null
+++ b/src/constants/zones.ts
@@ -0,0 +1,109 @@
+export enum Zone {
+    Cyprus1 = '0x00',
+    Cyprus2 = '0x01',
+    Cyprus3 = '0x02',
+    Paxos1 = '0x10',
+    Paxos2 = '0x11',
+    Paxos3 = '0x12',
+    Hydra1 = '0x20',
+    Hydra2 = '0x21',
+    Hydra3 = '0x22',
+}
+
+function zoneFromBytes(zone: string): Zone {
+    switch (zone) {
+        case '0x00':
+            return Zone.Cyprus1;
+        case '0x01':
+            return Zone.Cyprus2;
+        case '0x02':
+            return Zone.Cyprus3;
+        case '0x10':
+            return Zone.Paxos1;
+        case '0x11':
+            return Zone.Paxos2;
+        case '0x12':
+            return Zone.Paxos3;
+        case '0x20':
+            return Zone.Hydra1;
+        case '0x21':
+            return Zone.Hydra2;
+        case '0x22':
+            return Zone.Hydra3;
+        default:
+            throw new Error('Invalid zone');
+    }
+}
+
+export const ZoneData = [
+    {
+        name: 'Cyprus One',
+        nickname: 'cyprus1',
+        shard: 'zone-0-0',
+        context: 2,
+        byte: '0x00', //0000 0000 region-0 zone-0
+    },
+    {
+        name: 'Cyprus Two',
+        nickname: 'cyprus2',
+        shard: 'zone-0-1',
+        context: 2,
+        byte: '0x01', // 0000 0001 region-0 zone-1
+    },
+    {
+        name: 'Cyprus Three',
+        nickname: 'cyprus3',
+        shard: 'zone-0-2',
+        context: 2,
+        byte: '0x02', // 0000 0010 region-0 zone-2
+    },
+    {
+        name: 'Paxos One',
+        nickname: 'paxos1',
+        shard: 'zone-1-0',
+        context: 2,
+        byte: '0x10', // 0001 0000 region-1 zone-0
+    },
+    {
+        name: 'Paxos Two',
+        nickname: 'paxos2',
+        shard: 'zone-1-1',
+        context: 2,
+        byte: '0x11', // 0001 0001 region-1 zone-1
+    },
+    {
+        name: 'Paxos Three',
+        nickname: 'paxos3',
+        shard: 'zone-1-2',
+        context: 2,
+        byte: '0x12', // 0001 0010 region-1 zone-2
+    },
+    {
+        name: 'Hydra One',
+        nickname: 'hydra1',
+        shard: 'zone-2-0',
+        context: 2,
+        byte: '0x20', // 0010 0000 region-2 zone-0
+    },
+    {
+        name: 'Hydra Two',
+        nickname: 'hydra2',
+        shard: 'zone-2-1',
+        context: 2,
+        byte: '0x21', // 0010 0001 region-2 zone-1
+    },
+    {
+        name: 'Hydra Three',
+        nickname: 'hydra3',
+        shard: 'zone-2-2',
+        context: 2,
+        byte: '0x22', // 0010 0010 region-2 zone-2
+    },
+];
+
+export function toZone(shard: string): Zone {
+    return zoneFromBytes(
+        ZoneData.find((it) => it.name == shard || it.byte == shard || it.nickname == shard || it.shard == shard)
+            ?.byte || '',
+    );
+}
diff --git a/src/contract/contract.ts b/src/contract/contract.ts
index fea12455..2c1c557a 100644
--- a/src/contract/contract.ts
+++ b/src/contract/contract.ts
@@ -46,6 +46,7 @@ import type {
     DeferredTopicFilter,
     WrappedFallback,
 } from './types.js';
+import { toShard, Zone } from '../constants/index.js';
 
 const BN_0 = BigInt(0);
 
@@ -1032,7 +1033,7 @@ export class BaseContract implements Addressable, EventEmitterable<ContractEvent
      * Provide historic access to event data for `event` in the range `fromBlock` (default: `0`) to `toBlock` (default:
      * `"latest"`) inclusive.
      *
-     * @param {string} shard - The shard to query.
+     * @param {Zone} zone - The zone to query.
      * @param {ContractEventName} event - The event to query.
      * @param {BlockTag} fromBlock - The block to start querying from.
      * @param {BlockTag} toBlock - The block to stop querying at.
@@ -1040,7 +1041,7 @@ export class BaseContract implements Addressable, EventEmitterable<ContractEvent
      * @returns An array of event logs.
      */
     async queryFilter(
-        shard: string,
+        zone: Zone,
         event: ContractEventName,
         fromBlock?: BlockTag,
         toBlock?: BlockTag,
@@ -1054,7 +1055,7 @@ export class BaseContract implements Addressable, EventEmitterable<ContractEvent
         const { addr, addrPromise } = getInternal(this);
         const address = addr ? addr : await addrPromise;
         const { fragment, topics } = await getSubInfo(this, event);
-        const filter = { address, topics, fromBlock, toBlock, shard: shard };
+        const filter = { address, topics, fromBlock, toBlock, shard: toShard(zone) };
 
         const provider = getProvider(this.runner);
         assert(provider, 'contract runner does not have a provider', 'UNSUPPORTED_OPERATION', {
diff --git a/src/contract/factory.ts b/src/contract/factory.ts
index 87e6c59e..304a5dd0 100644
--- a/src/contract/factory.ts
+++ b/src/contract/factory.ts
@@ -6,7 +6,7 @@ import { BaseContract, copyOverrides, resolveArgs } from './contract.js';
 import type { InterfaceAbi } from '../abi/index.js';
 import type { Addressable } from '../address/index.js';
 import type { BytesLike } from '../utils/index.js';
-import { getShardForAddress, isQiAddress } from '../utils/index.js';
+import { getZoneForAddress, isQiAddress } from '../utils/index.js';
 import type { ContractInterface, ContractMethodArgs, ContractDeployTransaction, ContractRunner } from './types.js';
 import type { ContractTransactionResponse } from './wrappers.js';
 import { Wallet, randomBytes } from '../quais.js';
@@ -164,14 +164,14 @@ export class ContractFactory<A extends Array<any> = Array<any>, I = BaseContract
         }
 
         const sender = String(tx.from);
-        const toShard = getShardForAddress(sender);
+        const toShard = getZoneForAddress(sender);
         let i = 0;
         const startingData = tx.data;
         while (i < 10000) {
-            var contractAddress = getContractAddress(sender, BigInt(tx.nonce || 0), tx.data || '');
-            var contractShard = getShardForAddress(contractAddress);
-            console.log("contractAddress ", contractAddress);
-            var utxo = isQiAddress(contractAddress);
+            const contractAddress = getContractAddress(sender, BigInt(tx.nonce || 0), tx.data || '');
+            const contractShard = getZoneForAddress(contractAddress);
+            console.log('contractAddress ', contractAddress);
+            const utxo = isQiAddress(contractAddress);
             if (contractShard === toShard && !utxo) {
                 return tx;
             }
diff --git a/src/contract/wrappers.ts b/src/contract/wrappers.ts
index e28d41ba..bc5b793f 100644
--- a/src/contract/wrappers.ts
+++ b/src/contract/wrappers.ts
@@ -9,6 +9,7 @@ import type { Provider } from '../providers/index.js';
 
 import type { BaseContract } from './contract.js';
 import type { ContractEventName } from './types.js';
+import { Shard } from '../constants/index.js';
 
 /**
  * An **EventLog** contains additional properties parsed from the {@link Log | **Log**}.
@@ -170,11 +171,11 @@ export class ContractUnknownEventPayload extends EventPayload<ContractEventName>
     /**
      * Resolves to the block the event occured in.
      *
-     * @param {string} shard - The shard to get the block from.
+     * @param {Shard} shard - The shard to get the block from.
      *
      * @returns {Promise<Block>} A promise resolving to the block the event occured in.
      */
-    async getBlock(shard: string): Promise<Block> {
+    async getBlock(shard: Shard): Promise<Block> {
         return await this.log.getBlock(shard);
     }
 
diff --git a/src/providers/abstract-provider.ts b/src/providers/abstract-provider.ts
index 831d92b9..cf0becc8 100644
--- a/src/providers/abstract-provider.ts
+++ b/src/providers/abstract-provider.ts
@@ -8,14 +8,14 @@
 
 // @TODO
 // Event coalescence
-//   When we register an event with an async value (e.g. address is a Signer), 
+//   When we register an event with an async value (e.g. address is a Signer),
 //   we need to add it immeidately for the Event API, but also
 //   need time to resolve the address. Upon resolving the address, we need to
 //   migrate the listener to the static event. We also need to maintain a map
 //   of Signer to address so we can sync respond to listenerCount.
 
 import { getAddress, resolveAddress } from '../address/index.js';
-import { ShardData } from '../constants/index.js';
+import { Shard, toShard, toZone, Zone } from '../constants/index.js';
 import { TxInput, TxOutput } from '../transaction/index.js';
 import { Outpoint } from '../transaction/utxo.js';
 import {
@@ -74,11 +74,11 @@ import type {
     Provider,
     ProviderEvent,
     TransactionRequest,
-} from "./provider.js";
-import { WorkObjectLike } from "../transaction/work-object.js";
-import {QiTransaction, QuaiTransaction} from "../transaction/index.js";
-import {QuaiTransactionResponseParams} from "./formatting.js";
-import {keccak256, SigningKey} from "../crypto/index.js";
+} from './provider.js';
+import { WorkObjectLike } from '../transaction/work-object.js';
+import { QiTransaction, QuaiTransaction } from '../transaction/index.js';
+import { QuaiTransactionResponseParams } from './formatting.js';
+import { keccak256, SigningKey } from '../crypto/index.js';
 
 type Timer = ReturnType<typeof setTimeout>;
 
@@ -363,13 +363,13 @@ export type PerformActionFilter =
           topics?: Array<null | string | Array<string>>;
           fromBlock?: BlockTag;
           toBlock?: BlockTag;
-          shard: string;
+          shard: Shard;
       }
     | {
           address?: string | Array<string>;
           topics?: Array<null | string | Array<string>>;
           blockHash?: string;
-          shard: string;
+          shard: Shard;
       };
 
 /**
@@ -425,117 +425,117 @@ export type PerformActionRequest =
     | {
           method: 'broadcastTransaction';
           signedTransaction: string;
-          shard: string;
+          zone: Zone;
       }
     | {
           method: 'call';
           transaction: PerformActionTransaction;
           blockTag: BlockTag;
-          shard?: string;
+          zone?: Zone;
       }
     | {
           method: 'chainId';
-          shard?: string;
+          zone?: Zone;
       }
     | {
           method: 'estimateGas';
           transaction: PerformActionTransaction;
-          shard?: string;
+          zone?: Zone;
       }
     | {
           method: 'getBalance';
           address: string;
           blockTag: BlockTag;
-          shard: string;
+          zone: Zone;
       }
     | {
           method: 'getOutpointsByAddress';
           address: string;
-          shard: string;
+          zone: Zone;
       }
     | {
           method: 'getBlock';
           blockTag: BlockTag;
           includeTransactions: boolean;
-          shard: string;
+          shard: Shard;
       }
     | {
           method: 'getBlock';
           blockHash: string;
           includeTransactions: boolean;
-          shard: string;
+          shard: Shard;
       }
     | {
           method: 'getBlockNumber';
-          shard?: string;
+          shard?: Shard;
       }
     | {
           method: 'getCode';
           address: string;
           blockTag: BlockTag;
-          shard: string;
+          zone: Zone;
       }
     | {
           method: 'getGasPrice';
           txType: boolean;
-          shard?: string;
+          zone?: Zone;
       }
     | {
           method: 'getLogs';
           filter: PerformActionFilter;
-          shard: string;
+          zone: Zone;
       }
     | {
           method: 'getMaxPriorityFeePerGas';
-          shard?: string;
+          zone?: Zone;
       }
     | {
           method: 'getStorage';
           address: string;
           position: bigint;
           blockTag: BlockTag;
-          shard: string;
+          zone: Zone;
       }
     | {
           method: 'getTransaction';
           hash: string;
-          shard: string;
+          zone: Zone;
       }
     | {
           method: 'getTransactionCount';
           address: string;
           blockTag: BlockTag;
-          shard: string;
+          zone: Zone;
       }
     | {
           method: 'getTransactionReceipt';
           hash: string;
-          shard: string;
+          zone: Zone;
       }
     | {
           method: 'getTransactionResult';
           hash: string;
-          shard: string;
+          zone: Zone;
       }
     | {
           method: 'getRunningLocations';
-          shard?: string;
+          shard?: Shard;
       }
     | {
           method: 'getProtocolTrieExpansionCount';
-          shard: string;
+          shard: Shard;
       }
     | {
           method: 'getQiRateAtBlock';
           blockTag: BlockTag;
           amt: number;
-          shard: string;
+          zone: Zone;
       }
     | {
           method: 'getQuaiRateAtBlock';
           blockTag: BlockTag;
           amt: number;
-          shard: string;
+          zone: Zone;
       }
     | {
           method: 'getProtocolExpansionNumber';
@@ -581,7 +581,7 @@ const defaultOptions = {
  * @category Providers
  */
 export class AbstractProvider<C = FetchRequest> implements Provider {
-    _urlMap: Map<string, C>;
+    _urlMap: Map<Shard, C>;
     #connect: FetchRequest[];
     #subs: Map<string, Sub>;
     #plugins: Map<string, AbstractProviderPlugin>;
@@ -649,13 +649,13 @@ export class AbstractProvider<C = FetchRequest> implements Provider {
     async initUrlMap<U = string[] | FetchRequest>(urls: U): Promise<void> {
         if (urls instanceof FetchRequest) {
             urls.url = urls.url.split(':')[0] + ':' + urls.url.split(':')[1] + ':9001';
-            this._urlMap.set('0x', urls as C);
+            this._urlMap.set(Shard.Prime, urls as C);
             this.#connect.push(urls);
             const shards = await this.getRunningLocations();
             shards.forEach((shard) => {
                 const port = 9200 + 20 * shard[0] + shard[1];
                 this._urlMap.set(
-                    `0x${shard[0].toString(16)}${shard[1].toString(16)}`,
+                    toShard(`0x${shard[0].toString(16)}${shard[1].toString(16)}`),
                     new FetchRequest(urls.url.split(':')[0] + ':' + urls.url.split(':')[1] + ':' + port) as C,
                 );
             });
@@ -665,13 +665,13 @@ export class AbstractProvider<C = FetchRequest> implements Provider {
             for (const url of urls) {
                 const primeUrl = url.split(':')[0] + ':' + url.split(':')[1] + ':9001';
                 const primeConnect = new FetchRequest(primeUrl);
-                this._urlMap.set('0x', primeConnect as C);
+                this._urlMap.set(Shard.Prime, primeConnect as C);
                 this.#connect.push(primeConnect);
                 const shards = await this.getRunningLocations();
                 shards.forEach((shard) => {
                     const port = 9200 + 20 * shard[0] + shard[1];
                     this._urlMap.set(
-                        `0x${shard[0].toString(16)}${shard[1].toString(16)}`,
+                        toShard(`0x${shard[0].toString(16)}${shard[1].toString(16)}`),
                         new FetchRequest(url.split(':')[0] + ':' + url.split(':')[1] + ':' + port) as C,
                     );
                 });
@@ -679,33 +679,26 @@ export class AbstractProvider<C = FetchRequest> implements Provider {
         }
     }
 
-    shardBytes(shard: string): string {
-        return (
-            ShardData.find((it) => it.name == shard || it.byte == shard || it.nickname == shard || it.shard == shard)
-                ?.byte || ''
-        );
-    }
-
     get connect(): FetchRequest[] {
         return this.#connect;
     }
 
-    async shardFromAddress(_address: AddressLike): Promise<string> {
+    async zoneFromAddress(_address: AddressLike): Promise<Zone> {
         const address: string | Promise<string> = this._getAddress(_address);
-        return (await address).slice(0, 4);
+        return toZone((await address).slice(0, 4));
     }
 
-    shardFromHash(hash: string): string {
-        return hash.slice(0, 4);
+    shardFromHash(hash: string): Shard {
+        return toShard(hash.slice(0, 4));
     }
 
-    async getLatestQuaiRate(shard: string, amt: number = 1): Promise<bigint> {
-        const blockNumber = await this.getBlockNumber(shard);
-        return this.getQuaiRateAtBlock(shard, blockNumber, amt);
+    async getLatestQuaiRate(zone: Zone, amt: number = 1): Promise<bigint> {
+        const blockNumber = await this.getBlockNumber(toShard(zone));
+        return this.getQuaiRateAtBlock(zone, blockNumber, amt);
     }
 
-    async getQuaiRateAtBlock(shard: string, blockTag: BlockTag, amt: number = 1): Promise<bigint> {
-        let resolvedBlockTag = this._getBlockTag(shard, blockTag);
+    async getQuaiRateAtBlock(zone: Zone, blockTag: BlockTag, amt: number = 1): Promise<bigint> {
+        let resolvedBlockTag = this._getBlockTag(toShard(zone), blockTag);
         if (typeof resolvedBlockTag !== 'string') {
             resolvedBlockTag = await resolvedBlockTag;
         }
@@ -714,7 +707,7 @@ export class AbstractProvider<C = FetchRequest> implements Provider {
             method: 'getQuaiRateAtBlock',
             blockTag: resolvedBlockTag,
             amt,
-            shard: shard,
+            zone: zone,
         });
     }
 
@@ -724,13 +717,13 @@ export class AbstractProvider<C = FetchRequest> implements Provider {
         });
     }
 
-    async getLatestQiRate(shard: string, amt: number = 1): Promise<bigint> {
-        const blockNumber = await this.getBlockNumber(shard);
-        return this.getQiRateAtBlock(shard, blockNumber, amt);
+    async getLatestQiRate(zone: Zone, amt: number = 1): Promise<bigint> {
+        const blockNumber = await this.getBlockNumber(toShard(zone));
+        return this.getQiRateAtBlock(zone, blockNumber, amt);
     }
 
-    async getQiRateAtBlock(shard: string, blockTag: BlockTag, amt: number = 1): Promise<bigint> {
-        let resolvedBlockTag = this._getBlockTag(shard, blockTag);
+    async getQiRateAtBlock(zone: Zone, blockTag: BlockTag, amt: number = 1): Promise<bigint> {
+        let resolvedBlockTag = this._getBlockTag(toShard(zone), blockTag);
         if (typeof resolvedBlockTag !== 'string') {
             resolvedBlockTag = await resolvedBlockTag;
         }
@@ -739,7 +732,7 @@ export class AbstractProvider<C = FetchRequest> implements Provider {
             method: 'getQiRateAtBlock',
             blockTag: resolvedBlockTag,
             amt,
-            shard: shard,
+            zone: zone,
         });
     }
 
@@ -886,12 +879,12 @@ export class AbstractProvider<C = FetchRequest> implements Provider {
      *
      * Sub-classes **must** override this.
      *
-     * @param {string} [shard] - The shard to use for the network detection.
+     * @param {Shard} [shard] - The shard to use for the network detection.
      *
      * @returns {Promise<Network>} A promise resolving to the network.
      */
     // eslint-disable-next-line @typescript-eslint/no-unused-vars
-    _detectNetwork(shard?: string): Promise<Network> {
+    _detectNetwork(shard?: Shard): Promise<Network> {
         assert(false, 'sub-classes must implement this', 'UNSUPPORTED_OPERATION', {
             operation: '_detectNetwork',
         });
@@ -916,7 +909,7 @@ export class AbstractProvider<C = FetchRequest> implements Provider {
 
     // State
 
-    async getBlockNumber(shard?: string): Promise<number> {
+    async getBlockNumber(shard?: Shard): Promise<number> {
         const blockNumber = getNumber(await this.#perform({ method: 'getBlockNumber', shard: shard }), '%response');
         if (this.#lastBlockNumber >= 0) {
             this.#lastBlockNumber = blockNumber;
@@ -925,8 +918,8 @@ export class AbstractProvider<C = FetchRequest> implements Provider {
     }
 
     /**
-     * Returns or resolves to the address for `address`, resolving {@link Addressable | **Addressable**}
-     * objects and returning if already an address.
+     * Returns or resolves to the address for `address`, resolving {@link Addressable | **Addressable**} objects and
+     * returning if already an address.
      *
      * @param {AddressLike} address - The address to normalize.
      *
@@ -940,12 +933,12 @@ export class AbstractProvider<C = FetchRequest> implements Provider {
      * Returns or resolves to a valid block tag for `blockTag`, resolving negative values and returning if already a
      * valid block tag.
      *
-     * @param {string} [shard] - The shard to use for the block tag.
+     * @param {Shard} [shard] - The shard to use for the block tag.
      * @param {BlockTag} [blockTag] - The block tag to normalize.
      *
      * @returns {string | Promise<string>} A promise that resolves to a valid block tag.
      */
-    _getBlockTag(shard?: string, blockTag?: BlockTag): string | Promise<string> {
+    _getBlockTag(shard?: Shard, blockTag?: BlockTag): string | Promise<string> {
         if (blockTag == null) {
             return 'latest';
         }
@@ -985,8 +978,8 @@ export class AbstractProvider<C = FetchRequest> implements Provider {
     }
 
     /**
-     * Returns or resolves to a filter for `filter`, resolving any {@link Addressable | **Addressable**}
-     * object and returning if already a valid filter.
+     * Returns or resolves to a filter for `filter`, resolving any {@link Addressable | **Addressable**} object and
+     * returning if already a valid filter.
      *
      * @param {Filter | FilterByBlockHash} filter - The filter to normalize.
      *
@@ -1006,7 +999,7 @@ export class AbstractProvider<C = FetchRequest> implements Provider {
 
         const blockHash = 'blockHash' in filter ? filter.blockHash : undefined;
 
-        const resolve = (_address: Array<string>, fromBlock?: string, toBlock?: string, shard?: string) => {
+        const resolve = (_address: Array<string>, fromBlock?: string, toBlock?: string, shard?: Shard) => {
             let address: undefined | string | Array<string> = undefined;
             switch (_address.length) {
                 case 0:
@@ -1086,8 +1079,8 @@ export class AbstractProvider<C = FetchRequest> implements Provider {
     }
 
     /**
-     * Returns or resovles to a transaction for `request`, resolving any
-     * {@link Addressable | **Addressable**} and returning if already a valid transaction.
+     * Returns or resovles to a transaction for `request`, resolving any {@link Addressable | **Addressable**} and
+     * returning if already a valid transaction.
      *
      * @param {PerformActionTransaction} _request - The transaction to normalize.
      *
@@ -1136,7 +1129,10 @@ export class AbstractProvider<C = FetchRequest> implements Provider {
         });
 
         if (request.blockTag != null) {
-            const blockTag = this._getBlockTag(request.chainId?.toString(), request.blockTag);
+            const blockTag = this._getBlockTag(
+                request.chainId ? toShard(request.chainId.toString()) : undefined,
+                request.blockTag,
+            );
             if (isPromise(blockTag)) {
                 promises.push(
                     (async function () {
@@ -1158,7 +1154,7 @@ export class AbstractProvider<C = FetchRequest> implements Provider {
         return request;
     }
 
-    async getNetwork(shard: string = 'prime'): Promise<Network> {
+    async getNetwork(shard: Shard = Shard.Prime): Promise<Network> {
         // No explicit network was set and this is our first time
         if (this.#networkPromise == null) {
             // Detect the current network (shared with all calls)
@@ -1206,22 +1202,22 @@ export class AbstractProvider<C = FetchRequest> implements Provider {
         return expected.clone();
     }
 
-    async getRunningLocations(shard?: string): Promise<number[][]> {
+    async getRunningLocations(shard?: Shard): Promise<number[][]> {
         return await this.#perform(
             shard ? { method: 'getRunningLocations', shard: shard } : { method: 'getRunningLocations' },
         );
     }
 
-    async getProtocolTrieExpansionCount(shard: string): Promise<number> {
+    async getProtocolTrieExpansionCount(shard: Shard): Promise<number> {
         return await this.#perform({ method: 'getProtocolTrieExpansionCount', shard: shard });
     }
 
-    async getFeeData(shard?: string, txType: boolean = true): Promise<FeeData> {
+    async getFeeData(zone?: Zone, txType: boolean = true): Promise<FeeData> {
         const getFeeDataFunc = async () => {
             const { gasPrice, priorityFee } = await resolveProperties({
                 gasPrice: (async () => {
                     try {
-                        const value = await this.#perform({ method: 'getGasPrice', txType, shard: shard });
+                        const value = await this.#perform({ method: 'getGasPrice', txType, zone: zone });
                         return getBigInt(value, '%response');
                     } catch (error) {
                         console.log(error);
@@ -1231,7 +1227,7 @@ export class AbstractProvider<C = FetchRequest> implements Provider {
                 priorityFee: (async () => {
                     try {
                         const value = txType
-                            ? await this.#perform({ method: 'getMaxPriorityFeePerGas', shard: shard })
+                            ? await this.#perform({ method: 'getMaxPriorityFeePerGas', zone: zone })
                             : 0;
                         return getBigInt(value, '%response');
                         // eslint-disable-next-line no-empty
@@ -1263,12 +1259,12 @@ export class AbstractProvider<C = FetchRequest> implements Provider {
         if (isPromise(tx)) {
             tx = await tx;
         }
-        const shard = await this.shardFromAddress(addressFromTransactionRequest(tx));
+        const zone = await this.zoneFromAddress(addressFromTransactionRequest(tx));
         return getBigInt(
             await this.#perform({
                 method: 'estimateGas',
                 transaction: tx,
-                shard: shard,
+                zone: zone,
             }),
             '%response',
         );
@@ -1276,15 +1272,15 @@ export class AbstractProvider<C = FetchRequest> implements Provider {
 
     // TODO: `attempt` is not used, remove or re-write
     // eslint-disable-next-line @typescript-eslint/no-unused-vars
-    async #call(tx: PerformActionTransaction, blockTag: string, attempt: number, shard?: string): Promise<string> {
+    async #call(tx: PerformActionTransaction, blockTag: string, attempt: number, zone?: Zone): Promise<string> {
         // This came in as a PerformActionTransaction, so to/from are safe; we can cast
         const transaction = <PerformActionTransaction>copyRequest(tx);
-        return hexlify(await this._perform({ method: "call", transaction, blockTag, shard }));
+        return hexlify(await this._perform({ method: 'call', transaction, blockTag, zone }));
     }
 
     // TODO: `shard` is not used, remove or re-write
     // eslint-disable-next-line @typescript-eslint/no-unused-vars
-    async #checkNetwork<T>(promise: Promise<T>, shard?: string): Promise<T> {
+    async #checkNetwork<T>(promise: Promise<T>, shard?: Shard): Promise<T> {
         const { value } = await resolveProperties({
             network: this.getNetwork(),
             value: promise,
@@ -1293,19 +1289,21 @@ export class AbstractProvider<C = FetchRequest> implements Provider {
     }
 
     async call(_tx: QuaiTransactionRequest): Promise<string> {
-        const shard = await this.shardFromAddress(addressFromTransactionRequest(_tx));
+        const zone = await this.zoneFromAddress(addressFromTransactionRequest(_tx));
+        const shard = toShard(zone);
         const { tx, blockTag } = await resolveProperties({
             tx: this._getTransactionRequest(_tx),
             blockTag: this._getBlockTag(shard, _tx.blockTag),
         });
 
-        return await this.#checkNetwork(this.#call(tx, blockTag, -1, shard), shard);
+        return await this.#checkNetwork(this.#call(tx, blockTag, -1, zone), shard);
     }
 
     // Account
     async #getAccountValue(request: _PerformAccountRequest, _address: AddressLike, _blockTag?: BlockTag): Promise<any> {
         let address: string | Promise<string> = this._getAddress(_address);
-        const shard = await this.shardFromAddress(_address);
+        const zone = await this.zoneFromAddress(_address);
+        const shard = toShard(zone);
 
         let blockTag: string | Promise<string> = this._getBlockTag(shard, _blockTag);
 
@@ -1314,7 +1312,7 @@ export class AbstractProvider<C = FetchRequest> implements Provider {
         }
 
         return await this.#checkNetwork(
-            this.#perform(Object.assign(request, { address, blockTag, shard: shard }) as PerformActionRequest),
+            this.#perform(Object.assign(request, { address, blockTag, zone: zone }) as PerformActionRequest),
             shard,
         );
     }
@@ -1348,14 +1346,14 @@ export class AbstractProvider<C = FetchRequest> implements Provider {
     }
 
     // Write
-    async broadcastTransaction(shard: string, signedTx: string): Promise<TransactionResponse> {
+    async broadcastTransaction(zone: Zone, signedTx: string): Promise<TransactionResponse> {
         const type = decodeProtoTransaction(getBytes(signedTx)).type;
         const { blockNumber, hash, network } = await resolveProperties({
-            blockNumber: this.getBlockNumber(shard),
+            blockNumber: this.getBlockNumber(toShard(zone)),
             hash: this._perform({
                 method: 'broadcastTransaction',
                 signedTransaction: signedTx,
-                shard: shard,
+                zone: zone,
             }),
             network: this.getNetwork(),
         });
@@ -1372,7 +1370,7 @@ export class AbstractProvider<C = FetchRequest> implements Provider {
         }
     }
 
-    async #getBlock(shard: string, block: BlockTag | string, includeTransactions: boolean): Promise<any> {
+    async #getBlock(shard: Shard, block: BlockTag | string, includeTransactions: boolean): Promise<any> {
         // @TODO: Add CustomBlockPlugin check
         if (isHexString(block, 32)) {
             return await this.#perform({
@@ -1397,7 +1395,7 @@ export class AbstractProvider<C = FetchRequest> implements Provider {
     }
 
     // Queries
-    async getBlock(shard: string, block: BlockTag | string, prefetchTxs?: boolean): Promise<null | Block> {
+    async getBlock(shard: Shard, block: BlockTag | string, prefetchTxs?: boolean): Promise<null | Block> {
         const { network, params } = await resolveProperties({
             network: this.getNetwork(),
             params: this.#getBlock(shard, block, !!prefetchTxs),
@@ -1409,10 +1407,10 @@ export class AbstractProvider<C = FetchRequest> implements Provider {
     }
 
     async getTransaction(hash: string): Promise<null | TransactionResponse> {
-        const shard = this.shardFromHash(hash);
+        const zone = toZone(this.shardFromHash(hash));
         const { network, params } = await resolveProperties({
             network: this.getNetwork(),
-            params: this.#perform({ method: 'getTransaction', hash, shard: shard }),
+            params: this.#perform({ method: 'getTransaction', hash, zone: zone }),
         });
         if (params == null) {
             return null;
@@ -1422,10 +1420,10 @@ export class AbstractProvider<C = FetchRequest> implements Provider {
     }
 
     async getTransactionReceipt(hash: string): Promise<null | TransactionReceipt> {
-        const shard = this.shardFromHash(hash);
+        const zone = toZone(this.shardFromHash(hash));
         const { network, params } = await resolveProperties({
             network: this.getNetwork(),
-            params: this.#perform({ method: 'getTransactionReceipt', hash, shard: shard }),
+            params: this.#perform({ method: 'getTransactionReceipt', hash, zone: zone }),
         });
         if (params == null) {
             return null;
@@ -1433,7 +1431,7 @@ export class AbstractProvider<C = FetchRequest> implements Provider {
         // Some backends did not backfill the effectiveGasPrice in to old transactions
         // in the receipt, so we look it up manually and inject it.
         if (params.gasPrice == null && params.effectiveGasPrice == null) {
-            const tx = await this.#perform({ method: 'getTransaction', hash, shard: shard });
+            const tx = await this.#perform({ method: 'getTransaction', hash, zone: zone });
             if (tx == null) {
                 throw new Error('report this; could not find tx or effectiveGasPrice');
             }
@@ -1444,10 +1442,10 @@ export class AbstractProvider<C = FetchRequest> implements Provider {
     }
 
     async getTransactionResult(hash: string): Promise<null | string> {
-        const shard = this.shardFromHash(hash);
+        const zone = toZone(this.shardFromHash(hash));
         const { result } = await resolveProperties({
             network: this.getNetwork(),
-            result: this.#perform({ method: 'getTransactionResult', hash, shard: shard }),
+            result: this.#perform({ method: 'getTransactionResult', hash, zone: zone }),
         });
         if (result == null) {
             return null;
@@ -1461,11 +1459,11 @@ export class AbstractProvider<C = FetchRequest> implements Provider {
         if (isPromise(filter)) {
             filter = await filter;
         }
-        const shard = filter.shard;
+        const zone = toZone(filter.shard);
 
         const { network, params } = await resolveProperties({
             network: this.getNetwork(),
-            params: this.#perform<Array<LogParams>>({ method: 'getLogs', filter, shard: shard }),
+            params: this.#perform<Array<LogParams>>({ method: 'getLogs', filter, zone: zone }),
         });
 
         return params.map((p) => this._wrapLog(p, network));
@@ -1531,7 +1529,7 @@ export class AbstractProvider<C = FetchRequest> implements Provider {
 
     // TODO: not implemented yet
     // eslint-disable-next-line @typescript-eslint/no-unused-vars
-    async waitForBlock(shard: string, blockTag?: BlockTag): Promise<Block> {
+    async waitForBlock(shard: Shard, blockTag?: BlockTag): Promise<Block> {
         assert(false, 'not implemented yet', 'NOT_IMPLEMENTED', {
             operation: 'waitForBlock',
         });
diff --git a/src/providers/provider-jsonrpc.ts b/src/providers/provider-jsonrpc.ts
index 9d99e2c2..60bbc318 100644
--- a/src/providers/provider-jsonrpc.ts
+++ b/src/providers/provider-jsonrpc.ts
@@ -14,26 +14,30 @@
 
 // https://playground.open-rpc.org/?schemaUrl=https://raw.githubusercontent.com/ethereum/eth1.0-apis/assembled-spec/openrpc.json&uiSchema%5BappBar%5D%5Bui:splitView%5D=true&uiSchema%5BappBar%5D%5Bui:input%5D=false&uiSchema%5BappBar%5D%5Bui:examplesDropdown%5D=false
 
-import { AbiCoder } from "../abi/index.js";
-import { accessListify } from "../transaction/index.js";
+import { AbiCoder } from '../abi/index.js';
+import { accessListify } from '../transaction/index.js';
 import {
-    getBigInt, hexlify, isHexString, toQuantity,
-    makeError, assert, assertArgument,
-    FetchRequest
-} from "../utils/index.js";
-
-import { AbstractProvider, UnmanagedSubscriber } from "./abstract-provider.js";
-import { Network } from "./network.js";
-import { FilterIdEventSubscriber, FilterIdPendingSubscriber } from "./subscriber-filterid.js";
-
-import type { TransactionLike } from "../transaction/index.js";
-
-import type { PerformActionRequest, Subscriber, Subscription } from "./abstract-provider.js";
-import type { Networkish } from "./network.js";
-import type {TransactionRequest} from "./provider.js";
-import type { Signer } from "../signers/signer.js";
-import { UTXOEntry, UTXOTransactionOutput } from "../transaction/utxo.js";
-
+    getBigInt,
+    hexlify,
+    isHexString,
+    toQuantity,
+    makeError,
+    assert,
+    assertArgument,
+    FetchRequest,
+} from '../utils/index.js';
+
+import { AbstractProvider, UnmanagedSubscriber } from './abstract-provider.js';
+import { Network } from './network.js';
+import { FilterIdEventSubscriber, FilterIdPendingSubscriber } from './subscriber-filterid.js';
+
+import type { TransactionLike } from '../transaction/index.js';
+
+import type { PerformActionRequest, Subscriber, Subscription } from './abstract-provider.js';
+import type { Networkish } from './network.js';
+import type { TransactionRequest } from './provider.js';
+import { UTXOEntry, UTXOTransactionOutput } from '../transaction/utxo.js';
+import { Shard, toShard } from '../constants/index.js';
 
 type Timer = ReturnType<typeof setTimeout>;
 
@@ -257,7 +261,7 @@ export interface QuaiJsonRpcTransactionRequest extends AbstractJsonRpcTransactio
 type ResolveFunc = (result: JsonRpcResult) => void;
 type RejectFunc = (error: Error) => void;
 
-type Payload = { payload: JsonRpcPayload; resolve: ResolveFunc; reject: RejectFunc; shard?: string };
+type Payload = { payload: JsonRpcPayload; resolve: ResolveFunc; reject: RejectFunc; shard?: Shard };
 
 /**
  * The JsonRpcApiProvider is an abstract class and **MUST** be sub-classed.
@@ -337,7 +341,7 @@ export abstract class JsonRpcApiProvider<C = FetchRequest> extends AbstractProvi
                     await Promise.all(
                         Array.from(payloadMap).map(async ([key, value]) => {
                             const payload = value.length === 1 ? value[0] : value;
-                            const shard = key;
+                            const shard = key ? toShard(key) : undefined;
 
                             this.emit('debug', { action: 'sendRpcPayload', payload });
 
@@ -464,7 +468,7 @@ export abstract class JsonRpcApiProvider<C = FetchRequest> extends AbstractProvi
      */
     abstract _send(
         payload: JsonRpcPayload | Array<JsonRpcPayload>,
-        shard?: string,
+        shard?: Shard,
     ): Promise<Array<JsonRpcResult | JsonRpcError>>;
 
     /**
@@ -484,7 +488,7 @@ export abstract class JsonRpcApiProvider<C = FetchRequest> extends AbstractProvi
             if (tx && tx.type != null && getBigInt(tx.type)) {
                 // If there are no EIP-1559 properties, it might be non-EIP-a559
                 if (tx.maxFeePerGas == null && tx.maxPriorityFeePerGas == null) {
-                    const feeData = await this.getFeeData(req.shard);
+                    const feeData = await this.getFeeData(req.zone);
                     if (feeData.maxFeePerGas == null && feeData.maxPriorityFeePerGas == null) {
                         // Network doesn't know about EIP-1559 (and hence type)
                         req = Object.assign({}, req, {
@@ -498,7 +502,7 @@ export abstract class JsonRpcApiProvider<C = FetchRequest> extends AbstractProvi
         const request = this.getRpcRequest(req);
 
         if (request != null) {
-            const shard = 'shard' in req ? req.shard : undefined;
+            const shard = 'shard' in req ? req.shard : 'zone' in req ? toShard(req.zone!) : undefined;
             return await this.send(request.method, request.args, shard);
         }
 
@@ -979,11 +983,11 @@ export abstract class JsonRpcApiProvider<C = FetchRequest> extends AbstractProvi
      *
      * @param {string} method - The method to call.
      * @param {any[] | Record<string, any>} params - The parameters to pass to the method.
-     * @param {string} shard - The shard to send the request to.
+     * @param {Shard} shard - The shard to send the request to.
      *
      * @returns {Promise<any>} A promise that resolves to the result of the method call.
      */
-    send(method: string, params: Array<any> | Record<string, any>, shard?: string): Promise<any> {
+    send(method: string, params: Array<any> | Record<string, any>, shard?: Shard): Promise<any> {
         // @TODO: cache chainId?? purge on switch_networks
 
         // We have been destroyed; no operations are supported anymore
@@ -1076,18 +1080,17 @@ export class JsonRpcProvider extends JsonRpcApiProvider {
         return subscriber;
     }
 
-    _getConnection(shard?: string): FetchRequest {
+    _getConnection(shard?: Shard): FetchRequest {
         let connection;
-        if (typeof shard === 'string') {
-            const shardBytes = this.shardBytes(shard);
-            connection = this._urlMap.get(shardBytes) ?? this.connect[this.connect.length - 1]!.clone();
+        if (shard !== undefined) {
+            connection = this._urlMap.get(shard) ?? this.connect[this.connect.length - 1]!.clone();
         } else {
             connection = this.connect[this.connect.length - 1]!.clone();
         }
         return new FetchRequest(connection.url);
     }
 
-    async send(method: string, params: Array<any> | Record<string, any>, shard?: string): Promise<any> {
+    async send(method: string, params: Array<any> | Record<string, any>, shard?: Shard): Promise<any> {
         // All requests are over HTTP, so we can just start handling requests
         // We do this here rather than the constructor so that we don't send any
         // requests to the network (i.e. quai_chainId) until we absolutely have to.
@@ -1096,7 +1099,7 @@ export class JsonRpcProvider extends JsonRpcApiProvider {
         return await super.send(method, params, shard);
     }
 
-    async _send(payload: JsonRpcPayload | Array<JsonRpcPayload>, shard?: string): Promise<Array<JsonRpcResult>> {
+    async _send(payload: JsonRpcPayload | Array<JsonRpcPayload>, shard?: Shard): Promise<Array<JsonRpcResult>> {
         // Configure a POST connection for the requested method
         const request = this._getConnection(shard);
         request.body = JSON.stringify(payload);
diff --git a/src/providers/provider-socket.ts b/src/providers/provider-socket.ts
index 3588e29b..5c5b2702 100644
--- a/src/providers/provider-socket.ts
+++ b/src/providers/provider-socket.ts
@@ -19,6 +19,7 @@ import type { EventFilter } from './provider.js';
 import type { JsonRpcApiProviderOptions, JsonRpcError, JsonRpcPayload, JsonRpcResult } from './provider-jsonrpc.js';
 import type { Networkish } from './network.js';
 import type { WebSocketLike } from './provider-websocket.js';
+import { Shard } from '../constants/index.js';
 
 type JsonRpcSubscription = {
     method: string;
@@ -275,7 +276,7 @@ export class SocketProvider extends JsonRpcApiProvider<WebSocketLike> {
 
     async _send(
         payload: JsonRpcPayload | Array<JsonRpcPayload>,
-        shard?: string,
+        shard?: Shard,
     ): Promise<Array<JsonRpcResult | JsonRpcError>> {
         // WebSocket provider doesn't accept batches
         assertArgument(!Array.isArray(payload), 'WebSocket does not support batch send', 'payload', payload);
@@ -346,7 +347,7 @@ export class SocketProvider extends JsonRpcApiProvider<WebSocketLike> {
      * Sub-classes **must** override this to send `message` over their transport.
      */
     // eslint-disable-next-line @typescript-eslint/no-unused-vars
-    async _write(message: string, shard?: string): Promise<void> {
+    async _write(message: string, shard?: Shard): Promise<void> {
         throw new Error('sub-classes must override this');
     }
 }
diff --git a/src/providers/provider-websocket.ts b/src/providers/provider-websocket.ts
index 05c19fcc..a9773e9f 100644
--- a/src/providers/provider-websocket.ts
+++ b/src/providers/provider-websocket.ts
@@ -4,6 +4,7 @@ import { SocketProvider } from './provider-socket.js';
 
 import type { JsonRpcApiProviderOptions } from './provider-jsonrpc.js';
 import type { Networkish } from './network.js';
+import { Shard, toShard } from '../constants/index.js';
 
 /**
  * A generic interface to a Websocket-like object.
@@ -44,7 +45,7 @@ export type WebSocketCreator = () => WebSocketLike;
 export class WebSocketProvider extends SocketProvider {
     #websockets: WebSocketLike[];
 
-    readyMap: Map<string, boolean> = new Map();
+    readyMap: Map<Shard, boolean> = new Map();
 
     get websocket(): WebSocketLike[] {
         if (this.#websockets == null) {
@@ -63,7 +64,7 @@ export class WebSocketProvider extends SocketProvider {
         this.initPromise = this.initUrlMap(typeof url === 'string' ? [url] : url);
     }
 
-    initWebSocket(websocket: WebSocketLike, shard: string): void {
+    initWebSocket(websocket: WebSocketLike, shard: Shard): void {
         websocket.onopen = async () => {
             try {
                 await this._start();
@@ -80,7 +81,7 @@ export class WebSocketProvider extends SocketProvider {
         };
     }
 
-    async waitShardReady(shard: string): Promise<void> {
+    async waitShardReady(shard: Shard): Promise<void> {
         let count = 0;
         while (!this.readyMap.get(shard)) {
             await new Promise((resolve) => setTimeout(resolve, Math.pow(2, count)));
@@ -103,10 +104,10 @@ export class WebSocketProvider extends SocketProvider {
                     const port = 8200 + 20 * shard[0] + shard[1];
                     const shardUrl = baseUrl.split(':').slice(0, 2).join(':');
                     const websocket = createWebSocket(shardUrl, port);
-                    this.initWebSocket(websocket, `0x${shard[0].toString(16)}${shard[1].toString(16)}`);
+                    this.initWebSocket(websocket, toShard(`0x${shard[0].toString(16)}${shard[1].toString(16)}`));
                     this.#websockets.push(websocket);
-                    this._urlMap.set(`0x${shard[0].toString(16)}${shard[1].toString(16)}`, websocket);
-                    await this.waitShardReady(`0x${shard[0].toString(16)}${shard[1].toString(16)}`);
+                    this._urlMap.set(toShard(`0x${shard[0].toString(16)}${shard[1].toString(16)}`), websocket);
+                    await this.waitShardReady(toShard(`0x${shard[0].toString(16)}${shard[1].toString(16)}`));
                 }),
             );
         };
@@ -115,45 +116,44 @@ export class WebSocketProvider extends SocketProvider {
             for (const url of urls) {
                 const baseUrl = `${url.split(':')[0]}:${url.split(':')[1]}`;
                 const primeWebsocket = createWebSocket(baseUrl, 8001);
-                this.initWebSocket(primeWebsocket, '0x');
+                this.initWebSocket(primeWebsocket, Shard.Prime);
                 this.#websockets.push(primeWebsocket);
-                this._urlMap.set('0x', primeWebsocket);
-                await this.waitShardReady('0x');
+                this._urlMap.set(Shard.Prime, primeWebsocket);
+                await this.waitShardReady(Shard.Prime);
                 await initShardWebSockets(baseUrl);
             }
         } else if (typeof urls === 'function') {
             const primeWebsocket = urls();
-            this.initWebSocket(primeWebsocket, '0x');
+            this.initWebSocket(primeWebsocket, Shard.Prime);
             this.#websockets.push(primeWebsocket);
-            this._urlMap.set('0x', primeWebsocket);
-            await this.waitShardReady('0x');
+            this._urlMap.set(Shard.Prime, primeWebsocket);
+            await this.waitShardReady(Shard.Prime);
             const baseUrl = this.#websockets[0].url.split(':').slice(0, 2).join(':');
             await initShardWebSockets(baseUrl);
         } else {
             const primeWebsocket = urls as WebSocketLike;
-            this.initWebSocket(primeWebsocket, '0x');
+            this.initWebSocket(primeWebsocket, Shard.Prime);
             this.#websockets.push(primeWebsocket);
-            this._urlMap.set('0x', primeWebsocket);
-            await this.waitShardReady('0x');
+            this._urlMap.set(Shard.Prime, primeWebsocket);
+            await this.waitShardReady(Shard.Prime);
             const baseUrl = primeWebsocket.url.split(':').slice(0, 2).join(':');
             await initShardWebSockets(baseUrl);
         }
     }
 
-    async _write(message: string, shard?: string): Promise<void> {
-        const shardKey = shard ? this.shardBytes(shard) : undefined;
+    async _write(message: string, shard?: Shard): Promise<void> {
         if (this.websocket.length < 1) {
             throw new Error('Websocket closed');
         }
-        if (shardKey && !this._urlMap.has(shardKey)) {
+        if (shard && !this._urlMap.has(shard)) {
             throw new Error('Shard not found');
         }
-        const websocket = shardKey ? this._urlMap.get(shardKey) : this.websocket[this.websocket.length - 1];
+        const websocket = shard ? this._urlMap.get(shard) : this.websocket[this.websocket.length - 1];
         if (!websocket) {
             throw new Error('Websocket is undefined');
         }
-        if (shardKey) {
-            await this.waitShardReady(shardKey);
+        if (shard) {
+            await this.waitShardReady(shard);
         }
         websocket.send(message);
     }
diff --git a/src/providers/provider.ts b/src/providers/provider.ts
index fcd2e774..da53f679 100644
--- a/src/providers/provider.ts
+++ b/src/providers/provider.ts
@@ -22,6 +22,7 @@ import type { ContractRunner } from '../contract/index.js';
 import type { Network } from './network.js';
 import type { Outpoint } from '../transaction/utxo.js';
 import type { TxInput, TxOutput } from '../transaction/utxo.js';
+import type { Zone, Shard } from '../constants/index.js';
 
 const BN_0 = BigInt(0);
 
@@ -49,6 +50,7 @@ import {
 import { WorkObjectLike } from '../transaction/work-object.js';
 import { QiTransactionLike } from '../transaction/qi-transaction.js';
 import { QuaiTransactionLike } from '../transaction/quai-transaction.js';
+import { toShard, toZone } from '../constants/index.js';
 
 // -----------------------
 
@@ -1044,11 +1046,11 @@ export class Log implements LogParams {
     /**
      * Returns the block that this log occurred in.
      *
-     * @param {string} shard - The shard to fetch the block from.
+     * @param {Shard} shard - The shard to fetch the block from.
      *
      * @returns {Promise<Block>} A promise resolving to the block.
      */
-    async getBlock(shard: string): Promise<Block> {
+    async getBlock(shard: Shard): Promise<Block> {
         const block = await this.provider.getBlock(shard, this.blockHash);
         assert(!!block, 'failed to find transaction', 'UNKNOWN_ERROR', {});
         return block;
@@ -1087,8 +1089,8 @@ export class Log implements LogParams {
 //////////////////////
 // Transaction Receipt
 
-export function shardFromHash(hash: string): string {
-    return hash.slice(0, 4);
+export function zoneFromHash(hash: string): Zone {
+    return toZone(hash.slice(0, 4));
 }
 /**
  * A **TransactionReceipt** includes additional information about a transaction that is only available after it has been
@@ -1305,12 +1307,12 @@ export class TransactionReceipt implements TransactionReceiptParams, Iterable<Lo
     /**
      * Resolves to the block this transaction occurred in.
      *
-     * @param {string} shard - The shard to fetch the block from.
+     * @param {Shard} shard - The shard to fetch the block from.
      *
      * @returns {Promise<Block>} A promise resolving to the block.
      * @throws {Error} If the block is not found.
      */
-    async getBlock(shard: string): Promise<Block> {
+    async getBlock(shard: Shard): Promise<Block> {
         const block = await this.provider.getBlock(shard, this.blockHash);
         if (block == null) {
             throw new Error('TODO');
@@ -1351,8 +1353,8 @@ export class TransactionReceipt implements TransactionReceiptParams, Iterable<Lo
      * @throws {Error} If the block is not found.
      */
     async confirmations(): Promise<number> {
-        const shard = shardFromHash(this.hash);
-        return (await this.provider.getBlockNumber(shard)) - this.blockNumber + 1;
+        const zone = zoneFromHash(this.hash);
+        return (await this.provider.getBlockNumber(toShard(zone))) - this.blockNumber + 1;
     }
 
     /**
@@ -1612,11 +1614,11 @@ export class QuaiTransactionResponse implements QuaiTransactionLike, QuaiTransac
      *
      * This will return null if the transaction has not been included yet.
      *
-     * @param {string} shard - The shard to fetch the block from.
+     * @param {Shard} shard - The shard to fetch the block from.
      *
      * @returns {null | Promise<Block>} A promise resolving to the block.
      */
-    async getBlock(shard: string): Promise<null | Block> {
+    async getBlock(shard: Shard): Promise<null | Block> {
         let blockNumber = this.blockNumber;
         if (blockNumber == null) {
             const tx = await this.getTransaction();
@@ -1656,11 +1658,11 @@ export class QuaiTransactionResponse implements QuaiTransactionLike, QuaiTransac
      * @throws {Error} If the block is not found.
      */
     async confirmations(): Promise<number> {
-        const shard = shardFromHash(this.hash);
+        const zone = zoneFromHash(this.hash);
         if (this.blockNumber == null) {
             const { tx, blockNumber } = await resolveProperties({
                 tx: this.getTransaction(),
-                blockNumber: this.provider.getBlockNumber(shard),
+                blockNumber: this.provider.getBlockNumber(toShard(zone)),
             });
 
             // Not mined yet...
@@ -1671,7 +1673,7 @@ export class QuaiTransactionResponse implements QuaiTransactionLike, QuaiTransac
             return blockNumber - tx.blockNumber + 1;
         }
 
-        const blockNumber = await this.provider.getBlockNumber(shard);
+        const blockNumber = await this.provider.getBlockNumber(toShard(zone));
         return blockNumber - this.blockNumber + 1;
     }
 
@@ -1695,14 +1697,14 @@ export class QuaiTransactionResponse implements QuaiTransactionLike, QuaiTransac
         let startBlock = this.startBlock;
         let nextScan = -1;
         let stopScanning = startBlock === -1 ? true : false;
-        const shard = shardFromHash(this.hash);
+        const zone = zoneFromHash(this.hash);
         const checkReplacement = async () => {
             // Get the current transaction count for this sender
             if (stopScanning) {
                 return null;
             }
             const { blockNumber, nonce } = await resolveProperties({
-                blockNumber: this.provider.getBlockNumber(shard),
+                blockNumber: this.provider.getBlockNumber(toShard(zone)),
                 nonce: this.provider.getTransactionCount(this.from),
             });
 
@@ -1737,7 +1739,7 @@ export class QuaiTransactionResponse implements QuaiTransactionLike, QuaiTransac
                 if (stopScanning) {
                     return null;
                 }
-                const block = await this.provider.getBlock(shard, nextScan, true);
+                const block = await this.provider.getBlock(toShard(zone), nextScan, true);
 
                 // This should not happen; but we'll try again shortly
                 if (block == null) {
@@ -2073,11 +2075,11 @@ export class QiTransactionResponse implements QiTransactionLike, QiTransactionRe
      *
      * This will return null if the transaction has not been included yet.
      *
-     * @param {string} shard - The shard to fetch the block from.
+     * @param {Shard} shard - The shard to fetch the block from.
      *
      * @returns {null | Promise<Block>} A promise resolving to the block or null if not found.
      */
-    async getBlock(shard: string): Promise<null | Block> {
+    async getBlock(shard: Shard): Promise<null | Block> {
         let blockNumber = this.blockNumber;
         if (blockNumber == null) {
             const tx = await this.getTransaction();
@@ -2117,11 +2119,11 @@ export class QiTransactionResponse implements QiTransactionLike, QiTransactionRe
      * @returns {Promise<number>} A promise resolving to the number of confirmations.
      */
     async confirmations(): Promise<number> {
-        const shard = shardFromHash(this.hash);
+        const zone = zoneFromHash(this.hash);
         if (this.blockNumber == null) {
             const { tx, blockNumber } = await resolveProperties({
                 tx: this.getTransaction(),
-                blockNumber: this.provider.getBlockNumber(shard),
+                blockNumber: this.provider.getBlockNumber(toShard(zone)),
             });
 
             // Not mined yet...
@@ -2132,7 +2134,7 @@ export class QiTransactionResponse implements QiTransactionLike, QiTransactionRe
             return blockNumber - tx.blockNumber + 1;
         }
 
-        const blockNumber = await this.provider.getBlockNumber(shard);
+        const blockNumber = await this.provider.getBlockNumber(toShard(zone));
         return blockNumber - this.blockNumber + 1;
     }
 
@@ -2322,7 +2324,7 @@ export interface Filter extends EventFilter {
      */
     toBlock?: BlockTag;
 
-    shard: string;
+    shard: Shard;
 }
 
 /**
@@ -2335,7 +2337,7 @@ export interface FilterByBlockHash extends EventFilter {
      * The blockhash of the specific block for the filter.
      */
     blockHash?: string;
-    shard: string;
+    shard: Shard;
 }
 
 //////////////////////
@@ -2407,35 +2409,33 @@ export interface Provider extends ContractRunner, EventEmitterable<ProviderEvent
     /**
      * Get the current block number.
      *
-     * @param {string} shard - The shard to fetch the block number from.
+     * @param {Shard} shard - The shard to fetch the block number from.
      *
      * @returns {Promise<number>} A promise resolving to the block number.
      */
-    getBlockNumber(shard: string): Promise<number>;
+    getBlockNumber(shard: Shard): Promise<number>;
 
     /**
      * Get the connected {@link Network | **Network**}.
      *
-     * @param {string} shard - The shard to fetch the network from.
+     * @param {Shard} shard - The shard to fetch the network from.
      *
      * @returns {Promise<Network>} A promise resolving to the network.
      */
-    getNetwork(shard?: string): Promise<Network>;
+    getNetwork(shard?: Shard): Promise<Network>;
 
     /**
      * Get the best guess at the recommended {@link FeeData | **FeeData**}.
      *
-     * @param {string} shard - The shard to fetch the fee data from.
+     * @param {Zone} zone - The shard to fetch the fee data from.
      *
      * @returns {Promise<FeeData>} A promise resolving to the fee data.
      */
-    getFeeData(shard: string): Promise<FeeData>;
+    getFeeData(zone: Zone): Promise<FeeData>;
 
     /**
      * Get a work object to package a transaction in.
      *
-     * @param {string} shard - The shard to fetch the work object from.
-     *
      * @returns {Promise<WorkObjectLike>} A promise resolving to the work object.
      */
     getPendingHeader(): Promise<WorkObjectLike>;
@@ -2534,14 +2534,14 @@ export interface Provider extends ContractRunner, EventEmitterable<ProviderEvent
      * Broadcasts the `signedTx` to the network, adding it to the memory pool of any node for which the transaction
      * meets the rebroadcast requirements.
      *
-     * @param {string} shard - The shard to broadcast the transaction to.
+     * @param {Zone} zone - The zone to broadcast the transaction to.
      * @param {string} signedTx - The signed transaction to broadcast.
      * @param {AddressLike} [from] - The address that signed the transaction.
      *
      * @returns {Promise<TransactionResponse>} A promise resolving to the transaction response.
      * @throws {Error} If the transaction is invalid or the transaction is replaced.
      */
-    broadcastTransaction(shard: string, signedTx: string, from?: AddressLike): Promise<TransactionResponse>;
+    broadcastTransaction(zone: Zone, signedTx: string, from?: AddressLike): Promise<TransactionResponse>;
 
     ////////////////////
     // Queries
@@ -2552,14 +2552,14 @@ export interface Provider extends ContractRunner, EventEmitterable<ProviderEvent
      * If `prefetchTxs`, and the backend supports including transactions with block requests, all transactions will be
      * included and the {@link Block | **Block**} object will not need to make remote calls for getting transactions.
      *
-     * @param {string} shard - The shard to fetch the block from.
+     * @param {Shard} shard - The shard to fetch the block from.
      * @param {BlockTag | string} blockHashOrBlockTag - The block hash or block tag to fetch.
      * @param {boolean} [prefetchTxs] - If true, prefetch the transactions.
      *
      * @returns {Promise<null | Block>} A promise resolving to the block or null if not found.
      * @throws {Error} If the block is not found.
      */
-    getBlock(shard: string, blockHashOrBlockTag: BlockTag | string, prefetchTxs?: boolean): Promise<null | Block>;
+    getBlock(shard: Shard, blockHashOrBlockTag: BlockTag | string, prefetchTxs?: boolean): Promise<null | Block>;
 
     /**
      * Resolves to the transaction for `hash`.
@@ -2625,12 +2625,12 @@ export interface Provider extends ContractRunner, EventEmitterable<ProviderEvent
      *
      * This can be useful for waiting some number of blocks by using the `currentBlockNumber + N`.
      *
-     * @param {string} shard - The shard to fetch the block from.
+     * @param {Shard} shard - The shard to fetch the block from.
      * @param {BlockTag} [blockTag] - The block tag to fetch.
      *
      * @returns {Promise<Block>} A promise resolving to the block.
      */
-    waitForBlock(shard: string, blockTag?: BlockTag): Promise<Block>;
+    waitForBlock(shard: Shard, blockTag?: BlockTag): Promise<Block>;
 
     /**
      * Resolves to the number indicating the size of the network
diff --git a/src/quais.ts b/src/quais.ts
index 89de19fe..004f6c67 100644
--- a/src/quais.ts
+++ b/src/quais.ts
@@ -1,16 +1,29 @@
 // VERSION
-export { version } from "./_version.js";
+export { version } from './_version.js';
 
 // APPLICATION BINARY INTERFACE
 export {
-    decodeBytes32String, encodeBytes32String,
-
+    decodeBytes32String,
+    encodeBytes32String,
     AbiCoder,
-    ConstructorFragment, ErrorFragment, EventFragment, Fragment, FallbackFragment, FunctionFragment, NamedFragment, ParamType, StructFragment,
-
-    checkResultErrors, ErrorDescription, Indexed, Interface, LogDescription, Result, TransactionDescription,
+    ConstructorFragment,
+    ErrorFragment,
+    EventFragment,
+    Fragment,
+    FallbackFragment,
+    FunctionFragment,
+    NamedFragment,
+    ParamType,
+    StructFragment,
+    checkResultErrors,
+    ErrorDescription,
+    Indexed,
+    Interface,
+    LogDescription,
+    Result,
+    TransactionDescription,
     Typed,
-} from "./abi/index.js";
+} from './abi/index.js';
 
 // ADDRESS
 export {
@@ -23,17 +36,28 @@ export {
 //CONSTANTS
 export {
     ZeroAddress,
-    WeiPerEther, MaxUint256, MinInt256, MaxInt256, N,
+    WeiPerEther,
+    MaxUint256,
+    MinInt256,
+    MaxInt256,
+    N,
     ZeroHash,
-    quaisymbol, MessagePrefix
-} from "./constants/index.js";
+    quaisymbol,
+    MessagePrefix,
+} from './constants/index.js';
 
 // CONTRACT
 export {
-    BaseContract, Contract,
+    BaseContract,
+    Contract,
     ContractFactory,
-    ContractEventPayload, ContractTransactionReceipt, ContractTransactionResponse, ContractUnknownEventPayload, EventLog, UndecodedEventLog
-} from "./contract/index.js";
+    ContractEventPayload,
+    ContractTransactionReceipt,
+    ContractTransactionResponse,
+    ContractUnknownEventPayload,
+    EventLog,
+    UndecodedEventLog,
+} from './contract/index.js';
 
 // CRYPTO
 export {
@@ -41,12 +65,15 @@ export {
     randomBytes,
     keccak256,
     ripemd160,
-    sha256, sha512,
+    sha256,
+    sha512,
     pbkdf2,
-    scrypt, scryptSync,
+    scrypt,
+    scryptSync,
     lock,
-    Signature, SigningKey
-} from "./crypto/index.js";
+    Signature,
+    SigningKey,
+} from './crypto/index.js';
 
 // HASH
 export {
@@ -54,8 +81,8 @@ export {
     hashMessage, verifyMessage,
     solidityPacked, solidityPackedKeccak256, solidityPackedSha256,
     TypedDataEncoder,
-    verifyTypedData
-} from "./hash/index.js";
+    verifyTypedData,
+} from './hash/index.js';
 
 // PROVIDERS
 export {
@@ -102,7 +129,7 @@ export {
     getBigInt, getNumber, getUint, toBeArray, toBigInt, toBeHex, toNumber, toQuantity,
     fromTwos, toTwos, mask,
     formatQuai, parseQuai, formatEther, parseEther, formatUnits, parseUnits,
-    uuidV4, getTxType, getShardForAddress, getAddressDetails, isQiAddress,
+    uuidV4, getTxType, getZoneForAddress, getAddressDetails, isQiAddress,
 } from "./utils/index.js";
 
 export {
@@ -124,27 +151,24 @@ export {
 } from "./wallet/index.js";
 
 // WORDLIST
-export {
-    Wordlist, LangEn, LangEs, WordlistOwl, WordlistOwlA, wordlists
-} from "./wordlists/index.js";
-
-
+export { Wordlist, LangEn, LangEs, WordlistOwl, WordlistOwlA, wordlists } from './wordlists/index.js';
 
 /////////////////////////////
 // Types
 
 // APPLICATION BINARY INTERFACE
 export type {
-    JsonFragment, JsonFragmentType,
-    FormatType, FragmentType,
+    JsonFragment,
+    JsonFragmentType,
+    FormatType,
+    FragmentType,
     InterfaceAbi,
-    ParamTypeWalkFunc, ParamTypeWalkAsyncFunc
-} from "./abi/index.js";
+    ParamTypeWalkFunc,
+    ParamTypeWalkAsyncFunc,
+} from './abi/index.js';
 
 // ADDRESS
-export type {
-    Addressable, AddressLike
-} from "./address/index.js";
+export type { Addressable, AddressLike } from './address/index.js';
 
 // CONTRACT
 export type {
@@ -156,10 +180,10 @@ export type {
 } from "./contract/index.js";
 
 // CRYPTO
-export type { ProgressCallback, SignatureLike } from "./crypto/index.js";
+export type { ProgressCallback, SignatureLike } from './crypto/index.js';
 
 // HASH
-export type { TypedDataDomain, TypedDataField } from "./hash/index.js";
+export type { TypedDataDomain, TypedDataField } from './hash/index.js';
 
 // PROVIDERS
 export type {
@@ -183,10 +207,7 @@ export type {
 } from "./signers/index.js";
 
 // TRANSACTION
-export type {
-    AccessList, AccessListish, AccessListEntry,
-    TransactionLike
-} from "./transaction/index.js";
+export type { AccessList, AccessListish, AccessListEntry, TransactionLike } from './transaction/index.js';
 
 // UTILS
 export type {
diff --git a/src/signers/abstract-signer.ts b/src/signers/abstract-signer.ts
index 0f0371b1..273d552b 100644
--- a/src/signers/abstract-signer.ts
+++ b/src/signers/abstract-signer.ts
@@ -20,6 +20,7 @@ import type {
 import type { Signer } from "./signer.js";
 import { getTxType } from "../utils/index.js";
 import {QiTransaction, QiTransactionLike, QuaiTransaction, QuaiTransactionLike} from "../transaction/index.js";
+import { toZone, Zone } from '../constants/index.js';
 
 function checkProvider(signer: AbstractSigner, operation: string): Provider {
     if (signer.provider) {
@@ -76,9 +77,9 @@ export abstract class AbstractSigner<P extends null | Provider = null | Provider
         return resolveAddress(address);
     }
 
-    async shardFromAddress(_address: AddressLike): Promise<string> {
+    async zoneFromAddress(_address: AddressLike): Promise<Zone> {
         const address: string | Promise<string> = this._getAddress(_address);
-        return (await address).slice(0, 4);
+        return toZone((await address).slice(0, 4));
     }
     /**
      * Returns the signer connected to `provider`.
@@ -103,7 +104,7 @@ export abstract class AbstractSigner<P extends null | Provider = null | Provider
 
     async populateQuaiTransaction(tx: QuaiTransactionRequest): Promise<QuaiTransactionLike> {
         const provider = checkProvider(this, 'populateTransaction');
-        const shard = await this.shardFromAddress(tx.from);
+        const zone = await this.zoneFromAddress(tx.from);
 
         const pop = (await populate(this, tx)) as QuaiTransactionLike;
 
@@ -135,12 +136,12 @@ export abstract class AbstractSigner<P extends null | Provider = null | Provider
 
         if (pop.chainId != null) {
             const chainId = getBigInt(pop.chainId);
-            assertArgument(chainId === network.chainId, 'transaction chainId mismatch', 'tx.chainId', shard);
+            assertArgument(chainId === network.chainId, 'transaction chainId mismatch', 'tx.chainId', zone);
         } else {
             pop.chainId = network.chainId;
         }
         if (pop.maxFeePerGas == null || pop.maxPriorityFeePerGas == null) {
-            const feeData = await provider.getFeeData(shard);
+            const feeData = await provider.getFeeData(zone);
 
             if (pop.maxFeePerGas == null) {
                 pop.maxFeePerGas = feeData.maxFeePerGas;
@@ -178,7 +179,7 @@ export abstract class AbstractSigner<P extends null | Provider = null | Provider
     async sendTransaction(tx: TransactionRequest): Promise<TransactionResponse> {
         const provider = checkProvider(this, 'sendTransaction');
         const sender = await this.getAddress();
-        const shard = await this.shardFromAddress(addressFromTransactionRequest(tx));
+        const zone = await this.zoneFromAddress(addressFromTransactionRequest(tx));
 
         let pop;
         let txObj;
@@ -192,7 +193,7 @@ export abstract class AbstractSigner<P extends null | Provider = null | Provider
 
         const signedTx = await this.signTransaction(txObj);
 
-        return await provider.broadcastTransaction(shard, signedTx, "from" in tx ? tx.from : undefined);
+        return await provider.broadcastTransaction(zone, signedTx, 'from' in tx ? tx.from : undefined);
     }
 
     abstract signTransaction(tx: TransactionRequest): Promise<string>;
diff --git a/src/transaction/abstract-transaction.ts b/src/transaction/abstract-transaction.ts
index 0bad6377..e3f24444 100644
--- a/src/transaction/abstract-transaction.ts
+++ b/src/transaction/abstract-transaction.ts
@@ -5,6 +5,7 @@ import type { BigNumberish } from '../utils/index.js';
 import type { SignatureLike } from '../crypto/index.js';
 import { encodeProtoTransaction } from '../encoding/proto-encode.js';
 import type { TxInput, TxOutput } from './utxo.js';
+import { Zone } from '../constants/index.js';
 
 /**
  * A **TransactionLike** is a JSON representation of a transaction.
@@ -32,10 +33,10 @@ export interface TransactionLike {
 }
 
 /**
- * @TODO write documentation for this interface.
- *
  * @category Transaction
  * @todo Write documentation for this interface.
+ *
+ * @todo Write documentation for this interface.
  */
 export interface ProtoTransaction {
     /**
@@ -46,7 +47,7 @@ export interface ProtoTransaction {
     /**
      * @todo Write documentation for this property.
      */
-    to?: Uint8Array | null
+    to?: Uint8Array | null;
 
     /**
      * @todo Write documentation for this property.
@@ -160,18 +161,16 @@ export interface ProtoTransaction {
 }
 
 /**
- * @TODO write documentation for this interface.
- *
  * @category Transaction
  * @todo Write documentation for this interface.
+ *
+ * @todo Write documentation for this interface.
  */
 export interface ProtoAccessList {
     access_tuples: Array<ProtoAccessTuple>;
 }
 
 /**
- * @TODO write documentation for this interface.
- *
  * @category Transaction
  * @todo Write documentation for this interface.
  */
@@ -194,11 +193,9 @@ type allowedSignatureTypes = Signature | string;
  * tx = new Transaction();
  * //_result:
  *
- *    tx.data = "0x1234";
- *    //_result:
- *  ```
- *
- *  @category Transaction
+ * tx.data = '0x1234';
+ * //_result:
+ * ```
  */
 export abstract class AbstractTransaction<S extends allowedSignatureTypes> implements TransactionLike {
     protected _type: number | null;
@@ -291,10 +288,9 @@ export abstract class AbstractTransaction<S extends allowedSignatureTypes> imple
     /**
      * Returns true if signed.
      *
-     *  This provides a Type Guard that properties requiring a signed
-     *  transaction are non-null.
+     * This provides a Type Guard that properties requiring a signed transaction are non-null.
      *
-     *  @returns {boolean} Indicates if the transaction is signed.
+     * @returns {boolean} Indicates if the transaction is signed.
      */
     isSigned(): this is AbstractTransaction<S> & {
         type: number;
@@ -332,50 +328,48 @@ export abstract class AbstractTransaction<S extends allowedSignatureTypes> imple
     }
 
     /**
-     *  Return the most "likely" type; currently the highest
-     *  supported transaction type.
+     * Return the most "likely" type; currently the highest supported transaction type.
      *
-     *  @returns {number} The inferred transaction type.
+     * @returns {number} The inferred transaction type.
      */
     inferType(): number {
         return <number>this.inferTypes().pop();
     }
 
     /**
-     *  Validates the explicit properties and returns a list of compatible
-     *  transaction types.
+     * Validates the explicit properties and returns a list of compatible transaction types.
      *
-     *  @returns {Array<number>} The compatible transaction types.
+     * @returns {number[]} The compatible transaction types.
      */
     abstract inferTypes(): Array<number>;
 
     /**
-     *  Create a copy of this transaciton.
+     * Create a copy of this transaciton.
      *
-     *  @returns {AbstractTransaction} The cloned transaction.
+     * @returns {AbstractTransaction} The cloned transaction.
      */
     abstract clone(): AbstractTransaction<S>;
 
     /**
-     *  Return a JSON-friendly object.
+     * Return a JSON-friendly object.
      *
-     *  @returns {TransactionLike} The JSON-friendly object.
+     * @returns {TransactionLike} The JSON-friendly object.
      */
     abstract toJSON(): TransactionLike;
 
     /**
-     *  Return a protobuf-friendly JSON object.
+     * Return a protobuf-friendly JSON object.
      *
-     *  @returns {ProtoTransaction} The protobuf-friendly JSON object.
+     * @returns {ProtoTransaction} The protobuf-friendly JSON object.
      */
     abstract toProtobuf(): ProtoTransaction;
 
-    abstract get originShard(): string | undefined;
+    abstract get originZone(): Zone | undefined;
 
-    abstract get destShard(): string | undefined;
+    abstract get destZone(): Zone | undefined;
 
     get isExternal(): boolean {
-        return this.destShard !== undefined && this.originShard !== this.destShard
+        return this.destZone !== undefined && this.originZone !== this.destZone;
     }
 
     /**
diff --git a/src/transaction/qi-transaction.ts b/src/transaction/qi-transaction.ts
index 706e8faf..e11fe752 100644
--- a/src/transaction/qi-transaction.ts
+++ b/src/transaction/qi-transaction.ts
@@ -2,7 +2,7 @@ import {keccak256} from "../crypto/index.js";
 import {AbstractTransaction, TransactionLike, TxInput, TxOutput} from "./index.js";
 import {
     assertArgument,
-    getBytes, getShardForAddress,
+    getBytes, getZoneForAddress,
     hexlify, isQiAddress,
     toBigInt
 } from "../utils/index.js";
@@ -10,6 +10,7 @@ import { decodeProtoTransaction } from '../encoding/index.js';
 import {formatNumber} from "../providers/format.js";
 import { computeAddress } from "../address/index.js";
 import { ProtoTransaction} from "./abstract-transaction.js";
+import { Zone } from '../constants/index.js';
 
 /**
  * @category Transaction
@@ -67,18 +68,18 @@ export class QiTransaction extends AbstractTransaction<string> implements QiTran
             throw new Error('Transaction must have at least one input and one output');
         }
 
-        const destUtxo = isQiAddress(hexlify(this.txOutputs[0].address) || "");
+        const destUtxo = isQiAddress(hexlify(this.txOutputs[0].address) || '');
         const pubKey = hexlify(this.txInputs[0].pub_key);
-        const senderAddr = computeAddress(pubKey || "");
+        const senderAddr = computeAddress(pubKey || '');
         const originUtxo = isQiAddress(senderAddr);
 
-        if (!this.destShard || !this.originShard) {
+        if (!this.destZone || !this.originZone) {
             throw new Error(
-                `Invalid shards: origin ${this.originShard} ->  destination ${this.destShard} (address: ${senderAddr})`,
+                `Invalid zones: origin ${this.originZone} ->  destination ${this.destZone} (address: ${senderAddr})`,
             );
         }
         if (this.isExternal && destUtxo !== originUtxo) {
-            throw new Error('Cross-shard & cross-ledger transactions are not supported');
+            throw new Error('Cross-zone & cross-ledger transactions are not supported');
         }
 
         const hexString = this.serialized.startsWith('0x') ? this.serialized.substring(2) : this.serialized;
@@ -87,7 +88,7 @@ export class QiTransaction extends AbstractTransaction<string> implements QiTran
         const hashHex = keccak256(dataBuffer);
         const hashBuffer = Buffer.from(hashHex.substring(2), 'hex');
 
-        const origin = this.originShard ? parseInt(this.originShard, 16) : 0;
+        const origin = this.originZone ? parseInt(this.originZone.slice(2), 16) : 0;
         hashBuffer[0] = origin;
         hashBuffer[1] |= 0x80;
         hashBuffer[2] = origin;
@@ -96,15 +97,17 @@ export class QiTransaction extends AbstractTransaction<string> implements QiTran
         return '0x' + hashBuffer.toString('hex');
     }
 
-    get originShard(): string | undefined {
+    get originZone(): Zone | undefined {
         const pubKey = hexlify(this.txInputs[0].pub_key);
         const senderAddr = computeAddress(pubKey || '');
 
-        return getShardForAddress(senderAddr)?.byte.slice(2);
+        const zone = getZoneForAddress(senderAddr);
+        return zone ?? undefined;
     }
 
-    get destShard(): string | undefined {
-        return getShardForAddress(hexlify(this.txOutputs[0].address) || '')?.byte.slice(2);
+    get destZone(): Zone | undefined {
+        const zone = getZoneForAddress(hexlify(this.txOutputs[0].address) || '');
+        return zone ?? undefined;
     }
 
     /**
diff --git a/src/transaction/quai-transaction.ts b/src/transaction/quai-transaction.ts
index 167ec6af..2382d43d 100644
--- a/src/transaction/quai-transaction.ts
+++ b/src/transaction/quai-transaction.ts
@@ -8,7 +8,7 @@ import {
     getBigInt,
     getBytes,
     getNumber,
-    getShardForAddress,
+    getZoneForAddress,
     hexlify, isQiAddress,
     toBeArray, toBigInt, zeroPadValue
 } from "../utils/index.js";
@@ -16,6 +16,7 @@ import { decodeProtoTransaction, encodeProtoTransaction } from '../encoding/inde
 import { getAddress, recoverAddress } from "../address/index.js";
 import { formatNumber, handleNumber } from "../providers/format.js";
 import { ProtoTransaction} from "./abstract-transaction.js";
+import { Zone } from '../constants';
 
 /**
  * @category Transaction
@@ -122,14 +123,14 @@ export class QuaiTransaction extends AbstractTransaction<Signature> implements Q
         return this.unsignedHash;
     }
     get unsignedHash(): string {
-        const destUtxo = isQiAddress(this.to || "");
+        const destUtxo = isQiAddress(this.to || '');
         const originUtxo = isQiAddress(this.from);
 
-        if (!this.originShard) {
-            throw new Error("Invalid Shard for from or to address");
+        if (!this.originZone) {
+            throw new Error('Invalid Shard for from or to address');
         }
         if (this.isExternal && destUtxo !== originUtxo) {
-            throw new Error('Cross-shard & cross-ledger transactions are not supported');
+            throw new Error('Cross-zone & cross-ledger transactions are not supported');
         }
 
         const hexString = this.serialized.startsWith('0x') ? this.serialized.substring(2) : this.serialized;
@@ -138,7 +139,7 @@ export class QuaiTransaction extends AbstractTransaction<Signature> implements Q
         const hashHex = keccak256(dataBuffer);
         const hashBuffer = Buffer.from(hashHex.substring(2), 'hex');
 
-        const origin = this.originShard ? parseInt(this.originShard, 16) : 0;
+        const origin = this.originZone ? parseInt(this.originZone.slice(2), 16) : 0;
         hashBuffer[0] = origin;
         hashBuffer[1] &= 0x7f;
         hashBuffer[2] = origin;
@@ -147,14 +148,16 @@ export class QuaiTransaction extends AbstractTransaction<Signature> implements Q
         return '0x' + hashBuffer.toString('hex');
     }
 
-    get originShard(): string | undefined {
+    get originZone(): Zone | undefined {
         const senderAddr = this.from;
 
-        return getShardForAddress(senderAddr)?.byte.slice(2);
+        const zone = getZoneForAddress(senderAddr);
+        return zone ?? undefined;
     }
 
-    get destShard(): string | undefined {
-        return this.to !== null ? getShardForAddress(this.to || "")?.byte.slice(2) : undefined;
+    get destZone(): Zone | undefined {
+        const zone = this.to !== null ? getZoneForAddress(this.to || '') : undefined;
+        return zone ?? undefined;
     }
 
     /**
@@ -362,8 +365,8 @@ export class QuaiTransaction extends AbstractTransaction<Signature> implements Q
             gas_fee_cap: formatNumber(this.maxFeePerGas || 0, 'maxFeePerGas'),
             gas: Number(this.gasLimit || 0),
             to: this.to != null ? getBytes(this.to as string) : null,
-            value: formatNumber(this.value || 0, "value"),
-            data: getBytes(this.data || "0x"),
+            value: formatNumber(this.value || 0, 'value'),
+            data: getBytes(this.data || '0x'),
             access_list: { access_tuples: [] },
         };
 
@@ -449,14 +452,10 @@ export class QuaiTransaction extends AbstractTransaction<Signature> implements Q
         let address;
         if (protoTx.v && protoTx.r && protoTx.s) {
             // check if protoTx.r is zero
-            if (protoTx.r.reduce((acc, val) => acc += val, 0) == 0) {
-                throw new Error("Proto decoding only supported for signed transactions")
+            if (protoTx.r.reduce((acc, val) => (acc += val), 0) == 0) {
+                throw new Error('Proto decoding only supported for signed transactions');
             }
-            const signatureFields = [
-                hexlify(protoTx.v!),
-                hexlify(protoTx.r!),
-                hexlify(protoTx.s!),
-            ];
+            const signatureFields = [hexlify(protoTx.v!), hexlify(protoTx.r!), hexlify(protoTx.s!)];
             signature = _parseSignature(signatureFields);
 
             const protoTxCopy = structuredClone(protoTx);
diff --git a/src/utils/index.ts b/src/utils/index.ts
index 2c8954f5..6a03eac0 100644
--- a/src/utils/index.ts
+++ b/src/utils/index.ts
@@ -56,7 +56,7 @@ export { formatQuai, parseQuai, formatEther, parseEther, formatUnits, parseUnits
 
 export { uuidV4 } from './uuid.js';
 
-export { getTxType, getShardForAddress, getAddressDetails, isQiAddress } from './shards.js';
+export { getTxType, getZoneForAddress, getAddressDetails, isQiAddress } from './shards.js';
 
 /////////////////////////////
 // Types
diff --git a/src/utils/shards.ts b/src/utils/shards.ts
index e4a3761a..7b5d42b4 100644
--- a/src/utils/shards.ts
+++ b/src/utils/shards.ts
@@ -1,4 +1,4 @@
-import { ShardData } from "../constants/shards.js";
+import { toZone, Zone } from '../constants/zones.js';
 /**
  * Retrieves the shard information for a given address based on its byte prefix. The function parses the address to
  * extract its byte prefix, then filters the ShardData to find a matching shard entry. If no matching shard is found, it
@@ -10,43 +10,28 @@ import { ShardData } from "../constants/shards.js";
  *
  * @returns {Object | null} An object containing the shard information, or null if no
  */
-export function getShardForAddress(
-    address: string,
-): { name: string; nickname: string; shard: string; context: number; byte: string } | null {
-    const addressByte = address.substring(2, 4);
-    const filteredShards = ShardData.filter((obj) => {
-        return parseInt(addressByte, 16) === parseInt(obj.byte, 16);
-    });
-
-    if (filteredShards.length === 0) {
+export function getZoneForAddress(address: string): Zone | null {
+    try {
+        return toZone(address.slice(0, 4));
+    } catch (error) {
         return null;
     }
-    return filteredShards[0];
 }
 
 /**
- * Extracts both shard and UTXO information from a given blockchain address. This function first determines the
- * address's shard by its byte prefix, then checks the 9th bit of the address to ascertain if it's a UTXO or non-UTXO
- * address.
+ * Extracts both zone and UTXO information from a given blockchain address. This function first determines the address's
+ * zone by its byte prefix, then checks the 9th bit of the address to ascertain if it's a UTXO or non-UTXO address.
  *
  * @category Utils
  * @param {string} address - The blockchain address to be analyzed, expected to start with "0x" followed by its
  *   hexadecimal representation.
  *
- * @returns {Object | null} An object containing the shard and UTXO information, or null if no address is found.
+ * @returns {Object | null} An object containing the zone and UTXO information, or null if no address is found.
  */
-export function getAddressDetails(address: string): { shard: any; isUTXO: boolean } | null {
-    const addressByte = address.substring(2, 4);
+export function getAddressDetails(address: string): { zone: Zone; isUTXO: boolean } | null {
     const isUTXO = (parseInt(address.substring(4, 5), 16) & 0x1) === 1;
 
-    const filteredShards = ShardData.filter((obj) => {
-        return parseInt(addressByte, 16) === parseInt(obj.byte, 16);
-    });
-
-    if (filteredShards.length === 0) {
-        return null;
-    }
-    return { shard: filteredShards[0], isUTXO };
+    return { zone: toZone(address.substring(0, 4)), isUTXO };
 }
 
 /**
@@ -63,9 +48,9 @@ export function getAddressDetails(address: string): { shard: any; isUTXO: boolea
  * @returns {number} The transaction type based on the addresses.
  */
 export function getTxType(from: string | null, to: string | null): number {
-  if (from === null || to === null) return 0;
-  const fromUTXO = isQiAddress(from);
-  const toUTXO = isQiAddress(to);
+    if (from === null || to === null) return 0;
+    const fromUTXO = isQiAddress(from);
+    const toUTXO = isQiAddress(to);
 
     switch (true) {
         case fromUTXO && toUTXO:
@@ -78,19 +63,19 @@ export function getTxType(from: string | null, to: string | null): number {
 }
 
 /**
-  *  Checks whether a given blockchain address is a UTXO address based on the 9th bit of
-  *  the address. This function extracts the second byte of the address and checks its
-  *  first bit to determine the UTXO status.
-  * 
-  *  @param {string} address - The blockchain address to be analyzed, expected to start with "0x" followed by its hexadecimal representation.
-  *  @returns {boolean} True if the address is a UTXO address, false otherwise.
-  * 
-  *  @category Utils
-  */
+ * Checks whether a given blockchain address is a UTXO address based on the 9th bit of the address. This function
+ * extracts the second byte of the address and checks its first bit to determine the UTXO status.
+ *
+ * @category Utils
+ * @param {string} address - The blockchain address to be analyzed, expected to start with "0x" followed by its
+ *   hexadecimal representation.
+ *
+ * @returns {boolean} True if the address is a UTXO address, false otherwise.
+ */
 export function isQiAddress(address: string): boolean {
-  const secondByte = address.substring(4, 6); 
-  const binaryString = parseInt(secondByte, 16).toString(2).padStart(8, '0'); 
-  const isUTXO = binaryString[0] === '1';
+    const secondByte = address.substring(4, 6);
+    const binaryString = parseInt(secondByte, 16).toString(2).padStart(8, '0');
+    const isUTXO = binaryString[0] === '1';
 
-  return isUTXO;
+    return isUTXO;
 }
diff --git a/src/wallet/hdwallet.ts b/src/wallet/hdwallet.ts
index 13fbe22c..f8482b01 100644
--- a/src/wallet/hdwallet.ts
+++ b/src/wallet/hdwallet.ts
@@ -18,7 +18,7 @@ import {
     assert,
     assertArgument,
     hexlify,
-    getShardForAddress,
+    getZoneForAddress,
     isQiAddress,
     BytesLike,
     Numeric,
@@ -30,7 +30,7 @@ import { decodeBase58 } from '../encoding/base58.js';
 import { BaseWallet } from './base-wallet.js';
 import { Mnemonic } from './mnemonic.js';
 import { encryptKeystoreJson, encryptKeystoreJsonSync } from './json-keystore.js';
-import { N } from '../constants/index.js';
+import { N, Zone } from '../constants/index.js';
 import type { ProgressCallback } from '../crypto/index.js';
 import type { Wordlist } from '../wordlists/index.js';
 import type { KeystoreAccount } from './json-keystore.js';
@@ -42,10 +42,10 @@ const MAX_ADDRESS_DERIVATION_ATTEMPTS = 10000000;
 
 // Used to type the instantiation of a child wallet class from static methods
 export interface HDWalletStatic<T> {
-	new(...args: any[]): T;
-	_fromSeed(_seed: BytesLike, mnemonic: null | Mnemonic): T;
-	isValidPath(path: string): boolean;
-	derivePath(path: string): T;
+    new (...args: any[]): T;
+    _fromSeed(_seed: BytesLike, mnemonic: null | Mnemonic): T;
+    isValidPath(path: string): boolean;
+    derivePath(path: string): T;
 }
 
 export type AddressInfo = {
@@ -160,54 +160,53 @@ export abstract class HDWallet extends BaseWallet implements HDNodeLike<HDWallet
         return new (this.constructor as new (...args: any[]) => this)(...params);
     }
 
-	protected account(): KeystoreAccount {
-		const account: KeystoreAccount = {
-			address: this.address,
-			privateKey: this.privateKey,
-		};
-		const m = this.mnemonic;
-		if (this.path && m && m.wordlist.locale === "en" && m.password === "") {
-			account.mnemonic = {
-				path: this.path,
-				locale: "en",
-				entropy: m.entropy,
-			};
-		}
+    protected account(): KeystoreAccount {
+        const account: KeystoreAccount = {
+            address: this.address,
+            privateKey: this.privateKey,
+        };
+        const m = this.mnemonic;
+        if (this.path && m && m.wordlist.locale === 'en' && m.password === '') {
+            account.mnemonic = {
+                path: this.path,
+                locale: 'en',
+                entropy: m.entropy,
+            };
+        }
 
         return account;
     }
 
-	/**
-	 *  Resolves to a [JSON Keystore Wallet](json-wallets) encrypted with
-	 *  `password`.
-	 *
-	 *  If `progressCallback` is specified, it will receive periodic
-	 *  updates as the encryption process progreses.
-	 *
-	 *  @param {Uint8Array | string} password - The password to encrypt the wallet with.
-	 *  @param {ProgressCallback} [progressCallback] - An optional callback to receive progress updates.
-	 *  @returns {Promise<string>} The encrypted JSON Keystore Wallet.
-	 */
-	async encrypt(password: Uint8Array | string,progressCallback?: ProgressCallback): Promise<string> {
-		return await encryptKeystoreJson(this.account(), password, {progressCallback});
-	}
-
-	/**
-	 *  Returns a [JSON Keystore Wallet](json-wallets) encryped with
-	 *  `password`.
-	 *
-	 *  It is preferred to use the [async version](encrypt) instead,
-	 *  which allows a {@link ProgressCallback | **ProgressCallback**} to keep the user informed.
-	 *
-	 *  This method will block the event loop (freezing all UI) until
-	 *  it is complete, which may be a non-trivial duration.
-	 *
-	 *  @param {Uint8Array | string} password - The password to encrypt the wallet with.
-	 *  @returns {string} The encrypted JSON Keystore Wallet.
-	 */
-	encryptSync(password: Uint8Array | string): string {
-		return encryptKeystoreJsonSync(this.account(), password);
-	}
+    /**
+     * Resolves to a [JSON Keystore Wallet](json-wallets) encrypted with `password`.
+     *
+     * If `progressCallback` is specified, it will receive periodic updates as the encryption process progreses.
+     *
+     * @param {Uint8Array | string} password - The password to encrypt the wallet with.
+     * @param {ProgressCallback} [progressCallback] - An optional callback to receive progress updates.
+     *
+     * @returns {Promise<string>} The encrypted JSON Keystore Wallet.
+     */
+    async encrypt(password: Uint8Array | string, progressCallback?: ProgressCallback): Promise<string> {
+        return await encryptKeystoreJson(this.account(), password, { progressCallback });
+    }
+
+    /**
+     * Returns a [JSON Keystore Wallet](json-wallets) encryped with `password`.
+     *
+     * It is preferred to use the [async version](encrypt) instead, which allows a
+     * {@link ProgressCallback | **ProgressCallback**} to keep the user informed.
+     *
+     * This method will block the event loop (freezing all UI) until it is complete, which may be a non-trivial
+     * duration.
+     *
+     * @param {Uint8Array | string} password - The password to encrypt the wallet with.
+     *
+     * @returns {string} The encrypted JSON Keystore Wallet.
+     */
+    encryptSync(password: Uint8Array | string): string {
+        return encryptKeystoreJsonSync(this.account(), password);
+    }
 
     /**
      * The extended key.
@@ -496,37 +495,40 @@ export abstract class HDWallet extends BaseWallet implements HDNodeLike<HDWallet
         return this._fromSeed(seed, null);
     }
 
-	/**
-	 * Derives address by incrementing address_index according to BIP44
-	 *
-	 *  @param {number} index - The index of the address to derive.
-	 *  @param {string} [zone] - The zone of the address to derive.
-	 *  @returns {HDWallet} The derived HD Node.
-	 *  @throws {Error} If the path is missing or the zone is invalid.
-	 */
-	protected deriveAddress(startingIndex: number, zone: string, ledgerType: 'Qi' | 'Quai'): AddressInfo {
-		if (!this.path) throw new Error("Missing wallet's address derivation path");
+    /**
+     * Derives address by incrementing address_index according to BIP44
+     *
+     * @param {number} index - The index of the address to derive.
+     * @param {Zone} [zone] - The zone of the address to derive.
+     *
+     * @returns {HDWallet} The derived HD Node.
+     * @throws {Error} If the path is missing or the zone is invalid.
+     */
+    protected deriveAddress(startingIndex: number, zone: Zone, ledgerType: 'Qi' | 'Quai'): AddressInfo {
+        if (!this.path) throw new Error("Missing wallet's address derivation path");
 
         let newWallet: this;
 
-		const isValidAddressForZone = (address: string) => {
-			const shardNickname = getShardForAddress(address)?.nickname.toLowerCase();
-			const isCorrectShard = shardNickname === zone;
-			const isCorrectCoinType = newWallet.coinType === this.coinType;
-			const isCorrectLedger = (ledgerType === 'Qi') ? isQiAddress(address) : !isQiAddress(address);
-	
-			return isCorrectShard && isCorrectCoinType && isCorrectLedger;
-		}
-
-		let addrIndex: number = startingIndex;
-		do {
-			newWallet = this.derivePath(addrIndex.toString());
-			addrIndex++;
-			// put a hard limit on the number of addresses to derive
-			if (addrIndex - startingIndex > MAX_ADDRESS_DERIVATION_ATTEMPTS) {
-				throw new Error(`Failed to derive a valid address for the zone ${zone} after MAX_ADDRESS_DERIVATION_ATTEMPTS attempts.`);
-			}
-		} while (!isValidAddressForZone(newWallet.address));
+        const isValidAddressForZone = (address: string) => {
+            const addressZone = getZoneForAddress(address);
+            const isCorrectShard = addressZone === zone;
+            const isCorrectCoinType = newWallet.coinType === this.coinType;
+            const isCorrectLedger = ledgerType === 'Qi' ? isQiAddress(address) : !isQiAddress(address);
+
+            return isCorrectShard && isCorrectCoinType && isCorrectLedger;
+        };
+
+        let addrIndex: number = startingIndex;
+        do {
+            newWallet = this.derivePath(addrIndex.toString());
+            addrIndex++;
+            // put a hard limit on the number of addresses to derive
+            if (addrIndex - startingIndex > MAX_ADDRESS_DERIVATION_ATTEMPTS) {
+                throw new Error(
+                    `Failed to derive a valid address for the zone ${zone} after MAX_ADDRESS_DERIVATION_ATTEMPTS attempts.`,
+                );
+            }
+        } while (!isValidAddressForZone(newWallet.address));
 
         const addresInfo = { address: newWallet.address, privKey: newWallet.privateKey, index: addrIndex - 1 };
 
diff --git a/src/wallet/qi-hdwallet.ts b/src/wallet/qi-hdwallet.ts
index 013ece45..ab7d24f1 100644
--- a/src/wallet/qi-hdwallet.ts
+++ b/src/wallet/qi-hdwallet.ts
@@ -1,6 +1,6 @@
-import { ShardData } from '../constants/index.js';
+import { ShardData, toShard, Zone } from '../constants/index.js';
 import { SigningKey, keccak256 as addressKeccak256 } from '../crypto/index.js';
-import { getBytes, getShardForAddress, hexlify } from '../utils/index.js';
+import { getBytes, getZoneForAddress, hexlify } from '../utils/index.js';
 import { Provider, QiTransactionRequest } from '../providers/index.js';
 import { TransactionLike, QiTransaction, TxInput } from '../transaction/index.js';
 import { Mnemonic } from './mnemonic.js';
@@ -90,11 +90,11 @@ export class QiHDWallet extends HDWallet {
      * Initializes the wallet by generating addresses and private keys for the specified zone. The wallet will generate
      * addresses until it has `GAP` number of naked addresses. A provider must be set before calling this method.
      *
-     * @param {string} zone - Zone identifier used to validate the derived address.
+     * @param {Zone} zone - Zone identifier used to validate the derived address.
      *
      * @returns {Promise<void>}
      */
-    public async init(zone: string): Promise<void> {
+    public async init(zone: Zone): Promise<void> {
         if (!this.validateZone(zone)) throw new Error(`Invalid zone: ${zone}`);
         if (!this.provider) throw new Error('Provider not set');
 
@@ -108,7 +108,7 @@ export class QiHDWallet extends HDWallet {
         let derivationIndex = 0;
 
         while (nakedCount < GAP) {
-            const addressInfo = this.deriveAddress(derivationIndex, zone, "Qi");
+            const addressInfo = this.deriveAddress(derivationIndex, zone, 'Qi');
             // store the address, private key and index
             shardWalletData.addressesInfo.push(addressInfo);
             // query the network node for the outpoints of the address and update the balance
@@ -182,11 +182,12 @@ export class QiHDWallet extends HDWallet {
         const pubKey = input.pub_key;
         const address = this.getAddressFromPubKey(hexlify(pubKey));
         // get shard from address
-        const shard = getShardForAddress(address);
+        const zone = getZoneForAddress(address);
+        const shard = zone ? toShard(zone) : undefined;
         if (!shard) throw new Error(`Invalid shard location for address: ${address}`);
         // get the wallet data corresponding to the shard
-        const shardWalletData = this.#shardWalletsMap.get(shard.nickname);
-        if (!shardWalletData) throw new Error(`Missing wallet data for shard: ${shard.name}`);
+        const shardWalletData = this.#shardWalletsMap.get(shard);
+        if (!shardWalletData) throw new Error(`Missing wallet data for shard: ${shard}`);
         // get the private key corresponding to the address
         const privKey = shardWalletData.addressesInfo.find((utxoAddr) => utxoAddr.address === address)?.privKey;
         if (!privKey) throw new Error(`Missing private key for ${hexlify(pubKey)}`);
@@ -207,11 +208,11 @@ export class QiHDWallet extends HDWallet {
             const address = computeAddress(hexlify(input.pub_key));
 
             // get shard from address
-            const shard = getShardForAddress(address);
+            const shard = getZoneForAddress(address);
             if (!shard) throw new Error(`Invalid address: ${address}`);
             // get the wallet data corresponding to the shard
-            const shardWalletData = this.#shardWalletsMap.get(shard.nickname);
-            if (!shardWalletData) throw new Error(`Missing wallet data for shard: ${(shard.name, shard.nickname)}`);
+            const shardWalletData = this.#shardWalletsMap.get(shard);
+            if (!shardWalletData) throw new Error(`Missing wallet data for shard: ${shard}`);
 
             const utxoAddrObj = shardWalletData.addressesInfo.find((utxoAddr) => utxoAddr.address === address);
             if (!utxoAddrObj) {
diff --git a/src/wallet/quai-hdwallet.ts b/src/wallet/quai-hdwallet.ts
index 9df7a1e6..0218034a 100644
--- a/src/wallet/quai-hdwallet.ts
+++ b/src/wallet/quai-hdwallet.ts
@@ -3,17 +3,16 @@
  *
  * @section api/wallet:HD Wallets  [hd-wallets]
  */
-import { SigningKey } from "../crypto/index.js";
-import { Mnemonic } from "./mnemonic.js";
-import type { Provider } from "../providers/index.js";
-import { HDWallet, AddressInfo} from "./hdwallet.js";
-import { QUAI_COIN_TYPE } from '../constants/index.js';
-
+import { SigningKey } from '../crypto/index.js';
+import { Mnemonic } from './mnemonic.js';
+import type { Provider } from '../providers/index.js';
+import { HDWallet, AddressInfo } from './hdwallet.js';
+import { QUAI_COIN_TYPE, Zone } from '../constants/index.js';
 
 // keeps track of the addresses and outpoints for a given shard (zone)
 type ShardWalletData = {
     addressesInfo: AddressInfo[];
-}
+};
 
 /**
  * An **QuaiHDWallet** is a [Signer](../interfaces/Signer) backed by the private key derived from an HD Node using the
@@ -25,16 +24,14 @@ type ShardWalletData = {
  * @category Wallet
  */
 export class QuaiHDWallet extends HDWallet {
-
     /**
-     *  The Quai cointype.
+     * The Quai cointype.
      */
     readonly coinType: number = QUAI_COIN_TYPE;
 
     /**
-     * Map of shard name (zone) to shardWalletData
-     * shardWalletData contains the private keys, addresses and derive indexes for the shard
-     * that are known to the wallet
+     * Map of shard name (zone) to shardWalletData shardWalletData contains the private keys, addresses and derive
+     * indexes for the shard that are known to the wallet
      */
     #shardWalletsMap: Map<string, ShardWalletData> = new Map();
 
@@ -44,24 +41,34 @@ export class QuaiHDWallet extends HDWallet {
 
     set shardWallets(shardWallets: Map<string, ShardWalletData>) {
         this.#shardWalletsMap = shardWallets;
-    }    
-    
-    constructor(guard: any, signingKey: SigningKey, accountFingerprint: string, chainCode: string, path: null | string, index: number, depth: number, mnemonic: null | Mnemonic, provider: null | Provider) {
+    }
+
+    constructor(
+        guard: any,
+        signingKey: SigningKey,
+        accountFingerprint: string,
+        chainCode: string,
+        path: null | string,
+        index: number,
+        depth: number,
+        mnemonic: null | Mnemonic,
+        provider: null | Provider,
+    ) {
         super(guard, signingKey, accountFingerprint, chainCode, path, index, depth, mnemonic, provider);
     }
 
-    async getAddress(zone: string): Promise<string> {
+    async getAddress(zone: Zone): Promise<string> {
         let index = 0;
         let shardWalletData: ShardWalletData | undefined = this.#shardWalletsMap.get(zone);
         if (shardWalletData) {
             const pos = shardWalletData.addressesInfo.length;
-            index = shardWalletData!.addressesInfo[pos-1].index + 1;
+            index = shardWalletData!.addressesInfo[pos - 1].index + 1;
         } else {
-            shardWalletData = {addressesInfo: []};
+            shardWalletData = { addressesInfo: [] };
             this.#shardWalletsMap.set(zone, shardWalletData);
         }
 
-        const addressInfo = this.deriveAddress(index, zone, "Quai");
+        const addressInfo = this.deriveAddress(index, zone, 'Quai');
         shardWalletData.addressesInfo.push(addressInfo);
         return addressInfo.address;
     }