Skip to content
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

chore!: support new ABI format #2747

Closed
wants to merge 20 commits into from
Closed
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
6 changes: 6 additions & 0 deletions .changeset/rare-snails-tan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@fuel-ts/abi-typegen": minor
"@fuel-ts/abi-coder": minor
---

chore!: support new ABI format
10 changes: 6 additions & 4 deletions apps/docs-snippets/test/fixtures/abi/encode-and-decode.jsonc
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
// #region encode-and-decode-2
{
"abiVersion": "1",
"specVersion": "1",
Comment on lines +3 to +4
Copy link
Member

Choose a reason for hiding this comment

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

Based on the new spec and incoming PR:

  • the abiVersion property was removed (unnecessary)
  • the encoding was renamed to encodingVersion (can be done in this PR as well)

We should have a basic switch approach (or similar) in place to lock the pattern for dealing with [future] different versions of specVersion, such as we have for encodingVersion.

@danielbate Thoughts?

/**
* Retrieves the appropriate encoding function for a given encoding version.
*
* @param encoding - the version to provide a strategy for.
* @throws for an unsupported encoding version.
* @returns the appropriate encoding strategy.
*/
export function getCoderForEncoding(encoding: EncodingVersion = ENCODING_V1): GetCoderFn {
switch (encoding) {
case ENCODING_V1:
return getCoderV1;
default:
throw new FuelError(
ErrorCode.UNSUPPORTED_ENCODING_VERSION,
`Encoding version ${encoding} is unsupported.`
);
}
}

Copy link
Contributor

Choose a reason for hiding this comment

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

A switch/strategy SGTM. It's been sound through development.

"encoding": "1",
"types": [
{
"typeId": 0,
"typeId": "0",
"type": "u32",
"components": null,
"typeParameters": null,
Expand All @@ -14,14 +16,14 @@
"inputs": [
{
"name": "inputted_amount",
"type": 0,
"type": "0",
"typeArguments": null,
},
],
"name": "main",
"output": {
"name": "",
"type": 0,
"type": "0",
"typeArguments": null,
},
"attributes": null,
Expand All @@ -34,7 +36,7 @@
"name": "AMOUNT",
"configurableType": {
"name": "",
"type": 0,
"type": "0",
"typeArguments": null,
},
"offset": 824,
Expand Down
2 changes: 1 addition & 1 deletion packages/abi-coder/src/Interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ export class Interface<TAbi extends JsonAbi = JsonAbi> {
});
}

getTypeById(typeId: number) {
getTypeById(typeId: string) {
return findTypeById(this.jsonAbi, typeId);
}
}
14 changes: 7 additions & 7 deletions packages/abi-coder/src/ResolvedAbiType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export class ResolvedAbiType {
}

this.type = jsonABIType.type;
this.originalTypeArguments = argument.typeArguments;
this.originalTypeArguments = argument.typeArguments as JsonAbiArgument[];
this.components = ResolvedAbiType.getResolvedGenericComponents(
abi,
argument,
Expand All @@ -40,7 +40,7 @@ export class ResolvedAbiType {
abi: JsonAbi,
arg: JsonAbiArgument,
components: readonly JsonAbiArgument[] | null,
typeParameters: readonly number[] | null
typeParameters: readonly string[] | null
) {
if (components === null) {
return null;
Expand All @@ -51,7 +51,7 @@ export class ResolvedAbiType {

const typeParametersAndArgsMap = typeParameters.reduce(
(obj, typeParameter, typeParameterIndex) => {
const o: Record<number, JsonAbiArgument> = { ...obj };
const o: Record<string, JsonAbiArgument> = { ...obj };
o[typeParameter] = structuredClone(
arg.typeArguments?.[typeParameterIndex]
) as JsonAbiArgument;
Expand All @@ -72,7 +72,7 @@ export class ResolvedAbiType {
private static resolveGenericArgTypes(
abi: JsonAbi,
args: readonly JsonAbiArgument[],
typeParametersAndArgsMap: Record<number, JsonAbiArgument>
typeParametersAndArgsMap: Record<string, JsonAbiArgument>
): readonly JsonAbiArgument[] {
return args.map((arg) => {
if (typeParametersAndArgsMap[arg.type] !== undefined) {
Expand All @@ -87,7 +87,7 @@ export class ResolvedAbiType {
...structuredClone(arg),
typeArguments: this.resolveGenericArgTypes(
abi,
arg.typeArguments,
arg.typeArguments as JsonAbiArgument[],
typeParametersAndArgsMap
),
};
Expand All @@ -110,13 +110,13 @@ export class ResolvedAbiType {
private static getImplicitGenericTypeParameters(
abi: JsonAbi,
args: readonly JsonAbiArgument[] | null,
implicitGenericParametersParam?: number[]
implicitGenericParametersParam?: string[]
) {
if (!Array.isArray(args)) {
return null;
}

const implicitGenericParameters: number[] = implicitGenericParametersParam ?? [];
const implicitGenericParameters: string[] = implicitGenericParametersParam ?? [];

args.forEach((a) => {
const argType = findTypeById(abi, a.type);
Expand Down
12 changes: 7 additions & 5 deletions packages/abi-coder/src/types/JsonAbi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,25 @@ export interface JsonAbi {
readonly messagesTypes: readonly JsonAbiMessagesType[];
readonly configurables: readonly JsonAbiConfigurable[];
readonly encoding?: string;
readonly specVersion: string;
readonly abiVersion: string;
}

export interface JsonAbiType {
readonly typeId: number;
readonly typeId: string;
readonly type: string;
readonly components: readonly JsonAbiArgument[] | null;
readonly typeParameters: readonly number[] | null;
readonly typeParameters: readonly string[] | null;
}

export interface JsonAbiArgument {
readonly type: number;
readonly name: string;
readonly typeArguments: readonly JsonAbiArgument[] | null;
readonly type: string;
readonly typeArguments: readonly JsonAbiArgumentWithoutName[] | null;
}

export interface JsonAbiArgumentWithoutName {
readonly type: number;
readonly type: string;
readonly typeArguments: readonly JsonAbiArgumentWithoutName[] | null;
}

Expand Down
30 changes: 17 additions & 13 deletions packages/abi-coder/src/utils/json-abi.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { ResolvedAbiType } from '../ResolvedAbiType';
import type { JsonAbi, JsonAbiArgument } from '../types/JsonAbi';
import type { JsonAbi, JsonAbiArgument, JsonAbiFunction } from '../types/JsonAbi';

import { ENCODING_V1 } from './constants';
import {
Expand All @@ -11,12 +11,16 @@ import {
} from './json-abi';

const MOCK_ABI: JsonAbi = {
abiVersion: '1',
messagesTypes: [],
specVersion: '1',
encoding: '1',
types: [
{ typeId: 1, type: '()', components: [], typeParameters: [] },
{ typeId: 2, type: 'u256', components: [], typeParameters: [] },
{ typeId: '1', type: '()', components: [], typeParameters: [] },
{ typeId: '2', type: 'u256', components: [], typeParameters: [] },
],
functions: [
{ name: 'foo', attributes: [], inputs: [], output: { name: '', type: 1, typeArguments: [] } },
{ name: 'foo', attributes: [], inputs: [], output: { name: '', type: '1', typeArguments: [] } },
],
loggedTypes: [],
configurables: [],
Expand Down Expand Up @@ -58,11 +62,11 @@ describe('json-abi', () => {

describe('findFunctionByName', () => {
it('should find a function by name', () => {
const expected = {
const expected: JsonAbiFunction = {
name: 'foo',
attributes: [],
inputs: [],
output: { name: '', type: 1, typeArguments: [] },
output: { name: '', type: '1', typeArguments: [] },
};

const actual = findFunctionByName(MOCK_ABI, 'foo');
Expand All @@ -80,19 +84,19 @@ describe('json-abi', () => {
describe('findTypeById', () => {
it('should find a type by id', () => {
const expected = {
typeId: 1,
typeId: '1',
type: '()',
components: [],
typeParameters: [],
};

const actual = findTypeById(MOCK_ABI, 1);
const actual = findTypeById(MOCK_ABI, '1');

expect(actual).toEqual(expected);
});

it('should throw an error if the type is not found', () => {
expect(() => findTypeById(MOCK_ABI, -1)).toThrowError(
expect(() => findTypeById(MOCK_ABI, '-1')).toThrowError(
`Type with typeId '-1' doesn't exist in the ABI.`
);
});
Expand All @@ -101,18 +105,18 @@ describe('json-abi', () => {
describe('findNonEmptyInputs', () => {
it('should find non-empty inputs', () => {
const inputs: JsonAbiArgument[] = [
{ name: 'a', type: 1, typeArguments: [] },
{ name: 'b', type: 2, typeArguments: [] },
{ name: 'a', type: '1', typeArguments: [] },
{ name: 'b', type: '2', typeArguments: [] },
];
const expected = [{ name: 'b', type: 2, typeArguments: [] }];
const expected = [{ name: 'b', type: '2', typeArguments: [] }];

const actual = findNonEmptyInputs(MOCK_ABI, inputs);

expect(actual).toEqual(expected);
});

it('should throw an error if the type is not found', () => {
const inputs: JsonAbiArgument[] = [{ name: 'a', type: -1, typeArguments: [] }];
const inputs: JsonAbiArgument[] = [{ name: 'a', type: '-1', typeArguments: [] }];

expect(() => findNonEmptyInputs(MOCK_ABI, inputs)).toThrowError(
`Type with typeId '-1' doesn't exist in the ABI.`
Expand Down
2 changes: 1 addition & 1 deletion packages/abi-coder/src/utils/json-abi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export const findFunctionByName = (abi: JsonAbi, name: string): JsonAbiFunction
* @param typeId - the typeId of the type to find
* @returns the JsonAbi type object
*/
export const findTypeById = (abi: JsonAbi, typeId: number): JsonAbiType => {
export const findTypeById = (abi: JsonAbi, typeId: string): JsonAbiType => {
const type = abi.types.find((t) => t.typeId === typeId);
if (!type) {
throw new FuelError(
Expand Down
5 changes: 3 additions & 2 deletions packages/abi-typegen/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,12 @@
"dist"
],
"scripts": {
"pretest": "run-s build:forc-callpaths build:forc",
"pretest": "run-s build:forc-callpaths build:forc transform:abi",
"build": "tsup",
"build:forc": "pnpm fuels-forc build -p test/fixtures/forc-projects --release",
"build:forc-callpaths": "pnpm fuels-forc build -p test/fixtures/forc-projects --json-abi-with-callpaths",
"postbuild": "tsx ../../scripts/postbuild.ts"
"postbuild": "tsx ../../scripts/postbuild.ts",
"transform:abi": "tsx ../abi-typegen/src/transform-abi.ts test/fixtures"
},
"license": "Apache-2.0",
"dependencies": {
Expand Down
3 changes: 2 additions & 1 deletion packages/abi-typegen/src/AbiTypeGen.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { ErrorCode, FuelError } from '@fuel-ts/errors';

import { Abi } from './abi/Abi';
import { mapAbi } from './transform-abi-mapper';
import { ProgramTypeEnum } from './types/enums/ProgramTypeEnum';
import type { IFile } from './types/interfaces/IFile';
import { assembleContracts } from './utils/assembleContracts';
Expand Down Expand Up @@ -56,7 +57,7 @@ export class AbiTypeGen {

const abi = new Abi({
filepath: abiFile.path,
rawContents: JSON.parse(abiFile.contents as string),
rawContents: mapAbi(JSON.parse(abiFile.contents as string)),
hexlifiedBinContents: relatedBinFile?.contents,
storageSlotsContents: relatedStorageSlotsFile?.contents,
outputDir,
Expand Down
2 changes: 1 addition & 1 deletion packages/abi-typegen/src/abi/Abi.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ describe('Abi.ts', () => {

function getRawTypeFor(params: { type: string }) {
const rawAbiType: JsonAbiType = {
typeId: 1,
typeId: '1',
type: params.type,
components: null,
typeParameters: null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { Configurable } from './Configurable';
describe('Configurable.ts', () => {
function mockAllDeps() {
const rawAbiType: JsonAbiType = {
typeId: 1,
typeId: '1',
type: 'mockType',
components: null,
typeParameters: null,
Expand Down
4 changes: 2 additions & 2 deletions packages/abi-typegen/src/abi/types/ArrayType.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ describe('ArrayType.ts', () => {
const types = rawTypes.map((rawAbiType: JsonAbiType) => makeType({ rawAbiType }));

// validating `struct B`, with simple tuples on property `x`
const b = findType({ types, typeId: 0 }) as ArrayType;
const b = findType({ types, typeId: '0' }) as ArrayType;

expect(b.attributes.inputLabel).toEqual('[BigNumberish, BigNumberish]');
expect(b.attributes.outputLabel).toEqual('[number, number]');
Expand All @@ -52,7 +52,7 @@ describe('ArrayType.ts', () => {
const rawTypes = project.abiContents.types;
const types = rawTypes.map((rawAbiType: JsonAbiType) => makeType({ rawAbiType }));

const a = findType({ types, typeId: 1 }) as ArrayType;
const a = findType({ types, typeId: '1' }) as ArrayType;

expect(a.attributes.inputLabel).toEqual(
'[Generic1Input<Generic2Input<BigNumberish>, string>, Generic1Input<Generic2Input<BigNumberish>, string>]'
Expand Down
2 changes: 1 addition & 1 deletion packages/abi-typegen/src/abi/types/AssetIdType.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ describe('AssetIdType.ts', () => {
rawAbiType: {
components: null,
typeParameters: null,
typeId: 1,
typeId: '1',
type: AssetIdType.swayType,
},
});
Expand Down
2 changes: 1 addition & 1 deletion packages/abi-typegen/src/abi/types/B256Type.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ describe('B256Type.ts', () => {
rawAbiType: {
components: null,
typeParameters: null,
typeId: 1,
typeId: '1',
type: B256Type.swayType,
},
});
Expand Down
2 changes: 1 addition & 1 deletion packages/abi-typegen/src/abi/types/B512Type.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ describe('B512Type.ts', () => {
rawAbiType: {
components: null,
typeParameters: null,
typeId: 1,
typeId: '1',
type: B512Type.swayType,
},
});
Expand Down
2 changes: 1 addition & 1 deletion packages/abi-typegen/src/abi/types/BoolType.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ describe('BoolType.ts', () => {
rawAbiType: {
components: null,
typeParameters: null,
typeId: 1,
typeId: '1',
type: BoolType.swayType,
},
});
Expand Down
2 changes: 1 addition & 1 deletion packages/abi-typegen/src/abi/types/BytesType.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ describe('BytesType.ts', () => {
rawAbiType: {
components: null,
typeParameters: null,
typeId: 1,
typeId: '1',
type: BytesType.swayType,
},
});
Expand Down
2 changes: 1 addition & 1 deletion packages/abi-typegen/src/abi/types/EmptyType.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ describe('EmptyType.ts', () => {
rawAbiType: {
components: null,
typeParameters: null,
typeId: 0,
typeId: '0',
type: EmptyType.swayType,
},
});
Expand Down
Loading
Loading