Skip to content

Commit

Permalink
feat!: adding abi transpiler (#2856)
Browse files Browse the repository at this point in the history
* Upgrading forc to temp branch

* Adding ABI transpiler and integrating it with related areas

* Updating typegen fixtures

* Fixing broken typegen tests; updating outdated IDs

* Re-instating the order

* Loading forc projects the standard and proper way

* Updating coder’s types, regexes, and fixing type matching everywhere

* Updating test using callpath-based naming for Option

* Fixing test, intercepting ABI loading so it can be transpiled

* Adding changeset

* Adjusting changeset

* Excluding sway-repo source files in `forc:check` script

* Ensuring branches are up to date before building

* Building internal packages in `--release` mode

* Fixing directory path for new build target

* Merging duplicated variables, standardizing terminologies

* Improving validation to handle strings / non-objects as well

* fix: option coder decoding incorrect value (#2870)

* Revert "Improving validation to handle strings / non-objects as well"

This reverts commit 45f3ef2.

* chore: fixing types on OptionCoder

* fix: match full qualifying type name with regex

* chore: added test groups

Co-authored-by: Daniel Bate <djbate23@gmail.com>

* chore: revert StructCoder name change

---------

Co-authored-by: Daniel Bate <djbate23@gmail.com>

* Standardizing timeout limits across workflows

* Ignoring `sway-repo`in links check  when building things from source

* Fixing ignore path

* Stop deleting `concreteTypeId`, used in public API

* Update .changeset/odd-horses-cheer.md

* Ignoring also `fuel-core-repo` for the same reasons as `sway-repo`

* Update .changeset/odd-horses-cheer.md

* Updating more fixtures

* Updating snippet

* Fixing random lint warning

* Incrasing test timeout limit

* Fixing ignored paths

* chore!: internalize old `JsonAbi` format (#2862)

* use `transpileAbi` in `Interface`

* add new interfaces to typegen

* no need for `debug` build anymore

* fix `getTypegenForcProject` return type

* added `as JsonAbi` type assertions to fix type errors

* fix typegen tests

* rename variable

* stop exporting `JsonAbi` from typegen

* revert changes that should be in another PR

* contttinue exporting

* rename to match `master`

* fix encode-and-decode test

* Renamed `JsonAbiNew` to `JsonAbi` and the old format to `JsonAbiOld`

* fix compilation errors

* Stop exporting `AbiCoder` and update `encode-and-decode` example

* Removed `Interface.findTypeById` method

* stop casting `as unknown as JsonAbi`

* use `argument` directly

* fix import

* fix: `Interface.encodeType/decodeType`

* Update packages/abi-coder/src/types/JsonAbi.ts

Co-authored-by: Peter Smith <peter@blueoceancomputing.co.uk>

* Update packages/abi-coder/src/types/JsonAbiNew.ts

Co-authored-by: Peter Smith <peter@blueoceancomputing.co.uk>

* Update packages/abi-typegen/src/types/interfaces/JsonAbi.ts

Co-authored-by: Peter Smith <peter@blueoceancomputing.co.uk>

* Update packages/account/test/fuel-wallet-connector.test.ts

Co-authored-by: Peter Smith <peter@blueoceancomputing.co.uk>

* Update packages/abi-typegen/src/utils/transpile-abi.ts

Co-authored-by: Peter Smith <peter@blueoceancomputing.co.uk>

* copy/paste transpile-abi

* fix compilation error

* eslint disable todo type

* use `{ transpile: T }` params object

* update `encode-and-decode.md` docs

* fix: spellcheck

* Update apps/docs/src/guide/encoding/encode-and-decode.md

Co-authored-by: Anderson Arboleya <anderson@arboleya.me>

* Update apps/docs/src/guide/encoding/encode-and-decode.md

Co-authored-by: Anderson Arboleya <anderson@arboleya.me>

* Update apps/docs/src/guide/encoding/encode-and-decode.md

Co-authored-by: Anderson Arboleya <anderson@arboleya.me>

---------

Co-authored-by: Anderson Arboleya <anderson@arboleya.me>
Co-authored-by: Peter Smith <peter@blueoceancomputing.co.uk>

* Getting around non-null assertions

* Adjusting changeset

* Adjusting scripts

* Updating template fixtures/snapshots

* Triggering CI

* The branch is gone - temporarily switching to `master`

* Temporarily patching sway std lib

* Temporarily skipping problematic sway projects and related tests

* Lintfix - deprecations, types mismatch, and broken imports

* DRYing test setup/teardown

* Fixing broken tests

* Patching base library individually

* Unskipping problematic workspace members

* Adjusting predicate data handling

* Undoing undesired changed

* Adjuting more projects

* Revert "Temporarily skipping problematic sway projects and related tests"

This reverts commit dc054ff.

* Formatting

* Revert "Temporarily patching sway std lib"

This reverts commit 48b0ab3.

* Revert "Patching base library individually"

This reverts commit b97c944.

* Replacing sway `branch` by `0.63.0` version

* Update .changeset/odd-horses-cheer.md

Co-authored-by: Peter Smith <peter@blueoceancomputing.co.uk>

* Updating forc version

---------

Co-authored-by: Peter Smith <peter@blueoceancomputing.co.uk>
Co-authored-by: Nedim Salkić <nedim.salkic@fuel.sh>
Co-authored-by: Daniel Bate <djbate23@gmail.com>
  • Loading branch information
4 people authored and maschad committed Aug 21, 2024
1 parent 9fef131 commit 4fee8a6
Show file tree
Hide file tree
Showing 66 changed files with 1,764 additions and 1,610 deletions.
9 changes: 9 additions & 0 deletions .changeset/odd-horses-cheer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
"@fuel-ts/abi-coder": minor
"@fuel-ts/abi-typegen": minor
"@fuel-ts/versions": minor
"@internal/forc": minor
"create-fuels": minor
---

feat!: adding `abi` transpiler
31 changes: 18 additions & 13 deletions apps/docs-snippets/src/guide/encoding/encode-and-decode.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { AbiCoder, Script, ReceiptType, arrayify, buildFunctionResult } from 'fuels';
import type { JsonAbi, JsonAbiArgument, TransactionResultReturnDataReceipt } from 'fuels';
import type { JsonAbi, TransactionResultReturnDataReceipt } from 'fuels';
import { buildFunctionResult, ReceiptType, arrayify, Script, Interface } from 'fuels';
import { launchTestNode } from 'fuels/test-utils';

// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore JSONC extension requires mapping but behaves fine
import abiSnippet from '../../../test/fixtures/abi/encode-and-decode.jsonc';
import { SumScript as factory } from '../../../test/typegen/scripts/SumScript';

Expand All @@ -27,7 +29,7 @@ describe('encode and decode', () => {
// First we need to build out the transaction via the script that we want to encode.
// For that we'll need the ABI and the bytecode of the script
const abi: JsonAbi = factory.abi;
const bytecode: string = factory.bytecode;
const bytecode = factory.bytecode;

// Create the invocation scope for the script call, passing the initial
// value for the configurable constant
Expand All @@ -42,18 +44,21 @@ describe('encode and decode', () => {
// #endregion encode-and-decode-3

// #region encode-and-decode-4
// #import { JsonAbiArgument, AbiCoder};
// #import { Interface };

// Now we can encode the argument we want to pass to the function. The argument is required
// as a function parameter for all `AbiCoder` functions and we can extract it from the ABI itself
const argument: JsonAbiArgument = abi.functions
// as a function parameter for all abi functions and we can extract it from the ABI itself
const argument = abi.functions
.find((f) => f.name === 'main')
?.inputs.find((i) => i.name === 'inputted_amount') as JsonAbiArgument;
?.inputs.find((i) => i.name === 'inputted_amount')?.concreteTypeId as string;

// Using the `AbiCoder`'s `encode` method, we can now create the encoding required for
// a u32 which takes 4 bytes up of property space
// The `Interface` class is the entry point for encoding and decoding all things abi-related.
// We will use its `encodeType` method and create the encoding required for
// a u32 which takes 4 bytes up of property space.

const abiInterface = new Interface(abi);
const argumentToAdd = 10;
const encodedArguments = AbiCoder.encode(abi, argument, [argumentToAdd]);
const encodedArguments = abiInterface.encodeType(argument, [argumentToAdd]);
// Therefore the value of 10 will be encoded to:
// Uint8Array([0, 0, 0, 10]

Expand All @@ -72,7 +77,7 @@ describe('encode and decode', () => {
// #endregion encode-and-decode-4

// #region encode-and-decode-5
// #import { AbiCoder, ReceiptType, TransactionResultReturnDataReceipt, arrayify, buildFunctionResult };
// #import { ReceiptType, TransactionResultReturnDataReceipt, arrayify, buildFunctionResult };

// Get result of the transaction, including the contract call result. For this we'll need
// the previously created invocation scope, the transaction response and the script
Expand All @@ -99,8 +104,8 @@ describe('encode and decode', () => {
// returnData = new Uint8Array([0, 0, 0, 20]

// And now we can decode the returned bytes in a similar fashion to how they were
// encoded, via the `AbiCoder`
const [decodedReturnData] = AbiCoder.decode(abi, argument, returnData, 0);
// encoded, via the `Interface`
const [decodedReturnData] = abiInterface.decodeType(argument, returnData);
// 20
// #endregion encode-and-decode-5

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ describe('Transaction Request', () => {
// #endregion transaction-request-7

expect(transactionId).toBe(
'0x5e12f588de0cbf2ec0f085078880d5eeb3e18cd239a288d4a06ee4247a97e4f2'
'0xf62e682e05fa17455999758d00875449bd6f06cdbe003a6431aa944f2d652642'
);
});
});
29 changes: 10 additions & 19 deletions apps/docs-snippets/test/fixtures/abi/encode-and-decode.jsonc
Original file line number Diff line number Diff line change
@@ -1,29 +1,25 @@
// #region encode-and-decode-2
{
"encoding": "1",
"types": [
"programType": "script",
"specVersion": "1",
"encodingVersion": "1",
"concreteTypes": [
{
"typeId": 0,
"type": "u32",
"components": null,
"typeParameters": null,
"concreteTypeId": "d7649d428b9ff33d188ecbf38a7e4d8fd167fa01b2e10fe9a8f9308e52f1d7cc",
},
],
"metadataTypes": [],
"functions": [
{
"inputs": [
{
"name": "inputted_amount",
"type": 0,
"typeArguments": null,
"concreteTypeId": "d7649d428b9ff33d188ecbf38a7e4d8fd167fa01b2e10fe9a8f9308e52f1d7cc",
},
],
"name": "main",
"output": {
"name": "",
"type": 0,
"typeArguments": null,
},
"output": "d7649d428b9ff33d188ecbf38a7e4d8fd167fa01b2e10fe9a8f9308e52f1d7cc",
"attributes": null,
},
],
Expand All @@ -32,14 +28,9 @@
"configurables": [
{
"name": "AMOUNT",
"configurableType": {
"name": "",
"type": 0,
"typeArguments": null,
},
"offset": 856,
"concreteTypeId": "d7649d428b9ff33d188ecbf38a7e4d8fd167fa01b2e10fe9a8f9308e52f1d7cc",
"offset": 920,
},
],
}

// #endregion encode-and-decode-2
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ predicate;
use std::{b512::B512, ecr::ec_recover_address, tx::{tx_id, tx_witness_data}};

fn main(signer: b256) -> bool {
let witness_data: B512 = tx_witness_data(1);
let witness_data: B512 = tx_witness_data(1).unwrap();
let address: b256 = ec_recover_address(witness_data, tx_id()).unwrap().bits();
return address == signer;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ script;
use std::{b512::B512, ecr::ec_recover_address, tx::{tx_id, tx_witness_data}};

fn main(signer: b256) -> bool {
let witness_data: B512 = tx_witness_data(1);
let witness_data: B512 = tx_witness_data(1).unwrap();
let address: b256 = ec_recover_address(witness_data, tx_id()).unwrap().bits();
return address == signer;
}
Expand Down
1 change: 1 addition & 0 deletions apps/docs/spell-check-custom-words.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
ABI
ABIs
ABI's
ASM
AssetId
IDE
Expand Down
15 changes: 6 additions & 9 deletions apps/docs/src/guide/encoding/encode-and-decode.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
# Encode and Decode

In order to interact with the FuelVM, types must be encoded and decoded as per the [argument encoding specification](https://docs.fuel.network/docs/specs/abi/argument-encoding/). The SDK provides the `AbiCoder` class to encode and decode data.
To interact with the FuelVM, types must be encoded and decoded per the [argument encoding specification](https://docs.fuel.network/docs/specs/abi/argument-encoding/). The SDK provides the `Interface` class to encode and decode data.

It has three static methods:
The relevant methods of `Interface` are:

- `encode`
- `decode`
- `getCoder`
- `encodeType`
- `decodeType`

The methods `encode` and `decode` describe the aforementioned process, while `getCoder` returns an instance of the internal coder required to serialize the passed type. This coder is then used internally by the `encode` and `decode` methods.

All methods expect you to pass the [ABI](https://docs.fuel.network/docs/specs/abi/json-abi-format/) and ABI Argument as function parameters to deduce the specific type coders that will be required to parse the data.
The `Interface` class requires you to pass the [ABI](https://docs.fuel.network/docs/specs/abi/json-abi-format/) on initialization. Both methods accept a `concreteTypeId`, which must exist in the ABI's `concreteTypes` array. After that, a suitable coder will be assigned to encode/decode that type.

Imagine we are working with the following script that returns the sum of two `u32` integers:

Expand All @@ -26,7 +23,7 @@ It will produce the following ABI:

<<< @/../../docs-snippets/test/fixtures/abi/encode-and-decode.jsonc#encode-and-decode-2{json:line-numbers}

Now, let's prepare some data to pass to the `main` function to retrieve the combined integer. The function expects and returns a `u32` integer. So here, we will encode the `u32` to pass it to the function and receive the same `u32` back, as bytes, that we'll use for decoding. We can do both of these with the `AbiCoder`.
Now, let's prepare some data to pass to the `main` function to retrieve the combined integer. The function expects and returns a `u32` integer. So here, we will encode the `u32` to pass it to the function and receive the same `u32` back, as bytes, that we'll use for decoding. We can do both of these with the `Interface`.

First, let's prepare the transaction:

Expand Down
2 changes: 1 addition & 1 deletion internal/forc/VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.62.0
0.63.1
19 changes: 14 additions & 5 deletions internal/forc/lib/shared.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,18 +52,27 @@ const swayRepoUrl = 'https://github.com/fuellabs/sway.git';

export const buildFromGitBranch = (branchName) => {
const swayRepoDir = join(__dirname, '..', 'sway-repo');
const swayRepoDebugDir = join(swayRepoDir, 'target', 'debug');
const swayRepoReleaseDir = join(swayRepoDir, 'target', 'release');
const stdioOpts = { stdio: 'inherit' };

if (existsSync(swayRepoDir)) {
execSync(`cd ${swayRepoDir} && git fetch origin && git checkout ${branchName}`, stdioOpts);
execSync(`cd ${swayRepoDir} && cargo build`, stdioOpts);
execSync(
[
`cd ${swayRepoDir}`,
`git fetch origin`,
`git checkout ${branchName}`,
`git pull origin ${branchName}`,
].join('&&'),
stdioOpts
);

execSync(`cd ${swayRepoDir} && cargo build --release`, stdioOpts);
} else {
execSync(`git clone --branch ${branchName} ${swayRepoUrl} ${swayRepoDir}`, stdioOpts);
execSync(`cd ${swayRepoDir} && cargo build`, stdioOpts);
execSync(`cd ${swayRepoDir} && cargo build --release`, stdioOpts);
}

const [from, to] = [swayRepoDebugDir, forcBinDirPath];
const [from, to] = [swayRepoReleaseDir, forcBinDirPath];

rmSync(to, { recursive: true, force: true });
mkdirSync(to, { recursive: true });
Expand Down
10 changes: 5 additions & 5 deletions internal/fuel-core/lib/shared.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,23 +51,23 @@ const fuelCoreRepoUrl = 'https://github.com/fuellabs/fuel-core.git';

export const buildFromGitBranch = (branchName) => {
const fuelCoreRepoDir = join(__dirname, '..', 'fuel-core-repo');
const fuelCoreRepoDebugDir = join(fuelCoreRepoDir, 'target', 'debug');
const fuelCoreRepoReleaseDir = join(fuelCoreRepoDir, 'target', 'release');
const stdioOpts = { stdio: 'inherit' };

if (existsSync(fuelCoreRepoDir)) {
spawnSync('git', ['pull'], { cwd: fuelCoreRepoDir, ...stdioOpts });
spawnSync('git', ['checkout', branchName], { cwd: fuelCoreRepoDir, ...stdioOpts });
spawnSync('cargo', ['build'], { cwd: fuelCoreRepoDir, ...stdioOpts });
spawnSync('git', ['pull'], { cwd: fuelCoreRepoDir, ...stdioOpts });
spawnSync('cargo', ['build', '--release'], { cwd: fuelCoreRepoDir, ...stdioOpts });
} else {
spawnSync(
'git',
['clone', '--branch', branchName, fuelCoreRepoUrl, fuelCoreRepoDir],
stdioOpts
);
spawnSync('cargo', ['build'], { cwd: fuelCoreRepoDir, ...stdioOpts });
spawnSync('cargo', ['build', '--release'], { cwd: fuelCoreRepoDir, ...stdioOpts });
}

const [from, to] = [fuelCoreRepoDebugDir, fuelCoreBinDirPath];
const [from, to] = [fuelCoreRepoReleaseDir, fuelCoreBinDirPath];

rmSync(to, { recursive: true, force: true });
mkdirSync(to, { recursive: true });
Expand Down
8 changes: 4 additions & 4 deletions packages/abi-coder/src/AbiCoder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ import { ResolvedAbiType } from './ResolvedAbiType';
import type { DecodedValue, InputValue, Coder } from './encoding/coders/AbstractCoder';
import { getCoderForEncoding } from './encoding/strategies/getCoderForEncoding';
import type { EncodingOptions } from './types/EncodingOptions';
import type { JsonAbi, JsonAbiArgument } from './types/JsonAbi';
import type { JsonAbiOld, JsonAbiArgument } from './types/JsonAbi';

export abstract class AbiCoder {
static getCoder(
abi: JsonAbi,
abi: JsonAbiOld,
argument: JsonAbiArgument,
options: EncodingOptions = {
padToWordSize: false,
Expand All @@ -17,7 +17,7 @@ export abstract class AbiCoder {
}

static encode(
abi: JsonAbi,
abi: JsonAbiOld,
argument: JsonAbiArgument,
value: InputValue,
options?: EncodingOptions
Expand All @@ -26,7 +26,7 @@ export abstract class AbiCoder {
}

static decode(
abi: JsonAbi,
abi: JsonAbiOld,
argument: JsonAbiArgument,
data: Uint8Array,
offset: number,
Expand Down
Loading

0 comments on commit 4fee8a6

Please sign in to comment.