Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
192 commits
Select commit Hold shift + click to select a range
92e08ec
naive first marshalling attemmpt
containerman17 Jul 24, 2024
6a3d006
int 8-int64 supported
containerman17 Jul 24, 2024
5618d6c
negative numbers support
containerman17 Jul 24, 2024
9fbd36c
support maps
containerman17 Jul 24, 2024
9b0c5c2
funky benchmark
containerman17 Jul 24, 2024
0f4d1c6
structs reflection caching attempt
containerman17 Jul 24, 2024
1c5b8a2
some fuzz tests
containerman17 Jul 24, 2024
fe39c66
fix speed comment
containerman17 Jul 24, 2024
66c86f8
relocate implementation out of test
containerman17 Jul 24, 2024
02c3643
benchmark
containerman17 Jul 24, 2024
8fb31da
rename test to TestMakeSureMarshalUnmarshalIsNotTooSlow
containerman17 Jul 24, 2024
acb7e45
fix fuzz test
containerman17 Jul 24, 2024
529d1c4
spec tests for js implant
containerman17 Jul 24, 2024
1a38839
update spec tests
containerman17 Jul 25, 2024
bfa9aea
Merge branch 'main' into containerman/standardize-marshal-function
containerman17 Jul 25, 2024
55e9bcd
Merge branch 'main' into containerman/standardize-marshal-function
containerman17 Jul 31, 2024
d31dc72
remove fuzz test
containerman17 Jul 31, 2024
5c08120
simplify to 2 types
containerman17 Jul 31, 2024
d7ec6e4
restore original logic
containerman17 Jul 31, 2024
103db88
rewrite marshal with avalanchego's wrappers.Packer
containerman17 Jul 31, 2024
2df75a4
pack bytes with uint32 and everything else with uint16
containerman17 Aug 1, 2024
c2c0e64
check for long arrays and strings, marshal maps with uint16
containerman17 Aug 1, 2024
3279d3d
Merge branch 'main' into containerman/standardize-marshal-function
containerman17 Aug 1, 2024
0d62a73
update benchmark results
containerman17 Aug 1, 2024
1229c35
move to codec
containerman17 Aug 1, 2024
917335b
come back to codec.packer
containerman17 Aug 1, 2024
c7b49bd
speed up TestMakeSureMarshalUnmarshalIsNotTooSlow a bit
containerman17 Aug 1, 2024
dfe750b
support pointer to a struct
containerman17 Aug 1, 2024
1eada5e
auto marshaller integration
containerman17 Aug 1, 2024
6d48163
lint
containerman17 Aug 1, 2024
d78337a
remove a slow test breaking CI
containerman17 Aug 1, 2024
08ca5fa
fix linter errors
containerman17 Aug 1, 2024
a760610
faster reflection cache
containerman17 Aug 1, 2024
d0b9b33
minimize test to exclude testing errors
containerman17 Aug 1, 2024
2b61fee
unsafe type caching
containerman17 Aug 1, 2024
88ad966
simplify benchmark
containerman17 Aug 1, 2024
ebf421e
Merge branch 'main' into containerman/standardize-marshal-function
containerman17 Aug 1, 2024
9d48156
Merge branch 'main' into containerman/standardize-marshal-function
containerman17 Aug 2, 2024
364ea97
update benchmarks
containerman17 Aug 5, 2024
5aa6aa6
add benchmark results
containerman17 Aug 5, 2024
70f5185
add benchmem
containerman17 Aug 5, 2024
55e9e90
add benchmem results
containerman17 Aug 5, 2024
bc99331
deprecate string operations
containerman17 Aug 6, 2024
bbd80e0
Merge branch 'main' into containerman/standardize-marshal-function
containerman17 Aug 14, 2024
2dcfe25
move empty address error
containerman17 Aug 14, 2024
38a6380
empty file
containerman17 Aug 14, 2024
efc1970
lint
containerman17 Aug 14, 2024
82cb7f8
Merge branch 'main' into containerman/standardize-marshal-function
containerman17 Aug 15, 2024
f92b4f5
Merge branch 'main' into containerman/standardize-marshal-function
containerman17 Aug 15, 2024
c2a7741
Merge branch 'containerman/standardize-marshal-function' of https://g…
containerman17 Aug 15, 2024
4146154
Merge branch 'main' into containerman/standardize-marshal-function
containerman17 Aug 16, 2024
43d55f8
Merge branch 'main' into containerman/standardize-marshal-function
containerman17 Aug 19, 2024
6b932ab
Merge branch 'main' into containerman/standardize-marshal-function
containerman17 Aug 20, 2024
5370f77
Merge branch 'main' into containerman/standardize-marshal-function
containerman17 Aug 21, 2024
30e4201
remove .prof
containerman17 Aug 21, 2024
2fdd6fe
correct 'marshall' to 'marshal' according to Go conventions
containerman17 Aug 21, 2024
cf0e771
Merge branch 'main' into containerman/standardize-marshal-function
containerman17 Aug 22, 2024
b43de9a
Merge branch 'main' into containerman/standardize-marshal-function
containerman17 Aug 23, 2024
0383d88
Merge branch 'main' into containerman/standardize-marshal-function
containerman17 Aug 26, 2024
7ec6da9
Merge branch 'main' into containerman/standardize-marshal-function
containerman17 Aug 27, 2024
a330078
simplify codec.Packer
containerman17 Aug 27, 2024
15b5a44
get chainid from tmpnet instead of the platform (#1458)
containerman17 Aug 27, 2024
630efb0
lint
containerman17 Aug 27, 2024
dc1a194
Merge branch 'main' into containerman/standardize-marshal-function
containerman17 Aug 27, 2024
10c51b2
change to linearcodec
containerman17 Aug 27, 2024
2aaac18
lint
containerman17 Aug 27, 2024
66df721
go mod tidy
containerman17 Aug 27, 2024
e8aed2e
add serialize tag to Transfer
containerman17 Aug 27, 2024
ef5be50
abi generation
containerman17 Aug 27, 2024
0b0ecc5
spec tests
containerman17 Aug 27, 2024
81472c7
ABI in RPC
containerman17 Aug 27, 2024
4f02e00
Merge branch 'main' into containerman/standardize-marshal-function
containerman17 Aug 28, 2024
0116d32
Merge branch 'containerman/standardize-marshal-function' into abi
containerman17 Aug 28, 2024
bb29003
HasTypeID as a separate iface
containerman17 Aug 28, 2024
f8865fa
add TypeParser.GetRegisteredTypes method
containerman17 Aug 28, 2024
efc7670
move ABI to core API
containerman17 Aug 28, 2024
b9406f3
remove unused errors
containerman17 Aug 28, 2024
0afbe10
auto size calculation
containerman17 Aug 28, 2024
bb3b03e
Merge branch 'containerman/standardize-marshal-function' into abi
containerman17 Aug 28, 2024
5b49eda
rename LinearCodecInstance
containerman17 Aug 28, 2024
534e82d
lint
containerman17 Aug 28, 2024
cb157e0
update from #1198
containerman17 Aug 29, 2024
9a22c00
from clean slate
containerman17 Aug 29, 2024
195b570
Merge branch 'main' into abi
containerman17 Aug 29, 2024
0a9ecf7
return abi logic
containerman17 Aug 29, 2024
3c0317b
nit: remove function name in panics
containerman17 Aug 29, 2024
f758d2b
transaction test nit
containerman17 Aug 29, 2024
74a2147
catch up with main
containerman17 Aug 30, 2024
848fa01
Merge branch 'main' into abi
containerman17 Aug 30, 2024
05b9a84
lint
containerman17 Aug 30, 2024
e3b4976
rename HasTypeID to Typed
containerman17 Aug 30, 2024
3a35d42
Merge branch 'main' into abi
containerman17 Aug 30, 2024
f960449
separate package for abi
containerman17 Aug 30, 2024
76762f9
restore spec tests
containerman17 Aug 30, 2024
9c38001
treat codec.Address as a byte array while serializing
containerman17 Aug 30, 2024
2dde532
comments and nits
containerman17 Aug 31, 2024
9018981
use set.Set instead of map[reflect.Type]bool
containerman17 Aug 31, 2024
0b4c679
Merge branch 'main' into abi
containerman17 Aug 31, 2024
c3daf14
lint
containerman17 Aug 31, 2024
52f44b5
Merge branch 'main' into abi
containerman17 Sep 4, 2024
0941d9b
remove memo field
containerman17 Sep 4, 2024
c92fc27
require serialize=true
containerman17 Sep 4, 2024
3bbe982
remove a breaker
containerman17 Sep 4, 2024
43e273c
calculate ABI in place
containerman17 Sep 4, 2024
d508fb3
use ABI as struct in implementation
containerman17 Sep 4, 2024
6448d62
stable ABI hash
containerman17 Sep 4, 2024
c74da71
ABI wants its own ABI
containerman17 Sep 4, 2024
60d3bdf
rename abi to vmabi
containerman17 Sep 4, 2024
90c1a23
remove ABI for ABI
containerman17 Sep 4, 2024
888678b
redo map as an array
containerman17 Sep 4, 2024
52f40ae
clean up test specs a bit
containerman17 Sep 4, 2024
1f627d0
basic codegen and refactor tests WIP
containerman17 Sep 4, 2024
8c0e813
trying different naming
containerman17 Sep 4, 2024
012c9be
spec simplification WIP
containerman17 Sep 5, 2024
1c6e9de
go generate
containerman17 Sep 5, 2024
6ea5052
lower case json
containerman17 Sep 5, 2024
b49e7dd
proper codegen test
containerman17 Sep 5, 2024
90d416f
further simplify spec tests
containerman17 Sep 5, 2024
913be5a
transfer test
containerman17 Sep 5, 2024
e26553d
file based spec test
containerman17 Sep 5, 2024
0d7fe63
simplify tests
containerman17 Sep 7, 2024
192d312
ABI of ABI
containerman17 Sep 8, 2024
65a7961
Outer/Inner struct tests for TS debug
containerman17 Sep 8, 2024
9386601
Merge branch 'main' into abi
containerman17 Sep 9, 2024
af3aaa1
lint
containerman17 Sep 9, 2024
80f26b1
check ABI
containerman17 Sep 10, 2024
2422191
Merge branch 'main' into abi
containerman17 Sep 10, 2024
063371c
lost in merge
containerman17 Sep 10, 2024
6b20600
remove comment lines in abi test
containerman17 Sep 10, 2024
6ea64b7
remove a debug statement
containerman17 Sep 10, 2024
357b943
Merge branch 'main' into abi
containerman17 Sep 10, 2024
e853d67
Merge branch 'main' into abi
containerman17 Sep 10, 2024
044f78f
move mock abi file
containerman17 Sep 10, 2024
df03e64
rename to abigen
containerman17 Sep 10, 2024
ecd2dcb
use cobra
containerman17 Sep 10, 2024
ce6316f
Update codec/address.go
containerman17 Sep 10, 2024
5056833
require that the " characters in address string
containerman17 Sep 10, 2024
e00eeb0
rename ABI-related stuff
containerman17 Sep 10, 2024
34e53bf
fix tests after renaming
containerman17 Sep 10, 2024
9256382
test full marshal cycle
containerman17 Sep 10, 2024
0f3467d
TestDescribeVM
containerman17 Sep 10, 2024
1a4fbd3
Update abi/codegen.go
containerman17 Sep 10, 2024
7cfce68
remove StringAsBytes
containerman17 Sep 10, 2024
4e5ab4d
Merge branch 'abi' of https://github.com/ava-labs/hypersdk into abi
containerman17 Sep 10, 2024
e28f5ca
add unicode package
containerman17 Sep 10, 2024
f191e3c
lint
containerman17 Sep 11, 2024
179729f
go mod tidy
containerman17 Sep 11, 2024
6733ad7
Merge branch 'main' into abi
containerman17 Sep 11, 2024
0ed9b62
flatten types def in abi
containerman17 Sep 11, 2024
a17b7a5
don't use mixed receivers
containerman17 Sep 11, 2024
8eb134a
inline vm.Hash into a test
containerman17 Sep 11, 2024
e58bea0
rename abi.VM to abi.ABI
containerman17 Sep 11, 2024
a08ca8d
remove embed
containerman17 Sep 11, 2024
0af8928
funish renaming
containerman17 Sep 11, 2024
8bf7870
get rid of vm.getabi
containerman17 Sep 11, 2024
6867827
nit avoid redundant import alias
containerman17 Sep 11, 2024
7c214da
DescribeVM -> NewABI
containerman17 Sep 11, 2024
a072bba
lint
containerman17 Sep 11, 2024
0738ff9
mock gen
containerman17 Sep 12, 2024
c8bc483
share typesAlreadyProcessed across describing multiple actions
containerman17 Sep 12, 2024
89bfae5
put a comment on each test
containerman17 Sep 12, 2024
ad0cdc7
Update abi/auto_marshal_abi_spec_test.go
containerman17 Sep 12, 2024
4e91369
nit: objectBytes
containerman17 Sep 12, 2024
790c1ea
Merge branch 'abi' of https://github.com/ava-labs/hypersdk into abi
containerman17 Sep 12, 2024
8769ec1
remove mustPrintOrderedJSON
containerman17 Sep 12, 2024
814122e
comment on empty names
containerman17 Sep 12, 2024
4505daf
comment on IsUpper
containerman17 Sep 12, 2024
23ef4b8
revert typealias
containerman17 Sep 12, 2024
58b77bb
TODO here to switch to the new address format
containerman17 Sep 12, 2024
9e918c6
We should follow the style of funcName does X
containerman17 Sep 12, 2024
a9a4a1d
use rune in cobra
containerman17 Sep 12, 2024
2d80339
comment on Dereference
containerman17 Sep 12, 2024
be0a7f6
comment on serialize tag
containerman17 Sep 12, 2024
0e10aa0
use %s and t instead of t.String()
containerman17 Sep 12, 2024
51ef70b
Merge branch 'main' into abi
containerman17 Sep 12, 2024
771cc44
readme
containerman17 Sep 12, 2024
2ed650e
rename mockabi_test
containerman17 Sep 12, 2024
0179e43
lint
containerman17 Sep 12, 2024
b2aa9df
Update api/jsonrpc/server.go
aaronbuchwald Sep 12, 2024
157c619
expectedABIJSON capitalization
containerman17 Sep 12, 2024
4a34fda
Merge branch 'main' into abi
containerman17 Sep 12, 2024
96b7446
adopt vm with contracts
containerman17 Sep 12, 2024
0d9c004
readme update
containerman17 Sep 12, 2024
dd093d4
readme fix
containerman17 Sep 12, 2024
69edc0f
formatting
containerman17 Sep 12, 2024
3abbc04
readme
containerman17 Sep 12, 2024
85f4e3a
typo
containerman17 Sep 12, 2024
dcaa47a
type table
containerman17 Sep 12, 2024
976ad57
explain why we need ABI
containerman17 Sep 12, 2024
75da953
Testing algo
containerman17 Sep 12, 2024
8de8534
whitespace
containerman17 Sep 12, 2024
2322462
ABI readme nits (#1548)
aaronbuchwald Sep 12, 2024
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
96 changes: 96 additions & 0 deletions abi/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# ABI Package

## Overview
The ABI package provides functionality for marshaling and unmarshaling actions. It is designed to work across different language implementations.

## ABI Format
The ABI is defined in JSON format, as shown in the `abi.json` file:
```json
{
"actions": [
{
"id": 1,
"action": "MockObjectSingleNumber"
},
],
"types": [
{
"name": "MockObjectSingleNumber",
"fields": [
{
"name": "Field1",
"type": "uint16"
}
]
},
]
}
```

The ABI consists of two main sections:
- actions: A list of action definitions, each with a typeID and action name (action name specifies the type)
- types: A dictionary of types including their name and corresponding fields

The type in each field must either be included in the ABI's `types` or in the list of [Supported Primitive Types](#supported-primitive-types).

## Test Vectors
This implementation provides `testdata/` for implementations in any other language.

To verify correctness, an implementation can implement the following pseudocode:
```
abi = abi.json

for filename in testdata/*.hex:
if filename.endswith(".hash.hex"):
continue
expectedHex = readFile(filename)
json = readFile(filename.replace(".hex", ".json"))

actualHex = Marshal(abi, json)
if actualHex != expectedHex:
raise "Hex values do not match"

```

## ABI Verification
Frontends can use the ABI to display proper action and field names. For a wallet to verify it knows what it's signing, it must ensure that a canonical hash of the ABI is included in the message it signs.

A correct VM will verify the signature against the same ABI hash, such that verification fails if the wallet signed an action against a different than expected ABI.

This enables frontends to provide a verifiable display of what they are asking users to sign.

## Constraints
- Actions require an ID, other structs / types do not require one
- Multiple structs with the same name from different packages are not supported
- Maps are not supported; use slices (arrays) instead
- Built-in types include the special case type aliases: `codec.Address` and `codec.Bytes`

## Generating Golang Bindings
Use cmd/abigen to automatically generate Go bindings from an ABI's JSON.

For example, to auto-generate golang bindings for the test ABI provided in `./abi/testdata/abi.json` run:

```sh
go run ./cmd/abigen/ ./abi/testdata/abi.json ./example.go --package=testpackage
```

This should generate the same code that is present in `./abi/mockabi_test.go`.

## Supported Primitive Types

| Type | Range/Description | JSON Serialization | Binary Serialization |
|----------|----------------------------------------------------------|--------------------|---------------------------------------|
| `bool` | true or false | boolean | 1 byte |
| `uint8` | numbers from 0 to 255 | number | 1 byte |
| `uint16` | numbers from 0 to 65535 | number | 2 bytes |
| `uint32` | numbers from 0 to 4294967295 | number | 4 bytes |
| `uint64` | numbers from 0 to 18446744073709551615 | number | 8 bytes |
| `int8` | numbers from -128 to 127 | number | 1 byte |
| `int16` | numbers from -32768 to 32767 | number | 2 bytes |
| `int32` | numbers from -2147483648 to 2147483647 | number | 4 bytes |
| `int64` | numbers from -9223372036854775808 to 9223372036854775807 | number | 8 bytes |
| `Address`| 33 byte array | base64 | 33 bytes |
| `Bytes` | byte array | base64 | uint32 length + bytes |
| `string` | string | string | uint16 length + bytes |
| `[]T` | for any `T` in the above list, serialized as an array | array | uint32 length + elements |

179 changes: 179 additions & 0 deletions abi/abi.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
// Copyright (C) 2024, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package abi

import (
"fmt"
"reflect"
"strings"

"github.com/ava-labs/avalanchego/utils/set"

"github.com/ava-labs/hypersdk/codec"
)

type ABI struct {
Actions []Action `serialize:"true" json:"actions"`
Types []Type `serialize:"true" json:"types"`
}

var _ codec.Typed = (*ABI)(nil)

func (ABI) GetTypeID() uint8 {
return 0
}

type Field struct {
Name string `serialize:"true" json:"name"`
Type string `serialize:"true" json:"type"`
}

type Action struct {
ID uint8 `serialize:"true" json:"id"`
Action string `serialize:"true" json:"action"`
}

type Type struct {
Name string `serialize:"true" json:"name"`
Fields []Field `serialize:"true" json:"fields"`
}

func NewABI(actions []codec.Typed) (ABI, error) {
vmActions := make([]Action, 0)
vmTypes := make([]Type, 0)
typesSet := set.Set[string]{}
typesAlreadyProcessed := set.Set[reflect.Type]{}

for _, action := range actions {
actionABI, typeABI, err := describeAction(action, typesAlreadyProcessed)
if err != nil {
return ABI{}, err
}
vmActions = append(vmActions, actionABI)
for _, t := range typeABI {
if !typesSet.Contains(t.Name) {
vmTypes = append(vmTypes, t)
typesSet.Add(t.Name)
}
}
}
return ABI{Actions: vmActions, Types: vmTypes}, nil
}

// describeAction generates the Action and Types for a single action.
// It handles both struct and pointer types, and recursively processes nested structs.
// Does not support maps or interfaces - only standard go types, slices, arrays and structs
func describeAction(action codec.Typed, typesAlreadyProcessed set.Set[reflect.Type]) (Action, []Type, error) {
t := reflect.TypeOf(action)
if t.Kind() == reflect.Ptr {
t = t.Elem()
}

actionABI := Action{
ID: action.GetTypeID(),
Action: t.Name(),
}

typesABI := make([]Type, 0)
typesLeft := []reflect.Type{t}

// Process all types, including nested ones
for {
var nextType reflect.Type
nextTypeFound := false
for _, anotherType := range typesLeft {
if !typesAlreadyProcessed.Contains(anotherType) {
nextType = anotherType
nextTypeFound = true
break
}
}
if !nextTypeFound {
break
}

fields, moreTypes, err := describeStruct(nextType)
if err != nil {
return Action{}, nil, err
}

typesABI = append(typesABI, Type{
Name: nextType.Name(),
Fields: fields,
})
typesLeft = append(typesLeft, moreTypes...)

typesAlreadyProcessed.Add(nextType)
}

return actionABI, typesABI, nil
}

// describeStruct analyzes a struct type and returns its fields and any nested struct types it found
func describeStruct(t reflect.Type) ([]Field, []reflect.Type, error) {
kind := t.Kind()

if kind != reflect.Struct {
return nil, nil, fmt.Errorf("type %s is not a struct", t)
}

fields := make([]Field, 0)
otherStructsSeen := make([]reflect.Type, 0)

for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
fieldType := field.Type
fieldName := field.Name

// Skip any field that will not be serialized by the codec
serializeTag := field.Tag.Get("serialize")
if serializeTag != "true" {
continue
}

// Handle JSON tag for field name override
jsonTag := field.Tag.Get("json")
if jsonTag != "" {
parts := strings.Split(jsonTag, ",")
fieldName = parts[0]
}

if field.Anonymous && fieldType.Kind() == reflect.Struct {
// Handle embedded struct by flattening its fields
embeddedFields, moreTypes, err := describeStruct(fieldType)
if err != nil {
return nil, nil, err
}
fields = append(fields, embeddedFields...)
otherStructsSeen = append(otherStructsSeen, moreTypes...)
} else {
arrayPrefix := ""

// Here we assume that all types without a name are slices.
// We completely ignore the fact that maps exist as we don't support them.
// Types like `type Bytes = []byte` are slices technically, but they have a name
// and we need them to be named types instead of slices.
for fieldType.Name() == "" {
arrayPrefix += "[]"
fieldType = fieldType.Elem()
}
Comment on lines +157 to +160
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we add a comment explaining the exact assumption we're using here ie. exactly what set of types will return their name as empty string?


typeName := arrayPrefix + fieldType.Name()

// Add nested structs and pointers to structs to the list for processing
if fieldType.Kind() == reflect.Struct {
otherStructsSeen = append(otherStructsSeen, fieldType)
} else if fieldType.Kind() == reflect.Ptr {
otherStructsSeen = append(otherStructsSeen, fieldType.Elem())
}

fields = append(fields, Field{
Name: fieldName,
Type: typeName,
})
}
}

return fields, otherStructsSeen, nil
}
45 changes: 45 additions & 0 deletions abi/abi_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Copyright (C) 2024, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package abi

import (
"testing"

"github.com/stretchr/testify/require"

"github.com/ava-labs/hypersdk/codec"
)

func TestNewABI(t *testing.T) {
require := require.New(t)

actualABI, err := NewABI([]codec.Typed{
MockObjectSingleNumber{},
MockActionTransfer{},
MockObjectAllNumbers{},
MockObjectStringAndBytes{},
MockObjectArrays{},
MockActionWithTransfer{},
MockActionWithTransferArray{},
Outer{},
})
require.NoError(err)

expectedABIJSON := mustReadFile(t, "testdata/abi.json")
expectedABI := mustJSONParse[ABI](t, string(expectedABIJSON))

require.Equal(expectedABI, actualABI)
}

func TestGetABIofABI(t *testing.T) {
require := require.New(t)

actualABI, err := NewABI([]codec.Typed{ABI{}})
require.NoError(err)

expectedABIJSON := mustReadFile(t, "testdata/abi.abi.json")
expectedABI := mustJSONParse[ABI](t, string(expectedABIJSON))

require.Equal(expectedABI, actualABI)
}
Loading
Loading