Skip to content

Solidity

Version

Running on Solidity v0.8.34 via Foundry and Forge Std v1.15.0 (pre-installed in lib/forge-std/).

Supported languages

Solidity

Testing framework

Foundry (forge test) with forge-std/Test.sol. Tests are written in Solidity, not JavaScript.

Project layout

challenge/
├── foundry.toml            # compiler + evm_version config
├── Main.s.sol              # runCode entrypoint (Foundry script)
├── src/                    # your contracts
│   └── HelloWorld.sol
├── tests/                  # *.t.sol test files
│   └── HelloWorld.t.sol
├── lib/forge-std/          # pre-installed, import-ready
└── node_modules/           # user-installed npm packages (OpenZeppelin, etc.)

Special reminders and implementation details

Contract (src/HelloWorld.sol)

solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.34;

contract HelloWorld {
    function helloWorld() public pure returns (string memory) {
        return "Hello World!";
    }
}

Test (tests/HelloWorld.t.sol)

solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.34;

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

contract HelloWorldTest is Test {
    HelloWorld helloWorld;

    function setUp() public {
        helloWorld = new HelloWorld();
    }

    /// Should return "Hello World!"
    function testReturnsHelloWorld() public view {
        assertEq(helloWorld.helloWorld(), "Hello World!");
    }
}

Notes on tests:

  • File name must end with .t.sol.
  • Test contract must extend Test from forge-std/Test.sol.
  • Test function names must start with test. Use testFuzz* for fuzzed inputs, testFail* for tests that are expected to revert.
  • A one-line comment (// …, /// …, or NatSpec /// @notice … / /// @dev …) directly above each test function becomes the human-readable label shown in the results panel. Without one, the raw function name is displayed.

Run Code script (Main.s.sol at project root)

solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.34;

import "forge-std/Script.sol";
import "forge-std/console.sol";
import "./src/HelloWorld.sol";

contract Main is Script {
    function run() external {
        HelloWorld instance = new HelloWorld();
        console.log(instance.helloWorld());
    }
}

forge script runs run() against an in-memory EVM; any console.log output is captured to the Run Code console panel. No local node (anvil) is required for simple read/deploy interactions.

Debugging

console.log

Import forge-std/console.sol and call console.log(...) from anywhere — including pure and view functions. Logs appear in the Run Code output panel (during forge script) and in the Tests panel (during forge test).

solidity
import "forge-std/console.sol";

function helloWorld() public pure returns (string memory) {
    console.log("helloWorld() was called");
    return "Hello World!";
}

Supported types: string, uint, int, bool, address, bytes, bytes32. Use console.logInt / console.logBytes when overload resolution is ambiguous.

Cheatcodes

From forge-std/Test.sol:

  • vm.prank(addr) — next call is made as addr.
  • vm.warp(ts) / vm.roll(bn) — time-travel / block number override.
  • vm.expectRevert() / vm.expectRevert("reason") — assert the next call reverts.
  • vm.expectEmit() — assert an event will be emitted.
  • vm.deal(addr, amount) — set ETH balance.

Assertions

  • assertEq, assertTrue, assertFalse
  • assertGt, assertGe, assertLt, assertLe
  • assertApproxEqAbs(a, b, tolerance) / assertApproxEqRel(a, b, maxDelta)

Package management

Solidity challenges support npm-based packages. The Dependencies panel searches the npm registry; install something like @openzeppelin/contracts, pick a version, and it is staged into node_modules/. foundry.toml declares libs = ["lib", "node_modules"] with auto_detect_remappings = true, so forge scans both paths and generates remappings like @openzeppelin/contracts/=node_modules/@openzeppelin/contracts/ automatically at build time.

solidity
import "@openzeppelin/contracts/utils/Strings.sol";

contract HelloWorld {
    using Strings for uint256;

    function helloWorld() public pure returns (string memory) {
        return string.concat("Hello World! ", uint256(42).toString());
    }
}

No remappings.txt needed — forge walks node_modules/ and generates remappings automatically at build time.

Included libraries