Skip to content

Add hardhat #6

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 19 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 37 additions & 16 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,43 @@ on:
workflow_dispatch:

jobs:
check:
strategy:
fail-fast: true
matrix:
foundry_profile: ["test-via-ir", "test-no-ir"]
hardhat-check:
name: Hardhat project
runs-on: ubuntu-latest
env:
FOUNDRY_PROFILE: hardhat
steps:
- uses: actions/checkout@v4
with:
submodules: recursive

- name: Install Foundry
uses: foundry-rs/foundry-toolchain@v1
with:
version: nightly

- name: Install pnpm
uses: pnpm/action-setup@v4
with:
run_install: true

- name: Format check
run: pnpm prettier --check .

- name: Run hardhat tests
env:
NODE_OPTIONS: "--experimental-loader ts-node/esm/transpile-only --no-warnings=ExperimentalWarning"
run: pnpm hardhat test

foundry-check:
name: Foundry project
runs-on: ubuntu-latest
strategy:
fail-fast: true
matrix:
foundry_profile: ["via-ir", "no-ir"]
env:
FOUNDRY_PROFILE: ${{ matrix.foundry_profile }}
FOUNDRY_PROFILE: test-${{ matrix.foundry_profile }}
steps:
- uses: actions/checkout@v4
with:
Expand All @@ -32,11 +59,6 @@ jobs:
run: |
forge --version

- name: Run Forge fmt
run: |
forge fmt --check
id: fmt

- name: Run Forge build
run: |
forge build --sizes
Expand All @@ -46,26 +68,25 @@ jobs:
# https://book.getfoundry.sh/forge/gas-section-snapshots
- name: Confirm comparison snapshot
run: |
forge snapshot --check ${{ env.FOUNDRY_PROFILE }}.gas-snapshot \
forge snapshot --check snapshots/${{ matrix.foundry_profile }}/comparison.gas-snapshot \
--match-path "test/comparison/*"
id: comparison-snapshot

- name: Run remaining Forge tests, confirm section snapshots
run: |
forge test -vvv \
--no-match-path "test/comparison/*"
git diff --exit-code snapshots-${{ env.FOUNDRY_PROFILE }}
git diff --exit-code snapshots/${{ matrix.foundry_profile }}
id: test


# Coverage testing affects gas cost, and creates different snapshots.
# Only `lcov.info` is diffed to confirm coverage is checked in. Coverage
# doesn't use the 'comparison' tests.
- name: Confirm coverage
run: |
forge coverage --report-file ${{ env.FOUNDRY_PROFILE }}.lcov.info \
forge coverage --report-file coverage/lcov.info \
--report lcov --report summary \
--no-match-path "test/comparison/*" \
--no-match-coverage "test/comparison/*"
git diff --exit-code ${{ env.FOUNDRY_PROFILE }}.lcov.info
git diff --exit-code coverage/lcov.info
id: diff-coverage
16 changes: 16 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,19 @@ docs/

# Dotenv file
.env

node_modules

# Hardhat files
/artifacts

# TypeChain files
/typechain
/typechain-types

/coverage.json

# Hardhat Ignition default folder for deployments against a local node
ignition/deployments/chain-31337

cache_hardhat
3 changes: 3 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
lib
snapshots
pnpm-lock.yaml
3 changes: 3 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"plugins": ["prettier-plugin-solidity"]
}
57 changes: 27 additions & 30 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,64 +1,61 @@
# turbocrime/solidity-cbor

**This is a library for parsing CBOR.**
**This is a library for parsing CBOR.** This library does not provide tools for writing CBOR.

This library does not provide tools for writing CBOR.

This project was initially forked from [filecoin's CborDecode.sol](https://github.com/Zondax/filecoin-solidity/blob/master/contracts/v0.8/utils/CborDecode.sol) by Zondax AG.
This project was initially forked from [filecoin's CborDecode.sol](https://github.com/filecoin-project/filecoin-solidity/blob/master/contracts/v0.8/utils/CborDecode.sol).

[RFC 8949](https://www.iana.org/go/rfc8949)

[CBOR Simple Values Registry](https://www.iana.org/assignments/cbor-simple-values/cbor-simple-values.xhtml)

[CBOR Tags Registry](https://www.iana.org/assignments/cbor-tags/cbor-tags.xhtml)


## Usage

Most methods accept parameters `bytes` of CBOR data and `uint256` index, and return an updated index (and one or more values if appropriate). Since the data parameter is always first, you may sugar calls via `using` directive.

CBOR natively supports values up to `uint64`, so the typical values returned are `uint64`. Some methods return other types.

Deserialization methods are a capitalized name of the type like `UInt`, `NInt`, `Text`, `Map`, and so on for every CBOR type. These return a value of the equivalent solidity type when possible.
Deserialization methods are a capitalized name of the type like `UInt`, `NInt`, `Bytes`, `Map`, and so on for every CBOR type. These return a value of the equivalent solidity type when possible.

When specific format constraints exist, some optimized method variants are available, such as `String1` when the next should be a 1-byte string.
When specific format constraints exist, some optimized method variants are available, such as `String1` when the next string should fit within a `bytes1`, or `String32` when the next string should fit within a `bytes32`.

You can peek at the type of the next item with `isBytes` and so on.
You can peek at the major type of the next CBOR item with `isBytes`, `isTag`, and so on.

The caller is responsible for handling the index and using it to index the appropriate data. No 'cursor' metaphor is provided, but the example below demonstrates how a caller may define and use a cursor for convenience.
The caller is responsible for managing the index and using it to index the appropriate data. No 'cursor' metaphor is provided, but the example below demonstrates how a caller may define and use a cursor for convenience.

```solidity
using ReadCbor for bytes;

bytes constant someBytes = hex"84616103616102";

struct Cursor {
bytes b;
uint256 i;
bytes b;
uint256 i;
}

function example() pure {
Cursor memory c = Cursor(someBytes, 0);
uint32 arrayLen;

(c.i, arrayLen) = c.b.Array(c.i);

// In this example, we know the array length.
assert(arrayLen == 4);
string[] memory arrayStrs = new string[](2);
uint64[] memory arrayNums = new uint64[](2);

// CBOR arrays may contain items of any type.
for (uint32 arrayIdx = 0; arrayIdx < arrayLen; arrayIdx++) {
if (c.b.isString(c.i)) {
(c.i, arrayStrs[arrayIdx / 2]) = c.b.String(c.i);
} else if (c.b.isUInt(c.i)) {
(c.i, arrayNums[arrayIdx / 2]) = c.b.UInt(c.i);
}
Cursor memory c = Cursor(someBytes, 0);
uint32 arrayLen;

(c.i, arrayLen) = c.b.Array(c.i);

// In this example, we know the array length.
assert(arrayLen == 4);
string[] memory arrayStrs = new string[](2);
uint64[] memory arrayNums = new uint64[](2);

// CBOR arrays may contain items of any type.
for (uint32 arrayIdx = 0; arrayIdx < arrayLen; arrayIdx++) {
if (c.b.isString(c.i)) {
(c.i, arrayStrs[arrayIdx / 2]) = c.b.String(c.i);
} else if (c.b.isUInt(c.i)) {
(c.i, arrayNums[arrayIdx / 2]) = c.b.UInt(c.i);
}
}

// Require that the data was fully consumed.
require(c.b.length == c.i);
// Require that the data was fully consumed.
require(c.b.length == c.i);
}
```

Expand Down
35 changes: 35 additions & 0 deletions contracts/TestFixture.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.28;

import "../src/ReadCbor.sol";

/// @title TestFixture
/// @notice A small example contract fixture to confirm minimal function.
contract TestFixture {
uint public unlockTime;
address payable public owner;

event ParsedBytes32(uint i, bytes32 item, uint8 len);

constructor() payable {
owner = payable(msg.sender);
}

using ReadCbor for bytes;
function readThis(bytes calldata cbor) public {
require(msg.sender == owner, "You aren't the owner");

uint8 limit = 12;
(uint i, bytes32 parsed, uint8 len) = cbor.Bytes32(0, limit);

require(
i <= cbor.length,
"TestFixture Must read within bounds of cbor"
);
require(i == cbor.length, "TestFixture Must read entire cbor");

emit ParsedBytes32(i, parsed, len);

owner.transfer(address(this).balance);
}
}
Loading