Skip to content

Commit

Permalink
Merge branch 'master' into st/fix/add-predicate-data-to-resource
Browse files Browse the repository at this point in the history
  • Loading branch information
Torres-ssf committed May 24, 2024
2 parents 80be382 + ba0f3d0 commit 86f7ece
Show file tree
Hide file tree
Showing 32 changed files with 290 additions and 25 deletions.
5 changes: 5 additions & 0 deletions .changeset/quiet-lobsters-design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"fuels": patch
---

feat: add new `node` command to `fuels` CLI
5 changes: 5 additions & 0 deletions .changeset/tidy-horses-taste.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@fuel-ts/abi-typegen": patch
---

feat: support `forc build --json-abi-with-callpaths` flag
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ Options:

Commands:
init [options] Create a sample `fuel.config.ts` file
node [options] Start a Fuel node
dev [options] Start a Fuel node and run build + deploy on every file change
build [options] Build Sway programs and generate Typescript for them
deploy [options] Deploy contracts to the Fuel network
Expand Down
8 changes: 8 additions & 0 deletions apps/docs/src/guide/fuels-cli/commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,14 @@ The `fuels dev` command does three things:

> _In `dev` mode, every time you update a contract on your Forc `workspace`, we re-generate type definitions and factory classes for it, following your pre-configured [`output`](./config-file.md#output) directory. If it's part of another build system running in dev mode (i.e. `next dev`), you can expect it to re-build / auto-reload as well._
## `fuels node`

```console-vue
npx fuels@{{fuels}} node
```

The `fuels node` command starts a short-lived `fuel-core` node ([docs](./config-file.md#autostartfuelcore)).

## `fuels typegen`

Manually generates type definitions and factory classes from ABI JSON files.
Expand Down
3 changes: 2 additions & 1 deletion packages/abi-typegen/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,10 @@
"dist"
],
"scripts": {
"pretest": "pnpm build:forc",
"pretest": "run-s build:forc-callpaths build:forc",
"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"
},
"license": "Apache-2.0",
Expand Down
2 changes: 1 addition & 1 deletion packages/abi-typegen/src/abi/types/B512Type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export class B512Type extends B256Type {

public name = 'b512';

static MATCH_REGEX = /^struct B512$/m;
static MATCH_REGEX = /^struct (std::b512::)?B512$/m;

static isSuitableFor(params: { type: string }) {
return B512Type.MATCH_REGEX.test(params.type);
Expand Down
2 changes: 1 addition & 1 deletion packages/abi-typegen/src/abi/types/BytesType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export class BytesType extends ArrayType {

public name = 'bytes';

static MATCH_REGEX: RegExp = /^struct Bytes/m;
static MATCH_REGEX: RegExp = /^struct (std::bytes::)?Bytes/m;

static isSuitableFor(params: { type: string }) {
return BytesType.MATCH_REGEX.test(params.type);
Expand Down
8 changes: 5 additions & 3 deletions packages/abi-typegen/src/abi/types/EnumType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,20 @@ import { parseTypeArguments } from '../../utils/parseTypeArguments';

import { AType } from './AType';
import { EmptyType } from './EmptyType';
import { OptionType } from './OptionType';
import { ResultType } from './ResultType';

export class EnumType extends AType implements IType {
public static swayType = 'enum MyEnumName';

public name = 'enum';

static MATCH_REGEX: RegExp = /^enum (.+)$/m;
static IGNORE_REGEX: RegExp = /^enum (Option|Result)$/m;
static MATCH_REGEX: RegExp = /^enum (.+::)?(.+)$/m;
static IGNORE_REGEXES: RegExp[] = [OptionType.MATCH_REGEX, ResultType.MATCH_REGEX];

static isSuitableFor(params: { type: string }) {
const isAMatch = EnumType.MATCH_REGEX.test(params.type);
const shouldBeIgnored = EnumType.IGNORE_REGEX.test(params.type);
const shouldBeIgnored = EnumType.IGNORE_REGEXES.some((r) => r.test(params.type));
return isAMatch && !shouldBeIgnored;
}

Expand Down
2 changes: 1 addition & 1 deletion packages/abi-typegen/src/abi/types/EvmAddressType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export class EvmAddressType extends AType implements IType {

public name = 'evmAddress';

static MATCH_REGEX: RegExp = /^struct EvmAddress$/m;
static MATCH_REGEX: RegExp = /^struct (std::vm::evm::evm_address::)?EvmAddress$/m;

static isSuitableFor(params: { type: string }) {
return EvmAddressType.MATCH_REGEX.test(params.type);
Expand Down
2 changes: 1 addition & 1 deletion packages/abi-typegen/src/abi/types/OptionType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export class OptionType extends AType implements IType {

public name = 'option';

static MATCH_REGEX: RegExp = /^enum Option$/m;
static MATCH_REGEX: RegExp = /^enum (std::option::)?Option$/m;

static isSuitableFor(params: { type: string }) {
return OptionType.MATCH_REGEX.test(params.type);
Expand Down
2 changes: 1 addition & 1 deletion packages/abi-typegen/src/abi/types/ResultType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export class ResultType extends AType implements IType {

public name = 'result';

static MATCH_REGEX: RegExp = /^enum Result$/m;
static MATCH_REGEX: RegExp = /^enum (std::result::)?Result$/m;

static isSuitableFor(params: { type: string }) {
return ResultType.MATCH_REGEX.test(params.type);
Expand Down
2 changes: 1 addition & 1 deletion packages/abi-typegen/src/abi/types/StdStringType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export class StdStringType extends AType implements IType {

public name = 'stdString';

static MATCH_REGEX: RegExp = /^struct String/m;
static MATCH_REGEX: RegExp = /^struct (std::string::)?String/m;

static isSuitableFor(params: { type: string }) {
return StdStringType.MATCH_REGEX.test(params.type);
Expand Down
4 changes: 2 additions & 2 deletions packages/abi-typegen/src/abi/types/StructType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ export class StructType extends AType implements IType {

public name = 'struct';

static MATCH_REGEX: RegExp = /^struct (.+)$/m;
static IGNORE_REGEX: RegExp = /^struct (Vec|RawVec|EvmAddress|Bytes|String)$/m;
static MATCH_REGEX: RegExp = /^struct (.+::)?(.+)$/m;
static IGNORE_REGEX: RegExp = /^struct (std::.*)?(Vec|RawVec|EvmAddress|Bytes|String|RawBytes)$/m;

static isSuitableFor(params: { type: string }) {
const isAMatch = StructType.MATCH_REGEX.test(params.type);
Expand Down
4 changes: 2 additions & 2 deletions packages/abi-typegen/src/abi/types/VectorType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ export class VectorType extends ArrayType {

public name = 'vector';

static MATCH_REGEX: RegExp = /^struct Vec/m;
static IGNORE_REGEX: RegExp = /^struct RawVec$/m;
static MATCH_REGEX: RegExp = /^struct (std::vec::)?Vec/m;
static IGNORE_REGEX: RegExp = /^struct (std::vec::)?RawVec$/m;

static isSuitableFor(params: { type: string }) {
const isAMatch = VectorType.MATCH_REGEX.test(params.type);
Expand Down
7 changes: 5 additions & 2 deletions packages/abi-typegen/src/templates/contract/dts.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,15 @@ import { renderDtsTemplate } from './dts';
* @group node
*/
describe('templates/dts', () => {
test('should render dts template', () => {
test.each(['debug', 'release'])('should render dts template', (build) => {
// mocking
const { restore } = mockVersions();

// executing
const project = getTypegenForcProject(AbiTypegenProjectsEnum.FULL);
const project = getTypegenForcProject(
AbiTypegenProjectsEnum.FULL,
build as 'release' | 'debug'
);
const { abiContents: rawContents } = project;

const abi = new Abi({
Expand Down
3 changes: 2 additions & 1 deletion packages/abi-typegen/src/templates/utils/formatEnums.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ export function formatEnums(params: { types: IType[] }) {
outputNativeValues,
typeAnnotations,
};
});
})
.sort((a, b) => (a.structName < b.structName ? -1 : 1));

return { enums };
}
3 changes: 2 additions & 1 deletion packages/abi-typegen/src/templates/utils/formatStructs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ export function formatStructs(params: { types: IType[] }) {
outputValues,
recycleRef: inputValues === outputValues, // reduces duplication
};
});
})
.sort((a, b) => (a.structName < b.structName ? -1 : 1));

return { structs };
}
3 changes: 2 additions & 1 deletion packages/abi-typegen/src/utils/extractStructName.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ import type { IRawAbiTypeRoot } from '../types/interfaces/IRawAbiType';
export function extractStructName(params: { rawAbiType: IRawAbiTypeRoot; regex: RegExp }) {
const { rawAbiType, regex } = params;

const match = rawAbiType.type.match(params.regex)?.[1];
const matches = rawAbiType.type.match(regex);
const match = matches?.[2] ?? matches?.[1];

if (!match) {
let errorMessage = `Couldn't extract struct name with: '${regex}'.\n\n`;
Expand Down
7 changes: 6 additions & 1 deletion packages/abi-typegen/src/utils/shouldSkipAbiType.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
export function shouldSkipAbiType(params: { type: string }) {
const ignoreList = ['struct RawVec'];
const ignoreList = [
'struct RawVec',
'struct std::vec::RawVec',
'struct RawBytes',
'struct std::bytes::RawBytes',
];
const shouldSkip = ignoreList.indexOf(params.type) >= 0;
return shouldSkip;
}
3 changes: 3 additions & 0 deletions packages/abi-typegen/src/utils/shouldSkipType.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ import { supportedTypes } from './supportedTypes';
describe('types.ts', () => {
test('should always skip these types', () => {
expect(shouldSkipAbiType({ type: 'struct RawVec' })).toEqual(true);
expect(shouldSkipAbiType({ type: 'struct std::vec::RawVec' })).toEqual(true);
expect(shouldSkipAbiType({ type: 'struct RawBytes' })).toEqual(true);
expect(shouldSkipAbiType({ type: 'struct std::bytes::RawBytes' })).toEqual(true);
});

test('should never skip known types', () => {
Expand Down
1 change: 1 addition & 0 deletions packages/abi-typegen/test/fixtures/forc-projects/Forc.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,5 @@ members = [
"./struct-with-array",
"./tuple-simple",
"./vector-simple",
"libs-for-testing",
]
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ license = "Apache-2.0"
name = "full"

[dependencies]
libs-for-testing = { path = "../libs-for-testing" }
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
contract;

use libs_for_testing::ExternalStruct;
use libs_for_testing::ExternalEnum;
use std::vm::evm::evm_address::EvmAddress;
use std::b512::B512;
use std::string::String;
Expand Down Expand Up @@ -81,6 +82,11 @@ abi MyContract {
fn types_raw_slice(x: raw_slice) -> raw_slice;
fn types_std_string(x: String) -> String;
fn types_result(x: Result<u64, u32>) -> Result<u64, str[10]>;
fn type_address(x: Address) -> Address;
fn type_contract_id(x: ContractId) -> ContractId;
fn type_identity(x: Identity) -> Identity;
fn type_external_struct(x: ExternalStruct) -> ExternalStruct;
fn type_external_enum(x: ExternalEnum) -> ExternalEnum;
fn types_generic_enum(x: GenericEnum<u8, u16>) -> GenericEnum<u8, u16>;
fn types_generic_struct(x: GenericStructWithEnum<u8, u16>) -> GenericStructWithEnum<u8, u16>;
}
Expand Down Expand Up @@ -183,6 +189,21 @@ impl MyContract for Contract {
Err(MyContractError::DivisionByZero) => Err(__to_str_array("DivisError")),
}
}
fn type_address(x: Address) -> Address {
x
}
fn type_contract_id(x: ContractId) -> ContractId {
x
}
fn type_identity(x: Identity) -> Identity {
x
}
fn type_external_enum(x: ExternalEnum) -> ExternalEnum {
x
}
fn type_external_struct(x: ExternalStruct) -> ExternalStruct {
x
}
fn types_generic_enum(x: GenericEnum<u8, u16>) -> GenericEnum<u8, u16> {
x
}
Expand Down
7 changes: 5 additions & 2 deletions packages/abi-typegen/test/fixtures/forc-projects/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,12 @@ export enum AbiTypegenProjectsEnum {
VECTOR_SIMPLE = 'vector-simple',
}

export const getTypegenForcProject = (project: AbiTypegenProjectsEnum) =>
export const getTypegenForcProject = (
project: AbiTypegenProjectsEnum,
build: 'release' | 'debug' = 'release'
) =>
getForcProject<IRawAbi>({
projectDir: join(__dirname, project),
projectName: project,
build: 'release',
build,
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[project]
authors = ["Fuel Labs <contact@fuel.sh>"]
entry = "lib.sw"
license = "Apache-2.0"
name = "libs-for-testing"

[dependencies]
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
library;

// anything `pub` here will be exported as a part of this library's API
pub struct ExternalStruct {
pub value: u64,
}

pub enum ExternalEnum {
A: (),
B: (),
}
32 changes: 30 additions & 2 deletions packages/abi-typegen/test/fixtures/templates/contract/dts.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -28,24 +28,37 @@ import type { Option, Enum, Vec, Result } from "./common";

export type EnumWithVectorInput = Enum<{ num: BigNumberish, vec: Vec<BigNumberish> }>;
export type EnumWithVectorOutput = Enum<{ num: number, vec: Vec<number> }>;
export enum ExternalEnumInput { A = 'A', B = 'B' };
export enum ExternalEnumOutput { A = 'A', B = 'B' };
export type GenericEnumInput<T1, T2> = Enum<{ a: T1, b: T2 }>;
export type GenericEnumOutput<T1, T2> = GenericEnumInput<T1, T2>;
export type IdentityInput = Enum<{ Address: AddressInput, ContractId: ContractIdInput }>;
export type IdentityOutput = Enum<{ Address: AddressOutput, ContractId: ContractIdOutput }>;
export enum MyEnumInput { Checked = 'Checked', Pending = 'Pending' };
export enum MyEnumOutput { Checked = 'Checked', Pending = 'Pending' };

export type AddressInput = { bits: string };
export type AddressOutput = AddressInput;
export type AssetIdInput = { bits: string };
export type AssetIdOutput = AssetIdInput;
export type ContractIdInput = { bits: string };
export type ContractIdOutput = ContractIdInput;
export type ExternalStructInput = { value: BigNumberish };
export type ExternalStructOutput = { value: BN };
export type GenericStructWithEnumInput<T1, T2> = { a: T1, b: GenericEnumInput<T1, T2> };
export type GenericStructWithEnumOutput<T1, T2> = { a: T1, b: GenericEnumOutput<T1, T2> };
export type MyStructInput = { x: BigNumberish, y: BigNumberish, state: MyEnumInput };
export type MyStructOutput = { x: number, y: number, state: MyEnumOutput };
export type RawBytesInput = { ptr: BigNumberish, cap: BigNumberish };
export type RawBytesOutput = { ptr: BN, cap: BN };
export type StructWithMultiOptionInput = { multiple: [Option<BigNumberish>, Option<BigNumberish>, Option<BigNumberish>, Option<BigNumberish>, Option<BigNumberish>] };
export type StructWithMultiOptionOutput = { multiple: [Option<number>, Option<number>, Option<number>, Option<number>, Option<number>] };

interface MyContractAbiInterface extends Interface {
functions: {
type_address: FunctionFragment;
type_contract_id: FunctionFragment;
type_external_enum: FunctionFragment;
type_external_struct: FunctionFragment;
type_identity: FunctionFragment;
types_array: FunctionFragment;
types_asset_id: FunctionFragment;
types_b256: FunctionFragment;
Expand Down Expand Up @@ -79,6 +92,11 @@ interface MyContractAbiInterface extends Interface {
types_vector_u8: FunctionFragment;
};

encodeFunctionData(functionFragment: 'type_address', values: [AddressInput]): Uint8Array;
encodeFunctionData(functionFragment: 'type_contract_id', values: [ContractIdInput]): Uint8Array;
encodeFunctionData(functionFragment: 'type_external_enum', values: [ExternalEnumInput]): Uint8Array;
encodeFunctionData(functionFragment: 'type_external_struct', values: [ExternalStructInput]): Uint8Array;
encodeFunctionData(functionFragment: 'type_identity', values: [IdentityInput]): Uint8Array;
encodeFunctionData(functionFragment: 'types_array', values: [[BigNumberish, BigNumberish, BigNumberish]]): Uint8Array;
encodeFunctionData(functionFragment: 'types_asset_id', values: [AssetIdInput]): Uint8Array;
encodeFunctionData(functionFragment: 'types_b256', values: [string]): Uint8Array;
Expand Down Expand Up @@ -111,6 +129,11 @@ interface MyContractAbiInterface extends Interface {
encodeFunctionData(functionFragment: 'types_vector_option', values: [Vec<StructWithMultiOptionInput>]): Uint8Array;
encodeFunctionData(functionFragment: 'types_vector_u8', values: [Vec<BigNumberish>]): Uint8Array;

decodeFunctionData(functionFragment: 'type_address', data: BytesLike): DecodedValue;
decodeFunctionData(functionFragment: 'type_contract_id', data: BytesLike): DecodedValue;
decodeFunctionData(functionFragment: 'type_external_enum', data: BytesLike): DecodedValue;
decodeFunctionData(functionFragment: 'type_external_struct', data: BytesLike): DecodedValue;
decodeFunctionData(functionFragment: 'type_identity', data: BytesLike): DecodedValue;
decodeFunctionData(functionFragment: 'types_array', data: BytesLike): DecodedValue;
decodeFunctionData(functionFragment: 'types_asset_id', data: BytesLike): DecodedValue;
decodeFunctionData(functionFragment: 'types_b256', data: BytesLike): DecodedValue;
Expand Down Expand Up @@ -147,6 +170,11 @@ interface MyContractAbiInterface extends Interface {
export class MyContractAbi extends Contract {
interface: MyContractAbiInterface;
functions: {
type_address: InvokeFunction<[x: AddressInput], AddressOutput>;
type_contract_id: InvokeFunction<[x: ContractIdInput], ContractIdOutput>;
type_external_enum: InvokeFunction<[x: ExternalEnumInput], ExternalEnumOutput>;
type_external_struct: InvokeFunction<[x: ExternalStructInput], ExternalStructOutput>;
type_identity: InvokeFunction<[x: IdentityInput], IdentityOutput>;
types_array: InvokeFunction<[x: [BigNumberish, BigNumberish, BigNumberish]], [number, number, number]>;
types_asset_id: InvokeFunction<[x: AssetIdInput], AssetIdOutput>;
types_b256: InvokeFunction<[x: string], string>;
Expand Down
Loading

0 comments on commit 86f7ece

Please sign in to comment.