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!: internalize old JsonAbi format #2862

Merged
merged 42 commits into from
Aug 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
26c6915
use `transpileAbi` in `Interface`
nedsalk Jul 30, 2024
c369176
add new interfaces to typegen
nedsalk Jul 30, 2024
76790dd
no need for `debug` build anymore
nedsalk Jul 30, 2024
a525745
fix `getTypegenForcProject` return type
nedsalk Jul 30, 2024
c1494c3
added `as JsonAbi` type assertions to fix type errors
nedsalk Jul 30, 2024
b181ebc
fix typegen tests
nedsalk Jul 30, 2024
8ee4d3f
rename variable
nedsalk Jul 30, 2024
91e3182
stop exporting `JsonAbi` from typegen
nedsalk Jul 30, 2024
ebc09c8
revert changes that should be in another PR
nedsalk Jul 30, 2024
a9ac7b8
contttinue exporting
nedsalk Jul 30, 2024
d00f7ca
Merge remote-tracking branch 'origin/master' into ns/feat/adding-abi-…
nedsalk Jul 30, 2024
16d1859
rename to match `master`
nedsalk Jul 30, 2024
bba16c8
fix encode-and-decode test
nedsalk Jul 30, 2024
cf01448
Merge branch 'aa/feat/adding-abi-transpiler' into ns/feat/adding-abi-…
nedsalk Jul 30, 2024
30bebbf
Renamed `JsonAbiNew` to `JsonAbi` and the old format to `JsonAbiOld`
nedsalk Jul 30, 2024
6148967
fix compilation errors
nedsalk Jul 30, 2024
6793b4b
Merge remote-tracking branch 'origin/aa/feat/adding-abi-transpiler' i…
nedsalk Jul 31, 2024
ee734b9
Stop exporting `AbiCoder` and update `encode-and-decode` example
nedsalk Jul 31, 2024
157bdba
Removed `Interface.findTypeById` method
nedsalk Jul 31, 2024
d6a6a71
stop casting `as unknown as JsonAbi`
nedsalk Jul 31, 2024
617ecbe
use `argument` directly
nedsalk Jul 31, 2024
dfb81b9
fix import
nedsalk Jul 31, 2024
4af88af
Merge branch 'aa/feat/adding-abi-transpiler' into ns/feat/adding-abi-…
arboleya Jul 31, 2024
4893c56
Merge branch 'aa/feat/adding-abi-transpiler' into ns/feat/adding-abi-…
arboleya Jul 31, 2024
cc2b9f0
Merge remote-tracking branch 'origin/aa/feat/adding-abi-transpiler' i…
nedsalk Aug 1, 2024
5a1776f
fix: `Interface.encodeType/decodeType`
nedsalk Aug 1, 2024
79c631f
Update packages/abi-coder/src/types/JsonAbi.ts
nedsalk Aug 1, 2024
c3e09a5
Update packages/abi-coder/src/types/JsonAbiNew.ts
nedsalk Aug 1, 2024
f40bff6
Update packages/abi-typegen/src/types/interfaces/JsonAbi.ts
nedsalk Aug 1, 2024
a882de6
Update packages/account/test/fuel-wallet-connector.test.ts
nedsalk Aug 1, 2024
64d6b38
Update packages/abi-typegen/src/utils/transpile-abi.ts
nedsalk Aug 1, 2024
3cb9a8a
copy/paste transpile-abi
nedsalk Aug 1, 2024
df11724
fix compilation error
nedsalk Aug 1, 2024
b345eaa
eslint disable todo type
nedsalk Aug 1, 2024
6b8edc9
use `{ transpile: T }` params object
nedsalk Aug 1, 2024
40a511d
Merge remote-tracking branch 'origin/aa/feat/adding-abi-transpiler' i…
nedsalk Aug 1, 2024
3df8bda
update `encode-and-decode.md` docs
nedsalk Aug 1, 2024
2d93ec2
fix: spellcheck
nedsalk Aug 1, 2024
825eb08
Merge remote-tracking branch 'origin/aa/feat/adding-abi-transpiler' i…
nedsalk Aug 2, 2024
ea21fb7
Update apps/docs/src/guide/encoding/encode-and-decode.md
nedsalk Aug 2, 2024
f57a2fb
Update apps/docs/src/guide/encoding/encode-and-decode.md
nedsalk Aug 2, 2024
7af2130
Update apps/docs/src/guide/encoding/encode-and-decode.md
nedsalk Aug 2, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 15 additions & 12 deletions apps/docs-snippets/src/guide/encoding/encode-and-decode.test.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import {
FUEL_NETWORK_URL,
Provider,
AbiCoder,
Script,
ReceiptType,
arrayify,
buildFunctionResult,
Interface,
} from 'fuels';
import type { Account, JsonAbi, JsonAbiArgument, TransactionResultReturnDataReceipt } from 'fuels';
import type { Account, JsonAbi, TransactionResultReturnDataReceipt } from 'fuels';
import { generateTestWallet } from 'fuels/test-utils';

// eslint-disable-next-line @typescript-eslint/ban-ts-comment
Expand Down Expand Up @@ -54,18 +54,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.
danielbate marked this conversation as resolved.
Show resolved Hide resolved
// 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 @@ -84,7 +87,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 @@ -111,8 +114,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
26 changes: 8 additions & 18 deletions apps/docs-snippets/test/fixtures/abi/encode-and-decode.jsonc
Original file line number Diff line number Diff line change
@@ -1,30 +1,25 @@
// #region encode-and-decode-2
{
"encoding": "1",
"types": [
"programType": "script",
petertonysmith94 marked this conversation as resolved.
Show resolved Hide resolved
"specVersion": "1",
"encodingVersion": "1",
"concreteTypes": [
{
"typeId": 0,
"type": "u32",
"components": null,
"concreteTypeId": "d7649d428b9ff33d188ecbf38a7e4d8fd167fa01b2e10fe9a8f9308e52f1d7cc",
"typeParameters": null,
},
],
"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 @@ -33,14 +28,9 @@
"configurables": [
{
"name": "AMOUNT",
"configurableType": {
"name": "",
"type": 0,
"typeArguments": null,
},
"concreteTypeId": "d7649d428b9ff33d188ecbf38a7e4d8fd167fa01b2e10fe9a8f9308e52f1d7cc",
"offset": 856,
},
],
}

// #endregion encode-and-decode-2
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
IDE
IDEs
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
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';
nedsalk marked this conversation as resolved.
Show resolved Hide resolved

export abstract class AbiCoder {
static getCoder(
abi: JsonAbi,
abi: JsonAbiOld,
arboleya marked this conversation as resolved.
Show resolved Hide resolved
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
53 changes: 26 additions & 27 deletions packages/abi-coder/src/FunctionFragment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,40 +10,39 @@ import { ResolvedAbiType } from './ResolvedAbiType';
import type { DecodedValue, InputValue } from './encoding/coders/AbstractCoder';
import { StdStringCoder } from './encoding/coders/StdStringCoder';
import { TupleCoder } from './encoding/coders/TupleCoder';
import type { JsonAbi, JsonAbiFunction, JsonAbiFunctionAttribute } from './types/JsonAbi';
import type { JsonAbiOld, JsonAbiFunction } from './types/JsonAbi';
import type { AbiFunction, AbiFunctionAttribute } from './types/JsonAbiNew';
import type { EncodingVersion } from './utils/constants';
import { getFunctionInputs } from './utils/getFunctionInputs';
import { findFunctionByName, findNonVoidInputs, getEncodingVersion } from './utils/json-abi';
import { findNonVoidInputs, getEncodingVersion } from './utils/json-abi';
import { padValuesWithUndefined } from './utils/padValuesWithUndefined';

export class FunctionFragment<
TAbi extends JsonAbi = JsonAbi,
FnName extends TAbi['functions'][number]['name'] = string,
> {
export class FunctionFragment {
readonly signature: string;
readonly selector: string;
readonly selectorBytes: Uint8Array;
readonly encoding: EncodingVersion;
readonly name: string;
readonly jsonFn: JsonAbiFunction;
readonly attributes: readonly JsonAbiFunctionAttribute[];

private readonly jsonAbi: JsonAbi;

constructor(jsonAbi: JsonAbi, name: FnName) {
this.jsonAbi = jsonAbi;
this.jsonFn = findFunctionByName(this.jsonAbi, name);

this.name = name;
this.signature = FunctionFragment.getSignature(this.jsonAbi, this.jsonFn);
readonly jsonFn: AbiFunction;
readonly attributes: readonly AbiFunctionAttribute[];

private readonly jsonAbiOld: JsonAbiOld;
private readonly jsonFnOld: JsonAbiFunction;

constructor(jsonAbi: JsonAbiOld, fn: AbiFunction) {
this.jsonFn = fn;
this.jsonAbiOld = jsonAbi;
this.jsonFnOld = jsonAbi.functions.find((f) => f.name === fn.name) as JsonAbiFunction;
this.name = fn.name;
this.signature = FunctionFragment.getSignature(this.jsonAbiOld, this.jsonFnOld);
this.selector = FunctionFragment.getFunctionSelector(this.signature);
this.selectorBytes = new StdStringCoder().encode(name);
this.selectorBytes = new StdStringCoder().encode(this.name);
this.encoding = getEncodingVersion(jsonAbi.encoding);

this.attributes = this.jsonFn.attributes ?? [];
}

private static getSignature(abi: JsonAbi, fn: JsonAbiFunction): string {
private static getSignature(abi: JsonAbiOld, fn: JsonAbiFunction): string {
const inputsSignatures = fn.inputs.map((input) =>
new ResolvedAbiType(abi, input).getSignature()
);
Expand All @@ -57,7 +56,7 @@ export class FunctionFragment<
}

encodeArguments(values: InputValue[]): Uint8Array {
const inputs = getFunctionInputs({ jsonAbi: this.jsonAbi, inputs: this.jsonFn.inputs });
const inputs = getFunctionInputs({ jsonAbi: this.jsonAbiOld, inputs: this.jsonFnOld.inputs });
const mandatoryInputLength = inputs.filter((i) => !i.isOptional).length;
if (values.length < mandatoryInputLength) {
throw new FuelError(
Expand All @@ -66,8 +65,8 @@ export class FunctionFragment<
);
}

const coders = this.jsonFn.inputs.map((t) =>
AbiCoder.getCoder(this.jsonAbi, t, {
const coders = this.jsonFnOld.inputs.map((t) =>
AbiCoder.getCoder(this.jsonAbiOld, t, {
encoding: this.encoding,
})
);
Expand All @@ -78,7 +77,7 @@ export class FunctionFragment<

decodeArguments(data: BytesLike) {
const bytes = arrayify(data);
const nonVoidInputs = findNonVoidInputs(this.jsonAbi, this.jsonFn.inputs);
const nonVoidInputs = findNonVoidInputs(this.jsonAbiOld, this.jsonFnOld.inputs);

if (nonVoidInputs.length === 0) {
// The VM is current return 0x0000000000000000, but we should treat it as undefined / void
Expand All @@ -103,9 +102,9 @@ export class FunctionFragment<
);
}

const result = this.jsonFn.inputs.reduce(
const result = this.jsonFnOld.inputs.reduce(
(obj: { decoded: unknown[]; offset: number }, input) => {
const coder = AbiCoder.getCoder(this.jsonAbi, input, { encoding: this.encoding });
const coder = AbiCoder.getCoder(this.jsonAbiOld, input, { encoding: this.encoding });
const [decodedValue, decodedValueByteSize] = coder.decode(bytes, obj.offset);

return {
Expand All @@ -121,7 +120,7 @@ export class FunctionFragment<

decodeOutput(data: BytesLike): [DecodedValue | undefined, number] {
const bytes = arrayify(data);
const coder = AbiCoder.getCoder(this.jsonAbi, this.jsonFn.output, {
const coder = AbiCoder.getCoder(this.jsonAbiOld, this.jsonFnOld.output, {
encoding: this.encoding,
});

Expand All @@ -135,6 +134,6 @@ export class FunctionFragment<
*/
isReadOnly(): boolean {
const storageAttribute = this.attributes.find((attr) => attr.name === 'storage');
return !storageAttribute?.arguments.includes('write');
return !storageAttribute?.arguments?.includes('write');
}
}
Loading
Loading