Skip to content
This repository has been archived by the owner on Feb 26, 2024. It is now read-only.

Commit

Permalink
Merge branch 'develop' into update-ganache-core-2.13.0
Browse files Browse the repository at this point in the history
  • Loading branch information
fainashalts authored Oct 13, 2020
2 parents d4464dc + 5d591c8 commit 459f8d1
Show file tree
Hide file tree
Showing 29 changed files with 1,498 additions and 215 deletions.
4 changes: 4 additions & 0 deletions packages/abi-utils/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
node_modules/*
yarn.lock
package-lock.json
dist
110 changes: 110 additions & 0 deletions packages/abi-utils/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
# `@truffle/abi-utils`

Contains a few utilities for dealing with ABIs.

## Contents

This package contains a few different components:

- [Normalize ABIs](#normalize-abis)
- [TypeScript types](#typescript-types)
- [Arbitrary random ABIs](#arbitrary-random-abis)

## Normalize ABIs

> ```typescript
> // handle function entries omitting "type" from JSON
> const isFunctionEntry = entry.type === "function" || !("type" in entry);
>
> // handle: v--- new way v--- old way v--- default
> const isPayable = entry.stateMutability === "payable" || entry.payable || false;
>
> // handle "outputs" possibly being undefined
> const outputs = entry.outputs || [];
> ```
_^ Have you ever had to do this sort of thing?_ :scream:
Solidity's official [JSON ABI specification](https://solidity.readthedocs.io/en/v0.7.3/abi-spec.html)
is rather permissive, since it remains backwards compatible with older
versions of the language and because it permits omitting fields with default
values. This can get annoying if you're programmatically processing ABIs.
:information_source: This package provides a `normalize` function to purge
these kinds of inconsistencies.
```javascript
const { normalize } = require("@truffle/abi-utils");
```
```typescript
import { normalize } from "@truffle/abi-utils";
```

Specifically, this normalizes by:
- Ensuring every ABI entry has a `type` field, since it's optional for
`type: "function"`
- Populating default value `[]` for function `outputs` field
- Removing all instances of the legacy `payable` and `constant` fields
- Replacing those two fields with the newer `stateMutability` field

To use, provide the ABI as a JavaScript array, as the sole argument to the
function:

```typescript
// accepts ABIs from Solidity versions back to 0.4.12 or earlier!
const abi = normalize([{"type": "constructor"/*, ...*/}/*, ...*/);

// don't even worry about it
const isFunctionEntry = entry.type === "function";
const isPayable = entry.stateMutability === "payable";
```
## TypeScript types
This package exports the following types for **normalized** ABIs.
- `Abi`, to represent the full ABI array
- `Entry`, to represent items in ABI arrays
- `FunctionEntry`, to represent named functions
- `ConstructorEntry`, to represent constructors
- `FallbackEntry`, to represent old or new fallback functions
- `ReceiveEntry`, to represent receive functions
- `Parameter`, to represent parameters defined in entry inputs or outputs
- `EventParameter`, to represent event parameters
To use these, you should first call [`normalize`](#normalize-abis), described
above.
```typescript
import * as Abi from "@truffle/abi-utils";

const abi: Abi.Abi = [{"type": "constructor"/*, ...*/}/*, ...*/];
const parameter: Abi.Parameter = {"type": "tuple[]", "components": [/*...*/]};
// etc.
```
## Arbitrary random ABIs
_Do you need to test all the different kinds of ABIs, including testing your
support for the various quirks across different Solidity versions?_ :flushed:
You can use this package for generating all sorts of random ABIs, random ABI
events, random ABI parameter values, etc.
This package provides [fast-check](https://github.com/dubzzz/fast-check)
arbitraries for property-based testing methodologies. If you're not familiar
with fast-check or property-based testing, please see the link above for more
information.
```typescript
import * as fc from "fast-check";
import { Arbitrary } from "@truffle/abi-utils";

// generate 10 random ABIs
const randomAbis = fc.sample(Arbitrary.Abi(), 10);
```
See this package's [internal tests for `normalize`](./lib/normalize.test.ts)
for example usage in automated tests.
4 changes: 4 additions & 0 deletions packages/abi-utils/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
module.exports = {
preset: "ts-jest",
testEnvironment: "node"
};
57 changes: 57 additions & 0 deletions packages/abi-utils/lib/arbitrary.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { testProp } from "jest-fast-check";
import * as abiSchema from "@truffle/contract-schema/spec/abi.spec.json";
import { matchers } from "jest-json-schema";

expect.extend(matchers);

import * as Arbitrary from "./arbitrary";

// helper function to ensure that, when we match against a given subschema,
// we also include all the definitions, in case the subschema references those
const withDefinitions = (schema: object) => ({
definitions: abiSchema.definitions,
...schema
});

const arbitraries = {
Parameter: {
arbitrary: Arbitrary.Parameter(),
schema: withDefinitions(abiSchema.definitions.Parameter)
},
EventParameter: {
arbitrary: Arbitrary.EventParameter(),
schema: withDefinitions(abiSchema.definitions.EventParameter)
},
EventEntry: {
arbitrary: Arbitrary.EventEntry(),
schema: withDefinitions(abiSchema.definitions.Event)
},
FunctionEntry: {
arbitrary: Arbitrary.FunctionEntry(),
schema: withDefinitions(abiSchema.definitions.NormalFunction)
},
ConstructorEntry: {
arbitrary: Arbitrary.ConstructorEntry(),
schema: withDefinitions(abiSchema.definitions.ConstructorFunction)
},
ReceiveEntry: {
arbitrary: Arbitrary.ReceiveEntry(),
schema: withDefinitions(abiSchema.definitions.ReceiveFunction)
},
FallbackEntry: {
arbitrary: Arbitrary.FallbackEntry(),
schema: withDefinitions(abiSchema.definitions.FallbackFunction)
},
Abi: {
arbitrary: Arbitrary.Abi(),
schema: abiSchema
}
};

for (const [name, { arbitrary, schema }] of Object.entries(arbitraries)) {
describe(`Arbitrary.${name}`, () => {
testProp("validates schema", [arbitrary], value => {
expect(value).toMatchSchema(schema);
});
});
}
Loading

0 comments on commit 459f8d1

Please sign in to comment.