diff --git a/.changeset/many-chairs-smell.md b/.changeset/many-chairs-smell.md new file mode 100644 index 00000000000..146df9c4519 --- /dev/null +++ b/.changeset/many-chairs-smell.md @@ -0,0 +1,5 @@ +--- +"@fuel-ts/abi-typegen": patch +--- + +Support configurables in typegen diff --git a/packages/abi-typegen/src/abi/Abi.test.ts b/packages/abi-typegen/src/abi/Abi.test.ts index 7ce8d412eaa..bfa178f7a68 100644 --- a/packages/abi-typegen/src/abi/Abi.test.ts +++ b/packages/abi-typegen/src/abi/Abi.test.ts @@ -3,6 +3,7 @@ import { safeExec } from '@fuel-ts/utils/test'; import { ForcProjectsEnum, getProjectResources } from '../../test/fixtures/forc-projects/index'; import { ProgramTypeEnum } from '../types/enums/ProgramTypeEnum'; import type { IRawAbiTypeRoot } from '../types/interfaces/IRawAbiType'; +import * as parseConfigurablesMod from '../utils/parseConfigurables'; import * as parseFunctionsMod from '../utils/parseFunctions'; import * as parseTypesMod from '../utils/parseTypes'; @@ -22,9 +23,14 @@ describe('Abi.ts', () => { .spyOn(parseFunctionsMod, 'parseFunctions') .mockImplementation(() => []); + const parseConfigurables = jest + .spyOn(parseConfigurablesMod, 'parseConfigurables') + .mockImplementation(() => []); + return { parseTypes, parseFunctions, + parseConfigurables, }; } @@ -66,12 +72,13 @@ describe('Abi.ts', () => { test('should create a new abi instance and parse root nodes', () => { const { abi, - mocks: { parseTypes, parseFunctions }, + mocks: { parseTypes, parseFunctions, parseConfigurables }, } = getMockedAbi(); expect(abi).toBeTruthy(); expect(parseTypes).toHaveBeenCalledTimes(1); expect(parseFunctions).toHaveBeenCalledTimes(1); + expect(parseConfigurables).toHaveBeenCalledTimes(1); }); test('should compute array of custom types in use', () => { diff --git a/packages/abi-typegen/src/abi/Abi.ts b/packages/abi-typegen/src/abi/Abi.ts index 07afa85a31a..a282436346b 100644 --- a/packages/abi-typegen/src/abi/Abi.ts +++ b/packages/abi-typegen/src/abi/Abi.ts @@ -1,9 +1,11 @@ import { normalizeString } from '@fuel-ts/utils'; import type { ProgramTypeEnum } from '../types/enums/ProgramTypeEnum'; +import type { IConfigurable } from '../types/interfaces/IConfigurable'; import type { IFunction } from '../types/interfaces/IFunction'; import type { IRawAbi } from '../types/interfaces/IRawAbi'; import type { IType } from '../types/interfaces/IType'; +import { parseConfigurables } from '../utils/parseConfigurables'; import { parseFunctions } from '../utils/parseFunctions'; import { parseTypes } from '../utils/parseTypes'; @@ -24,6 +26,7 @@ export class Abi { public types: IType[]; public functions: IFunction[]; + public configurables: IConfigurable[]; constructor(params: { filepath: string; @@ -53,23 +56,30 @@ export class Abi { this.hexlifiedBinContents = hexlifiedBinContents; this.outputDir = outputDir; - const { types, functions } = this.parse(); + const { types, functions, configurables } = this.parse(); this.types = types; this.functions = functions; + this.configurables = configurables; this.computeCommonTypesInUse(); } parse() { - const { types: rawAbiTypes, functions: rawAbiFunctions } = this.rawContents; + const { + types: rawAbiTypes, + functions: rawAbiFunctions, + configurables: rawAbiConfigurables, + } = this.rawContents; const types = parseTypes({ rawAbiTypes }); const functions = parseFunctions({ rawAbiFunctions, types }); + const configurables = parseConfigurables({ rawAbiConfigurables, types }); return { types, functions, + configurables, }; } diff --git a/packages/abi-typegen/src/abi/configurable/Configurable.test.ts b/packages/abi-typegen/src/abi/configurable/Configurable.test.ts new file mode 100644 index 00000000000..6ecca318b47 --- /dev/null +++ b/packages/abi-typegen/src/abi/configurable/Configurable.test.ts @@ -0,0 +1,52 @@ +import { getProjectResources, ForcProjectsEnum } from '../../../test/fixtures/forc-projects/index'; +import type { IRawAbiTypeRoot } from '../../types/interfaces/IRawAbiType'; +import type { IType } from '../../types/interfaces/IType'; +import * as findTypeMod from '../../utils/findType'; + +import { Configurable } from './Configurable'; + +describe('Configurable.ts', () => { + function mockAllDeps() { + const rawAbiType: IRawAbiTypeRoot = { + typeId: 1, + type: 'mockType', + components: null, + typeParameters: null, + }; + + const type: IType = { + name: 'mockType', + attributes: { + inputLabel: 'mockType', + outputLabel: 'mockType', + }, + rawAbiType, + requiredFuelsMembersImports: [], + parseComponentsAttributes: jest.fn(), + }; + + const findType = jest.spyOn(findTypeMod, 'findType').mockReturnValue(type); + + return { + type, + findType, + }; + } + + it('should get configurable declaration with type', () => { + const { type, findType } = mockAllDeps(); + const project = getProjectResources(ForcProjectsEnum.PREDICATE_WITH_CONFIGURABLE); + + const { configurables } = project.abiContents; + + const types: IType[] = [type]; + const rawAbiConfigurable = configurables[0]; + + const configurable = new Configurable({ types, rawAbiConfigurable }); + + expect(findType).toHaveBeenCalledTimes(1); + expect(configurable.name).toEqual('FEE'); + expect(configurable.type).toEqual(type); + expect(configurable.rawAbiConfigurable).toEqual(rawAbiConfigurable); + }); +}); diff --git a/packages/abi-typegen/src/abi/configurable/Configurable.ts b/packages/abi-typegen/src/abi/configurable/Configurable.ts new file mode 100644 index 00000000000..8df40577764 --- /dev/null +++ b/packages/abi-typegen/src/abi/configurable/Configurable.ts @@ -0,0 +1,18 @@ +import type { IConfigurable } from '../../types/interfaces/IConfigurable'; +import type { IRawAbiConfigurable } from '../../types/interfaces/IRawAbiConfigurable'; +import type { IType } from '../../types/interfaces/IType'; +import { findType } from '../../utils/findType'; + +export class Configurable implements IConfigurable { + public name: string; + public type: IType; + public rawAbiConfigurable: IRawAbiConfigurable; + + constructor(params: { types: IType[]; rawAbiConfigurable: IRawAbiConfigurable }) { + const { types, rawAbiConfigurable } = params; + + this.name = rawAbiConfigurable.name; + this.rawAbiConfigurable = rawAbiConfigurable; + this.type = findType({ types, typeId: rawAbiConfigurable.configurableType.type }); + } +} diff --git a/packages/abi-typegen/src/index.ts b/packages/abi-typegen/src/index.ts index a8dd431ed6b..64313d698d9 100644 --- a/packages/abi-typegen/src/index.ts +++ b/packages/abi-typegen/src/index.ts @@ -3,9 +3,11 @@ export * from './AbiTypeGen'; +export * from './types/interfaces/IConfigurable'; export * from './types/interfaces/IFile'; export * from './types/interfaces/IFunction'; export * from './types/interfaces/IRawAbi'; +export * from './types/interfaces/IRawAbiConfigurable'; export * from './types/interfaces/IRawAbiFunction'; export * from './types/interfaces/IRawAbiType'; export * from './types/interfaces/IRawAbiLoggedTypes'; diff --git a/packages/abi-typegen/src/templates/contract/dts.hbs b/packages/abi-typegen/src/templates/contract/dts.hbs index affed9d21e5..a1e4aebd864 100644 --- a/packages/abi-typegen/src/templates/contract/dts.hbs +++ b/packages/abi-typegen/src/templates/contract/dts.hbs @@ -40,6 +40,13 @@ export type {{structName}}Output{{typeAnnotations}} = { {{outputValues}} }; {{/if}} {{/each}} +{{#if formattedConfigurables}} +export type {{capitalizedName}}Configurables = { +{{#each formattedConfigurables}} + {{configurableName}}: {{configurableType}}; +{{/each}} +}; +{{/if}} interface {{capitalizedName}}Interface extends Interface { functions: { diff --git a/packages/abi-typegen/src/templates/contract/dts.test.ts b/packages/abi-typegen/src/templates/contract/dts.test.ts index 82d6d6fa5c5..6b5aa8cace2 100644 --- a/packages/abi-typegen/src/templates/contract/dts.test.ts +++ b/packages/abi-typegen/src/templates/contract/dts.test.ts @@ -1,4 +1,5 @@ import { getProjectResources, ForcProjectsEnum } from '../../../test/fixtures/forc-projects/index'; +import expectedDtsMinimalConfigurableTemplate from '../../../test/fixtures/templates/contract-with-configurable/dts.hbs'; import expectedDtsFullTemplate from '../../../test/fixtures/templates/contract/dts.hbs'; import { mockVersions } from '../../../test/utils/mockVersions'; import { Abi } from '../../abi/Abi'; @@ -30,6 +31,27 @@ describe('templates/dts', () => { expect(rendered).toEqual(expectedDtsFullTemplate); }); + test('should render dts template with configurable', () => { + const { restore } = mockVersions(); + + const project = getProjectResources(ForcProjectsEnum.MINIMAL_WITH_CONFIGURABLE); + + const rawContents = project.abiContents; + + const abi = new Abi({ + filepath: './my-contract-abi.json', + outputDir: 'stdout', + rawContents, + programType: ProgramTypeEnum.CONTRACT, + }); + + const rendered = renderDtsTemplate({ abi }); + + restore(); + + expect(rendered).toEqual(expectedDtsMinimalConfigurableTemplate); + }); + test('should render dts template w/ custom common types', () => { const project = getProjectResources(ForcProjectsEnum.VECTOR_SIMPLE); const { abiContents: rawContents } = project; diff --git a/packages/abi-typegen/src/templates/contract/dts.ts b/packages/abi-typegen/src/templates/contract/dts.ts index 82355255a9b..3acb12baf7c 100644 --- a/packages/abi-typegen/src/templates/contract/dts.ts +++ b/packages/abi-typegen/src/templates/contract/dts.ts @@ -1,5 +1,6 @@ import type { Abi } from '../../abi/Abi'; import { renderHbsTemplate } from '../renderHbsTemplate'; +import { formatConfigurables } from '../utils/formatConfigurables'; import { formatEnums } from '../utils/formatEnums'; import { formatImports } from '../utils/formatImports'; import { formatStructs } from '../utils/formatStructs'; @@ -7,7 +8,7 @@ import { formatStructs } from '../utils/formatStructs'; import dtsTemplate from './dts.hbs'; export function renderDtsTemplate(params: { abi: Abi }) { - const { name: capitalizedName, types, functions, commonTypesInUse } = params.abi; + const { name: capitalizedName, types, functions, commonTypesInUse, configurables } = params.abi; /* First we format all attributes @@ -38,6 +39,7 @@ export function renderDtsTemplate(params: { abi: Abi }) { 'InvokeFunction', ], }); + const { formattedConfigurables } = formatConfigurables({ configurables }); /* And finally render template @@ -54,6 +56,7 @@ export function renderDtsTemplate(params: { abi: Abi }) { structs, enums, imports, + formattedConfigurables, }, }); diff --git a/packages/abi-typegen/src/templates/predicate/factory.hbs b/packages/abi-typegen/src/templates/predicate/factory.hbs index 442773bd98b..5bf1c200a87 100644 --- a/packages/abi-typegen/src/templates/predicate/factory.hbs +++ b/packages/abi-typegen/src/templates/predicate/factory.hbs @@ -40,6 +40,12 @@ export type {{structName}}Output{{typeAnnotations}} = { {{outputValues}} }; {{/if}} {{/each}} +export type {{capitalizedName}}Configurables = { +{{#each formattedConfigurables}} + {{configurableName}}: {{configurableType}}; +{{/each}} +}; + type {{capitalizedName}}Inputs = [{{inputs}}]; const _abi = {{abiJsonString}} @@ -51,11 +57,11 @@ export class {{capitalizedName}}__factory { static readonly abi = _abi static readonly bin = _bin; - static createInstance(provider?: Provider) { + static createInstance(provider?: Provider, configurables?: {{capitalizedName}}Configurables) { const { abi, bin } = {{capitalizedName}}__factory - const predicate = new Predicate(bin, abi, provider); + const predicate = new Predicate(bin, abi, provider, configurables); return predicate; diff --git a/packages/abi-typegen/src/templates/predicate/factory.test.ts b/packages/abi-typegen/src/templates/predicate/factory.test.ts index 9db1e86f35a..39502463e1c 100644 --- a/packages/abi-typegen/src/templates/predicate/factory.test.ts +++ b/packages/abi-typegen/src/templates/predicate/factory.test.ts @@ -1,6 +1,7 @@ import { safeExec } from '@fuel-ts/utils/test'; import { getProjectResources, ForcProjectsEnum } from '../../../test/fixtures/forc-projects/index'; +import factoryWithConfigurablesTemplate from '../../../test/fixtures/templates/predicate-with-configurable/factory.hbs'; import factoryTemplate from '../../../test/fixtures/templates/predicate/factory.hbs'; import { mockVersions } from '../../../test/utils/mockVersions'; import { Abi } from '../../abi/Abi'; @@ -31,6 +32,28 @@ describe('factory.ts', () => { expect(rendered).toEqual(factoryTemplate); }); + test('should render factory template with configurable', () => { + const { restore } = mockVersions(); + + const project = getProjectResources(ForcProjectsEnum.PREDICATE_WITH_CONFIGURABLE); + + const rawContents = project.abiContents; + + const abi = new Abi({ + filepath: './my-predicate-abi.json', + hexlifiedBinContents: '0x000', + outputDir: 'stdout', + rawContents, + programType: ProgramTypeEnum.PREDICATE, + }); + + const rendered = renderFactoryTemplate({ abi }); + + restore(); + + expect(rendered).toEqual(factoryWithConfigurablesTemplate); + }); + test('should throw for invalid Predicate ABI', async () => { const { restore } = mockVersions(); diff --git a/packages/abi-typegen/src/templates/predicate/factory.ts b/packages/abi-typegen/src/templates/predicate/factory.ts index d30c94a13bb..e9c276fc597 100644 --- a/packages/abi-typegen/src/templates/predicate/factory.ts +++ b/packages/abi-typegen/src/templates/predicate/factory.ts @@ -1,5 +1,6 @@ import type { Abi } from '../../abi/Abi'; import { renderHbsTemplate } from '../renderHbsTemplate'; +import { formatConfigurables } from '../utils/formatConfigurables'; import { formatEnums } from '../utils/formatEnums'; import { formatImports } from '../utils/formatImports'; import { formatStructs } from '../utils/formatStructs'; @@ -9,7 +10,7 @@ import factoryTemplate from './factory.hbs'; export function renderFactoryTemplate(params: { abi: Abi }) { const { abi } = params; - const { types } = abi; + const { types, configurables } = abi; const { rawContents, @@ -28,6 +29,7 @@ export function renderFactoryTemplate(params: { abi: Abi }) { const { enums } = formatEnums({ types }); const { structs } = formatStructs({ types }); const { imports } = formatImports({ types, baseMembers: ['Predicate', 'Provider'] }); + const { formattedConfigurables } = formatConfigurables({ configurables }); const { prefixedInputs: inputs, output } = func.attributes; @@ -42,6 +44,7 @@ export function renderFactoryTemplate(params: { abi: Abi }) { hexlifiedBinString, capitalizedName, imports, + formattedConfigurables, }, }); diff --git a/packages/abi-typegen/src/templates/script/factory.hbs b/packages/abi-typegen/src/templates/script/factory.hbs index ff653253dae..d975e5a49e8 100644 --- a/packages/abi-typegen/src/templates/script/factory.hbs +++ b/packages/abi-typegen/src/templates/script/factory.hbs @@ -43,6 +43,14 @@ export type {{structName}}Output{{typeAnnotations}} = { {{outputValues}} }; type {{capitalizedName}}Inputs = [{{inputs}}]; type {{capitalizedName}}Output = {{output}}; +{{#if formattedConfigurables}} +export type {{capitalizedName}}Configurables = { +{{#each formattedConfigurables}} + {{configurableName}}: {{configurableType}}; +{{/each}} +}; +{{/if}} + const _abi = {{abiJsonString}} const _bin = '{{hexlifiedBinString}}' diff --git a/packages/abi-typegen/src/templates/script/factory.test.ts b/packages/abi-typegen/src/templates/script/factory.test.ts index 4b3454c9ade..5f934f3c0c7 100644 --- a/packages/abi-typegen/src/templates/script/factory.test.ts +++ b/packages/abi-typegen/src/templates/script/factory.test.ts @@ -1,6 +1,7 @@ import { safeExec } from '@fuel-ts/utils/test'; import { getProjectResources, ForcProjectsEnum } from '../../../test/fixtures/forc-projects/index'; +import factoryTemplateWithConfigurables from '../../../test/fixtures/templates/script-with-configurable/factory.hbs'; import factoryTemplate from '../../../test/fixtures/templates/script/factory.hbs'; import { mockVersions } from '../../../test/utils/mockVersions'; import { Abi } from '../../abi/Abi'; @@ -30,6 +31,27 @@ describe('factory.ts', () => { expect(rendered).toEqual(factoryTemplate); }); + test('should render factory template with configurables', () => { + const { restore } = mockVersions(); + + const project = getProjectResources(ForcProjectsEnum.SCRIPT_WITH_CONFIGURABLE); + const rawContents = project.abiContents; + + const abi = new Abi({ + filepath: './my-script-abi.json', + hexlifiedBinContents: '0x000', + outputDir: 'stdout', + rawContents, + programType: ProgramTypeEnum.SCRIPT, + }); + + const rendered = renderFactoryTemplate({ abi }); + + restore(); + + expect(rendered).toEqual(factoryTemplateWithConfigurables); + }); + test('should throw for invalid Script ABI', async () => { const { restore } = mockVersions(); diff --git a/packages/abi-typegen/src/templates/script/factory.ts b/packages/abi-typegen/src/templates/script/factory.ts index 252af09e7be..2ce5f3ceb69 100644 --- a/packages/abi-typegen/src/templates/script/factory.ts +++ b/packages/abi-typegen/src/templates/script/factory.ts @@ -1,5 +1,6 @@ import type { Abi } from '../../abi/Abi'; import { renderHbsTemplate } from '../renderHbsTemplate'; +import { formatConfigurables } from '../utils/formatConfigurables'; import { formatEnums } from '../utils/formatEnums'; import { formatImports } from '../utils/formatImports'; import { formatStructs } from '../utils/formatStructs'; @@ -9,7 +10,7 @@ import factoryTemplate from './factory.hbs'; export function renderFactoryTemplate(params: { abi: Abi }) { const { abi } = params; - const { types } = abi; + const { types, configurables } = abi; const { rawContents, @@ -28,6 +29,7 @@ export function renderFactoryTemplate(params: { abi: Abi }) { const { enums } = formatEnums({ types }); const { structs } = formatStructs({ types }); const { imports } = formatImports({ types, baseMembers: ['Script', 'Account'] }); + const { formattedConfigurables } = formatConfigurables({ configurables }); const { prefixedInputs: inputs, output } = func.attributes; @@ -42,6 +44,7 @@ export function renderFactoryTemplate(params: { abi: Abi }) { hexlifiedBinString, capitalizedName, imports, + formattedConfigurables, }, }); diff --git a/packages/abi-typegen/src/templates/utils/formatConfigurables.test.ts b/packages/abi-typegen/src/templates/utils/formatConfigurables.test.ts new file mode 100644 index 00000000000..c2b5f9f519f --- /dev/null +++ b/packages/abi-typegen/src/templates/utils/formatConfigurables.test.ts @@ -0,0 +1,54 @@ +import { formatConfigurables } from './formatConfigurables'; + +describe('formatConfigurables.ts', () => { + function mockAllDeps() { + const rawAbiType = { + typeId: 1, + type: 'mockType', + components: null, + typeParameters: null, + }; + + const type = { + name: 'mockType', + attributes: { + inputLabel: 'mockType', + outputLabel: 'mockType', + }, + rawAbiType, + requiredFuelsMembersImports: [], + parseComponentsAttributes: jest.fn(), + }; + + const rawAbiConfigurable = { + name: 'mockConfigurable', + configurableType: { + name: 'mockConfigurable', + type: 1, + typeArguments: null, + }, + offset: 0, + }; + + const configurable = { + name: 'mockConfigurable', + type, + rawAbiConfigurable, + }; + + return { + configurable, + }; + } + + it('should format a configurable instance', () => { + const { configurable } = mockAllDeps(); + const configurables = [configurable]; + + const { formattedConfigurables } = formatConfigurables({ configurables }); + const formattedConfigurable = formattedConfigurables[0]; + + expect(formattedConfigurable.configurableName).toEqual('mockConfigurable'); + expect(formattedConfigurable.configurableType).toEqual('mockType'); + }); +}); diff --git a/packages/abi-typegen/src/templates/utils/formatConfigurables.ts b/packages/abi-typegen/src/templates/utils/formatConfigurables.ts new file mode 100644 index 00000000000..2279cb42bd7 --- /dev/null +++ b/packages/abi-typegen/src/templates/utils/formatConfigurables.ts @@ -0,0 +1,21 @@ +import type { IConfigurable } from '../../types/interfaces/IConfigurable'; + +export function formatConfigurables(params: { configurables: IConfigurable[] }) { + const { configurables } = params; + + const formattedConfigurables = configurables.map((c) => { + const { + name, + type: { + attributes: { inputLabel }, + }, + } = c; + + return { + configurableName: name, + configurableType: inputLabel, + }; + }); + + return { formattedConfigurables }; +} diff --git a/packages/abi-typegen/src/types/interfaces/IConfigurable.ts b/packages/abi-typegen/src/types/interfaces/IConfigurable.ts new file mode 100644 index 00000000000..f399707316a --- /dev/null +++ b/packages/abi-typegen/src/types/interfaces/IConfigurable.ts @@ -0,0 +1,8 @@ +import type { IRawAbiConfigurable } from './IRawAbiConfigurable'; +import type { IType } from './IType'; + +export interface IConfigurable { + name: string; + type: IType; + rawAbiConfigurable: IRawAbiConfigurable; +} diff --git a/packages/abi-typegen/src/types/interfaces/IRawAbi.ts b/packages/abi-typegen/src/types/interfaces/IRawAbi.ts index f7229552ac4..a0c46accbde 100644 --- a/packages/abi-typegen/src/types/interfaces/IRawAbi.ts +++ b/packages/abi-typegen/src/types/interfaces/IRawAbi.ts @@ -1,3 +1,4 @@ +import type { IRawAbiConfigurable } from './IRawAbiConfigurable'; import type { IRawAbiFunction } from './IRawAbiFunction'; import type { IRawAbiLoggedTypes } from './IRawAbiLoggedTypes'; import type { IRawAbiTypeRoot } from './IRawAbiType'; @@ -6,4 +7,5 @@ export interface IRawAbi { types: IRawAbiTypeRoot[]; functions: IRawAbiFunction[]; loggedTypes: IRawAbiLoggedTypes[]; + configurables: IRawAbiConfigurable[]; } diff --git a/packages/abi-typegen/src/types/interfaces/IRawAbiConfigurable.ts b/packages/abi-typegen/src/types/interfaces/IRawAbiConfigurable.ts new file mode 100644 index 00000000000..2dc6194c356 --- /dev/null +++ b/packages/abi-typegen/src/types/interfaces/IRawAbiConfigurable.ts @@ -0,0 +1,11 @@ +export interface IRawAbiConfigurable { + name: string; + configurableType: IRawAbiConfigurableType; + offset: number; +} + +export interface IRawAbiConfigurableType { + name: string; + type: number; + typeArguments: null | IRawAbiConfigurableType[]; +} diff --git a/packages/abi-typegen/src/types/interfaces/IType.ts b/packages/abi-typegen/src/types/interfaces/IType.ts index ca93b5f4bdd..94560ad5f18 100644 --- a/packages/abi-typegen/src/types/interfaces/IType.ts +++ b/packages/abi-typegen/src/types/interfaces/IType.ts @@ -5,7 +5,7 @@ export interface ITypeAttributes { outputLabel: string; structName?: string; /* - If `structName` is set, intput/output labels will mirror it. + If `structName` is set, input/output labels will mirror it. */ } diff --git a/packages/abi-typegen/src/utils/makeConfigurable.test.ts b/packages/abi-typegen/src/utils/makeConfigurable.test.ts new file mode 100644 index 00000000000..0c46ed4f717 --- /dev/null +++ b/packages/abi-typegen/src/utils/makeConfigurable.test.ts @@ -0,0 +1,52 @@ +import { Configurable } from '../abi/configurable/Configurable'; + +import { makeConfigurable } from './makeConfigurable'; + +describe('makeConfigurable.ts', () => { + function mockAllDeps() { + const rawAbiType = { + typeId: 1, + type: 'mockType', + components: null, + typeParameters: null, + }; + + const type = { + name: 'mockType', + attributes: { + inputLabel: 'mockType', + outputLabel: 'mockType', + }, + rawAbiType, + requiredFuelsMembersImports: [], + parseComponentsAttributes: jest.fn(), + }; + + const rawAbiConfigurable = { + name: 'mockConfigurable', + configurableType: { + name: 'mockConfigurable', + type: 1, + typeArguments: null, + }, + offset: 0, + }; + + return { + type, + rawAbiConfigurable, + }; + } + + it('should instantiate a configurable instance', () => { + const { type, rawAbiConfigurable } = mockAllDeps(); + const types = [type]; + + const configurable = makeConfigurable({ types, rawAbiConfigurable }); + + expect(configurable).toBeInstanceOf(Configurable); + expect(configurable.name).toEqual(rawAbiConfigurable.name); + expect(configurable.type).toEqual(type); + expect(configurable.rawAbiConfigurable).toEqual(rawAbiConfigurable); + }); +}); diff --git a/packages/abi-typegen/src/utils/makeConfigurable.ts b/packages/abi-typegen/src/utils/makeConfigurable.ts new file mode 100644 index 00000000000..54936972f25 --- /dev/null +++ b/packages/abi-typegen/src/utils/makeConfigurable.ts @@ -0,0 +1,11 @@ +import { Configurable } from '../abi/configurable/Configurable'; +import type { IRawAbiConfigurable } from '../types/interfaces/IRawAbiConfigurable'; +import type { IType } from '../types/interfaces/IType'; + +export function makeConfigurable(params: { + types: IType[]; + rawAbiConfigurable: IRawAbiConfigurable; +}) { + const { types, rawAbiConfigurable } = params; + return new Configurable({ types, rawAbiConfigurable }); +} diff --git a/packages/abi-typegen/src/utils/parseConfigurables.test.ts b/packages/abi-typegen/src/utils/parseConfigurables.test.ts new file mode 100644 index 00000000000..5517a8b689e --- /dev/null +++ b/packages/abi-typegen/src/utils/parseConfigurables.test.ts @@ -0,0 +1,63 @@ +import * as makeConfigurableMod from './makeConfigurable'; +import { parseConfigurables } from './parseConfigurables'; + +describe('parseConfigurables.ts', () => { + function mockAllDeps() { + const rawAbiType = { + typeId: 1, + type: 'mockType', + components: null, + typeParameters: null, + }; + + const type = { + name: 'mockType', + attributes: { + inputLabel: 'mockType', + outputLabel: 'mockType', + }, + rawAbiType, + requiredFuelsMembersImports: [], + parseComponentsAttributes: jest.fn(), + }; + + const rawAbiConfigurable = { + name: 'mockConfigurable', + configurableType: { + name: 'mockConfigurable', + type: 1, + typeArguments: null, + }, + offset: 0, + }; + + const configurable = { + name: 'mockConfigurable', + type, + rawAbiConfigurable, + }; + + const makeConfigurable = jest + .spyOn(makeConfigurableMod, 'makeConfigurable') + .mockReturnValue(configurable); + + return { + type, + rawAbiConfigurable, + makeConfigurable, + }; + } + + it('should parse configurables ABI and return configurables instances', () => { + const { type, rawAbiConfigurable, makeConfigurable } = mockAllDeps(); + const rawAbiConfigurables = [rawAbiConfigurable]; + const types = [type]; + + const configurables = parseConfigurables({ rawAbiConfigurables, types }); + + expect(makeConfigurable).toHaveBeenCalledTimes(1); + + const configurable = configurables[0]; + expect(configurable.name).toEqual(rawAbiConfigurable.name); + }); +}); diff --git a/packages/abi-typegen/src/utils/parseConfigurables.ts b/packages/abi-typegen/src/utils/parseConfigurables.ts new file mode 100644 index 00000000000..3484bf3cd0c --- /dev/null +++ b/packages/abi-typegen/src/utils/parseConfigurables.ts @@ -0,0 +1,18 @@ +import type { IConfigurable } from '../types/interfaces/IConfigurable'; +import type { IRawAbiConfigurable } from '../types/interfaces/IRawAbiConfigurable'; +import type { IType } from '../types/interfaces/IType'; + +import { makeConfigurable } from './makeConfigurable'; + +export function parseConfigurables(params: { + types: IType[]; + rawAbiConfigurables: IRawAbiConfigurable[]; +}) { + const { types, rawAbiConfigurables } = params; + + const configurables: IConfigurable[] = rawAbiConfigurables.map((rawAbiConfigurable) => + makeConfigurable({ types, rawAbiConfigurable }) + ); + + return configurables; +} diff --git a/packages/abi-typegen/src/utils/parseTypes.ts b/packages/abi-typegen/src/utils/parseTypes.ts index 24f022a3aab..628b2699cba 100644 --- a/packages/abi-typegen/src/utils/parseTypes.ts +++ b/packages/abi-typegen/src/utils/parseTypes.ts @@ -17,7 +17,7 @@ export function parseTypes(params: { rawAbiTypes: IRawAbiTypeRoot[] }) { } }); - // Then we parse all thei r components' [attributes] + // Then we parse all their components' [attributes] types.forEach((type) => { type.parseComponentsAttributes({ types }); }); diff --git a/packages/abi-typegen/test/fixtures/forc-projects/Forc.toml b/packages/abi-typegen/test/fixtures/forc-projects/Forc.toml index 93b2641f3b4..d682bd1f674 100644 --- a/packages/abi-typegen/test/fixtures/forc-projects/Forc.toml +++ b/packages/abi-typegen/test/fixtures/forc-projects/Forc.toml @@ -10,9 +10,12 @@ members = [ "./fn-void", "./full", "./minimal", + "./minimal-with-configurable", "./option-simple", "./predicate", + "./predicate-with-configurable", "./script", + "./script-with-configurable", "./struct-nested", "./struct-simple", "./struct-with-array", diff --git a/packages/abi-typegen/test/fixtures/forc-projects/index.ts b/packages/abi-typegen/test/fixtures/forc-projects/index.ts index 8e94d3aab5d..124f8fe8862 100644 --- a/packages/abi-typegen/test/fixtures/forc-projects/index.ts +++ b/packages/abi-typegen/test/fixtures/forc-projects/index.ts @@ -14,9 +14,12 @@ export enum ForcProjectsEnum { FN_VOID = 'fn-void', FULL = 'full', MINIMAL = 'minimal', + MINIMAL_WITH_CONFIGURABLE = 'minimal-with-configurable', OPTION_SIMPLE = 'option-simple', PREDICATE = 'predicate', + PREDICATE_WITH_CONFIGURABLE = 'predicate-with-configurable', SCRIPT = 'script', + SCRIPT_WITH_CONFIGURABLE = 'script-with-configurable', STRUCT_NESTED = 'struct-nested', STRUCT_SIMPLE = 'struct-simple', STRUCT_WITH_ARRAY = 'struct-with-array', diff --git a/packages/abi-typegen/test/fixtures/forc-projects/minimal-with-configurable/Forc.toml b/packages/abi-typegen/test/fixtures/forc-projects/minimal-with-configurable/Forc.toml new file mode 100644 index 00000000000..ed01283f051 --- /dev/null +++ b/packages/abi-typegen/test/fixtures/forc-projects/minimal-with-configurable/Forc.toml @@ -0,0 +1,7 @@ +[project] +authors = ["FuelLabs"] +entry = "main.sw" +license = "Apache-2.0" +name = "minimal-with-configurable" + +[dependencies] diff --git a/packages/abi-typegen/test/fixtures/forc-projects/minimal-with-configurable/src/main.sw b/packages/abi-typegen/test/fixtures/forc-projects/minimal-with-configurable/src/main.sw new file mode 100644 index 00000000000..40bfd0b7a6a --- /dev/null +++ b/packages/abi-typegen/test/fixtures/forc-projects/minimal-with-configurable/src/main.sw @@ -0,0 +1,13 @@ +contract; + +configurable { + SHOULD_RETURN: bool = true, +} + +abi MyContract { + fn main(x: str[10], y: str[10]) -> bool; +} + +impl MyContract for Contract { + fn main(x: str[10], y: str[10]) -> bool { SHOULD_RETURN } +} diff --git a/packages/abi-typegen/test/fixtures/forc-projects/predicate-with-configurable/Forc.toml b/packages/abi-typegen/test/fixtures/forc-projects/predicate-with-configurable/Forc.toml new file mode 100644 index 00000000000..cdf3291c344 --- /dev/null +++ b/packages/abi-typegen/test/fixtures/forc-projects/predicate-with-configurable/Forc.toml @@ -0,0 +1,7 @@ +[project] +authors = ["FuelLabs"] +entry = "main.sw" +license = "Apache-2.0" +name = "predicate-with-configurable" + +[dependencies] diff --git a/packages/abi-typegen/test/fixtures/forc-projects/predicate-with-configurable/src/main.sw b/packages/abi-typegen/test/fixtures/forc-projects/predicate-with-configurable/src/main.sw new file mode 100644 index 00000000000..fab85f63de8 --- /dev/null +++ b/packages/abi-typegen/test/fixtures/forc-projects/predicate-with-configurable/src/main.sw @@ -0,0 +1,10 @@ +predicate; + +configurable { + FEE: u8 = 10, + ADDRESS: b256 = 0x38966262edb5997574be45f94c665aedb41a1663f5b0528e765f355086eebf96 +} + +fn main(fee: u8, address: b256) -> bool { + FEE == fee && address == ADDRESS +} diff --git a/packages/abi-typegen/test/fixtures/forc-projects/script-with-configurable/Forc.toml b/packages/abi-typegen/test/fixtures/forc-projects/script-with-configurable/Forc.toml new file mode 100644 index 00000000000..dc024934348 --- /dev/null +++ b/packages/abi-typegen/test/fixtures/forc-projects/script-with-configurable/Forc.toml @@ -0,0 +1,7 @@ +[project] +authors = ["FuelLabs"] +entry = "main.sw" +license = "Apache-2.0" +name = "script-with-configurable" + +[dependencies] diff --git a/packages/abi-typegen/test/fixtures/forc-projects/script-with-configurable/src/main.sw b/packages/abi-typegen/test/fixtures/forc-projects/script-with-configurable/src/main.sw new file mode 100644 index 00000000000..b4c0b4b0d70 --- /dev/null +++ b/packages/abi-typegen/test/fixtures/forc-projects/script-with-configurable/src/main.sw @@ -0,0 +1,14 @@ +script; + +struct Score { + user: u8, + points: u8 +} + +configurable { + SHOULD_RETURN: bool = true +} + +fn main(score: Score) -> bool { + return SHOULD_RETURN; +} diff --git a/packages/abi-typegen/test/fixtures/templates/contract-with-configurable/dts.hbs b/packages/abi-typegen/test/fixtures/templates/contract-with-configurable/dts.hbs new file mode 100644 index 00000000000..23410fcf29e --- /dev/null +++ b/packages/abi-typegen/test/fixtures/templates/contract-with-configurable/dts.hbs @@ -0,0 +1,40 @@ +/* Autogenerated file. Do not edit manually. */ + +/* tslint:disable */ +/* eslint-disable */ + +/* + Fuels version: 11.11.11 + Forc version: 22.22.22 + Fuel-Core version: 33.33.33 +*/ + +import type { + BytesLike, + Contract, + DecodedValue, + FunctionFragment, + Interface, + InvokeFunction, +} from 'fuels'; + +export type MyContractAbiConfigurables = { + SHOULD_RETURN: boolean; +}; + +interface MyContractAbiInterface extends Interface { + functions: { + main: FunctionFragment; + }; + + encodeFunctionData(functionFragment: 'main', values: [string, string]): Uint8Array; + + decodeFunctionData(functionFragment: 'main', data: BytesLike): DecodedValue; +} + +export class MyContractAbi extends Contract { + interface: MyContractAbiInterface; + functions: { + main: InvokeFunction<[x: string, y: string], boolean>; + }; +} diff --git a/packages/abi-typegen/test/fixtures/templates/predicate-with-configurable/factory.hbs b/packages/abi-typegen/test/fixtures/templates/predicate-with-configurable/factory.hbs new file mode 100644 index 00000000000..93ac9e70516 --- /dev/null +++ b/packages/abi-typegen/test/fixtures/templates/predicate-with-configurable/factory.hbs @@ -0,0 +1,110 @@ +/* Autogenerated file. Do not edit manually. */ + +/* tslint:disable */ +/* eslint-disable */ + +/* + Fuels version: 11.11.11 + Forc version: 22.22.22 + Fuel-Core version: 33.33.33 +*/ + +import { + BigNumberish, + Predicate, + Provider, +} from 'fuels'; + +export type MyPredicateAbiConfigurables = { + FEE: BigNumberish; + ADDRESS: string; +}; + +type MyPredicateAbiInputs = [fee: BigNumberish, address: string]; + +const _abi = { + "types": [ + { + "typeId": 0, + "type": "b256", + "components": null, + "typeParameters": null + }, + { + "typeId": 1, + "type": "bool", + "components": null, + "typeParameters": null + }, + { + "typeId": 2, + "type": "u8", + "components": null, + "typeParameters": null + } + ], + "functions": [ + { + "inputs": [ + { + "name": "fee", + "type": 2, + "typeArguments": null + }, + { + "name": "address", + "type": 0, + "typeArguments": null + } + ], + "name": "main", + "output": { + "name": "", + "type": 1, + "typeArguments": null + }, + "attributes": null + } + ], + "loggedTypes": [], + "messagesTypes": [], + "configurables": [ + { + "name": "FEE", + "configurableType": { + "name": "", + "type": 2, + "typeArguments": null + }, + "offset": 120 + }, + { + "name": "ADDRESS", + "configurableType": { + "name": "", + "type": 0, + "typeArguments": null + }, + "offset": 128 + } + ] +} + +const _bin = '0x000' + +export class MyPredicateAbi__factory { + + static readonly abi = _abi + static readonly bin = _bin; + + static createInstance(provider?: Provider, configurables?: MyPredicateAbiConfigurables) { + + const { abi, bin } = MyPredicateAbi__factory + + const predicate = new Predicate(bin, abi, provider, configurables); + + return predicate; + + } + +} diff --git a/packages/abi-typegen/test/fixtures/templates/predicate/factory.hbs b/packages/abi-typegen/test/fixtures/templates/predicate/factory.hbs index 195fc1da05f..c00937992bc 100644 --- a/packages/abi-typegen/test/fixtures/templates/predicate/factory.hbs +++ b/packages/abi-typegen/test/fixtures/templates/predicate/factory.hbs @@ -19,6 +19,9 @@ import { export type ValidationInput = { has_account: boolean, total_complete: BigNumberish }; export type ValidationOutput = { has_account: boolean, total_complete: BN }; +export type MyPredicateAbiConfigurables = { +}; + type MyPredicateAbiInputs = [received: ValidationInput]; const _abi = { @@ -83,11 +86,11 @@ export class MyPredicateAbi__factory { static readonly abi = _abi static readonly bin = _bin; - static createInstance(provider?: Provider) { + static createInstance(provider?: Provider, configurables?: MyPredicateAbiConfigurables) { const { abi, bin } = MyPredicateAbi__factory - const predicate = new Predicate(bin, abi, provider); + const predicate = new Predicate(bin, abi, provider, configurables); return predicate; diff --git a/packages/abi-typegen/test/fixtures/templates/script-with-configurable/factory.hbs b/packages/abi-typegen/test/fixtures/templates/script-with-configurable/factory.hbs new file mode 100644 index 00000000000..6c338566ce8 --- /dev/null +++ b/packages/abi-typegen/test/fixtures/templates/script-with-configurable/factory.hbs @@ -0,0 +1,113 @@ +/* Autogenerated file. Do not edit manually. */ + +/* tslint:disable */ +/* eslint-disable */ + +/* + Fuels version: 11.11.11 + Forc version: 22.22.22 + Fuel-Core version: 33.33.33 +*/ + +import { + Account, + BigNumberish, + Script, +} from 'fuels'; + +export type ScoreInput = { user: BigNumberish, points: BigNumberish }; +export type ScoreOutput = { user: number, points: number }; + +type MyScriptAbiInputs = [score: ScoreInput]; +type MyScriptAbiOutput = boolean; + +export type MyScriptAbiConfigurables = { + SHOULD_RETURN: boolean; +}; + +const _abi = { + "types": [ + { + "typeId": 0, + "type": "bool", + "components": null, + "typeParameters": null + }, + { + "typeId": 1, + "type": "struct Score", + "components": [ + { + "name": "user", + "type": 2, + "typeArguments": null + }, + { + "name": "points", + "type": 2, + "typeArguments": null + } + ], + "typeParameters": null + }, + { + "typeId": 2, + "type": "u8", + "components": null, + "typeParameters": null + } + ], + "functions": [ + { + "inputs": [ + { + "name": "score", + "type": 1, + "typeArguments": null + } + ], + "name": "main", + "output": { + "name": "", + "type": 0, + "typeArguments": null + }, + "attributes": null + } + ], + "loggedTypes": [], + "messagesTypes": [], + "configurables": [ + { + "name": "SHOULD_RETURN", + "configurableType": { + "name": "", + "type": 0, + "typeArguments": null + }, + "offset": 36 + } + ] +} + +const _bin = '0x000' + +export class MyScriptAbi__factory { + + static readonly abi = _abi + static readonly bin = _bin + + static createInstance(wallet: Account) { + + const { abi, bin } = MyScriptAbi__factory + + const script = new Script< + MyScriptAbiInputs, + MyScriptAbiOutput + >(bin, abi, wallet); + + return script; + + } + +} diff --git a/packages/abi-typegen/test/utils/getNewAbiTypegen.ts b/packages/abi-typegen/test/utils/getNewAbiTypegen.ts index c72b7f290d3..e7b28bc2756 100644 --- a/packages/abi-typegen/test/utils/getNewAbiTypegen.ts +++ b/packages/abi-typegen/test/utils/getNewAbiTypegen.ts @@ -1,4 +1,4 @@ -import type { IFile, IRawAbiTypeRoot } from '../../src/index'; +import type { IFile, IRawAbiTypeRoot, IRawAbiConfigurable } from '../../src/index'; import { AbiTypeGen } from '../../src/index'; import { ProgramTypeEnum } from '../../src/types/enums/ProgramTypeEnum'; @@ -72,7 +72,19 @@ export function getNewAbiTypegen( const functions = includeMainFunction ? [main] : []; - const stubAbi = JSON.stringify({ types, functions }, null, 2); + const configurables: IRawAbiConfigurable[] = [ + { + name: 'configurable', + configurableType: { + name: 'configurableType', + type: 1, + typeArguments: null, + }, + offset: 120, + }, + ]; + + const stubAbi = JSON.stringify({ types, functions, configurables }, null, 2); const stubBin = '0x000'; const abiFiles: IFile[] = [