solidity-examples

repository·master·Indexed 20 days ago

https://github.com/ethereum/solidity-examples

A draft standard library of Solidity contracts providing optimized implementations for common tasks, including math, string manipulation, Patricia Tries, bit manipulation, byte conversion, token standards, and low-level memory operations. Requires Solidity 0.5.0 or later and is intended for Metropolis-compliant networks. Includes the solstl CLI for compilation, testing, and performance benchmarking.

Tokens
6.4K
Snippets
32
Records
40
Agent score
70%

What's inside solidity-examples

  1. Overview of the Solidity Standard Library

    master

    The solidity-examples repository serves as a draft standard library of Solidity contracts designed for performing common tasks. It provides specialized packages for bit manipulation, byte conversion, mathematics, Patricia Tries, string manipulation, token standards, and low-level memory operations.

    Compatibility Requirements:

    • Solidity Version: Must be 0.5.0 or later.
    • Runtime: Code is intended to run in Metropolis-compliant networks.
  2. Use the ExactMath library for arithmetic operations

    master

    The ExactMath library (part of the math package) provides functions for performing exact arithmetic operations in Solidity. It is designed to handle arithmetic safely, drawing inspiration from OpenZeppelin's SafeMath library. Use this library when you need to prevent common arithmetic errors like underflow or overflow during mathematical computations in your smart contracts.

    // See ExactMathExamples.sol for usage patterns
    // Source: ../../src/math/ExactMath.sol
  3. Use the Strings library for UTF-8 validation

    master

    The strings package provides a static library designed to perform runtime validation of Solidity strings to ensure they conform to the UTF-8 encoding (as defined in the Unicode 10.0 standard). While Solidity performs compile-time checks on string literals, this library allows you to verify the validity of strings at runtime.

    // Example usage pattern (refer to StringsExamples.sol for implementation details)
    // import { Strings } from "@ethereum/solidity-examples/src/strings/Strings.sol";
    
    // Use the library to validate a string at runtime
    // bool isValid = Strings.isValidUtf8(someString);
  4. Use the Bits library for bitfield manipulation

    master

    The Bits library provides utilities for accessing and manipulating individual bits within uint numbers, treating them as bitfields. It is implemented as a Solidity library.

    Package: bits
    Contract type: library
    Source file: src/bits/Bits.sol

    // Example usage can be found in:
    // ../../examples/bits/BitsExamples.sol
  5. Understanding test success and failure logic

    master

    The test runner determines success or failure based on the contract name and the return value of the test() method (which calls your testImpl).

    Test Name contains Throws?Expected BehaviorPass Condition
    NoTest should NOT throwReturn value is true
    YesTest SHOULD throwReturn value is NOT true

    In the STLTest base contract, the return value is set to true before testImpl() is called. If an assert fails or an error occurs, the execution stops, and the return value remains true (or the EVM indicates an illegal jump), allowing the runner to distinguish between a successful execution and a thrown error.

  6. Understand the difference between `byte` (bytes1) and `uint8`

    master

    The byte type is an alias for bytes1 and stores a single byte. While it may seem similar to uint8, their internal representations differ significantly due to Ethereum's padding rules:

    • uint8: Padded on the left (higher-order side).
    • byte: Padded on the right (lower-order side).

    Warning on Conversions: When using inline assembly to extract a byte from a larger type (like bytes32) into a byte variable, the internal representation of that byte might be technically invalid if it occupies a position that expects left-padding.

    Example of representation difference:

    // Internal: 0x0000...0001
    uint8 u8 = 1;
    
    // Internal: 0x0100...0000
    byte b = 1;
    // 0x0000000000000000000000000000000000000000000000000000000000000001
    uint8 u8 = 1;
    
    // 0x0100000000000000000000000000000000000000000000000000000000000000
    byte b = 1;
  7. Naming conventions for test contracts

    master

    To ensure tests are correctly identified and interpreted by the runner, follow these naming patterns:

    1. Standard Tests: Start the contract name with Test, followed by the library name, and then the function name.

      • Pattern: Test<LibraryName><FunctionName>
      • Example: TestBitsBitXor (tests Bits.bitXor)
    2. Expected Failure Tests: If a test is designed to fail (i.e., it is expected to throw), the word Throws must be included somewhere in the contract name.

      • Pattern: Test<LibraryName><FunctionName>Throws

    All test contracts for a specific library should typically be kept within the same Solidity source file.

  8. Use the unsafe Memory library for direct memory manipulation

    master

    The Memory library is part of the unsafe package and is designed for low-level, direct memory operations. It provides methods for copying memory regions, performing equality checks, and converting between raw memory and various Solidity types.

    Warning: This library is categorized as unsafe because it performs operations that bypass standard Solidity safety checks, such as reading and writing directly to memory addresses. Use it only when performance or specific low-level requirements necessitate direct memory access.

  9. Use different padding for literals in `bytesN` types

    master

    When assigning literals to fixed-size byte types (bytesN), the padding behavior depends on the literal type:

    1. Number literals: Padded to the left (higher-order side).
    2. String literals: Padded to the right (lower-order side).

    Example behavior for bytes32:

    // Result: 0x0000000000000000000000000000000000000000000000000000000001020304
    var numLit = bytes32(0x01020304);
    
    // Result: 0x3031303230333034000000000000000000000000000000000000000000000000
    var strLit = bytes32("01020304");
    // 0x0000000000000000000000000000000000000000000000000000000001020304
    var numLit = bytes32(0x01020304);
    
    // 0x3031303230333034000000000000000000000000000000000000000000000000
    var strLit = bytes32("01020304");
  10. Understand padding rules for bytes and strings in Ethereum

    master

    In Ethereum, different data types follow different padding rules when stored in 32-byte words:

    • Strings and Bytes: Padded on the lower-order (right) side with zero-bytes. For example, the string "abcd" in a bytes32 word is 0x616263640000....
    • Numbers and Addresses: Padded on the higher-order (left) side. For example, the number 0x61626364 in a bytes32 word is 0x0000...61626364.

    Solidity and web3.js handle these padding rules automatically during encoding and decoding.

  11. How performance is measured in Solidity examples

    master

    Performance in this repository is measured by gas usage. Instead of using standard testing frameworks, performance tests use 'perf functors'—single-method contracts that implement a perf() function directly.

    When running these tests in the go-ethereum EVM, the perf() function returns the gas spent during the execution of the specific logic being tested.

    To ensure accuracy, gas metering is performed manually within the perf() function. This allows the implementor to exclude 'staging' code (such as variable initialization or data preparation) from the measurement, focusing only on the target function's execution cost.

    contract STLPerf {
        function perf() public payable returns (uint);
    }