> For the complete documentation index, see [llms.txt](https://bluwhale.gitbook.io/bluwhaleai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://bluwhale.gitbook.io/bluwhaleai/oceanum-oxn/smart-contract-development/testing-contracts-locally.md).

# Testing Contracts Locally

Local testing gives you fast iteration and deterministic reproducibility. But **local EVM emulators cannot fully model** Oceanum (Oceanum (OXN))**'s confidentiality behavior**. This page explains what works locally, what doesn't, and how to structure your test pyramid.

### What local networks can test <a href="#what-local-networks-can-test" id="what-local-networks-can-test"></a>

Standard Solidity contract logic — everything that would run on Ethereum unchanged — tests fine locally:

* Contract state transitions
* Access control (using `msg.sender`)
* Event emission (topic and data structure)
* Reverts and error conditions
* Interactions between multiple contracts
* Gas usage patterns (approximately)

### What local networks CANNOT test <a href="#what-local-networks-cannot-test" id="what-local-networks-cannot-test"></a>

The following behaviors depend on Oceanum (OXN)'s runtime, not the EVM alone:

* **Encrypted calldata handling** — a local network sees calldata in plain, so any assertion about "did this call arrive encrypted?" is meaningless.
* **Confidential storage** — local storage is public; a test that checks "an outsider cannot read this slot" gives a false positive against every local network.
* **Signed queries** — the signed-query path requires the Oceanum (OXN) gateway. Locally, `eth_call` is unauthenticated by default.
* **Confidential precompiles** — `Sapphire.randomBytes`, `Sapphire.encrypt`, etc. do not exist on standard Hardhat network.
* **PUSH0 rejection** — local networks (Hardhat, Anvil) implement PUSH0 by default. A contract compiled with `shanghai` will run fine locally and only fail on real Oceanum (OXN).

### Recommended test pyramid <a href="#recommended-test-pyramid" id="recommended-test-pyramid"></a>

| Layer             | Location                            | Coverage                                                      |
| ----------------- | ----------------------------------- | ------------------------------------------------------------- |
| Unit tests        | Hardhat / Foundry local             | Business logic, math, access control, revert conditions.      |
| Integration tests | Oceanum (OXN) Testnet               | Confidentiality behavior, encrypted calldata, signed queries. |
| End-to-end tests  | Oceanum (OXN) Testnet + real wallet | Wallet interaction, faucet flow, user-facing paths.           |

**Every dApp should run at least some integration tests against real** Oceanum (OXN)**.** Don't assume Hardhat green means production green.

### Hardhat local testing <a href="#hardhat-local-testing" id="hardhat-local-testing"></a>

Standard Hardhat testing works out of the box:

test/MyToken.test.js

```
const { expect } = require("chai");
const { ethers } = require("hardhat");

describe("MyToken", function () {
  it("mints initial supply to deployer", async function () {
    const [deployer] = await ethers.getSigners();
    const Token = await ethers.getContractFactory("MyToken");
    const token = await Token.deploy(ethers.parseUnits("1000", 18));

    expect(await token.balanceOf(deployer.address))
      .to.equal(ethers.parseUnits("1000", 18));
  });
});
```

Run with `npx hardhat test`. Hardhat spins up an in-memory network, deploys, and asserts.

### Foundry local testing <a href="#foundry-local-testing" id="foundry-local-testing"></a>

test/MyToken.t.sol

```
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import "forge-std/Test.sol";
import "../src/MyToken.sol";

contract MyTokenTest is Test {
    MyToken token;
    address deployer = address(this);

    function setUp() public {
        token = new MyToken(1_000_000 ether);
    }

    function testInitialSupply() public {
        assertEq(token.balanceOf(deployer), 1_000_000 ether);
    }
}
```

Run with `forge test`. Foundry's built-in `Test` contract provides assertion helpers and cheatcodes.

### Fixtures and snapshots <a href="#fixtures-and-snapshots" id="fixtures-and-snapshots"></a>

For faster tests, use fixtures to avoid redeploying:

Hardhat with loadFixture

```
const { loadFixture } = require("@nomicfoundation/hardhat-network-helpers");

async function deployTokenFixture() {
  const [deployer, other] = await ethers.getSigners();
  const Token = await ethers.getContractFactory("MyToken");
  const token = await Token.deploy(ethers.parseUnits("1000", 18));
  return { token, deployer, other };
}

describe("MyToken transfers", function () {
  it("transfers tokens", async function () {
    const { token, deployer, other } = await loadFixture(deployTokenFixture);
    await token.transfer(other.address, ethers.parseUnits("100", 18));
    expect(await token.balanceOf(other.address))
      .to.equal(ethers.parseUnits("100", 18));
  });
});
```

Fixtures snapshot the network state after `setUp` and restore it before each test, making a full test suite 10-100x faster than redeploying.

### Time and block manipulation <a href="#time-and-block-manipulation" id="time-and-block-manipulation"></a>

Hardhat and Foundry both expose "cheatcodes" to move time forward or set specific block conditions in local tests. Use these for time-locked contracts:

Hardhat time cheatcodes

```
const { time } = require("@nomicfoundation/hardhat-network-helpers");

// Fast-forward 1 hour
await time.increase(3600);

// Jump to a specific timestamp
await time.increaseTo(1700000000);
```

Foundry time cheatcodes

```
vm.warp(block.timestamp + 3600);   // fast-forward 1 hour
vm.roll(block.number + 100);       // advance 100 blocks
```

These cheatcodes are local-only. Real OXN does not accept time manipulation from clients.

### Next steps <a href="#next-steps" id="next-steps"></a>

* [**Testing Confidential Behavior**](https://docs.bout.network/build/testing-confidential) — integration testing against real Oceanum (OXN)
* [**Deploying Contracts**](https://docs.bout.network/build/deploying) — moving from tests to a live network

[Edit this page](https://github.com/oxn-network/oxn-docs/edit/main/docs/06-build/testing-local.md)[PreviousCompiling Contracts](https://docs.bout.network/build/compiling)[NextTesting Confidential Behavior](https://docs.bout.network/build/testing-confidential)
