diff --git a/.changeset/twelve-brooms-reflect.md b/.changeset/twelve-brooms-reflect.md new file mode 100644 index 0000000000..2a9b2a0813 --- /dev/null +++ b/.changeset/twelve-brooms-reflect.md @@ -0,0 +1,11 @@ +--- +"@fuel-ts/transactions": patch +"@fuel-ts/abi-coder": minor +"@fuel-ts/versions": patch +"@fuel-ts/account": minor +"@fuel-ts/program": patch +"@fuel-ts/script": minor +"@fuel-ts/forc": patch +--- + +feat!: upgrade `forc@0.58.0` and remove `V0` encoding diff --git a/apps/docs-snippets/src/guide/transactions/transaction-request.test.ts b/apps/docs-snippets/src/guide/transactions/transaction-request.test.ts index 6c27c7673c..a0ae106976 100644 --- a/apps/docs-snippets/src/guide/transactions/transaction-request.test.ts +++ b/apps/docs-snippets/src/guide/transactions/transaction-request.test.ts @@ -224,7 +224,7 @@ describe('Transaction Request', () => { // #endregion transaction-request-7 expect(transactionId).toBe( - '0x20995f5333a9cd4d7acfab212ee723faec022fd0bd17b7778d552f624ea55d8e' + '0xb82d9e3da13a1b56b623238c0d7a7ab4d602f2c7f886bf7a9c05ecfb99267ce3' ); }); }); diff --git a/apps/docs/src/guide/types/vectors.md b/apps/docs/src/guide/types/vectors.md index 9c2f974f0f..326dcaf3df 100644 --- a/apps/docs/src/guide/types/vectors.md +++ b/apps/docs/src/guide/types/vectors.md @@ -28,8 +28,4 @@ Some functions require you to pass in bytecode to the function. The type of the To pass bytecode to this function, you can make use of the `arrayify` function to convert the bytecode file contents into a `UInt8Array`, the TS compatible type for Sway's `Vec` type and pass it the function like so: -<<< @/../../docs-snippets/src/guide/types/vector.test.ts#vector-bytecode-input-ts{ts:line-numbers} - -## Returning vectors - -Currently, returning vectors is not supported by Sway. If you try returning a type that is or contains a Vector, you will get a compile-time error. +<<< @/../../docs-snippets/src/guide/types/vector.test.ts#vector-bytecode-input-ts{ts:line-numbers} \ No newline at end of file diff --git a/packages/abi-coder/src/AbiCoder.ts b/packages/abi-coder/src/AbiCoder.ts index 1714fbd75b..b7fd369f1d 100644 --- a/packages/abi-coder/src/AbiCoder.ts +++ b/packages/abi-coder/src/AbiCoder.ts @@ -9,7 +9,7 @@ export abstract class AbiCoder { abi: JsonAbi, argument: JsonAbiArgument, options: EncodingOptions = { - isSmallBytes: false, + padToWordSize: false, } ): Coder { const resolvedAbiType = new ResolvedAbiType(abi, argument); diff --git a/packages/abi-coder/src/FunctionFragment.ts b/packages/abi-coder/src/FunctionFragment.ts index 9934427160..e8941de523 100644 --- a/packages/abi-coder/src/FunctionFragment.ts +++ b/packages/abi-coder/src/FunctionFragment.ts @@ -8,11 +8,8 @@ import { arrayify } from '@fuel-ts/utils'; import { AbiCoder } from './AbiCoder'; import { ResolvedAbiType } from './ResolvedAbiType'; import type { DecodedValue, InputValue } from './encoding/coders/AbstractCoder'; -import { ByteCoder } from './encoding/coders/v0/ByteCoder'; -import { TupleCoder } from './encoding/coders/v0/TupleCoder'; -import { VecCoder } from './encoding/coders/v0/VecCoder'; -import { StdStringCoder } from './encoding/coders/v1/StdStringCoder'; -import { TupleCoder as TupleCoderV1 } from './encoding/coders/v1/TupleCoder'; +import { StdStringCoder } from './encoding/coders/StdStringCoder'; +import { TupleCoder } from './encoding/coders/TupleCoder'; import type { JsonAbi, JsonAbiArgument, @@ -20,15 +17,13 @@ import type { JsonAbiFunctionAttribute, } from './types/JsonAbi'; import type { EncodingVersion } from './utils/constants'; -import { ENCODING_V1, OPTION_CODER_TYPE } from './utils/constants'; +import { OPTION_CODER_TYPE } from './utils/constants'; import { findFunctionByName, findNonEmptyInputs, findTypeById, getEncodingVersion, } from './utils/json-abi'; -import type { Uint8ArrayWithDynamicData } from './utils/utilities'; -import { isHeapType, isPointerType, unpackDynamicData } from './utils/utilities'; export class FunctionFragment< TAbi extends JsonAbi = JsonAbi, @@ -41,11 +36,6 @@ export class FunctionFragment< readonly name: string; readonly jsonFn: JsonAbiFunction; readonly attributes: readonly JsonAbiFunctionAttribute[]; - readonly isInputDataPointer: boolean; - readonly outputMetadata: { - isHeapType: boolean; - encodedLength: number; - }; private readonly jsonAbi: JsonAbi; @@ -58,11 +48,6 @@ export class FunctionFragment< this.selector = FunctionFragment.getFunctionSelector(this.signature); this.selectorBytes = new StdStringCoder().encode(name); this.encoding = getEncodingVersion(jsonAbi.encoding); - this.isInputDataPointer = this.#isInputDataPointer(); - this.outputMetadata = { - isHeapType: this.#isOutputDataHeap(), - encodedLength: this.#getOutputEncodedLength(), - }; this.attributes = this.jsonFn.attributes ?? []; } @@ -80,35 +65,7 @@ export class FunctionFragment< return bn(hashedFunctionSignature.slice(0, 10)).toHex(8); } - #isInputDataPointer(): boolean { - const inputTypes = this.jsonFn.inputs.map((i) => findTypeById(this.jsonAbi, i.type)); - - return this.jsonFn.inputs.length > 1 || isPointerType(inputTypes[0]?.type || ''); - } - - #isOutputDataHeap(): boolean { - const outputType = findTypeById(this.jsonAbi, this.jsonFn.output.type); - - return isHeapType(outputType?.type || ''); - } - - #getOutputEncodedLength(): number { - try { - const heapCoder = AbiCoder.getCoder(this.jsonAbi, this.jsonFn.output); - if (heapCoder instanceof VecCoder) { - return heapCoder.coder.encodedLength; - } - if (heapCoder instanceof ByteCoder) { - return ByteCoder.memorySize; - } - - return heapCoder.encodedLength; - } catch (e) { - return 0; - } - } - - encodeArguments(values: InputValue[], offset = 0): Uint8Array { + encodeArguments(values: InputValue[]): Uint8Array { FunctionFragment.verifyArgsAndInputsAlign(values, this.jsonFn.inputs, this.jsonAbi); const shallowCopyValues = values.slice(); @@ -121,16 +78,11 @@ export class FunctionFragment< const coders = nonEmptyInputs.map((t) => AbiCoder.getCoder(this.jsonAbi, t, { - isRightPadded: nonEmptyInputs.length > 1, encoding: this.encoding, }) ); - if (this.encoding === ENCODING_V1) { - return new TupleCoderV1(coders).encode(shallowCopyValues); - } - const results: Uint8ArrayWithDynamicData = new TupleCoder(coders).encode(shallowCopyValues); - return unpackDynamicData(results, offset, results.byteLength); + return new TupleCoder(coders).encode(shallowCopyValues); } private static verifyArgsAndInputsAlign( diff --git a/packages/abi-coder/src/Interface.ts b/packages/abi-coder/src/Interface.ts index 69725f7aa0..96fc8157e3 100644 --- a/packages/abi-coder/src/Interface.ts +++ b/packages/abi-coder/src/Interface.ts @@ -7,7 +7,7 @@ import { AbiCoder } from './AbiCoder'; import { FunctionFragment } from './FunctionFragment'; import type { InputValue } from './encoding/coders/AbstractCoder'; import type { JsonAbi, JsonAbiConfigurable } from './types/JsonAbi'; -import { ENCODING_V0, type EncodingVersion } from './utils/constants'; +import { type EncodingVersion } from './utils/constants'; import { findTypeById, getEncodingVersion } from './utils/json-abi'; export class Interface { @@ -58,13 +58,12 @@ export class Interface { encodeFunctionData( functionFragment: FunctionFragment | string, - values: Array, - offset = 0 + values: Array ): Uint8Array { const fragment = typeof functionFragment === 'string' ? this.getFunction(functionFragment) : functionFragment; - return fragment.encodeArguments(values, offset); + return fragment.encodeArguments(values); } // Decode the result of a function call @@ -99,9 +98,7 @@ export class Interface { } return AbiCoder.encode(this.jsonAbi, configurable.configurableType, value, { - isRightPadded: true, - // TODO: Review support for configurables in v1 encoding when it becomes available - encoding: ENCODING_V0, + encoding: this.encoding, }); } diff --git a/packages/abi-coder/src/encoding/coders/AbstractCoder.ts b/packages/abi-coder/src/encoding/coders/AbstractCoder.ts index 105ef4e960..8088d78222 100644 --- a/packages/abi-coder/src/encoding/coders/AbstractCoder.ts +++ b/packages/abi-coder/src/encoding/coders/AbstractCoder.ts @@ -1,7 +1,7 @@ import type { BytesLike } from '@fuel-ts/interfaces'; import type { BN } from '@fuel-ts/math'; -import type { Option } from './v0/OptionCoder'; +import type { Option } from './OptionCoder'; type Primitive = string | number | boolean; diff --git a/packages/abi-coder/src/encoding/coders/v0/ArrayCoder.test.ts b/packages/abi-coder/src/encoding/coders/ArrayCoder.test.ts similarity index 83% rename from packages/abi-coder/src/encoding/coders/v0/ArrayCoder.test.ts rename to packages/abi-coder/src/encoding/coders/ArrayCoder.test.ts index daadfa6ffa..c667e3d2b8 100644 --- a/packages/abi-coder/src/encoding/coders/v0/ArrayCoder.test.ts +++ b/packages/abi-coder/src/encoding/coders/ArrayCoder.test.ts @@ -1,8 +1,7 @@ import { FuelError, ErrorCode } from '@fuel-ts/errors'; import { expectToThrowFuelError } from '@fuel-ts/errors/test-utils'; -import { U32_MAX, U8_MAX } from '../../../../test/utils/constants'; -import type { EncodingOptions } from '../../../types/EncodingOptions'; +import { U32_MAX, U8_MAX } from '../../../test/utils/constants'; import { ArrayCoder } from './ArrayCoder'; import { BooleanCoder } from './BooleanCoder'; @@ -13,12 +12,8 @@ import { NumberCoder } from './NumberCoder'; * @group node */ describe('ArrayCoder', () => { - const options: EncodingOptions = { - isSmallBytes: true, - }; - it('should encode a number array with zero inputs', () => { - const coder = new ArrayCoder(new NumberCoder('u8', options), 0); + const coder = new ArrayCoder(new NumberCoder('u8'), 0); const expected = new Uint8Array([]); const actual = coder.encode([]); @@ -26,7 +21,7 @@ describe('ArrayCoder', () => { }); it('should decode a number array with zero inputs', () => { - const coder = new ArrayCoder(new NumberCoder('u8', options), 0); + const coder = new ArrayCoder(new NumberCoder('u8'), 0); const expectedValue: number[] = []; const expectedLength = 0; const [actualValue, actualLength] = coder.decode(new Uint8Array([]), 0); @@ -36,7 +31,7 @@ describe('ArrayCoder', () => { }); it('should encode a number array with four inputs', () => { - const coder = new ArrayCoder(new NumberCoder('u8', options), 4); + const coder = new ArrayCoder(new NumberCoder('u8'), 4); const array = [0, 13, 37, U8_MAX]; const expected = new Uint8Array(array); const actual = coder.encode(array); @@ -44,7 +39,7 @@ describe('ArrayCoder', () => { }); it('should decode a number array with four inputs', () => { - const coder = new ArrayCoder(new NumberCoder('u8', options), 4); + const coder = new ArrayCoder(new NumberCoder('u8'), 4); const expectedValue = [0, 13, 37, U8_MAX]; const expectedLength = expectedValue.length; const [actualValue, actualLength] = coder.decode(new Uint8Array(expectedValue), 0); @@ -56,8 +51,8 @@ describe('ArrayCoder', () => { it('should encode an enum array with differently typed inputs', () => { const coder = new ArrayCoder( new EnumCoder('TestEnum', { - a: new NumberCoder('u8', options), - b: new BooleanCoder(options), + a: new NumberCoder('u8'), + b: new BooleanCoder(), }), 4 ); @@ -73,8 +68,8 @@ describe('ArrayCoder', () => { it('should decode an enum array with differently typed inputs', () => { const coder = new ArrayCoder( new EnumCoder('TestEnum', { - a: new NumberCoder('u8', options), - b: new BooleanCoder(options), + a: new NumberCoder('u8'), + b: new BooleanCoder(), }), 4 ); @@ -93,7 +88,7 @@ describe('ArrayCoder', () => { }); it('should throw when value to encode is not array', async () => { - const coder = new ArrayCoder(new NumberCoder('u8', options), 1); + const coder = new ArrayCoder(new NumberCoder('u8'), 1); const nonArrayInput = { ...[1] }; await expectToThrowFuelError( () => coder.encode(nonArrayInput), @@ -102,7 +97,7 @@ describe('ArrayCoder', () => { }); it('should throw when coder length is not match inputted array length', async () => { - const coder = new ArrayCoder(new NumberCoder('u8', options), 1); + const coder = new ArrayCoder(new NumberCoder('u8'), 1); await expectToThrowFuelError( () => coder.encode([1, 2]), new FuelError(ErrorCode.ENCODE_ERROR, 'Types/values length mismatch.') diff --git a/packages/abi-coder/src/encoding/coders/v0/ArrayCoder.ts b/packages/abi-coder/src/encoding/coders/ArrayCoder.ts similarity index 82% rename from packages/abi-coder/src/encoding/coders/v0/ArrayCoder.ts rename to packages/abi-coder/src/encoding/coders/ArrayCoder.ts index fe73ac678f..4927701f92 100644 --- a/packages/abi-coder/src/encoding/coders/v0/ArrayCoder.ts +++ b/packages/abi-coder/src/encoding/coders/ArrayCoder.ts @@ -1,9 +1,10 @@ import { ErrorCode, FuelError } from '@fuel-ts/errors'; +import { concat } from '@fuel-ts/utils'; -import { MAX_BYTES } from '../../../utils/constants'; -import { concatWithDynamicData } from '../../../utils/utilities'; -import type { TypesOfCoder } from '../AbstractCoder'; -import { Coder } from '../AbstractCoder'; +import { MAX_BYTES } from '../../utils/constants'; + +import type { TypesOfCoder } from './AbstractCoder'; +import { Coder } from './AbstractCoder'; type InputValueOf = Array['Input']>; type DecodedValueOf = Array['Decoded']>; @@ -30,7 +31,7 @@ export class ArrayCoder extends Coder< throw new FuelError(ErrorCode.ENCODE_ERROR, `Types/values length mismatch.`); } - return concatWithDynamicData(Array.from(value).map((v) => this.coder.encode(v))); + return concat(Array.from(value).map((v) => this.coder.encode(v))); } decode(data: Uint8Array, offset: number): [DecodedValueOf, number] { diff --git a/packages/abi-coder/src/encoding/coders/v0/B256Coder.test.ts b/packages/abi-coder/src/encoding/coders/B256Coder.test.ts similarity index 100% rename from packages/abi-coder/src/encoding/coders/v0/B256Coder.test.ts rename to packages/abi-coder/src/encoding/coders/B256Coder.test.ts diff --git a/packages/abi-coder/src/encoding/coders/v0/B256Coder.ts b/packages/abi-coder/src/encoding/coders/B256Coder.ts similarity index 92% rename from packages/abi-coder/src/encoding/coders/v0/B256Coder.ts rename to packages/abi-coder/src/encoding/coders/B256Coder.ts index b2a6b6c572..46e12f8a27 100644 --- a/packages/abi-coder/src/encoding/coders/v0/B256Coder.ts +++ b/packages/abi-coder/src/encoding/coders/B256Coder.ts @@ -2,8 +2,9 @@ import { ErrorCode, FuelError } from '@fuel-ts/errors'; import { bn, toHex } from '@fuel-ts/math'; import { arrayify } from '@fuel-ts/utils'; -import { WORD_SIZE } from '../../../utils/constants'; -import { Coder } from '../AbstractCoder'; +import { WORD_SIZE } from '../../utils/constants'; + +import { Coder } from './AbstractCoder'; export class B256Coder extends Coder { constructor() { diff --git a/packages/abi-coder/src/encoding/coders/v0/B512Coder.test.ts b/packages/abi-coder/src/encoding/coders/B512Coder.test.ts similarity index 100% rename from packages/abi-coder/src/encoding/coders/v0/B512Coder.test.ts rename to packages/abi-coder/src/encoding/coders/B512Coder.test.ts diff --git a/packages/abi-coder/src/encoding/coders/v0/B512Coder.ts b/packages/abi-coder/src/encoding/coders/B512Coder.ts similarity index 92% rename from packages/abi-coder/src/encoding/coders/v0/B512Coder.ts rename to packages/abi-coder/src/encoding/coders/B512Coder.ts index 8395be2b7f..65c576d250 100644 --- a/packages/abi-coder/src/encoding/coders/v0/B512Coder.ts +++ b/packages/abi-coder/src/encoding/coders/B512Coder.ts @@ -2,8 +2,9 @@ import { ErrorCode, FuelError } from '@fuel-ts/errors'; import { bn, toHex } from '@fuel-ts/math'; import { arrayify } from '@fuel-ts/utils'; -import { WORD_SIZE } from '../../../utils/constants'; -import { Coder } from '../AbstractCoder'; +import { WORD_SIZE } from '../../utils/constants'; + +import { Coder } from './AbstractCoder'; export class B512Coder extends Coder { constructor() { diff --git a/packages/abi-coder/src/encoding/coders/v0/BigNumberCoder.test.ts b/packages/abi-coder/src/encoding/coders/BigNumberCoder.test.ts similarity index 99% rename from packages/abi-coder/src/encoding/coders/v0/BigNumberCoder.test.ts rename to packages/abi-coder/src/encoding/coders/BigNumberCoder.test.ts index 97e517cb5b..2cd1632c75 100644 --- a/packages/abi-coder/src/encoding/coders/v0/BigNumberCoder.test.ts +++ b/packages/abi-coder/src/encoding/coders/BigNumberCoder.test.ts @@ -2,7 +2,7 @@ import { ErrorCode, FuelError } from '@fuel-ts/errors'; import { expectToThrowFuelError } from '@fuel-ts/errors/test-utils'; import { BN, bn } from '@fuel-ts/math'; -import { U16_MAX, U256_MAX, U32_MAX, U64_MAX, U8_MAX } from '../../../../test/utils/constants'; +import { U16_MAX, U256_MAX, U32_MAX, U64_MAX, U8_MAX } from '../../../test/utils/constants'; import { BigNumberCoder } from './BigNumberCoder'; diff --git a/packages/abi-coder/src/encoding/coders/v0/BigNumberCoder.ts b/packages/abi-coder/src/encoding/coders/BigNumberCoder.ts similarity index 92% rename from packages/abi-coder/src/encoding/coders/v0/BigNumberCoder.ts rename to packages/abi-coder/src/encoding/coders/BigNumberCoder.ts index 338ec8b29e..08e8c58eb5 100644 --- a/packages/abi-coder/src/encoding/coders/v0/BigNumberCoder.ts +++ b/packages/abi-coder/src/encoding/coders/BigNumberCoder.ts @@ -1,8 +1,9 @@ import { ErrorCode, FuelError } from '@fuel-ts/errors'; import { type BNInput, type BN, toBytes, bn } from '@fuel-ts/math'; -import { WORD_SIZE } from '../../../utils/constants'; -import { Coder } from '../AbstractCoder'; +import { WORD_SIZE } from '../../utils/constants'; + +import { Coder } from './AbstractCoder'; type BigNumberCoderType = 'u64' | 'u256'; diff --git a/packages/abi-coder/src/encoding/coders/v1/BooleanCoder.test.ts b/packages/abi-coder/src/encoding/coders/BooleanCoder.test.ts similarity index 62% rename from packages/abi-coder/src/encoding/coders/v1/BooleanCoder.test.ts rename to packages/abi-coder/src/encoding/coders/BooleanCoder.test.ts index b33931bbdc..ab4dced2e0 100644 --- a/packages/abi-coder/src/encoding/coders/v1/BooleanCoder.test.ts +++ b/packages/abi-coder/src/encoding/coders/BooleanCoder.test.ts @@ -1,5 +1,8 @@ import { ErrorCode, FuelError } from '@fuel-ts/errors'; import { expectToThrowFuelError } from '@fuel-ts/errors/test-utils'; +import { concat } from '@fuel-ts/utils'; + +import { WORD_SIZE } from '../../utils/constants'; import { BooleanCoder } from './BooleanCoder'; @@ -13,6 +16,7 @@ describe('BooleanCoder', () => { const FALSE_ENCODED = new Uint8Array([0]); const coder = new BooleanCoder(); + const paddedCoder = new BooleanCoder({ padToWordSize: true }); it('encodes a true boolean', () => { const expected = TRUE_ENCODED; @@ -46,6 +50,46 @@ describe('BooleanCoder', () => { expect(actualLength).toBe(expectedLength); }); + it('encodes a true boolean [padded]', () => { + const expected = concat([new Uint8Array(7), TRUE_ENCODED]); + const actual = paddedCoder.encode(TRUE_DECODED); + + expect(actual).toStrictEqual(expected); + }); + + it('encodes a false boolean [padded]', () => { + const expected = concat([new Uint8Array(7), FALSE_ENCODED]); + const actual = paddedCoder.encode(FALSE_DECODED); + + expect(actual).toStrictEqual(expected); + }); + + it('decodes a true boolean [padded]', () => { + const expectedValue = TRUE_DECODED; + const expectedLength = WORD_SIZE; + + const [actualValue, actualLength] = paddedCoder.decode( + concat([new Uint8Array(7), TRUE_ENCODED]), + 0 + ); + + expect(actualValue).toStrictEqual(expectedValue); + expect(actualLength).toBe(expectedLength); + }); + + it('decodes a false boolean [padded]', () => { + const expectedValue = FALSE_DECODED; + const expectedLength = WORD_SIZE; + + const [actualValue, actualLength] = paddedCoder.decode( + concat([new Uint8Array(7), FALSE_ENCODED]), + 0 + ); + + expect(actualValue).toStrictEqual(expectedValue); + expect(actualLength).toBe(expectedLength); + }); + it.each([undefined, null, 0, {}, [], '', 'a', Symbol('asd')])( 'should throw an error when encoding an invalid boolean value', (val) => { diff --git a/packages/abi-coder/src/encoding/coders/v1/BooleanCoder.ts b/packages/abi-coder/src/encoding/coders/BooleanCoder.ts similarity index 69% rename from packages/abi-coder/src/encoding/coders/v1/BooleanCoder.ts rename to packages/abi-coder/src/encoding/coders/BooleanCoder.ts index 350b945b98..6b8bf0348b 100644 --- a/packages/abi-coder/src/encoding/coders/v1/BooleanCoder.ts +++ b/packages/abi-coder/src/encoding/coders/BooleanCoder.ts @@ -1,11 +1,23 @@ import { ErrorCode, FuelError } from '@fuel-ts/errors'; import { bn, toBytes } from '@fuel-ts/math'; -import { Coder } from '../AbstractCoder'; +import type { EncodingOptions } from '../../types/EncodingOptions'; +import { WORD_SIZE } from '../../utils/constants'; + +import { Coder } from './AbstractCoder'; export class BooleanCoder extends Coder { - constructor() { - super('boolean', 'boolean', 1); + options: EncodingOptions; + + constructor( + options: EncodingOptions = { + padToWordSize: false, + } + ) { + const encodedLength = options.padToWordSize ? WORD_SIZE : 1; + super('boolean', 'boolean', encodedLength); + + this.options = options; } encode(value: boolean): Uint8Array { diff --git a/packages/abi-coder/src/encoding/coders/v1/ByteCoder.test.ts b/packages/abi-coder/src/encoding/coders/ByteCoder.test.ts similarity index 100% rename from packages/abi-coder/src/encoding/coders/v1/ByteCoder.test.ts rename to packages/abi-coder/src/encoding/coders/ByteCoder.test.ts diff --git a/packages/abi-coder/src/encoding/coders/v1/ByteCoder.ts b/packages/abi-coder/src/encoding/coders/ByteCoder.ts similarity index 88% rename from packages/abi-coder/src/encoding/coders/v1/ByteCoder.ts rename to packages/abi-coder/src/encoding/coders/ByteCoder.ts index 285ec8dd98..a2504d48d6 100644 --- a/packages/abi-coder/src/encoding/coders/v1/ByteCoder.ts +++ b/packages/abi-coder/src/encoding/coders/ByteCoder.ts @@ -1,9 +1,10 @@ import { ErrorCode, FuelError } from '@fuel-ts/errors'; import { bn } from '@fuel-ts/math'; -import { WORD_SIZE } from '../../../utils/constants'; -import { Coder } from '../AbstractCoder'; -import { BigNumberCoder } from '../v0/BigNumberCoder'; +import { WORD_SIZE } from '../../utils/constants'; + +import { Coder } from './AbstractCoder'; +import { BigNumberCoder } from './BigNumberCoder'; export class ByteCoder extends Coder { static memorySize = 1; diff --git a/packages/abi-coder/src/encoding/coders/v1/EnumCoder.test.ts b/packages/abi-coder/src/encoding/coders/EnumCoder.test.ts similarity index 95% rename from packages/abi-coder/src/encoding/coders/v1/EnumCoder.test.ts rename to packages/abi-coder/src/encoding/coders/EnumCoder.test.ts index fbdabfb1f1..47d154de43 100644 --- a/packages/abi-coder/src/encoding/coders/v1/EnumCoder.test.ts +++ b/packages/abi-coder/src/encoding/coders/EnumCoder.test.ts @@ -2,9 +2,9 @@ import { ErrorCode, FuelError } from '@fuel-ts/errors'; import { expectToThrowFuelError } from '@fuel-ts/errors/test-utils'; import { bn } from '@fuel-ts/math'; -import { U64_MAX } from '../../../../test/utils/constants'; -import { BigNumberCoder } from '../v0/BigNumberCoder'; +import { U64_MAX } from '../../../test/utils/constants'; +import { BigNumberCoder } from './BigNumberCoder'; import { BooleanCoder } from './BooleanCoder'; import { EnumCoder } from './EnumCoder'; diff --git a/packages/abi-coder/src/encoding/coders/v1/EnumCoder.ts b/packages/abi-coder/src/encoding/coders/EnumCoder.ts similarity index 94% rename from packages/abi-coder/src/encoding/coders/v1/EnumCoder.ts rename to packages/abi-coder/src/encoding/coders/EnumCoder.ts index 680bc1e01e..159e19d341 100644 --- a/packages/abi-coder/src/encoding/coders/v1/EnumCoder.ts +++ b/packages/abi-coder/src/encoding/coders/EnumCoder.ts @@ -3,10 +3,11 @@ import { toNumber } from '@fuel-ts/math'; import { concat } from '@fuel-ts/utils'; import type { RequireExactlyOne } from 'type-fest'; -import { WORD_SIZE } from '../../../utils/constants'; -import type { TypesOfCoder } from '../AbstractCoder'; -import { Coder } from '../AbstractCoder'; -import { BigNumberCoder } from '../v0/BigNumberCoder'; +import { WORD_SIZE } from '../../utils/constants'; + +import type { TypesOfCoder } from './AbstractCoder'; +import { Coder } from './AbstractCoder'; +import { BigNumberCoder } from './BigNumberCoder'; export type InputValueOf> = RequireExactlyOne<{ [P in keyof TCoders]: TypesOfCoder['Input']; diff --git a/packages/abi-coder/src/encoding/coders/v1/NumberCoder.test.ts b/packages/abi-coder/src/encoding/coders/NumberCoder.test.ts similarity index 70% rename from packages/abi-coder/src/encoding/coders/v1/NumberCoder.test.ts rename to packages/abi-coder/src/encoding/coders/NumberCoder.test.ts index 90cd807b22..836297e38b 100644 --- a/packages/abi-coder/src/encoding/coders/v1/NumberCoder.test.ts +++ b/packages/abi-coder/src/encoding/coders/NumberCoder.test.ts @@ -1,7 +1,7 @@ import { ErrorCode, FuelError } from '@fuel-ts/errors'; import { expectToThrowFuelError } from '@fuel-ts/errors/test-utils'; -import { U8_MAX, U16_MAX, U32_MAX } from '../../../../test/utils/constants'; +import { U8_MAX, U16_MAX, U32_MAX } from '../../../test/utils/constants'; import { NumberCoder } from './NumberCoder'; @@ -166,4 +166,70 @@ describe('NumberCoder', () => { new FuelError(ErrorCode.TYPE_NOT_SUPPORTED, `Invalid number type: ${invalidNumber}`) ); }); + + it('encodes a u8 number [padded]', () => { + const coder = new NumberCoder('u8', { padToWordSize: true }); + const expected = new Uint8Array([0, 0, 0, 0, 0, 0, 0, U8_MAX]); + const actual = coder.encode(U8_MAX); + + expect(actual).toStrictEqual(expected); + }); + + it('decodes a u8 number [padded]', () => { + const coder = new NumberCoder('u8', { padToWordSize: true }); + const expectedValue = U8_MAX; + const expectedLength = 8; + + const [actualValue, actualLength] = coder.decode( + new Uint8Array([0, 0, 0, 0, 0, 0, 0, U8_MAX]), + 0 + ); + + expect(actualValue).toStrictEqual(expectedValue); + expect(actualLength).toBe(expectedLength); + }); + + it('encodes a u16 number [padded]', () => { + const coder = new NumberCoder('u16', { padToWordSize: true }); + const expected = new Uint8Array([0, 0, 0, 0, 0, 0, U8_MAX, U8_MAX]); + const actual = coder.encode(U16_MAX); + + expect(actual).toStrictEqual(expected); + }); + + it('decodes a u16 number [padded]', () => { + const coder = new NumberCoder('u16', { padToWordSize: true }); + const expectedValue = U16_MAX; + const expectedLength = 8; + + const [actualValue, actualLength] = coder.decode( + new Uint8Array([0, 0, 0, 0, 0, 0, U8_MAX, U8_MAX]), + 0 + ); + + expect(actualValue).toStrictEqual(expectedValue); + expect(actualLength).toBe(expectedLength); + }); + + it('encodes a u32 number [padded]', () => { + const coder = new NumberCoder('u32', { padToWordSize: true }); + const expected = new Uint8Array([0, 0, 0, 0, U8_MAX, U8_MAX, U8_MAX, U8_MAX]); + const actual = coder.encode(U32_MAX); + + expect(actual).toStrictEqual(expected); + }); + + it('decodes a u32 number [padded]', () => { + const coder = new NumberCoder('u32', { padToWordSize: true }); + const expectedValue = U32_MAX; + const expectedLength = 8; + + const [actualValue, actualLength] = coder.decode( + new Uint8Array([0, 0, 0, 0, U8_MAX, U8_MAX, U8_MAX, U8_MAX]), + 0 + ); + + expect(actualValue).toStrictEqual(expectedValue); + expect(actualLength).toBe(expectedLength); + }); }); diff --git a/packages/abi-coder/src/encoding/coders/v1/NumberCoder.ts b/packages/abi-coder/src/encoding/coders/NumberCoder.ts similarity index 66% rename from packages/abi-coder/src/encoding/coders/v1/NumberCoder.ts rename to packages/abi-coder/src/encoding/coders/NumberCoder.ts index 43f2e6c19d..df89020435 100644 --- a/packages/abi-coder/src/encoding/coders/v1/NumberCoder.ts +++ b/packages/abi-coder/src/encoding/coders/NumberCoder.ts @@ -1,7 +1,10 @@ import { ErrorCode, FuelError } from '@fuel-ts/errors'; import { toNumber, toBytes } from '@fuel-ts/math'; -import { Coder } from '../AbstractCoder'; +import type { EncodingOptions } from '../../types/EncodingOptions'; +import { WORD_SIZE } from '../../utils/constants'; + +import { Coder } from './AbstractCoder'; type NumberCoderType = 'u8' | 'u16' | 'u32' | 'u64'; @@ -19,14 +22,19 @@ const getLength = (baseType: NumberCoderType): number => { }; export class NumberCoder extends Coder { - length: number; baseType: NumberCoderType; + options: EncodingOptions; - constructor(baseType: NumberCoderType) { - const length = getLength(baseType); + constructor( + baseType: NumberCoderType, + options: EncodingOptions = { + padToWordSize: false, + } + ) { + const length = options.padToWordSize ? WORD_SIZE : getLength(baseType); super('number', baseType, length); this.baseType = baseType; - this.length = length; + this.options = options; } encode(value: number | string): Uint8Array { @@ -38,11 +46,11 @@ export class NumberCoder extends Coder { throw new FuelError(ErrorCode.ENCODE_ERROR, `Invalid ${this.baseType}.`); } - if (bytes.length > this.length) { + if (bytes.length > this.encodedLength) { throw new FuelError(ErrorCode.ENCODE_ERROR, `Invalid ${this.baseType}, too many bytes.`); } - return toBytes(bytes, this.length); + return toBytes(bytes, this.encodedLength); } decode(data: Uint8Array, offset: number): [number, number] { @@ -50,12 +58,12 @@ export class NumberCoder extends Coder { throw new FuelError(ErrorCode.DECODE_ERROR, `Invalid number data size.`); } - const bytes = data.slice(offset, offset + this.length); + const bytes = data.slice(offset, offset + this.encodedLength); if (bytes.length !== this.encodedLength) { throw new FuelError(ErrorCode.DECODE_ERROR, `Invalid number byte data size.`); } - return [toNumber(bytes), offset + this.length]; + return [toNumber(bytes), offset + this.encodedLength]; } } diff --git a/packages/abi-coder/src/encoding/coders/v1/OptionCoder.ts b/packages/abi-coder/src/encoding/coders/OptionCoder.ts similarity index 95% rename from packages/abi-coder/src/encoding/coders/v1/OptionCoder.ts rename to packages/abi-coder/src/encoding/coders/OptionCoder.ts index 45f16d8035..e706bdd1dc 100644 --- a/packages/abi-coder/src/encoding/coders/v1/OptionCoder.ts +++ b/packages/abi-coder/src/encoding/coders/OptionCoder.ts @@ -1,5 +1,4 @@ -import type { Coder } from '../AbstractCoder'; - +import type { Coder } from './AbstractCoder'; import type { InputValueOf, DecodedValueOf } from './EnumCoder'; import { EnumCoder } from './EnumCoder'; diff --git a/packages/abi-coder/src/encoding/coders/v1/RawSliceCoder.test.ts b/packages/abi-coder/src/encoding/coders/RawSliceCoder.test.ts similarity index 100% rename from packages/abi-coder/src/encoding/coders/v1/RawSliceCoder.test.ts rename to packages/abi-coder/src/encoding/coders/RawSliceCoder.test.ts diff --git a/packages/abi-coder/src/encoding/coders/v1/RawSliceCoder.ts b/packages/abi-coder/src/encoding/coders/RawSliceCoder.ts similarity index 88% rename from packages/abi-coder/src/encoding/coders/v1/RawSliceCoder.ts rename to packages/abi-coder/src/encoding/coders/RawSliceCoder.ts index 58105a51e4..7c7882f820 100644 --- a/packages/abi-coder/src/encoding/coders/v1/RawSliceCoder.ts +++ b/packages/abi-coder/src/encoding/coders/RawSliceCoder.ts @@ -1,11 +1,11 @@ import { ErrorCode, FuelError } from '@fuel-ts/errors'; import { bn } from '@fuel-ts/math'; -import { WORD_SIZE } from '../../../utils/constants'; -import { Coder } from '../AbstractCoder'; -import { ArrayCoder } from '../v0/ArrayCoder'; -import { BigNumberCoder } from '../v0/BigNumberCoder'; +import { WORD_SIZE } from '../../utils/constants'; +import { Coder } from './AbstractCoder'; +import { ArrayCoder } from './ArrayCoder'; +import { BigNumberCoder } from './BigNumberCoder'; import { NumberCoder } from './NumberCoder'; export class RawSliceCoder extends Coder { diff --git a/packages/abi-coder/src/encoding/coders/v1/StdStringCoder.test.ts b/packages/abi-coder/src/encoding/coders/StdStringCoder.test.ts similarity index 100% rename from packages/abi-coder/src/encoding/coders/v1/StdStringCoder.test.ts rename to packages/abi-coder/src/encoding/coders/StdStringCoder.test.ts diff --git a/packages/abi-coder/src/encoding/coders/v1/StdStringCoder.ts b/packages/abi-coder/src/encoding/coders/StdStringCoder.ts similarity index 88% rename from packages/abi-coder/src/encoding/coders/v1/StdStringCoder.ts rename to packages/abi-coder/src/encoding/coders/StdStringCoder.ts index aecbe013ce..f98fc5318b 100644 --- a/packages/abi-coder/src/encoding/coders/v1/StdStringCoder.ts +++ b/packages/abi-coder/src/encoding/coders/StdStringCoder.ts @@ -2,9 +2,10 @@ import { ErrorCode, FuelError } from '@fuel-ts/errors'; import { bn } from '@fuel-ts/math'; import { toUtf8Bytes, toUtf8String } from '@fuel-ts/utils'; -import { WORD_SIZE } from '../../../utils/constants'; -import { Coder } from '../AbstractCoder'; -import { BigNumberCoder } from '../v0/BigNumberCoder'; +import { WORD_SIZE } from '../../utils/constants'; + +import { Coder } from './AbstractCoder'; +import { BigNumberCoder } from './BigNumberCoder'; export class StdStringCoder extends Coder { static memorySize = 1; diff --git a/packages/abi-coder/src/encoding/coders/v1/StrSliceCoder.test.ts b/packages/abi-coder/src/encoding/coders/StrSliceCoder.test.ts similarity index 100% rename from packages/abi-coder/src/encoding/coders/v1/StrSliceCoder.test.ts rename to packages/abi-coder/src/encoding/coders/StrSliceCoder.test.ts diff --git a/packages/abi-coder/src/encoding/coders/v1/StrSliceCoder.ts b/packages/abi-coder/src/encoding/coders/StrSliceCoder.ts similarity index 88% rename from packages/abi-coder/src/encoding/coders/v1/StrSliceCoder.ts rename to packages/abi-coder/src/encoding/coders/StrSliceCoder.ts index ba84b30f88..cbc00de9b1 100644 --- a/packages/abi-coder/src/encoding/coders/v1/StrSliceCoder.ts +++ b/packages/abi-coder/src/encoding/coders/StrSliceCoder.ts @@ -2,9 +2,10 @@ import { ErrorCode, FuelError } from '@fuel-ts/errors'; import { bn } from '@fuel-ts/math'; import { toUtf8Bytes, toUtf8String } from '@fuel-ts/utils'; -import { WORD_SIZE } from '../../../utils/constants'; -import { Coder } from '../AbstractCoder'; -import { BigNumberCoder } from '../v0/BigNumberCoder'; +import { WORD_SIZE } from '../../utils/constants'; + +import { Coder } from './AbstractCoder'; +import { BigNumberCoder } from './BigNumberCoder'; export class StrSliceCoder extends Coder { static memorySize = 1; diff --git a/packages/abi-coder/src/encoding/coders/v1/StringCoder.test.ts b/packages/abi-coder/src/encoding/coders/StringCoder.test.ts similarity index 100% rename from packages/abi-coder/src/encoding/coders/v1/StringCoder.test.ts rename to packages/abi-coder/src/encoding/coders/StringCoder.test.ts diff --git a/packages/abi-coder/src/encoding/coders/v1/StringCoder.ts b/packages/abi-coder/src/encoding/coders/StringCoder.ts similarity index 95% rename from packages/abi-coder/src/encoding/coders/v1/StringCoder.ts rename to packages/abi-coder/src/encoding/coders/StringCoder.ts index 67516ae384..eca5956ae3 100644 --- a/packages/abi-coder/src/encoding/coders/v1/StringCoder.ts +++ b/packages/abi-coder/src/encoding/coders/StringCoder.ts @@ -1,7 +1,7 @@ import { ErrorCode, FuelError } from '@fuel-ts/errors'; import { toUtf8Bytes, toUtf8String } from '@fuel-ts/utils'; -import { Coder } from '../AbstractCoder'; +import { Coder } from './AbstractCoder'; export class StringCoder extends Coder { constructor(length: TLength) { diff --git a/packages/abi-coder/src/encoding/coders/v1/StructCoder.test.ts b/packages/abi-coder/src/encoding/coders/StructCoder.test.ts similarity index 93% rename from packages/abi-coder/src/encoding/coders/v1/StructCoder.test.ts rename to packages/abi-coder/src/encoding/coders/StructCoder.test.ts index e1b7f44652..f962272534 100644 --- a/packages/abi-coder/src/encoding/coders/v1/StructCoder.test.ts +++ b/packages/abi-coder/src/encoding/coders/StructCoder.test.ts @@ -2,9 +2,9 @@ import { FuelError, ErrorCode } from '@fuel-ts/errors'; import { expectToThrowFuelError } from '@fuel-ts/errors/test-utils'; import { bn } from '@fuel-ts/math'; -import { U32_MAX } from '../../../../test/utils/constants'; -import { BigNumberCoder } from '../v0/BigNumberCoder'; +import { U32_MAX } from '../../../test/utils/constants'; +import { BigNumberCoder } from './BigNumberCoder'; import { BooleanCoder } from './BooleanCoder'; import { StructCoder } from './StructCoder'; diff --git a/packages/abi-coder/src/encoding/coders/v1/StructCoder.ts b/packages/abi-coder/src/encoding/coders/StructCoder.ts similarity index 95% rename from packages/abi-coder/src/encoding/coders/v1/StructCoder.ts rename to packages/abi-coder/src/encoding/coders/StructCoder.ts index 55f96895b2..54bea7fa21 100644 --- a/packages/abi-coder/src/encoding/coders/v1/StructCoder.ts +++ b/packages/abi-coder/src/encoding/coders/StructCoder.ts @@ -1,9 +1,8 @@ import { ErrorCode, FuelError } from '@fuel-ts/errors'; import { concatBytes } from '@fuel-ts/utils'; -import type { TypesOfCoder } from '../AbstractCoder'; -import { Coder } from '../AbstractCoder'; - +import type { TypesOfCoder } from './AbstractCoder'; +import { Coder } from './AbstractCoder'; import { OptionCoder } from './OptionCoder'; type InputValueOf> = { diff --git a/packages/abi-coder/src/encoding/coders/v1/TupleCoder.test.ts b/packages/abi-coder/src/encoding/coders/TupleCoder.test.ts similarity index 94% rename from packages/abi-coder/src/encoding/coders/v1/TupleCoder.test.ts rename to packages/abi-coder/src/encoding/coders/TupleCoder.test.ts index 8afcbc90e9..ffe1828d9c 100644 --- a/packages/abi-coder/src/encoding/coders/v1/TupleCoder.test.ts +++ b/packages/abi-coder/src/encoding/coders/TupleCoder.test.ts @@ -2,9 +2,9 @@ import { ErrorCode, FuelError } from '@fuel-ts/errors'; import { expectToThrowFuelError } from '@fuel-ts/errors/test-utils'; import { bn } from '@fuel-ts/math'; -import { U64_MAX } from '../../../../test/utils/constants'; -import { BigNumberCoder } from '../v0/BigNumberCoder'; +import { U64_MAX } from '../../../test/utils/constants'; +import { BigNumberCoder } from './BigNumberCoder'; import { BooleanCoder } from './BooleanCoder'; import { TupleCoder } from './TupleCoder'; diff --git a/packages/abi-coder/src/encoding/coders/v1/TupleCoder.ts b/packages/abi-coder/src/encoding/coders/TupleCoder.ts similarity index 93% rename from packages/abi-coder/src/encoding/coders/v1/TupleCoder.ts rename to packages/abi-coder/src/encoding/coders/TupleCoder.ts index 1b787505a7..39186a0f94 100644 --- a/packages/abi-coder/src/encoding/coders/v1/TupleCoder.ts +++ b/packages/abi-coder/src/encoding/coders/TupleCoder.ts @@ -1,8 +1,8 @@ import { ErrorCode, FuelError } from '@fuel-ts/errors'; import { concatBytes } from '@fuel-ts/utils'; -import type { TypesOfCoder } from '../AbstractCoder'; -import { Coder } from '../AbstractCoder'; +import type { TypesOfCoder } from './AbstractCoder'; +import { Coder } from './AbstractCoder'; type InputValueOf = { [P in keyof TCoders]: TypesOfCoder['Input']; diff --git a/packages/abi-coder/src/encoding/coders/v1/VecCoder.test.ts b/packages/abi-coder/src/encoding/coders/VecCoder.test.ts similarity index 97% rename from packages/abi-coder/src/encoding/coders/v1/VecCoder.test.ts rename to packages/abi-coder/src/encoding/coders/VecCoder.test.ts index 15a331549a..3adb4a7b0c 100644 --- a/packages/abi-coder/src/encoding/coders/v1/VecCoder.test.ts +++ b/packages/abi-coder/src/encoding/coders/VecCoder.test.ts @@ -2,7 +2,7 @@ import { ErrorCode, FuelError } from '@fuel-ts/errors'; import { expectToThrowFuelError } from '@fuel-ts/errors/test-utils'; import { arrayify } from '@fuel-ts/utils'; -import { U32_MAX } from '../../../../test/utils/constants'; +import { U32_MAX } from '../../../test/utils/constants'; import { BooleanCoder } from './BooleanCoder'; import { NumberCoder } from './NumberCoder'; diff --git a/packages/abi-coder/src/encoding/coders/v1/VecCoder.ts b/packages/abi-coder/src/encoding/coders/VecCoder.ts similarity index 89% rename from packages/abi-coder/src/encoding/coders/v1/VecCoder.ts rename to packages/abi-coder/src/encoding/coders/VecCoder.ts index 9582318377..f09cc313c8 100644 --- a/packages/abi-coder/src/encoding/coders/v1/VecCoder.ts +++ b/packages/abi-coder/src/encoding/coders/VecCoder.ts @@ -2,12 +2,12 @@ import { ErrorCode, FuelError } from '@fuel-ts/errors'; import { bn } from '@fuel-ts/math'; import { concatBytes } from '@fuel-ts/utils'; -import { MAX_BYTES, WORD_SIZE } from '../../../utils/constants'; -import { isUint8Array } from '../../../utils/utilities'; -import type { TypesOfCoder } from '../AbstractCoder'; -import { Coder } from '../AbstractCoder'; -import { BigNumberCoder } from '../v0/BigNumberCoder'; +import { MAX_BYTES, WORD_SIZE } from '../../utils/constants'; +import { isUint8Array } from '../../utils/utilities'; +import { Coder } from './AbstractCoder'; +import type { TypesOfCoder } from './AbstractCoder'; +import { BigNumberCoder } from './BigNumberCoder'; import { OptionCoder } from './OptionCoder'; type InputValueOf = Array['Input']> | Uint8Array; diff --git a/packages/abi-coder/src/encoding/coders/index.ts b/packages/abi-coder/src/encoding/coders/index.ts new file mode 100644 index 0000000000..b7a96853de --- /dev/null +++ b/packages/abi-coder/src/encoding/coders/index.ts @@ -0,0 +1,16 @@ +export { ArrayCoder } from './ArrayCoder'; +export { B256Coder } from './B256Coder'; +export { B512Coder } from './B512Coder'; +export { BigNumberCoder } from './BigNumberCoder'; +export { BooleanCoder } from './BooleanCoder'; +export { ByteCoder } from './ByteCoder'; +export { EnumCoder } from './EnumCoder'; +export { NumberCoder } from './NumberCoder'; +export { OptionCoder } from './OptionCoder'; +export { RawSliceCoder } from './RawSliceCoder'; +export { StdStringCoder } from './StdStringCoder'; +export { StrSliceCoder } from './StrSliceCoder'; +export { StringCoder } from './StringCoder'; +export { StructCoder } from './StructCoder'; +export { TupleCoder } from './TupleCoder'; +export { VecCoder } from './VecCoder'; diff --git a/packages/abi-coder/src/encoding/coders/v0/BooleanCoder.test.ts b/packages/abi-coder/src/encoding/coders/v0/BooleanCoder.test.ts deleted file mode 100644 index d8bea77fd4..0000000000 --- a/packages/abi-coder/src/encoding/coders/v0/BooleanCoder.test.ts +++ /dev/null @@ -1,74 +0,0 @@ -import { ErrorCode, FuelError } from '@fuel-ts/errors'; -import { expectToThrowFuelError } from '@fuel-ts/errors/test-utils'; - -import { BooleanCoder } from './BooleanCoder'; - -/** - * @group node - */ -describe('BooleanCoder', () => { - const TRUE_DECODED = true; - const TRUE_ENCODED = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 1]); - const FALSE_DECODED = false; - const FALSE_ENCODED = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0]); - - const coder = new BooleanCoder(); - - it('should encode a true boolean', () => { - const expected = TRUE_ENCODED; - const actual = coder.encode(TRUE_DECODED); - - expect(actual).toStrictEqual(expected); - }); - - it('should encode a false boolean', () => { - const expected = FALSE_ENCODED; - const actual = coder.encode(FALSE_DECODED); - - expect(actual).toStrictEqual(expected); - }); - - it('should decode a true boolean', () => { - const expectedValue = TRUE_DECODED; - const expectedLength = TRUE_ENCODED.length; - const [actualValue, actualLength] = coder.decode(TRUE_ENCODED, 0); - - expect(actualValue).toStrictEqual(expectedValue); - expect(actualLength).toBe(expectedLength); - }); - - it('should decode a false boolean', () => { - const expectedValue = FALSE_DECODED; - const expectedLength = FALSE_ENCODED.length; - const [actualValue, actualLength] = coder.decode(FALSE_ENCODED, 0); - - expect(actualValue).toStrictEqual(expectedValue); - expect(actualLength).toBe(expectedLength); - }); - - it.each([undefined, null, 0, {}, [], '', 'a', Symbol('asd')])( - 'should throw an error when encoding an invalid boolean value', - (val) => { - expect(() => { - // @ts-expect-error val isn't boolean due to nature of test - coder.encode(val); - }).toThrow('Invalid bool'); - } - ); - it('should throw an error when decoding an invalid boolean value', async () => { - const invalidInput = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 2]); - await expectToThrowFuelError( - () => coder.decode(invalidInput, 0), - new FuelError(ErrorCode.DECODE_ERROR, 'Invalid boolean value.') - ); - }); - - it('throws when decoding empty bytes', async () => { - const input = new Uint8Array(0); - - await expectToThrowFuelError( - () => coder.decode(input, 0), - new FuelError(ErrorCode.DECODE_ERROR, 'Invalid boolean data size.') - ); - }); -}); diff --git a/packages/abi-coder/src/encoding/coders/v0/BooleanCoder.ts b/packages/abi-coder/src/encoding/coders/v0/BooleanCoder.ts deleted file mode 100644 index 07a69f5557..0000000000 --- a/packages/abi-coder/src/encoding/coders/v0/BooleanCoder.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { ErrorCode, FuelError } from '@fuel-ts/errors'; -import { bn, toBytes } from '@fuel-ts/math'; - -import type { EncodingOptions } from '../../../types/EncodingOptions'; -import { Coder } from '../AbstractCoder'; - -export class BooleanCoder extends Coder { - paddingLength: number; - options: EncodingOptions; - - constructor( - options: EncodingOptions = { - isSmallBytes: false, - isRightPadded: false, - } - ) { - const paddingLength = options.isSmallBytes ? 1 : 8; - - super('boolean', 'boolean', paddingLength); - - this.paddingLength = paddingLength; - this.options = options; - } - - encode(value: boolean): Uint8Array { - const isTrueBool = value === true || value === false; - - if (!isTrueBool) { - throw new FuelError(ErrorCode.ENCODE_ERROR, `Invalid boolean value.`); - } - - const output: Uint8Array = toBytes(value ? 1 : 0, this.paddingLength); - - if (this.options.isRightPadded) { - return output.reverse(); - } - - return output; - } - - decode(data: Uint8Array, offset: number): [boolean, number] { - if (data.length < this.paddingLength) { - throw new FuelError(ErrorCode.DECODE_ERROR, `Invalid boolean data size.`); - } - - let bytes; - - if (this.options.isRightPadded) { - bytes = data.slice(offset, offset + 1); - } else { - bytes = data.slice(offset, offset + this.paddingLength); - } - - const decodedValue = bn(bytes); - if (decodedValue.isZero()) { - return [false, offset + this.paddingLength]; - } - - if (!decodedValue.eq(bn(1))) { - throw new FuelError(ErrorCode.DECODE_ERROR, `Invalid boolean value.`); - } - - return [true, offset + this.paddingLength]; - } -} diff --git a/packages/abi-coder/src/encoding/coders/v0/ByteCoder.test.ts b/packages/abi-coder/src/encoding/coders/v0/ByteCoder.test.ts deleted file mode 100644 index d54e552c6b..0000000000 --- a/packages/abi-coder/src/encoding/coders/v0/ByteCoder.test.ts +++ /dev/null @@ -1,104 +0,0 @@ -import { FuelError, ErrorCode } from '@fuel-ts/errors'; -import { expectToThrowFuelError } from '@fuel-ts/errors/test-utils'; - -import type { Uint8ArrayWithDynamicData } from '../../../utils/utilities'; - -import { ByteCoder } from './ByteCoder'; - -/** - * @group node - * @group browser - */ -describe('ByteCoder', () => { - it('should encode a byte', () => { - const coder = new ByteCoder(); - const expected: Uint8ArrayWithDynamicData = new Uint8Array([ - 0, 0, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 3, - ]); - expected.dynamicData = { - 0: new Uint8Array([1, 2, 3, 0, 0, 0, 0, 0]), - }; - - const actual = coder.encode([1, 2, 3]); - - expect(actual).toStrictEqual(expected); - }); - - it('should encode a byte [byte array]', () => { - const coder = new ByteCoder(); - const expected: Uint8ArrayWithDynamicData = new Uint8Array([ - 0, 0, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 3, - ]); - expected.dynamicData = { - 0: new Uint8Array([1, 2, 3, 0, 0, 0, 0, 0]), - }; - - const actual = coder.encode(Uint8Array.from([1, 2, 3])); - - expect(actual).toStrictEqual(expected); - }); - - it('should encode a byte [full word]', () => { - const coder = new ByteCoder(); - const expected: Uint8ArrayWithDynamicData = new Uint8Array([ - 0, 0, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 8, - ]); - expected.dynamicData = { - 0: new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]), - }; - - const actual = coder.encode([1, 2, 3, 4, 5, 6, 7, 8]); - - expect(actual).toStrictEqual(expected); - }); - - it('should decode a byte', () => { - const coder = new ByteCoder(); - const input = new Uint8Array([ - 0, 0, 0, 0, 3, 255, 255, 225, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 10, 0, 1, 2, 3, 4, - 5, 6, 7, 8, 9, - ]); - const expected = new Uint8Array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); - - const [actual, newOffset] = coder.decode(input, 0); - - expect(actual).toEqual(expected); - expect(newOffset).toEqual(24); - }); - - it('should decode a byte [with padding]', () => { - const coder = new ByteCoder(); - const input = new Uint8Array([ - 0, 0, 0, 0, 3, 255, 255, 225, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 11, 0, 1, 2, 3, 4, - 5, 6, 7, 8, 9, 10, 0, 0, 0, 0, 0, - ]); - const expected = new Uint8Array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); - - const [actual, newOffset] = coder.decode(input, 0); - - expect(actual).toEqual(expected); - expect(newOffset).toEqual(24); - }); - - it('throws when decoding empty bytes', async () => { - const coder = new ByteCoder(); - const input = new Uint8Array(0); - - await expectToThrowFuelError( - () => coder.decode(input, 0), - new FuelError(ErrorCode.DECODE_ERROR, 'Invalid byte data size.') - ); - }); - - it('throws when decoding empty byte data', async () => { - const coder = new ByteCoder(); - const input = new Uint8Array([ - 0, 0, 0, 0, 3, 255, 255, 225, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 255, - ]); - - await expectToThrowFuelError( - () => coder.decode(input, 0), - new FuelError(ErrorCode.DECODE_ERROR, 'Invalid bytes byte data size.') - ); - }); -}); diff --git a/packages/abi-coder/src/encoding/coders/v0/ByteCoder.ts b/packages/abi-coder/src/encoding/coders/v0/ByteCoder.ts deleted file mode 100644 index 444d3877a3..0000000000 --- a/packages/abi-coder/src/encoding/coders/v0/ByteCoder.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { ErrorCode, FuelError } from '@fuel-ts/errors'; -import { bn } from '@fuel-ts/math'; -import { concat } from '@fuel-ts/utils'; - -import { WORD_SIZE } from '../../../utils/constants'; -import type { Uint8ArrayWithDynamicData } from '../../../utils/utilities'; -import { BASE_VECTOR_OFFSET, concatWithDynamicData } from '../../../utils/utilities'; -import { Coder } from '../AbstractCoder'; - -import { BigNumberCoder } from './BigNumberCoder'; - -export class ByteCoder extends Coder { - static memorySize = 1; - constructor() { - super('struct', 'struct Bytes', BASE_VECTOR_OFFSET); - } - - encode(value: number[] | Uint8Array): Uint8Array { - const parts: Uint8Array[] = []; - - // pointer (ptr) - const pointer: Uint8ArrayWithDynamicData = new BigNumberCoder('u64').encode(BASE_VECTOR_OFFSET); - - // pointer dynamicData, encode the byte vector now and attach to its pointer - const data = this.#getPaddedData(value); - pointer.dynamicData = { - 0: concatWithDynamicData([data]), - }; - - parts.push(pointer); - - // capacity (cap) - parts.push(new BigNumberCoder('u64').encode(data.byteLength)); - - // length (len) - parts.push(new BigNumberCoder('u64').encode(value.length)); - - return concatWithDynamicData(parts); - } - - #getPaddedData(value: number[] | Uint8Array): Uint8Array { - const data = value instanceof Uint8Array ? [value] : [new Uint8Array(value)]; - - const paddingLength = (WORD_SIZE - (value.length % WORD_SIZE)) % WORD_SIZE; - if (paddingLength) { - data.push(new Uint8Array(paddingLength)); - } - - return concat(data); - } - - decode(data: Uint8Array, offset: number): [Uint8Array, number] { - if (data.length < BASE_VECTOR_OFFSET) { - throw new FuelError(ErrorCode.DECODE_ERROR, `Invalid byte data size.`); - } - - const len = data.slice(16, 24); - const encodedLength = bn(new BigNumberCoder('u64').decode(len, 0)[0]).toNumber(); - const byteData = data.slice(BASE_VECTOR_OFFSET, BASE_VECTOR_OFFSET + encodedLength); - - if (byteData.length !== encodedLength) { - throw new FuelError(ErrorCode.DECODE_ERROR, `Invalid bytes byte data size.`); - } - - return [byteData, offset + BASE_VECTOR_OFFSET]; - } -} diff --git a/packages/abi-coder/src/encoding/coders/v0/EnumCoder.test.ts b/packages/abi-coder/src/encoding/coders/v0/EnumCoder.test.ts deleted file mode 100644 index 9e26b7d48b..0000000000 --- a/packages/abi-coder/src/encoding/coders/v0/EnumCoder.test.ts +++ /dev/null @@ -1,120 +0,0 @@ -/* eslint-disable @typescript-eslint/ban-ts-comment */ -import { ErrorCode, FuelError } from '@fuel-ts/errors'; -import { expectToThrowFuelError } from '@fuel-ts/errors/test-utils'; -import { bn } from '@fuel-ts/math'; - -import { U64_MAX } from '../../../../test/utils/constants'; - -import { BigNumberCoder } from './BigNumberCoder'; -import { BooleanCoder } from './BooleanCoder'; -import { EnumCoder } from './EnumCoder'; - -/** - * @group node - * @group browser - */ -describe('EnumCoder', () => { - const coder = new EnumCoder('TestEnum', { a: new BooleanCoder(), b: new BigNumberCoder('u64') }); - - it('should encode an enum containing a boolean', () => { - const expected = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]); - const actual = coder.encode({ a: true }); - - expect(actual).toStrictEqual(expected); - }); - - it('should decode an enum containing a boolean', () => { - const expectedValue = { a: true }; - const expectedLength = 16; - const [actualValue, actualLength] = coder.decode( - new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]), - 0 - ); - - expect(actualValue).toStrictEqual(expectedValue); - expect(actualLength).toBe(expectedLength); - }); - - it('should encode an enum containing a u64', () => { - const expected = new Uint8Array([ - 0, 0, 0, 0, 0, 0, 0, 1, 255, 255, 255, 255, 255, 255, 255, 255, - ]); - const actual = coder.encode({ b: bn(U64_MAX) }); - - expect(actual).toStrictEqual(expected); - }); - - it('should decode an enum containing a u64', () => { - const expectedValue = { b: bn(U64_MAX) }; - const expectedLength = 16; - const [actualValue, actualLength] = coder.decode( - new Uint8Array([0, 0, 0, 0, 0, 0, 0, 1, 255, 255, 255, 255, 255, 255, 255, 255]), - 0 - ); - - expect(actualValue).toStrictEqual(expectedValue); - expect(actualLength).toBe(expectedLength); - }); - - it('should throw an error when encoding if no enum key is provided', async () => { - await expectToThrowFuelError( - () => coder.encode({} as never), - new FuelError(ErrorCode.DECODE_ERROR, 'A field for the case must be provided.') - ); - }); - - it('should throw an error when decoded value accesses an invalid index', async () => { - const input = new Uint8Array(Array.from(Array(8).keys())); - - await expectToThrowFuelError( - () => coder.decode(input, 0), - new FuelError( - ErrorCode.DECODE_ERROR, - 'Invalid caseIndex "283686952306183". Valid cases: a,b.' - ) - ); - }); - - it('should not throw given correctly typed inputs', () => { - expect(() => coder.encode({ a: true })).not.toThrow(); - expect(() => coder.encode({ b: bn(1234) })).not.toThrow(); - }); - - it('should throw when provided with extra inputs', async () => { - await expectToThrowFuelError( - () => - coder.encode( - // @ts-expect-error - { a: true, b: bn(1234), c: false } - ), - new FuelError(ErrorCode.ENCODE_ERROR, 'Only one field must be provided.') - ); - }); - - it('should throw type error with invalid input for coder', async () => { - await expectToThrowFuelError( - () => - coder.encode( - // @ts-expect-error - { b: true } - ), - new FuelError(ErrorCode.ENCODE_ERROR, 'Invalid u64.') - ); - }); - - it('should throw type error with invalid input key', () => { - expect(() => - coder.encode( - // @ts-expect-error - { nope: 42 } - ) - ).toThrow(); - }); - - it('throws when decoding empty bytes', async () => { - await expectToThrowFuelError( - () => coder.decode(new Uint8Array(), 0), - new FuelError(ErrorCode.DECODE_ERROR, 'Invalid enum data size.') - ); - }); -}); diff --git a/packages/abi-coder/src/encoding/coders/v0/EnumCoder.ts b/packages/abi-coder/src/encoding/coders/v0/EnumCoder.ts deleted file mode 100644 index 17afb3cb59..0000000000 --- a/packages/abi-coder/src/encoding/coders/v0/EnumCoder.ts +++ /dev/null @@ -1,109 +0,0 @@ -import { ErrorCode, FuelError } from '@fuel-ts/errors'; -import { toNumber } from '@fuel-ts/math'; -import { concat } from '@fuel-ts/utils'; -import type { RequireExactlyOne } from 'type-fest'; - -import { concatWithDynamicData } from '../../../utils/utilities'; -import type { TypesOfCoder } from '../AbstractCoder'; -import { Coder } from '../AbstractCoder'; - -import { BigNumberCoder } from './BigNumberCoder'; - -export type InputValueOf> = RequireExactlyOne<{ - [P in keyof TCoders]: TypesOfCoder['Input']; -}>; -export type DecodedValueOf> = RequireExactlyOne<{ - [P in keyof TCoders]: TypesOfCoder['Decoded']; -}>; - -const isFullyNativeEnum = (enumCoders: { [s: string]: unknown } | ArrayLike): boolean => - Object.values(enumCoders).every( - // @ts-expect-error complicated types - ({ type, coders }) => type === '()' && JSON.stringify(coders) === JSON.stringify([]) - ); - -export class EnumCoder> extends Coder< - InputValueOf, - DecodedValueOf -> { - name: string; - coders: TCoders; - #caseIndexCoder: BigNumberCoder; - #encodedValueSize: number; - - constructor(name: string, coders: TCoders) { - const caseIndexCoder = new BigNumberCoder('u64'); - const encodedValueSize = Object.values(coders).reduce( - (max, coder) => Math.max(max, coder.encodedLength), - 0 - ); - super(`enum ${name}`, `enum ${name}`, caseIndexCoder.encodedLength + encodedValueSize); - this.name = name; - this.coders = coders; - this.#caseIndexCoder = caseIndexCoder; - this.#encodedValueSize = encodedValueSize; - } - - #encodeNativeEnum(value: string): Uint8Array { - const valueCoder = this.coders[value]; - const encodedValue = valueCoder.encode([]); - const caseIndex = Object.keys(this.coders).indexOf(value); - - const padding = new Uint8Array(this.#encodedValueSize - valueCoder.encodedLength); - return concat([this.#caseIndexCoder.encode(caseIndex), padding, encodedValue]); - } - - encode(value: InputValueOf): Uint8Array { - if (typeof value === 'string' && this.coders[value]) { - return this.#encodeNativeEnum(value); - } - - const [caseKey, ...empty] = Object.keys(value); - if (!caseKey) { - throw new FuelError(ErrorCode.INVALID_DECODE_VALUE, 'A field for the case must be provided.'); - } - if (empty.length !== 0) { - throw new FuelError(ErrorCode.INVALID_DECODE_VALUE, 'Only one field must be provided.'); - } - const valueCoder = this.coders[caseKey]; - const caseIndex = Object.keys(this.coders).indexOf(caseKey); - const encodedValue = valueCoder.encode(value[caseKey]); - - const padding = new Uint8Array(this.#encodedValueSize - valueCoder.encodedLength); - return concatWithDynamicData([this.#caseIndexCoder.encode(caseIndex), padding, encodedValue]); - } - - #decodeNativeEnum(caseKey: string, newOffset: number): [DecodedValueOf, number] { - return [caseKey as unknown as DecodedValueOf, newOffset]; - } - - decode(data: Uint8Array, offset: number): [DecodedValueOf, number] { - if (data.length < this.#encodedValueSize) { - throw new FuelError(ErrorCode.DECODE_ERROR, `Invalid enum data size.`); - } - - let newOffset = offset; - - let decoded; - [decoded, newOffset] = new BigNumberCoder('u64').decode(data, newOffset); - const caseIndex = toNumber(decoded); - const caseKey = Object.keys(this.coders)[caseIndex]; - if (!caseKey) { - throw new FuelError( - ErrorCode.INVALID_DECODE_VALUE, - `Invalid caseIndex "${caseIndex}". Valid cases: ${Object.keys(this.coders)}.` - ); - } - - const valueCoder = this.coders[caseKey]; - const padding = this.#encodedValueSize - valueCoder.encodedLength; - newOffset += padding; - [decoded, newOffset] = valueCoder.decode(data, newOffset); - - if (isFullyNativeEnum(this.coders)) { - return this.#decodeNativeEnum(caseKey, newOffset); - } - - return [{ [caseKey]: decoded } as DecodedValueOf, newOffset]; - } -} diff --git a/packages/abi-coder/src/encoding/coders/v0/NumberCoder.test.ts b/packages/abi-coder/src/encoding/coders/v0/NumberCoder.test.ts deleted file mode 100644 index 1d53ad877b..0000000000 --- a/packages/abi-coder/src/encoding/coders/v0/NumberCoder.test.ts +++ /dev/null @@ -1,166 +0,0 @@ -import { ErrorCode, FuelError } from '@fuel-ts/errors'; -import { expectToThrowFuelError } from '@fuel-ts/errors/test-utils'; - -import { U8_MAX, U16_MAX, U32_MAX } from '../../../../test/utils/constants'; - -import { NumberCoder } from './NumberCoder'; - -/** - * @group node - * @group browser - */ -describe('NumberCoder', () => { - it('should encode min u8 number as a u8 coder', () => { - const coder = new NumberCoder('u8'); - const expected = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0]); - const actual = coder.encode(0); - - expect(actual).toStrictEqual(expected); - }); - - it('should decode a min u8 number as a u8 coder', () => { - const coder = new NumberCoder('u8'); - const expectedValue = 0; - const expectedLength = 8; - const [actualValue, actualLength] = coder.decode(new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0]), 0); - - expect(actualValue).toBe(expectedValue); - expect(actualLength).toBe(expectedLength); - }); - - it('should encode max u8 number as a u8 coder', () => { - const coder = new NumberCoder('u8'); - const expected = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 255]); - const actual = coder.encode(U8_MAX); - - expect(actual).toStrictEqual(expected); - }); - - it('should decode a max u8 number as a u8 coder', () => { - const coder = new NumberCoder('u8'); - const expectedValue = U8_MAX; - const expectedLength = 8; - const [actualValue, actualLength] = coder.decode(new Uint8Array([0, 0, 0, 0, 0, 0, 0, 255]), 0); - - expect(actualValue).toBe(expectedValue); - expect(actualLength).toBe(expectedLength); - }); - - it('should encode min u16 number as a u16 coder', () => { - const coder = new NumberCoder('u16'); - const expected = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0]); - const actual = coder.encode(0); - - expect(actual).toStrictEqual(expected); - }); - - it('should decode a min u16 number as a u16 coder', () => { - const coder = new NumberCoder('u16'); - const expectedValue = 0; - const expectedLength = 8; - const [actualValue, actualLength] = coder.decode(new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0]), 0); - - expect(actualValue).toBe(expectedValue); - expect(actualLength).toBe(expectedLength); - }); - - it('should encode max u16 number as a u16 coder', () => { - const coder = new NumberCoder('u16'); - const expected = new Uint8Array([0, 0, 0, 0, 0, 0, 255, 255]); - const actual = coder.encode(U16_MAX); - - expect(actual).toStrictEqual(expected); - }); - - it('should decode a max u16 number as a u16 coder', () => { - const coder = new NumberCoder('u16'); - const expectedValue = U16_MAX; - const expectedLength = 8; - const [actualValue, actualLength] = coder.decode( - new Uint8Array([0, 0, 0, 0, 0, 0, 255, 255]), - 0 - ); - - expect(actualValue).toBe(expectedValue); - expect(actualLength).toBe(expectedLength); - }); - - it('should encode min u32 number as a u32 coder', () => { - const coder = new NumberCoder('u32'); - const expected = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0]); - const actual = coder.encode(0); - - expect(actual).toStrictEqual(expected); - }); - - it('should decode a min u32 number as a u32 coder', () => { - const coder = new NumberCoder('u32'); - const expectedValue = 0; - const expectedLength = 8; - const [actualValue, actualLength] = coder.decode(new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0]), 0); - - expect(actualValue).toBe(expectedValue); - expect(actualLength).toBe(expectedLength); - }); - - it('should encode max u32 number as a u32 coder', () => { - const coder = new NumberCoder('u32'); - const expected = new Uint8Array([0, 0, 0, 0, 255, 255, 255, 255]); - const actual = coder.encode(U32_MAX); - - expect(actual).toStrictEqual(expected); - }); - - it('should decode a max u32 number as a u32 coder', () => { - const coder = new NumberCoder('u32'); - const expectedValue = U32_MAX; - const expectedLength = 8; - const [actualValue, actualLength] = coder.decode( - new Uint8Array([0, 0, 0, 0, 255, 255, 255, 255]), - 0 - ); - - expect(actualValue).toBe(expectedValue); - expect(actualLength).toBe(expectedLength); - }); - - it('should throw if a negative number is encoded', async () => { - const coder = new NumberCoder('u8'); - const invalidInput = -1; - - await expectToThrowFuelError( - () => coder.encode(invalidInput), - new FuelError(ErrorCode.ENCODE_ERROR, 'Invalid u8.') - ); - }); - - it('should throw if coder is too small for number size', async () => { - const coder = new NumberCoder('u8'); - const invalidInput = U32_MAX; - - await expectToThrowFuelError( - () => coder.encode(invalidInput), - new FuelError(ErrorCode.ENCODE_ERROR, `Invalid u8, too many bytes.`) - ); - }); - - it('throws when decoding empty bytes', async () => { - const coder = new NumberCoder('u32'); - const input = new Uint8Array(0); - - await expectToThrowFuelError( - () => coder.decode(input, 0), - new FuelError(ErrorCode.DECODE_ERROR, 'Invalid number data size.') - ); - }); - - it('throws when decoding empty byte data', async () => { - const coder = new NumberCoder('u32'); - const input = new Uint8Array([0, 1, 2, 3, 4, 5, 6, 7]); - - await expectToThrowFuelError( - () => coder.decode(input, 8), - new FuelError(ErrorCode.DECODE_ERROR, 'Invalid number byte data size.') - ); - }); -}); diff --git a/packages/abi-coder/src/encoding/coders/v0/NumberCoder.ts b/packages/abi-coder/src/encoding/coders/v0/NumberCoder.ts deleted file mode 100644 index 14f30c51e9..0000000000 --- a/packages/abi-coder/src/encoding/coders/v0/NumberCoder.ts +++ /dev/null @@ -1,97 +0,0 @@ -import { ErrorCode, FuelError } from '@fuel-ts/errors'; -import { toNumber, toBytes } from '@fuel-ts/math'; - -import type { EncodingOptions } from '../../../types/EncodingOptions'; -import { Coder } from '../AbstractCoder'; - -type NumberCoderType = 'u8' | 'u16' | 'u32'; - -export class NumberCoder extends Coder { - // This is to align the bits to the total bytes - // See https://github.com/FuelLabs/fuel-specs/blob/master/specs/protocol/abi.md#unsigned-integers - length: number; - paddingLength: number; - baseType: NumberCoderType; - options: EncodingOptions; - - constructor( - baseType: NumberCoderType, - options: EncodingOptions = { - isSmallBytes: false, - isRightPadded: false, - } - ) { - const paddingLength = options.isSmallBytes && baseType === 'u8' ? 1 : 8; - - super('number', baseType, paddingLength); - this.baseType = baseType; - switch (baseType) { - case 'u8': - this.length = 1; - break; - case 'u16': - this.length = 2; - break; - case 'u32': - default: - this.length = 4; - break; - } - - this.paddingLength = paddingLength; - this.options = options; - } - - encode(value: number | string): Uint8Array { - let bytes; - - try { - bytes = toBytes(value); - } catch (error) { - throw new FuelError(ErrorCode.ENCODE_ERROR, `Invalid ${this.baseType}.`); - } - - if (bytes.length > this.length) { - throw new FuelError(ErrorCode.ENCODE_ERROR, `Invalid ${this.baseType}, too many bytes.`); - } - - const output = toBytes(bytes, this.paddingLength); - - if (this.baseType !== 'u8') { - return output; - } - - return this.options.isRightPadded ? output.reverse() : output; - } - - private decodeU8(data: Uint8Array, offset: number): [number, number] { - let bytes; - if (this.options.isRightPadded) { - bytes = data.slice(offset, offset + 1); - } else { - bytes = data.slice(offset, offset + this.paddingLength); - bytes = bytes.slice(this.paddingLength - this.length, this.paddingLength); - } - - return [toNumber(bytes), offset + this.paddingLength]; - } - - decode(data: Uint8Array, offset: number): [number, number] { - if (data.length < this.paddingLength) { - throw new FuelError(ErrorCode.DECODE_ERROR, `Invalid number data size.`); - } - - if (this.baseType === 'u8') { - return this.decodeU8(data, offset); - } - - let bytes = data.slice(offset, offset + this.paddingLength); - bytes = bytes.slice(8 - this.length, 8); - - if (bytes.length !== this.paddingLength - (this.paddingLength - this.length)) { - throw new FuelError(ErrorCode.DECODE_ERROR, `Invalid number byte data size.`); - } - - return [toNumber(bytes), offset + 8]; - } -} diff --git a/packages/abi-coder/src/encoding/coders/v0/OptionCoder.ts b/packages/abi-coder/src/encoding/coders/v0/OptionCoder.ts deleted file mode 100644 index f333d2dea0..0000000000 --- a/packages/abi-coder/src/encoding/coders/v0/OptionCoder.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { ErrorCode, FuelError } from '@fuel-ts/errors'; - -import type { Coder } from '../AbstractCoder'; - -import type { InputValueOf, DecodedValueOf } from './EnumCoder'; -import { EnumCoder } from './EnumCoder'; - -type SwayOption = { None: [] } | { Some: T }; -export type Option = T | undefined; - -export class OptionCoder> extends EnumCoder { - encode(value: InputValueOf): Uint8Array { - const result = super.encode(this.toSwayOption(value) as unknown as InputValueOf); - return result; - } - - toSwayOption(input: InputValueOf): SwayOption { - if (input !== undefined) { - return { Some: input }; - } - - return { None: [] }; - } - - decode(data: Uint8Array, offset: number): [DecodedValueOf, number] { - if (data.length < this.encodedLength) { - throw new FuelError(ErrorCode.DECODE_ERROR, `Invalid option data size.`); - } - - const [decoded, newOffset] = super.decode(data, offset); - return [this.toOption(decoded) as DecodedValueOf, newOffset]; - } - - toOption(output?: DecodedValueOf): Option { - if (output && 'Some' in output) { - return output.Some; - } - - return undefined; - } -} diff --git a/packages/abi-coder/src/encoding/coders/v0/RawSliceCoder.test.ts b/packages/abi-coder/src/encoding/coders/v0/RawSliceCoder.test.ts deleted file mode 100644 index 1631f9da3a..0000000000 --- a/packages/abi-coder/src/encoding/coders/v0/RawSliceCoder.test.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { FuelError, ErrorCode } from '@fuel-ts/errors'; -import { expectToThrowFuelError } from '@fuel-ts/errors/test-utils'; - -import type { Uint8ArrayWithDynamicData } from '../../../utils/utilities'; - -import { RawSliceCoder } from './RawSliceCoder'; - -/** - * @group node - * @group browser - */ -describe('RawSliceCoder', () => { - it('should encode a raw-slice', () => { - const coder = new RawSliceCoder(); - const expected: Uint8ArrayWithDynamicData = new Uint8Array([ - 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 3, - ]); - expected.dynamicData = { - 0: new Uint8Array([1, 2, 3]), - }; - - const actual = coder.encode([1, 2, 3]); - - expect(actual).toStrictEqual(expected); - }); - - it('should throw when value to encode is not array', async () => { - const coder = new RawSliceCoder(); - const nonArrayInput = { ...[1] }; - await expectToThrowFuelError( - () => coder.encode(nonArrayInput), - new FuelError(ErrorCode.ENCODE_ERROR, 'Expected array value.') - ); - }); - - it('should decode a raw-slice', () => { - const coder = new RawSliceCoder(); - const expected = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; - const [actual, newOffset] = coder.decode(new Uint8Array(expected), 0); - - expect(actual).toStrictEqual(expected); - expect(newOffset).toEqual(10); - }); -}); diff --git a/packages/abi-coder/src/encoding/coders/v0/RawSliceCoder.ts b/packages/abi-coder/src/encoding/coders/v0/RawSliceCoder.ts deleted file mode 100644 index b0f5aed0f1..0000000000 --- a/packages/abi-coder/src/encoding/coders/v0/RawSliceCoder.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { ErrorCode, FuelError } from '@fuel-ts/errors'; - -import type { Uint8ArrayWithDynamicData } from '../../../utils/utilities'; -import { BASE_RAW_SLICE_OFFSET, concatWithDynamicData } from '../../../utils/utilities'; -import { Coder } from '../AbstractCoder'; - -import { ArrayCoder } from './ArrayCoder'; -import { BigNumberCoder } from './BigNumberCoder'; -import { NumberCoder } from './NumberCoder'; - -export class RawSliceCoder extends Coder { - constructor() { - super('raw untyped slice', 'raw untyped slice', BASE_RAW_SLICE_OFFSET); - } - - encode(value: number[]): Uint8Array { - if (!Array.isArray(value)) { - throw new FuelError(ErrorCode.ENCODE_ERROR, `Expected array value.`); - } - - const parts: Uint8Array[] = []; - const coder = new NumberCoder('u8', { isSmallBytes: true }); - - // pointer (ptr) - const pointer: Uint8ArrayWithDynamicData = new BigNumberCoder('u64').encode( - BASE_RAW_SLICE_OFFSET - ); - - // pointer dynamicData, encode the vector now and attach to its pointer - pointer.dynamicData = { - 0: concatWithDynamicData(value.map((v) => coder.encode(v))), - }; - - parts.push(pointer); - - // length (len) - parts.push(new BigNumberCoder('u64').encode(value.length)); - - return concatWithDynamicData(parts); - } - - decode(data: Uint8Array, offset: number): [number[], number] { - const dataBytes = data.slice(offset); - const internalCoder = new ArrayCoder( - new NumberCoder('u8', { isSmallBytes: true }), - dataBytes.length - ); - const [decodedValue] = internalCoder.decode(dataBytes, 0); - - return [decodedValue, offset + dataBytes.length]; - } -} diff --git a/packages/abi-coder/src/encoding/coders/v0/StdStringCoder.test.ts b/packages/abi-coder/src/encoding/coders/v0/StdStringCoder.test.ts deleted file mode 100644 index 5e976a42d2..0000000000 --- a/packages/abi-coder/src/encoding/coders/v0/StdStringCoder.test.ts +++ /dev/null @@ -1,121 +0,0 @@ -import { ErrorCode, FuelError } from '@fuel-ts/errors'; -import { expectToThrowFuelError } from '@fuel-ts/errors/test-utils'; - -import type { Uint8ArrayWithDynamicData } from '../../../utils/utilities'; - -import { StdStringCoder } from './StdStringCoder'; - -/** - * @group node - * @group browser - */ -describe('StdStringCoder', () => { - it('should encode an empty string', () => { - const coder = new StdStringCoder(); - const expected: Uint8ArrayWithDynamicData = new Uint8Array([ - 0, 0, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - ]); - expected.dynamicData = { - 0: new Uint8Array([]), - }; - - const actual = coder.encode(''); - expect(actual).toStrictEqual(expected); - }); - - it('should encode [hello world]', () => { - const coder = new StdStringCoder(); - const expected: Uint8ArrayWithDynamicData = new Uint8Array([ - 0, 0, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 11, - ]); - expected.dynamicData = { - 0: new Uint8Array([104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 0, 0, 0, 0, 0]), - }; - - const actual = coder.encode('hello world'); - expect(actual).toStrictEqual(expected); - }); - - it('should encode [H3llo W0rld]', () => { - const coder = new StdStringCoder(); - const expected: Uint8ArrayWithDynamicData = new Uint8Array([ - 0, 0, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 11, - ]); - expected.dynamicData = { - 0: new Uint8Array([72, 51, 108, 108, 111, 32, 87, 48, 114, 108, 100, 0, 0, 0, 0, 0]), - }; - - const actual = coder.encode('H3llo W0rld'); - expect(actual).toStrictEqual(expected); - }); - - it('should encode [abcdefghijklmnopqrstuvwxyz1234567890]', () => { - const coder = new StdStringCoder(); - const expected: Uint8ArrayWithDynamicData = new Uint8Array([ - 0, 0, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 36, - ]); - expected.dynamicData = { - 0: new Uint8Array([ - 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, - 116, 117, 118, 119, 120, 121, 122, 49, 50, 51, 52, 53, 54, 55, 56, 57, 48, 0, 0, 0, 0, - ]), - }; - - const actual = coder.encode('abcdefghijklmnopqrstuvwxyz1234567890'); - expect(actual).toStrictEqual(expected); - }); - - it('should decode a string', () => { - const coder = new StdStringCoder(); - const input = new Uint8Array([ - 0, 0, 0, 0, 0, 0, 49, 120, 0, 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 11, 72, 101, 108, - 108, 111, 32, 87, 111, 114, 108, 100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - ]); - const expected = 'Hello World'; - - const [actual, newOffset] = coder.decode(input, 0); - - expect(actual).toEqual(expected); - expect(newOffset).toEqual(24); - }); - - it('should decode a string [with offset]', () => { - const coder = new StdStringCoder(); - const input = new Uint8Array([ - 0, 0, 0, 0, 0, 0, 49, 120, 0, 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 11, 72, 101, 108, - 108, 111, 32, 87, 111, 114, 108, 100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - ]); - const expected = 'Hello World'; - - const [actual, newOffset] = coder.decode(input, 16); - - expect(actual).toEqual(expected); - expect(newOffset).toEqual(40); - }); - - it('throws when decoding a string with empty bytes', async () => { - const coder = new StdStringCoder(); - const input = new Uint8Array(0); - - await expectToThrowFuelError( - () => coder.decode(input, 0), - new FuelError(ErrorCode.ENCODE_ERROR, 'Invalid std string data size.') - ); - }); - - it('throws when decoding a string with empty byte data', async () => { - const coder = new StdStringCoder(); - const input = new Uint8Array([ - 0, 0, 0, 0, 3, 255, 255, 225, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 255, - ]); - - await expectToThrowFuelError( - () => coder.decode(input, 0), - new FuelError(ErrorCode.DECODE_ERROR, 'Invalid std string byte data size.') - ); - }); -}); diff --git a/packages/abi-coder/src/encoding/coders/v0/StdStringCoder.ts b/packages/abi-coder/src/encoding/coders/v0/StdStringCoder.ts deleted file mode 100644 index ae75bac109..0000000000 --- a/packages/abi-coder/src/encoding/coders/v0/StdStringCoder.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { ErrorCode, FuelError } from '@fuel-ts/errors'; -import { bn } from '@fuel-ts/math'; -import { concat, toUtf8String, toUtf8Bytes } from '@fuel-ts/utils'; - -import { WORD_SIZE } from '../../../utils/constants'; -import type { Uint8ArrayWithDynamicData } from '../../../utils/utilities'; -import { BASE_VECTOR_OFFSET, concatWithDynamicData } from '../../../utils/utilities'; -import { Coder } from '../AbstractCoder'; - -import { BigNumberCoder } from './BigNumberCoder'; - -export class StdStringCoder extends Coder { - static memorySize = 1; - constructor() { - super('struct', 'struct String', 1); - } - - encode(value: string): Uint8Array { - const parts: Uint8Array[] = []; - - // pointer (ptr) - const pointer: Uint8ArrayWithDynamicData = new BigNumberCoder('u64').encode(BASE_VECTOR_OFFSET); - - // pointer dynamicData, encode the string vector now and attach to its pointer - const data = this.#getPaddedData(value); - pointer.dynamicData = { - 0: concatWithDynamicData([data]), - }; - - parts.push(pointer); - - // capacity (cap) - parts.push(new BigNumberCoder('u64').encode(data.byteLength)); - - // length (len) - parts.push(new BigNumberCoder('u64').encode(value.length)); - - return concatWithDynamicData(parts); - } - - #getPaddedData(value: string): Uint8Array { - const data: Uint8Array[] = [toUtf8Bytes(value)]; - - const paddingLength = (WORD_SIZE - (value.length % WORD_SIZE)) % WORD_SIZE; - if (paddingLength) { - data.push(new Uint8Array(paddingLength)); - } - - return concat(data); - } - - decode(data: Uint8Array, offset: number): [string, number] { - if (data.length < this.encodedLength) { - throw new FuelError(ErrorCode.DECODE_ERROR, `Invalid std string data size.`); - } - - const len = data.slice(16, 24); - const encodedLength = bn(new BigNumberCoder('u64').decode(len, 0)[0]).toNumber(); - const byteData = data.slice(BASE_VECTOR_OFFSET, BASE_VECTOR_OFFSET + encodedLength); - - if (byteData.length !== encodedLength) { - throw new FuelError(ErrorCode.DECODE_ERROR, `Invalid std string byte data size.`); - } - - const value = toUtf8String(byteData); - return [value, offset + BASE_VECTOR_OFFSET]; - } -} diff --git a/packages/abi-coder/src/encoding/coders/v0/StringCoder.test.ts b/packages/abi-coder/src/encoding/coders/v0/StringCoder.test.ts deleted file mode 100644 index 1954ce7f81..0000000000 --- a/packages/abi-coder/src/encoding/coders/v0/StringCoder.test.ts +++ /dev/null @@ -1,106 +0,0 @@ -import { ErrorCode, FuelError } from '@fuel-ts/errors'; -import { expectToThrowFuelError } from '@fuel-ts/errors/test-utils'; - -import { U8_MAX } from '../../../../test/utils/constants'; - -import { StringCoder } from './StringCoder'; - -/** - * @group node - * @group browser - */ -describe('StringCoder', () => { - const STRING_MIN_DECODED = ''; - const STRING_MIN_ENCODED = new Uint8Array(); - const STRING_MAX_DECODED = 'a'.repeat(U8_MAX); - const STRING_MAX_ENCODED = new Uint8Array([...Array.from(Array(U8_MAX + 1).fill(97, 0, U8_MAX))]); - - it('should encode an empty string', () => { - const coder = new StringCoder(0); - const expected = STRING_MIN_ENCODED; - const actual = coder.encode(STRING_MIN_DECODED); - - expect(actual).toStrictEqual(expected); - }); - - it('should encode a max len string', () => { - const coder = new StringCoder(U8_MAX); - const expected = STRING_MAX_ENCODED; - const actual = coder.encode(STRING_MAX_DECODED); - - expect(actual).toStrictEqual(expected); - }); - - it('should decode an empty string', () => { - const coder = new StringCoder(0); - const expectedValue = STRING_MIN_DECODED; - const expectedLength = STRING_MIN_ENCODED.length; - const [actualValue, actualLength] = coder.decode(STRING_MIN_ENCODED, 0); - - expect(actualValue).toStrictEqual(expectedValue); - expect(actualLength).toBe(expectedLength); - }); - - it('should decode a max len string', () => { - const coder = new StringCoder(U8_MAX); - const expectedValue = STRING_MAX_DECODED; - const expectedLength = STRING_MAX_ENCODED.length; - const [actualValue, actualLength] = coder.decode(STRING_MAX_ENCODED, 0); - - expect(actualValue).toStrictEqual(expectedValue); - expect(actualLength).toBe(expectedLength); - }); - - it('should throw when encoding a string that is too big', async () => { - const coder = new StringCoder(0); - const invalidInput = STRING_MAX_DECODED; - - await expectToThrowFuelError( - () => coder.encode(invalidInput), - new FuelError(ErrorCode.ENCODE_ERROR, 'Value length mismatch during encode.') - ); - }); - - it('should throw when encoding a string that is too small', async () => { - const coder = new StringCoder(1); - const invalidInput = STRING_MIN_DECODED; - - expect(() => { - coder.encode(invalidInput); - }).toThrow(); - - await expectToThrowFuelError( - () => coder.encode(invalidInput), - new FuelError(ErrorCode.ENCODE_ERROR, 'Value length mismatch during encode.') - ); - }); - - it('should not completely decode a string that is too big for the coder', () => { - const coder = new StringCoder(1); - const invalidInput = STRING_MAX_ENCODED; - const [actualValue, actualLength] = coder.decode(invalidInput, 0); - - expect(actualValue).not.toBe(STRING_MAX_DECODED); - expect(actualLength).toBe(8); - }); - - it('throws when decoding empty bytes', async () => { - const coder = new StringCoder(1); - const input = new Uint8Array(0); - - await expectToThrowFuelError( - () => coder.decode(input, 0), - new FuelError(ErrorCode.DECODE_ERROR, 'Invalid string data size.') - ); - }); - - it('throws when decoding empty byte data', async () => { - const coder = new StringCoder(1); - const input = new Uint8Array([0, 1, 2, 3, 4, 5, 6, 7]); - - await expectToThrowFuelError( - () => coder.decode(input, 8), - new FuelError(ErrorCode.DECODE_ERROR, 'Invalid string byte data size.') - ); - }); -}); diff --git a/packages/abi-coder/src/encoding/coders/v0/StringCoder.ts b/packages/abi-coder/src/encoding/coders/v0/StringCoder.ts deleted file mode 100644 index 6b8bb521f9..0000000000 --- a/packages/abi-coder/src/encoding/coders/v0/StringCoder.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { ErrorCode, FuelError } from '@fuel-ts/errors'; -import { concat, toUtf8Bytes, toUtf8String } from '@fuel-ts/utils'; - -import { Coder } from '../AbstractCoder'; - -export class StringCoder extends Coder { - length: TLength; - #paddingLength: number; - - constructor(length: TLength) { - let paddingLength = (8 - length) % 8; - paddingLength = paddingLength < 0 ? paddingLength + 8 : paddingLength; - super('string', `str[${length}]`, length + paddingLength); - this.length = length; - this.#paddingLength = paddingLength; - } - - encode(value: string): Uint8Array { - if (this.length !== value.length) { - throw new FuelError(ErrorCode.ENCODE_ERROR, `Value length mismatch during encode.`); - } - - const encoded = toUtf8Bytes(value); - const padding = new Uint8Array(this.#paddingLength); - return concat([encoded, padding]); - } - - decode(data: Uint8Array, offset: number): [string, number] { - if (data.length < this.encodedLength) { - throw new FuelError(ErrorCode.DECODE_ERROR, `Invalid string data size.`); - } - - const bytes = data.slice(offset, offset + this.length); - - if (bytes.length !== this.length) { - throw new FuelError(ErrorCode.DECODE_ERROR, `Invalid string byte data size.`); - } - - const value = toUtf8String(bytes); - - const padding = this.#paddingLength; - return [value, offset + this.length + padding]; - } -} diff --git a/packages/abi-coder/src/encoding/coders/v0/StructCoder.test.ts b/packages/abi-coder/src/encoding/coders/v0/StructCoder.test.ts deleted file mode 100644 index e34daa08e0..0000000000 --- a/packages/abi-coder/src/encoding/coders/v0/StructCoder.test.ts +++ /dev/null @@ -1,158 +0,0 @@ -/* eslint-disable @typescript-eslint/ban-ts-comment */ -import { FuelError, ErrorCode } from '@fuel-ts/errors'; -import { expectToThrowFuelError } from '@fuel-ts/errors/test-utils'; -import { bn } from '@fuel-ts/math'; - -import { U32_MAX } from '../../../../test/utils/constants'; - -import { BigNumberCoder } from './BigNumberCoder'; -import { BooleanCoder } from './BooleanCoder'; -import { StructCoder } from './StructCoder'; - -/** - * @group node - * @group browser - */ -describe('StructCoder', () => { - const STRUCT_NAME = 'TestStruct'; - const coder = new StructCoder(STRUCT_NAME, { - a: new BooleanCoder(), - b: new BigNumberCoder('u64'), - }); - - it('should encode a struct containing a boolean and number', () => { - const expected = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 255, 255, 255, 255]); - const actual = coder.encode({ a: true, b: U32_MAX }); - - expect(actual).toStrictEqual(expected); - }); - - it('should decode a struct containing a boolean and number', () => { - const expectedValue = { a: true, b: bn(U32_MAX) }; - const expectedLength = 16; - const [actualValue, actualLength] = coder.decode( - new Uint8Array([0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 255, 255, 255, 255]), - 0 - ); - - expect(JSON.stringify(actualValue)).toStrictEqual(JSON.stringify(expectedValue)); - expect(actualLength).toBe(expectedLength); - }); - - it('should not throw given correctly typed inputs', () => { - expect(() => coder.encode({ a: true, b: bn(1234) })).not.toThrow(); - }); - - it('pads to word size for encoded data with small bytes', () => { - const options = { isSmallBytes: true }; - const unpaddedCoder = new StructCoder(STRUCT_NAME, { - a: new BooleanCoder(options), - b: new BooleanCoder(options), - }); - const expected = new Uint8Array([1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); - const actual = unpaddedCoder.encode({ a: true, b: false }); - - expect(actual).toStrictEqual(expected); - }); - - it('pads new offset to word size when decoding data with small bytes', () => { - const options = { isSmallBytes: true }; - const unpaddedCoder = new StructCoder(STRUCT_NAME, { - a: new BooleanCoder(options), - b: new BooleanCoder(options), - }); - - const expectedValue = { a: true, b: false }; - const expectedLength = 16; - const [actualValue, actualLength] = unpaddedCoder.decode(new Uint8Array([1, 0]), 0); - - expect(JSON.stringify(actualValue)).toStrictEqual(JSON.stringify(expectedValue)); - expect(actualLength).toBe(expectedLength); - }); - - it('should not throw when provided with extra inputs', () => { - expect(() => - coder.encode( - // @ts-expect-error - { a: true, b: bn(1234), c: false } - ) - ).not.toThrow(); - }); - - it('should throw type error with both missing inputs', () => { - expect(() => - coder.encode( - // @ts-expect-error - {} - ) - ).toThrow(`Invalid struct ${STRUCT_NAME}`); - }); - - it('should throw type error with missing input for second coder', () => { - expect(() => - coder.encode( - // @ts-expect-error - { a: true } - ) - ).toThrow(`Invalid struct ${STRUCT_NAME}`); - }); - - it('should throw type error with missing input for first coder', () => { - expect(() => - coder.encode( - // @ts-expect-error - { b: bn(1234) } - ) - ).toThrow(`Invalid struct ${STRUCT_NAME}`); - }); - - it.skip('should throw type error with invalid input for first coder and missing input for second', () => { - // Skipped because this is failing with a different message because it's now failing on encoding a: 1234, - // which should be boolean, - // whereas previously it wasn't failing because of this but rather because the second 'b' prop is missing. - // This test should be deleted as it's testing the same thing as the - // 'should throw type error with missing input for second coder' test. - expect(() => - coder.encode( - // @ts-expect-error - { a: 1234 } - ) - ).toThrow(`Invalid struct ${STRUCT_NAME}`); - }); - - it('should throw type error with invalid input for second coder and missing input for first', () => { - expect(() => - coder.encode( - // @ts-expect-error - { b: true } - ) - ).toThrow(`Invalid struct ${STRUCT_NAME}`); - }); - - it('should throw type error with invalid input key', () => { - expect(() => - coder.encode( - // @ts-expect-error - { nope: 1234, alsoNope: true } - ) - ).toThrow(`Invalid struct ${STRUCT_NAME}`); - }); - - it('throws when decoding empty bytes', async () => { - const input = new Uint8Array(0); - - await expectToThrowFuelError( - () => coder.decode(input, 0), - new FuelError(ErrorCode.DECODE_ERROR, 'Invalid struct data size.') - ); - }); - - it('throws when decoding empty bytes', async () => { - const input = new Uint8Array(0); - - await expectToThrowFuelError( - () => coder.decode(input, 0), - new FuelError(ErrorCode.DECODE_ERROR, 'Invalid struct data size.') - ); - }); -}); diff --git a/packages/abi-coder/src/encoding/coders/v0/StructCoder.ts b/packages/abi-coder/src/encoding/coders/v0/StructCoder.ts deleted file mode 100644 index e4aca0a2b9..0000000000 --- a/packages/abi-coder/src/encoding/coders/v0/StructCoder.ts +++ /dev/null @@ -1,84 +0,0 @@ -import { ErrorCode, FuelError } from '@fuel-ts/errors'; - -import { - concatWithDynamicData, - getWordSizePadding, - isMultipleOfWordSize, - rightPadToWordSize, -} from '../../../utils/utilities'; -import type { TypesOfCoder } from '../AbstractCoder'; -import { Coder } from '../AbstractCoder'; - -import { OptionCoder } from './OptionCoder'; - -type InputValueOf> = { - [P in keyof TCoders]: TypesOfCoder['Input']; -}; -type DecodedValueOf> = { - [P in keyof TCoders]: TypesOfCoder['Decoded']; -}; - -export class StructCoder> extends Coder< - InputValueOf, - DecodedValueOf -> { - name: string; - coders: TCoders; - - constructor(name: string, coders: TCoders) { - const encodedLength = Object.values(coders).reduce( - (acc, coder) => acc + coder.encodedLength, - 0 - ); - super('struct', `struct ${name}`, encodedLength); - this.name = name; - this.coders = coders; - } - - encode(value: InputValueOf) { - const encodedFields = Object.keys(this.coders).map((fieldName) => { - const fieldCoder = this.coders[fieldName]; - const fieldValue = value[fieldName]; - - if (!(fieldCoder instanceof OptionCoder) && fieldValue == null) { - throw new FuelError( - ErrorCode.ENCODE_ERROR, - `Invalid ${this.type}. Field "${fieldName}" not present.` - ); - } - - const encoded = fieldCoder.encode(fieldValue); - - if (!isMultipleOfWordSize(encoded.length)) { - return rightPadToWordSize(encoded); - } - - return encoded; - }); - - return concatWithDynamicData([concatWithDynamicData(encodedFields)]); - } - - decode(data: Uint8Array, offset: number): [DecodedValueOf, number] { - if (data.length < this.encodedLength) { - throw new FuelError(ErrorCode.DECODE_ERROR, `Invalid struct data size.`); - } - - let newOffset = offset; - const decodedValue = Object.keys(this.coders).reduce((obj, fieldName) => { - const fieldCoder = this.coders[fieldName]; - let decoded; - [decoded, newOffset] = fieldCoder.decode(data, newOffset); - - if (!isMultipleOfWordSize(newOffset)) { - newOffset += getWordSizePadding(newOffset); - } - - // eslint-disable-next-line no-param-reassign - obj[fieldName as keyof DecodedValueOf] = decoded; - return obj; - }, {} as DecodedValueOf); - - return [decodedValue, newOffset]; - } -} diff --git a/packages/abi-coder/src/encoding/coders/v0/TupleCoder.test.ts b/packages/abi-coder/src/encoding/coders/v0/TupleCoder.test.ts deleted file mode 100644 index 0f04fbcd78..0000000000 --- a/packages/abi-coder/src/encoding/coders/v0/TupleCoder.test.ts +++ /dev/null @@ -1,135 +0,0 @@ -/* eslint-disable @typescript-eslint/ban-ts-comment */ -import { ErrorCode, FuelError } from '@fuel-ts/errors'; -import { expectToThrowFuelError } from '@fuel-ts/errors/test-utils'; -import { bn } from '@fuel-ts/math'; - -import { U64_MAX } from '../../../../test/utils/constants'; - -import { BigNumberCoder } from './BigNumberCoder'; -import { BooleanCoder } from './BooleanCoder'; -import { TupleCoder } from './TupleCoder'; - -/** - * @group node - * @group browser - */ -describe('Tuple Coder', () => { - const coder = new TupleCoder<[BooleanCoder, BigNumberCoder]>([ - new BooleanCoder(), - new BigNumberCoder('u64'), - ]); - - it('should encode a tuple containing a boolean and u64', () => { - const expected = new Uint8Array([ - 0, 0, 0, 0, 0, 0, 0, 1, 255, 255, 255, 255, 255, 255, 255, 255, - ]); - const actual = coder.encode([true, U64_MAX]); - - expect(actual).toStrictEqual(expected); - }); - - it('should decode a tuple containing a boolean and u64', () => { - const expectedValue = [true, bn(U64_MAX)]; - const expectedLength = 16; - const [actualValue, actualLength] = coder.decode( - new Uint8Array([0, 0, 0, 0, 0, 0, 0, 1, 255, 255, 255, 255, 255, 255, 255, 255]), - 0 - ); - - expect(JSON.stringify(actualValue)).toStrictEqual(JSON.stringify(expectedValue)); - expect(actualLength).toBe(expectedLength); - }); - - it('pads to word size for encoded data with small bytes', () => { - const options = { isSmallBytes: true }; - const unpaddedCoder = new TupleCoder<[BooleanCoder, BooleanCoder]>([ - new BooleanCoder(options), - new BooleanCoder(options), - ]); - const expected = new Uint8Array([1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); - const actual = unpaddedCoder.encode([true, false]); - expect(actual).toStrictEqual(expected); - }); - - it('pads new offset to word size when decoding data with small bytes', () => { - const options = { isSmallBytes: true }; - const unpaddedCoder = new TupleCoder<[BooleanCoder, BooleanCoder]>([ - new BooleanCoder(options), - new BooleanCoder(options), - ]); - - const expectedValue = [true, false]; - const expectedLength = 16; - const [actualValue, actualLength] = unpaddedCoder.decode(new Uint8Array([1, 0]), 0); - - expect(JSON.stringify(actualValue)).toStrictEqual(JSON.stringify(expectedValue)); - expect(actualLength).toBe(expectedLength); - }); - - it('should not throw given correctly typed inputs', () => { - expect(() => coder.encode([true, bn(1234)])).not.toThrow(); - }); - - it('should throw when provided with extra inputs', () => { - expect(() => - coder.encode( - // @ts-expect-error - [true, bn(1337), false] - ) - ).toThrow('Types/values length mismatch'); - }); - - it('should throw type error with both missing inputs', () => { - expect(() => - coder.encode( - // @ts-expect-error - [] - ) - ).toThrow('Types/values length mismatch'); - }); - - it('should throw type error with a missing input', () => { - expect(() => - coder.encode( - // @ts-expect-error - [true] - ) - ).toThrow('Types/values length mismatch'); - }); - - it('should throw type error with invalid inputs', () => { - expect(() => - coder.encode( - // @ts-expect-error - [bn(1234), true] - ) - ).toThrow(); - }); - - it('should throw when input is an object', () => { - expect(() => - coder.encode( - // @ts-expect-error - { nope: 42 } - ) - ).toThrow(); - }); - - it('throws when decoding empty bytes', async () => { - const input = new Uint8Array(0); - - await expectToThrowFuelError( - () => coder.decode(input, 0), - new FuelError(ErrorCode.DECODE_ERROR, 'Invalid tuple data size.') - ); - }); - - it('throws when decoding empty bytes', async () => { - const input = new Uint8Array(0); - - await expectToThrowFuelError( - () => coder.decode(input, 0), - new FuelError(ErrorCode.DECODE_ERROR, 'Invalid tuple data size.') - ); - }); -}); diff --git a/packages/abi-coder/src/encoding/coders/v0/TupleCoder.ts b/packages/abi-coder/src/encoding/coders/v0/TupleCoder.ts deleted file mode 100644 index e3b7c63bcd..0000000000 --- a/packages/abi-coder/src/encoding/coders/v0/TupleCoder.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { ErrorCode, FuelError } from '@fuel-ts/errors'; - -import { - concatWithDynamicData, - getWordSizePadding, - isMultipleOfWordSize, - rightPadToWordSize, -} from '../../../utils/utilities'; -import type { TypesOfCoder } from '../AbstractCoder'; -import { Coder } from '../AbstractCoder'; - -type InputValueOf = { - [P in keyof TCoders]: TypesOfCoder['Input']; -}; -type DecodedValueOf = { - [P in keyof TCoders]: TypesOfCoder['Decoded']; -}; - -export class TupleCoder extends Coder< - InputValueOf, - DecodedValueOf -> { - coders: TCoders; - - constructor(coders: TCoders) { - const encodedLength = coders.reduce((acc, coder) => acc + coder.encodedLength, 0); - super('tuple', `(${coders.map((coder) => coder.type).join(', ')})`, encodedLength); - this.coders = coders; - } - - encode(value: InputValueOf): Uint8Array { - if (this.coders.length !== value.length) { - throw new FuelError(ErrorCode.ENCODE_ERROR, `Types/values length mismatch.`); - } - - return concatWithDynamicData( - this.coders.map((coder, i) => { - const encoded = coder.encode(value[i]); - if (!isMultipleOfWordSize(encoded.length)) { - return rightPadToWordSize(encoded); - } - return encoded; - }) - ); - } - - decode(data: Uint8Array, offset: number): [DecodedValueOf, number] { - if (data.length < this.encodedLength) { - throw new FuelError(ErrorCode.DECODE_ERROR, `Invalid tuple data size.`); - } - - let newOffset = offset; - const decodedValue = this.coders.map((coder) => { - let decoded; - [decoded, newOffset] = coder.decode(data, newOffset); - - if (!isMultipleOfWordSize(newOffset)) { - newOffset += getWordSizePadding(newOffset); - } - - return decoded; - }); - - return [decodedValue as DecodedValueOf, newOffset]; - } -} diff --git a/packages/abi-coder/src/encoding/coders/v0/VecCoder.test.ts b/packages/abi-coder/src/encoding/coders/v0/VecCoder.test.ts deleted file mode 100644 index 24b3523764..0000000000 --- a/packages/abi-coder/src/encoding/coders/v0/VecCoder.test.ts +++ /dev/null @@ -1,89 +0,0 @@ -import { ErrorCode, FuelError } from '@fuel-ts/errors'; -import { expectToThrowFuelError } from '@fuel-ts/errors/test-utils'; - -import { U32_MAX } from '../../../../test/utils/constants'; -import type { EncodingOptions } from '../../../types/EncodingOptions'; -import type { Uint8ArrayWithDynamicData } from '../../../utils/utilities'; - -import { BooleanCoder } from './BooleanCoder'; -import { NumberCoder } from './NumberCoder'; -import { VecCoder } from './VecCoder'; - -/** - * @group node - */ -describe('VecCoder', () => { - const options: EncodingOptions = { - isSmallBytes: true, - }; - - it('should encode a Vec of Booleans', () => { - const coder = new VecCoder(new BooleanCoder(options)); - const expected: Uint8ArrayWithDynamicData = new Uint8Array([ - 0, 0, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 2, - ]); - expected.dynamicData = { - 0: new Uint8Array([1, 0]), - }; - - const actual = coder.encode([true, false]); - - expect(actual).toEqual(expected); - }); - - it('should throw when encoding non array input', async () => { - const coder = new VecCoder(new BooleanCoder(options)); - await expectToThrowFuelError( - () => coder.encode('Nope' as never), - new FuelError( - ErrorCode.ENCODE_ERROR, - 'Expected array value, or a Uint8Array. You can use arrayify to convert a value to a Uint8Array.' - ) - ); - }); - - it('should decode a u8 Vec', () => { - const coder = new VecCoder(new NumberCoder('u8', options)); - const input = new Uint8Array([ - 0, 0, 0, 0, 0, 0, 41, 16, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 3, 8, 6, 7, - ]); - const expected = [8, 6, 7]; - - const [actual, newOffset] = coder.decode(input, 0); - - expect(actual).toEqual(expected); - expect(newOffset).toEqual(24); - }); - - it('throws when decoding empty vec bytes', async () => { - const coder = new VecCoder(new NumberCoder('u8')); - const input = new Uint8Array(0); - - await expectToThrowFuelError( - () => coder.decode(input, 0), - new FuelError(ErrorCode.ENCODE_ERROR, 'Invalid vec data size.') - ); - }); - - it('throws when decoding empty vec byte data', async () => { - const coder = new VecCoder(new NumberCoder('u8')); - const input = new Uint8Array([ - 0, 0, 0, 0, 3, 255, 255, 225, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 255, - ]); - - await expectToThrowFuelError( - () => coder.decode(input, 0), - new FuelError(ErrorCode.DECODE_ERROR, 'Invalid vec byte data size.') - ); - }); - - it('throws when decoding vec larger than max size', async () => { - const coder = new VecCoder(new NumberCoder('u8')); - const input = new Uint8Array(U32_MAX + 1); - - await expectToThrowFuelError( - () => coder.decode(input, 0), - new FuelError(ErrorCode.DECODE_ERROR, 'Invalid vec data size.') - ); - }); -}); diff --git a/packages/abi-coder/src/encoding/coders/v0/VecCoder.ts b/packages/abi-coder/src/encoding/coders/v0/VecCoder.ts deleted file mode 100644 index 9b715e2198..0000000000 --- a/packages/abi-coder/src/encoding/coders/v0/VecCoder.ts +++ /dev/null @@ -1,80 +0,0 @@ -import { ErrorCode, FuelError } from '@fuel-ts/errors'; -import { bn } from '@fuel-ts/math'; - -import { MAX_BYTES } from '../../../utils/constants'; -import type { Uint8ArrayWithDynamicData } from '../../../utils/utilities'; -import { - concatWithDynamicData, - BASE_VECTOR_OFFSET, - chunkByLength, - isUint8Array, -} from '../../../utils/utilities'; -import type { TypesOfCoder } from '../AbstractCoder'; -import { Coder } from '../AbstractCoder'; - -import { BigNumberCoder } from './BigNumberCoder'; - -type InputValueOf = Array['Input']>; -type DecodedValueOf = Array['Decoded']>; - -export class VecCoder extends Coder< - InputValueOf, - DecodedValueOf -> { - coder: TCoder; - - constructor(coder: TCoder) { - super('struct', `struct Vec`, coder.encodedLength + BASE_VECTOR_OFFSET); - this.coder = coder; - } - - encode(value: InputValueOf): Uint8Array { - if (!Array.isArray(value) && !isUint8Array(value)) { - throw new FuelError( - ErrorCode.ENCODE_ERROR, - `Expected array value, or a Uint8Array. You can use arrayify to convert a value to a Uint8Array.` - ); - } - - const parts: Uint8Array[] = []; - - // pointer (ptr) - const pointer: Uint8ArrayWithDynamicData = new BigNumberCoder('u64').encode(BASE_VECTOR_OFFSET); - // pointer dynamicData, encode the vector now and attach to its pointer - pointer.dynamicData = { - 0: concatWithDynamicData(Array.from(value).map((v) => this.coder.encode(v))), - }; - - parts.push(pointer); - - // capacity (cap) - parts.push(new BigNumberCoder('u64').encode(value.length)); - - // length (len) - parts.push(new BigNumberCoder('u64').encode(value.length)); - - return concatWithDynamicData(parts); - } - - decode(data: Uint8Array, offset: number): [DecodedValueOf, number] { - if (data.length < BASE_VECTOR_OFFSET || data.length > MAX_BYTES) { - throw new FuelError(ErrorCode.DECODE_ERROR, `Invalid vec data size.`); - } - - const len = data.slice(16, 24); - const encodedLength = bn(new BigNumberCoder('u64').decode(len, 0)[0]).toNumber(); - const vectorRawDataLength = encodedLength * this.coder.encodedLength; - const vectorRawData = data.slice(BASE_VECTOR_OFFSET, BASE_VECTOR_OFFSET + vectorRawDataLength); - - if (vectorRawData.length !== vectorRawDataLength) { - throw new FuelError(ErrorCode.DECODE_ERROR, `Invalid vec byte data size.`); - } - - return [ - chunkByLength(vectorRawData, this.coder.encodedLength).map( - (chunk) => this.coder.decode(chunk, 0)[0] - ), - offset + BASE_VECTOR_OFFSET, - ]; - } -} diff --git a/packages/abi-coder/src/encoding/strategies/getCoderForEncoding.test.ts b/packages/abi-coder/src/encoding/strategies/getCoderForEncoding.test.ts index 657ae674b4..15020c8859 100644 --- a/packages/abi-coder/src/encoding/strategies/getCoderForEncoding.test.ts +++ b/packages/abi-coder/src/encoding/strategies/getCoderForEncoding.test.ts @@ -1,7 +1,6 @@ -import { ENCODING_V0, ENCODING_V1 } from '../../utils/constants'; +import { ENCODING_V1 } from '../../utils/constants'; import { getCoderForEncoding } from './getCoderForEncoding'; -import { getCoder as getCoderV0 } from './getCoderV0'; import { getCoder as getCoderV1 } from './getCoderV1'; /** @@ -9,18 +8,14 @@ import { getCoder as getCoderV1 } from './getCoderV1'; * @group browser */ describe('getEncodingStrategy', () => { - it('defaults to encoding version 0', () => { - expect(getCoderForEncoding()).toBe(getCoderV0); + it('defaults to encoding version 1', () => { + expect(getCoderForEncoding()).toBe(getCoderV1); }); it('returns getCoderV1 for encoding version 1', () => { expect(getCoderForEncoding(ENCODING_V1)).toBe(getCoderV1); }); - it('returns getCoderV0 for encoding version 0', () => { - expect(getCoderForEncoding(ENCODING_V0)).toBe(getCoderV0); - }); - it('throws for an unsupported encoding version', () => { expect(() => getCoderForEncoding('2')).toThrowError('Encoding version 2 is unsupported.'); }); diff --git a/packages/abi-coder/src/encoding/strategies/getCoderForEncoding.ts b/packages/abi-coder/src/encoding/strategies/getCoderForEncoding.ts index ca4f2b35aa..33a1956285 100644 --- a/packages/abi-coder/src/encoding/strategies/getCoderForEncoding.ts +++ b/packages/abi-coder/src/encoding/strategies/getCoderForEncoding.ts @@ -2,9 +2,8 @@ import { ErrorCode, FuelError } from '@fuel-ts/errors'; import type { GetCoderFn } from '../../types/GetCoder'; import type { EncodingVersion } from '../../utils/constants'; -import { ENCODING_V0, ENCODING_V1 } from '../../utils/constants'; +import { ENCODING_V1 } from '../../utils/constants'; -import { getCoder as getCoderV0 } from './getCoderV0'; import { getCoder as getCoderV1 } from './getCoderV1'; /** @@ -14,12 +13,10 @@ import { getCoder as getCoderV1 } from './getCoderV1'; * @throws for an unsupported encoding version. * @returns the appropriate encoding strategy. */ -export function getCoderForEncoding(encoding: EncodingVersion = ENCODING_V0): GetCoderFn { +export function getCoderForEncoding(encoding: EncodingVersion = ENCODING_V1): GetCoderFn { switch (encoding) { case ENCODING_V1: return getCoderV1; - case ENCODING_V0: - return getCoderV0; default: throw new FuelError( ErrorCode.UNSUPPORTED_ENCODING_VERSION, diff --git a/packages/abi-coder/src/encoding/strategies/getCoderV0.ts b/packages/abi-coder/src/encoding/strategies/getCoderV0.ts deleted file mode 100644 index c812b1d4cb..0000000000 --- a/packages/abi-coder/src/encoding/strategies/getCoderV0.ts +++ /dev/null @@ -1,157 +0,0 @@ -import { ErrorCode, FuelError } from '@fuel-ts/errors'; - -import { ResolvedAbiType } from '../../ResolvedAbiType'; -import type { EncodingOptions } from '../../types/EncodingOptions'; -import type { GetCoderFn } from '../../types/GetCoder'; -import { - B256_CODER_TYPE, - B512_CODER_TYPE, - BOOL_CODER_TYPE, - BYTES_CODER_TYPE, - ENCODING_V0, - OPTION_CODER_TYPE, - RAW_PTR_CODER_TYPE, - RAW_SLICE_CODER_TYPE, - STD_STRING_CODER_TYPE, - STR_SLICE_CODER_TYPE, - U16_CODER_TYPE, - U256_CODER_TYPE, - U32_CODER_TYPE, - U64_CODER_TYPE, - U8_CODER_TYPE, - VEC_CODER_TYPE, - arrayRegEx, - enumRegEx, - stringRegEx, - structRegEx, - tupleRegEx, -} from '../../utils/constants'; -import { findVectorBufferArgument } from '../../utils/json-abi'; -import type { Coder } from '../coders/AbstractCoder'; -import { ArrayCoder } from '../coders/v0/ArrayCoder'; -import { B256Coder } from '../coders/v0/B256Coder'; -import { B512Coder } from '../coders/v0/B512Coder'; -import { BigNumberCoder } from '../coders/v0/BigNumberCoder'; -import { BooleanCoder } from '../coders/v0/BooleanCoder'; -import { ByteCoder } from '../coders/v0/ByteCoder'; -import { EnumCoder } from '../coders/v0/EnumCoder'; -import { NumberCoder } from '../coders/v0/NumberCoder'; -import { OptionCoder } from '../coders/v0/OptionCoder'; -import { RawSliceCoder } from '../coders/v0/RawSliceCoder'; -import { StdStringCoder } from '../coders/v0/StdStringCoder'; -import { StringCoder } from '../coders/v0/StringCoder'; -import { StructCoder } from '../coders/v0/StructCoder'; -import { TupleCoder } from '../coders/v0/TupleCoder'; -import { VecCoder } from '../coders/v0/VecCoder'; - -import { getCoders } from './getCoders'; - -/** - * Retrieves coders that adhere to the v0 spec. - * - * @param resolvedAbiType - the resolved type to return a coder for. - * @param options - options to be utilized during the encoding process. - * @returns the coder for a given type. - */ -export const getCoder: GetCoderFn = ( - resolvedAbiType: ResolvedAbiType, - options?: EncodingOptions -): Coder => { - switch (resolvedAbiType.type) { - case U8_CODER_TYPE: - case U16_CODER_TYPE: - case U32_CODER_TYPE: - return new NumberCoder(resolvedAbiType.type, options); - case U64_CODER_TYPE: - case RAW_PTR_CODER_TYPE: - return new BigNumberCoder('u64'); - case U256_CODER_TYPE: - return new BigNumberCoder('u256'); - case RAW_SLICE_CODER_TYPE: - return new RawSliceCoder(); - case BOOL_CODER_TYPE: - return new BooleanCoder(options); - case B256_CODER_TYPE: - return new B256Coder(); - case B512_CODER_TYPE: - return new B512Coder(); - case BYTES_CODER_TYPE: - return new ByteCoder(); - case STD_STRING_CODER_TYPE: - return new StdStringCoder(); - default: - break; - } - - const stringMatch = stringRegEx.exec(resolvedAbiType.type)?.groups; - if (stringMatch) { - const length = parseInt(stringMatch.length, 10); - - return new StringCoder(length); - } - - // ABI types underneath MUST have components by definition - - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const components = resolvedAbiType.components!; - - const arrayMatch = arrayRegEx.exec(resolvedAbiType.type)?.groups; - if (arrayMatch) { - const length = parseInt(arrayMatch.length, 10); - const arg = components[0]; - if (!arg) { - throw new FuelError( - ErrorCode.INVALID_COMPONENT, - `The provided Array type is missing an item of 'component'.` - ); - } - - const arrayElementCoder = getCoder(arg, { isSmallBytes: true }); - return new ArrayCoder(arrayElementCoder as Coder, length); - } - - if (resolvedAbiType.type === VEC_CODER_TYPE) { - const arg = findVectorBufferArgument(components); - const argType = new ResolvedAbiType(resolvedAbiType.abi, arg); - - const itemCoder = getCoder(argType, { isSmallBytes: true, encoding: ENCODING_V0 }); - return new VecCoder(itemCoder as Coder); - } - - const structMatch = structRegEx.exec(resolvedAbiType.type)?.groups; - if (structMatch) { - const coders = getCoders(components, { isRightPadded: true, getCoder }); - return new StructCoder(structMatch.name, coders); - } - - const enumMatch = enumRegEx.exec(resolvedAbiType.type)?.groups; - if (enumMatch) { - const coders = getCoders(components, { getCoder }); - - const isOptionEnum = resolvedAbiType.type === OPTION_CODER_TYPE; - if (isOptionEnum) { - return new OptionCoder(enumMatch.name, coders); - } - return new EnumCoder(enumMatch.name, coders); - } - - const tupleMatch = tupleRegEx.exec(resolvedAbiType.type)?.groups; - if (tupleMatch) { - const coders = components.map((component) => - getCoder(component, { isRightPadded: true, encoding: ENCODING_V0 }) - ); - return new TupleCoder(coders as Coder[]); - } - - if (resolvedAbiType.type === STR_SLICE_CODER_TYPE) { - throw new FuelError( - ErrorCode.INVALID_DATA, - 'String slices can not be decoded from logs. Convert the slice to `str[N]` with `__to_str_array`' - ); - } - - throw new FuelError( - ErrorCode.CODER_NOT_FOUND, - `Coder not found: ${JSON.stringify(resolvedAbiType)}.` - ); -}; diff --git a/packages/abi-coder/src/encoding/strategies/getCoderV1.ts b/packages/abi-coder/src/encoding/strategies/getCoderV1.ts index bbe5b82d12..2b746061ab 100644 --- a/packages/abi-coder/src/encoding/strategies/getCoderV1.ts +++ b/packages/abi-coder/src/encoding/strategies/getCoderV1.ts @@ -8,7 +8,7 @@ import { B512_CODER_TYPE, BOOL_CODER_TYPE, BYTES_CODER_TYPE, - ENCODING_V0, + ENCODING_V1, OPTION_CODER_TYPE, RAW_PTR_CODER_TYPE, RAW_SLICE_CODER_TYPE, @@ -28,22 +28,22 @@ import { } from '../../utils/constants'; import { findVectorBufferArgument } from '../../utils/json-abi'; import type { Coder } from '../coders/AbstractCoder'; -import { ArrayCoder } from '../coders/v0/ArrayCoder'; -import { B256Coder } from '../coders/v0/B256Coder'; -import { B512Coder } from '../coders/v0/B512Coder'; -import { BigNumberCoder } from '../coders/v0/BigNumberCoder'; -import { BooleanCoder } from '../coders/v1/BooleanCoder'; -import { ByteCoder } from '../coders/v1/ByteCoder'; -import { EnumCoder } from '../coders/v1/EnumCoder'; -import { NumberCoder } from '../coders/v1/NumberCoder'; -import { OptionCoder } from '../coders/v1/OptionCoder'; -import { RawSliceCoder } from '../coders/v1/RawSliceCoder'; -import { StdStringCoder } from '../coders/v1/StdStringCoder'; -import { StrSliceCoder } from '../coders/v1/StrSliceCoder'; -import { StringCoder } from '../coders/v1/StringCoder'; -import { StructCoder } from '../coders/v1/StructCoder'; -import { TupleCoder } from '../coders/v1/TupleCoder'; -import { VecCoder } from '../coders/v1/VecCoder'; +import { ArrayCoder } from '../coders/ArrayCoder'; +import { B256Coder } from '../coders/B256Coder'; +import { B512Coder } from '../coders/B512Coder'; +import { BigNumberCoder } from '../coders/BigNumberCoder'; +import { BooleanCoder } from '../coders/BooleanCoder'; +import { ByteCoder } from '../coders/ByteCoder'; +import { EnumCoder } from '../coders/EnumCoder'; +import { NumberCoder } from '../coders/NumberCoder'; +import { OptionCoder } from '../coders/OptionCoder'; +import { RawSliceCoder } from '../coders/RawSliceCoder'; +import { StdStringCoder } from '../coders/StdStringCoder'; +import { StrSliceCoder } from '../coders/StrSliceCoder'; +import { StringCoder } from '../coders/StringCoder'; +import { StructCoder } from '../coders/StructCoder'; +import { TupleCoder } from '../coders/TupleCoder'; +import { VecCoder } from '../coders/VecCoder'; import { getCoders } from './getCoders'; @@ -109,7 +109,7 @@ export const getCoder: GetCoderFn = ( ); } - const arrayElementCoder = getCoder(arg, { isSmallBytes: true }); + const arrayElementCoder = getCoder(arg); return new ArrayCoder(arrayElementCoder as Coder, length); } @@ -117,13 +117,13 @@ export const getCoder: GetCoderFn = ( const arg = findVectorBufferArgument(components); const argType = new ResolvedAbiType(resolvedAbiType.abi, arg); - const itemCoder = getCoder(argType, { isSmallBytes: true, encoding: ENCODING_V0 }); + const itemCoder = getCoder(argType, { encoding: ENCODING_V1 }); return new VecCoder(itemCoder as Coder); } const structMatch = structRegEx.exec(resolvedAbiType.type)?.groups; if (structMatch) { - const coders = getCoders(components, { isRightPadded: true, getCoder }); + const coders = getCoders(components, { getCoder }); return new StructCoder(structMatch.name, coders); } @@ -140,9 +140,7 @@ export const getCoder: GetCoderFn = ( const tupleMatch = tupleRegEx.exec(resolvedAbiType.type)?.groups; if (tupleMatch) { - const coders = components.map((component) => - getCoder(component, { isRightPadded: true, encoding: ENCODING_V0 }) - ); + const coders = components.map((component) => getCoder(component, { encoding: ENCODING_V1 })); return new TupleCoder(coders as Coder[]); } diff --git a/packages/abi-coder/src/index.ts b/packages/abi-coder/src/index.ts index 3437f3723c..93c8078e46 100644 --- a/packages/abi-coder/src/index.ts +++ b/packages/abi-coder/src/index.ts @@ -1,19 +1,6 @@ export { Coder, InputValue, DecodedValue } from './encoding/coders/AbstractCoder'; -export { ArrayCoder } from './encoding/coders/v0/ArrayCoder'; -export { B256Coder } from './encoding/coders/v0/B256Coder'; -export { B512Coder } from './encoding/coders/v0/B512Coder'; -export { BooleanCoder } from './encoding/coders/v0/BooleanCoder'; -export { ByteCoder } from './encoding/coders/v0/ByteCoder'; -export { EnumCoder } from './encoding/coders/v0/EnumCoder'; -export { OptionCoder } from './encoding/coders/v0/OptionCoder'; -export { NumberCoder } from './encoding/coders/v0/NumberCoder'; -export { RawSliceCoder } from './encoding/coders/v0/RawSliceCoder'; -export { StdStringCoder } from './encoding/coders/v0/StdStringCoder'; -export { StringCoder } from './encoding/coders/v0/StringCoder'; -export { StructCoder } from './encoding/coders/v0/StructCoder'; -export { TupleCoder } from './encoding/coders/v0/TupleCoder'; -export { VecCoder } from './encoding/coders/v0/VecCoder'; export type { FunctionFragment } from './FunctionFragment'; +export * from './encoding/coders'; export { Interface } from './Interface'; export { JsonAbi } from './types/JsonAbi'; export { @@ -26,7 +13,5 @@ export { BYTES_32, calculateVmTxMemory, type EncodingVersion, - ENCODING_V0, ENCODING_V1, } from './utils/constants'; -export { BigNumberCoder } from './encoding/coders/v0/BigNumberCoder'; diff --git a/packages/abi-coder/src/types/EncodingOptions.ts b/packages/abi-coder/src/types/EncodingOptions.ts index 7577288937..df14a41cec 100644 --- a/packages/abi-coder/src/types/EncodingOptions.ts +++ b/packages/abi-coder/src/types/EncodingOptions.ts @@ -6,59 +6,21 @@ import type { EncodingVersion } from '../utils/constants'; * Firstly we should consider the encoding version being used. For more info on this * please refer to the fuel specs (https://github.com/FuelLabs/fuel-specs); * - * Encoding Version 0: - * - * This is the currently supported version. It offers the following configurable options - * regarding the encoding of small bytes: - * - * These options relates only to: - * - NumberCoder (u8, u16, u32) - * - BooleanCoder - * - * 1) isSmallBytes (default=false) - * - * Describes how many bytes it will occupy: - * - * false — occupies 8 bytes (default), and should be used when underneath: - * • standalone - * • tuple - * • struct - * • enum - * - * true — occupies 1 byte, and should be used when underneath: - * • array - * • vector - * - * - * - * 2) isRightPadded (default=false) - * - * Used only when `isSmallBytes` is FALSE. - * - * Describes how the padding should happen: - * - * false —— left padded (default), and should be used when underneath: - * • standalone - * • array - * • vector - * • enum - * • only one function argument + * Encoding Version 1: * - * true —— right padded, and should be used when underneath: - * • struct - * • tuple - * • multiple function arguments - * • configurable + * As version 1 aims to make call data as compact as possible, types are only using their required + * property space. In the VM, they are still padded. Therefore the following option is available: * + * 1) padToWordSize (default=false) * - * Encoding Version 1: + * Describes if the encoding should be padded to the word size. * - * It currently is supported only by logs, but has no specific configurable options. - * More information on the improvements made in this version can be found in the - * fuel specs (https://github.com/FuelLabs/fuel-specs/blob/master/src/abi/argument-encoding.md#version-1 + * false —— no padding (default). + * true —— padding to the word size, and should be used when underneath: + * • number(u8, u16, u32) + * • boolean */ export type EncodingOptions = { encoding?: EncodingVersion; - isSmallBytes?: boolean; - isRightPadded?: boolean; + padToWordSize?: boolean; }; diff --git a/packages/abi-coder/src/utils/constants.ts b/packages/abi-coder/src/utils/constants.ts index d8e37a076c..a533ddf8f5 100644 --- a/packages/abi-coder/src/utils/constants.ts +++ b/packages/abi-coder/src/utils/constants.ts @@ -25,9 +25,8 @@ export const genericRegEx = /^generic (?\w+)$/; /** * Encoding versions */ -export const ENCODING_V0 = '0'; export const ENCODING_V1 = '1'; -export type EncodingVersion = typeof ENCODING_V0 | typeof ENCODING_V1; +export type EncodingVersion = typeof ENCODING_V1; /** * Property space and config constants diff --git a/packages/abi-coder/src/utils/json-abi.test.ts b/packages/abi-coder/src/utils/json-abi.test.ts index 243f77b466..853530c87b 100644 --- a/packages/abi-coder/src/utils/json-abi.test.ts +++ b/packages/abi-coder/src/utils/json-abi.test.ts @@ -1,7 +1,7 @@ import type { ResolvedAbiType } from '../ResolvedAbiType'; import type { JsonAbi, JsonAbiArgument } from '../types/JsonAbi'; -import { ENCODING_V0, ENCODING_V1 } from './constants'; +import { ENCODING_V1 } from './constants'; import { findFunctionByName, findNonEmptyInputs, @@ -22,7 +22,7 @@ const MOCK_ABI: JsonAbi = { configurables: [], }; -const DEFAULT_ENCODING_VERSION = '0'; +const DEFAULT_ENCODING_VERSION = ENCODING_V1; /** * @group node @@ -39,16 +39,13 @@ describe('json-abi', () => { expect(actual).toBe(expected); }); - it.each([ENCODING_V0, ENCODING_V1])( - 'should return the encoding version (when defined)', - (version) => { - const expected = version; + it('should return the encoding version (when defined)', () => { + const expected = ENCODING_V1; - const actual = getEncodingVersion(version); + const actual = getEncodingVersion(ENCODING_V1); - expect(actual).toBe(expected); - } - ); + expect(actual).toBe(expected); + }); it('should throw an error if the encoding version is not supported', () => { const encodingVersion = '-1'; diff --git a/packages/abi-coder/src/utils/json-abi.ts b/packages/abi-coder/src/utils/json-abi.ts index 1e6abf579b..753244174a 100644 --- a/packages/abi-coder/src/utils/json-abi.ts +++ b/packages/abi-coder/src/utils/json-abi.ts @@ -3,7 +3,7 @@ import { ErrorCode, FuelError } from '@fuel-ts/errors'; import type { ResolvedAbiType } from '../ResolvedAbiType'; import type { JsonAbi, JsonAbiArgument, JsonAbiFunction, JsonAbiType } from '../types/JsonAbi'; -import { ENCODING_V0, ENCODING_V1, type EncodingVersion } from './constants'; +import { ENCODING_V1, type EncodingVersion } from './constants'; /** * Asserts that the encoding version is supported by the ABI coder. @@ -15,9 +15,6 @@ import { ENCODING_V0, ENCODING_V1, type EncodingVersion } from './constants'; export const getEncodingVersion = (encoding?: string): EncodingVersion => { switch (encoding) { case undefined: - case ENCODING_V0: - return ENCODING_V0; - case ENCODING_V1: return ENCODING_V1; diff --git a/packages/abi-coder/src/utils/utilities.test.ts b/packages/abi-coder/src/utils/utilities.test.ts deleted file mode 100644 index d0e04ab529..0000000000 --- a/packages/abi-coder/src/utils/utilities.test.ts +++ /dev/null @@ -1,292 +0,0 @@ -import { concat } from '@fuel-ts/utils'; - -import type { Uint8ArrayWithDynamicData } from './utilities'; -import { unpackDynamicData, concatWithDynamicData } from './utilities'; - -/** - * @group node - * @group browser - */ -describe('Abi Coder Utilities', () => { - it('can concatWithVectorData [no dynamicData, should match original concat]', () => { - const data1 = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 24]); - const data2 = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 4]); - const data3 = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 4]); - const data4 = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 16]); - const EXPECTED = concat([data1, data2, data3, data4]); - - const RESULT = concatWithDynamicData([data1, data2, data3, data4]); - expect(RESULT).toEqual(EXPECTED); - }); - - it('can concatWithVectorData [relocate single dynamicData]', () => { - const pointer: Uint8ArrayWithDynamicData = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 24]); - pointer.dynamicData = { 0: new Uint8Array([0, 0, 0, 0, 0, 0, 0, 36]) }; - const capacity = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 4]); - const length = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 4]); - const someData = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 16]); - const EXPECTED: Uint8ArrayWithDynamicData = concat([pointer, capacity, length, someData]); - EXPECTED.dynamicData = { 0: new Uint8Array([0, 0, 0, 0, 0, 0, 0, 36]) }; - - const RESULT = concatWithDynamicData([pointer, capacity, length, someData]); - expect(RESULT).toEqual(EXPECTED); - - // is idempotent - const RESULT_NEW = concatWithDynamicData([RESULT]); - expect(RESULT_NEW).toEqual(EXPECTED); - }); - - it('can concatWithVectorData [two distinct dynamicData]', () => { - const pointer = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 24]); - const capacity = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 4]); - const length = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 4]); - const EXPECTED: Uint8ArrayWithDynamicData = concat([ - pointer, - capacity, - length, - pointer, - capacity, - length, - ]); - EXPECTED.dynamicData = { - 0: new Uint8Array([0, 0, 0, 0, 0, 0, 0, 36]), - 3: new Uint8Array([0, 0, 0, 0, 0, 0, 0, 36]), - }; - - const arrayWithVectorData: Uint8ArrayWithDynamicData = concat([pointer, capacity, length]); - arrayWithVectorData.dynamicData = { 0: new Uint8Array([0, 0, 0, 0, 0, 0, 0, 36]) }; - - const RESULT = concatWithDynamicData([arrayWithVectorData, arrayWithVectorData]); - - expect(RESULT).toEqual(EXPECTED); - - // is idempotent - const RESULT_NEW = concatWithDynamicData([RESULT]); - expect(RESULT_NEW).toEqual(EXPECTED); - }); - - it('can concatWithVectorData [three distinct dynamicData]', () => { - const pointer = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 24]); - const capacity = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 4]); - const length = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 4]); - const EXPECTED: Uint8ArrayWithDynamicData = concat([ - pointer, - capacity, - length, - pointer, - capacity, - length, - pointer, - capacity, - length, - ]); - EXPECTED.dynamicData = { - 0: new Uint8Array([0, 0, 0, 0, 0, 0, 0, 33]), - 3: new Uint8Array([0, 0, 0, 0, 0, 0, 0, 35]), - 6: new Uint8Array([0, 0, 0, 0, 0, 0, 0, 37]), - }; - - const arrayWithVectorData1: Uint8ArrayWithDynamicData = concat([pointer, capacity, length]); - const arrayWithVectorData2: Uint8ArrayWithDynamicData = concat([pointer, capacity, length]); - const arrayWithVectorData3: Uint8ArrayWithDynamicData = concat([pointer, capacity, length]); - arrayWithVectorData1.dynamicData = { 0: new Uint8Array([0, 0, 0, 0, 0, 0, 0, 33]) }; - arrayWithVectorData2.dynamicData = { 0: new Uint8Array([0, 0, 0, 0, 0, 0, 0, 35]) }; - arrayWithVectorData3.dynamicData = { 0: new Uint8Array([0, 0, 0, 0, 0, 0, 0, 37]) }; - - const RESULT = concatWithDynamicData([ - arrayWithVectorData1, - arrayWithVectorData2, - arrayWithVectorData3, - ]); - - expect(RESULT).toEqual(EXPECTED); - - // is idempotent - const RESULT_NEW = concatWithDynamicData([RESULT]); - expect(RESULT_NEW).toEqual(EXPECTED); - }); - - it('can concatWithVectorData [relocate three dynamicData]', () => { - const pointerA: Uint8ArrayWithDynamicData = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 24]); - pointerA.dynamicData = { 0: new Uint8Array([0, 0, 0, 0, 0, 0, 0, 33]) }; - const pointerB: Uint8ArrayWithDynamicData = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 24]); - pointerB.dynamicData = { 0: new Uint8Array([0, 0, 0, 0, 0, 0, 0, 12]) }; - const pointerC: Uint8ArrayWithDynamicData = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 24]); - pointerC.dynamicData = { 0: new Uint8Array([0, 0, 0, 0, 0, 0, 0, 4]) }; - const capacity = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 4]); - const length = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 4]); - const someData = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 16]); - const EXPECTED: Uint8ArrayWithDynamicData = concat([ - pointerA, - capacity, - length, - pointerB, - capacity, - length, - pointerC, - capacity, - length, - someData, - ]); - EXPECTED.dynamicData = { - 0: new Uint8Array([0, 0, 0, 0, 0, 0, 0, 33]), - 3: new Uint8Array([0, 0, 0, 0, 0, 0, 0, 12]), - 6: new Uint8Array([0, 0, 0, 0, 0, 0, 0, 4]), - }; - - const RESULT = concatWithDynamicData([ - pointerA, - capacity, - length, - pointerB, - capacity, - length, - pointerC, - capacity, - length, - someData, - ]); - - expect(RESULT).toEqual(EXPECTED); - - // is idempotent - const RESULT_NEW = concatWithDynamicData([RESULT]); - expect(RESULT_NEW).toEqual(EXPECTED); - }); - - it('can concatWithVectorData [with dynamicData in middle, should relocate]', () => { - const otherData = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 9]); - const pointer: Uint8ArrayWithDynamicData = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 24]); - pointer.dynamicData = { 0: new Uint8Array([0, 0, 0, 0, 0, 0, 0, 36]) }; - const capacity = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 4]); - const length = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 4]); - const data = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 16]); - const EXPECTED: Uint8ArrayWithDynamicData = concat([ - otherData, - pointer, - capacity, - length, - data, - ]); - EXPECTED.dynamicData = { 2: new Uint8Array([0, 0, 0, 0, 0, 0, 0, 36]) }; - - const RESULT = concatWithDynamicData([otherData, pointer, capacity, length, data]); - - expect(RESULT).toEqual(EXPECTED); - - // is idempotent - const RESULT_NEW = concatWithDynamicData([RESULT]); - expect(RESULT_NEW).toEqual(EXPECTED); - }); - - it('can unpackDynamicData [with dynamicData]', () => { - const results: Uint8ArrayWithDynamicData = new Uint8Array([ - 0, 0, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, - 24, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, - ]); - const DATA_1 = new Uint8Array([ - 0, 0, 0, 0, 0, 0, 0, 29, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 7, 228, 0, 0, 0, 0, 0, 0, - 0, 12, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 7, 227, - ]); - const DATA_2 = new Uint8Array([ - 0, 0, 0, 0, 0, 0, 0, 22, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 7, 188, - ]); - results.dynamicData = { - 0: new Uint8Array(DATA_1), - 3: new Uint8Array(DATA_2), - }; - const BASE_OFFSET = 0; - const DATA_OFFSET = 0; - // prettier-ignore - const EXPECTED = new Uint8Array([ - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 2, - 0, 0, 0, 0, 0, 0, 0, 2, - 0, 0, 0, 0, 0, 0, 0, 48, - 0, 0, 0, 0, 0, 0, 0, 1, - 0, 0, 0, 0, 0, 0, 0, 1, - ...DATA_1, - ...DATA_2, - ]); - - const RESULT = unpackDynamicData(results, BASE_OFFSET, DATA_OFFSET); - - expect(RESULT).toEqual(EXPECTED); - }); - - it('can unpackDynamicData [with dynamicData before regular data]', () => { - const results: Uint8ArrayWithDynamicData = new Uint8Array([ - 0, 0, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, - 0, 2, - ]); - const DATA_1 = new Uint8Array([ - 0, 0, 0, 0, 0, 0, 0, 29, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 7, 228, 0, 0, 0, 0, 0, 0, - 0, 12, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 7, 227, - ]); - const DATA_2 = new Uint8Array([ - 0, 0, 0, 0, 0, 0, 0, 22, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 7, 188, - ]); - results.dynamicData = { - 0: new Uint8Array(DATA_1), - 4: new Uint8Array(DATA_2), - }; - const BASE_OFFSET = 0; - const DATA_OFFSET = 0; - // prettier-ignore - const EXPECTED = new Uint8Array([ - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 2, - 0, 0, 0, 0, 0, 0, 0, 2, - 0, 0, 0, 0, 0, 0, 0, 1, - 0, 0, 0, 0, 0, 0, 0, 48, - 0, 0, 0, 0, 0, 0, 0, 1, - 0, 0, 0, 0, 0, 0, 0, 1, - 0, 0, 0, 0, 0, 0, 0, 2, - ...DATA_1, - ...DATA_2, - ]); - - const RESULT = unpackDynamicData(results, BASE_OFFSET, DATA_OFFSET); - - expect(RESULT).toEqual(EXPECTED); - }); - - it('can unpackDynamicData [with dynamicData before regular data, with offset]', () => { - const results: Uint8ArrayWithDynamicData = new Uint8Array([ - 0, 0, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, - 0, 2, - ]); - const DATA_1 = new Uint8Array([ - 0, 0, 0, 0, 0, 0, 0, 29, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 7, 228, 0, 0, 0, 0, 0, 0, - 0, 12, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 7, 227, - ]); - const DATA_2 = new Uint8Array([ - 0, 0, 0, 0, 0, 0, 0, 22, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 7, 188, - ]); - results.dynamicData = { - 0: new Uint8Array(DATA_1), - 4: new Uint8Array(DATA_2), - }; - const BASE_OFFSET = 12584; - const DATA_OFFSET = 352; - // prettier-ignore - const EXPECTED = new Uint8Array([ - 0, 0, 0, 0, 0, 0, 50, 136, - 0, 0, 0, 0, 0, 0, 0, 2, - 0, 0, 0, 0, 0, 0, 0, 2, - 0, 0, 0, 0, 0, 0, 0, 1, - 0, 0, 0, 0, 0, 0, 50, 184, - 0, 0, 0, 0, 0, 0, 0, 1, - 0, 0, 0, 0, 0, 0, 0, 1, - 0, 0, 0, 0, 0, 0, 0, 2, - ...DATA_1, - ...DATA_2, - ]); - - const RESULT = unpackDynamicData(results, BASE_OFFSET, DATA_OFFSET); - - expect(RESULT).toEqual(EXPECTED); - }); -}); diff --git a/packages/abi-coder/src/utils/utilities.ts b/packages/abi-coder/src/utils/utilities.ts index 1f096dafef..00626d1938 100644 --- a/packages/abi-coder/src/utils/utilities.ts +++ b/packages/abi-coder/src/utils/utilities.ts @@ -1,95 +1,4 @@ -import type { BytesLike } from '@fuel-ts/interfaces'; -import { concat, concatBytes, arrayify } from '@fuel-ts/utils'; - -import { BigNumberCoder } from '../encoding/coders/v0/BigNumberCoder'; - -import { BYTES_CODER_TYPE, VEC_CODER_TYPE, STD_STRING_CODER_TYPE, WORD_SIZE } from './constants'; - -export type DynamicData = { - [pointerIndex: number]: Uint8ArrayWithDynamicData; -}; - -export type Uint8ArrayWithDynamicData = Uint8Array & { - dynamicData?: DynamicData; -}; - -const VEC_PROPERTY_SPACE = 3; // ptr + cap + length -export const BASE_VECTOR_OFFSET = VEC_PROPERTY_SPACE * WORD_SIZE; - -const RAW_SLICE_PROPERTY_SPACE = 2; // ptr + length -export const BASE_RAW_SLICE_OFFSET = RAW_SLICE_PROPERTY_SPACE * WORD_SIZE; - -// this is a fork of @ethersproject/bytes:concat -// this collects individual dynamicData data and relocates it to top level -export function concatWithDynamicData(items: ReadonlyArray): Uint8ArrayWithDynamicData { - const topLevelData: DynamicData = {}; - - let totalIndex = 0; - const objects = items.map((item) => { - const dynamicData = (item as Uint8ArrayWithDynamicData).dynamicData; - if (dynamicData) { - Object.entries(dynamicData).forEach(([pointerIndex, vData]) => { - topLevelData[parseInt(pointerIndex, 10) + totalIndex] = vData; - }); - } - - const byteArray = arrayify(item); - totalIndex += byteArray.byteLength / WORD_SIZE; - - return byteArray; - }); - - const length = objects.reduce((accum, item) => accum + item.length, 0); - const result: Uint8ArrayWithDynamicData = new Uint8Array(length); - - objects.reduce((offset, object) => { - result.set(object, offset); - return offset + object.length; - }, 0); - - // store vector data and pointer indices, but only if data exist - if (Object.keys(topLevelData).length) { - result.dynamicData = topLevelData; - } - - return result; -} - -export function unpackDynamicData( - results: Uint8ArrayWithDynamicData, - baseOffset: number, - dataOffset: number -): Uint8Array { - if (!results.dynamicData) { - return concat([results]); - } - - let cumulativeDynamicByteLength = 0; - let updatedResults = results; - Object.entries(results.dynamicData).forEach(([pointerIndex, vData]) => { - // update value of pointer - const pointerOffset = parseInt(pointerIndex, 10) * WORD_SIZE; - const adjustedValue = new BigNumberCoder('u64').encode( - dataOffset + baseOffset + cumulativeDynamicByteLength - ); - updatedResults.set(adjustedValue, pointerOffset); - - // append dynamic data at the end - const dataToAppend = vData.dynamicData - ? // unpack child dynamic data - unpackDynamicData( - vData, - baseOffset, - dataOffset + vData.byteLength + cumulativeDynamicByteLength - ) - : vData; - updatedResults = concat([updatedResults, dataToAppend]); - - cumulativeDynamicByteLength += dataToAppend.byteLength; - }); - - return updatedResults; -} +import { WORD_SIZE } from './constants'; /** * Turns: @@ -124,44 +33,4 @@ export const chunkByLength = (data: Uint8Array, length = WORD_SIZE): Uint8Array[ return chunks; }; -/** - * Checks if a given type is a pointer type - * See: https://github.com/FuelLabs/sway/issues/1368 - */ -export const isPointerType = (type: string) => { - switch (type) { - case 'u8': - case 'u16': - case 'u32': - case 'u64': - case 'bool': { - return false; - } - default: { - return true; - } - } -}; - -export const isHeapType = (type: string) => - type === VEC_CODER_TYPE || type === BYTES_CODER_TYPE || type === STD_STRING_CODER_TYPE; - -/** - * Because some properties can be single-bytes, we need to pad them - * with zeros until they are aligned to a word-sized increment. - * This is the case for `tuple` and `struct` properties. - * Please refer to packages/abi-coder/src/coders/abstract-coder.ts for more details - */ -export const isMultipleOfWordSize = (length: number) => length % WORD_SIZE === 0; - -export const getWordSizePadding = (length: number) => WORD_SIZE - (length % WORD_SIZE); - -export const rightPadToWordSize = (encoded: Uint8Array) => { - if (isMultipleOfWordSize(encoded.length)) { - return encoded; - } - const padding = new Uint8Array(WORD_SIZE - (encoded.length % WORD_SIZE)); - return concatBytes([encoded, padding]); -}; - export const isUint8Array = (value: unknown): value is Uint8Array => value instanceof Uint8Array; diff --git a/packages/abi-coder/test/Interface.test.ts b/packages/abi-coder/test/Interface.test.ts index 55fc386f02..d93c26ca5f 100644 --- a/packages/abi-coder/test/Interface.test.ts +++ b/packages/abi-coder/test/Interface.test.ts @@ -135,7 +135,7 @@ describe('Abi interface', () => { it('encodes configurables', () => { const encoded = exhaustiveExamplesInterface.encodeConfigurable('U8', 55); - expect(encoded).toEqual(new Uint8Array([55, 0, 0, 0, 0, 0, 0, 0])); + expect(encoded).toEqual(new Uint8Array([55])); }); it('throws when encoding non-existent configurable', () => { @@ -599,8 +599,8 @@ describe('Abi interface', () => { '$title: $value', ({ fn, title: _title, value, encodedValue, decodedTransformer, offset, skipDecoding }) => { const encoded = Array.isArray(value) - ? fn.encodeArguments(value, offset) - : fn.encodeArguments([value], offset); + ? fn.encodeArguments(value) + : fn.encodeArguments([value]); const encodedVal = encodedValue instanceof Function ? encodedValue(value, offset) : encodedValue; diff --git a/packages/abi-typegen/test/fixtures/templates/contract/bytecode.hbs b/packages/abi-typegen/test/fixtures/templates/contract/bytecode.hbs index e24f89fb66..77bfba6625 100644 --- a/packages/abi-typegen/test/fixtures/templates/contract/bytecode.hbs +++ b/packages/abi-typegen/test/fixtures/templates/contract/bytecode.hbs @@ -9,4 +9,4 @@ Fuel-Core version: 33.33.33 */ -export default '0x1af030007400000200000000000004405dffc00110ffff00740000001aec5000910001a85d43f009104100c01a4460005d4d10491b441000104934405d47f002104404405d4920001b44144010453440504fb0205fed10045fed20055047b19872500010284535005047b198504fb08072500010284d15005d453000504fb0105fed10025fed20035047b17872480010284534805047b1785fed00005d43f0035fed00015043b058724800102843b480504bb0e8724c0010284914c01ae9200020f8330058fbe00250fbe004740000991a4bd000504fb0f872500010284d05001ae9300020f8330058fbe00250fbe004740000901a4fd000134924c0134920001a4c00007648001c504bb118724c0010284914c01ae9200020f8330058fbe00250fbe004740000931a4bd000504fb12872500010284d05001ae9300020f8330058fbe00250fbe0047400008a1a43d000504fb10872500010284d15001ae9300020f8330058fbe00250fbe004740000711a47d000294d2411764c00017400006b1a4060005d41004a5fed002a5fec002b5043b1505047b0c81ae900001ae5100020f8330058fbe00250fbe004740000815047b0d81ae900001ae5100020f8330058fbe00250fbe0047400007a5d43f005264000001a4070005fed002c5d43f0055fed002d5fec002e504fb1605d43b02c5d47b02d5d4bb02e10492040165114807650000113511480765000065043b0685fec000d5047b13872480018284504807400000d12492440104920401b49148026480000281d04401a4470005043b0305fec10065fed10075fed20085047b13872480018284504805043b0b072480018284114805d43b027134100007640000f5d43b01613410040764000025d43f006364000005043b0b0504100085047b0b0504510085045100872480008284d04805041300872480008284114805d4130005d4530021b441440104104401a4410005e4110005d413002104100405f4d00025043b16050450010504bb048724c0008284904c050412008724c0008284114c05043b18872440010284124405043b1885047b09072480010284504805d4110005047b188504bb0a0724c0010284914c05d45200112451040254110005d43f0073640000095000007960800001aec5000910000101a43a0001a47e0007248001028ed04801a43b0005d4100011af50000920000101af9100098080000970000074af8000095000007960800001aec5000910000101a43a0001a47e0007248001028ed04801a43b0005d4100001af50000920000101af9100098080000970000074af800009500007f960800001aec5000910000301a43a0001a4790001a4be0005d4d00015d53f008104d35005d5100005d5500011b541540105145405fed40005d53f0085fed40011a53b0005057b02072580010285545805f4130015043b020504fb01072500010284d05005d413000724c0010284504c01af51000920000301af92000980800009700007f4af800006d61696e0000000000000000000002480000000000000008000000000000000400000000000002500000000000000400cccccccccccc0002000000000000007b000000000000000a0000000000000418' +export default '0x1af030007400000200000000000003e85dffc00110ffff00740000001aec5000910001f05d43f009104100c01a4460005d4d10491b441000104934405d47f002104404405d4920001b44144010453440504fb0205fed10045fed20055047b1e072500010284535005047b1e0504fb0c872500010284d15005d453000504fb0105fed10025fed20035047b1c072480010284534805047b1c05fed00005d43f0035fed00015043b078724800102843b480504bb148724c0010284914c01ae9200020f8330058fbe00250fbe004740000821a4bd000504fb15872500010284d05001ae9300020f8330058fbe00250fbe004740000791a4fd000134924c0134920001a4c00007648001c504bb178724c0010284914c01ae9200020f8330058fbe00250fbe0047400007c1a4bd000504fb18872500010284d05001ae9300020f8330058fbe00250fbe004740000731a43d000504fb16872500010284d15001ae9300020f8330058fbe00250fbe0047400005a1a47d000294d2411764c0001740000541a4060005d41004a5fed00335fec00345043b1985047b1281ae900001ae5100020f8330058fbe00250fbe0047400006a5047b1381ae900001ae5100020f8330058fbe00250fbe004740000635d43f005264000001a4070005047b0605fed000c5d43f0055fed000d5fec000e5043b08872480018284114805047b0d872480018284504805043b03072480018284114805d47b006504100085d4bb008104d14805c53f0305e4d400010492040504fb0a05fed10145045300872500008284505005fed20165d4930005d4130015d4530025fed20355fed00365fed10375043b1a85047b0f072480018284504805043b04872480018284114805d47b00950410010504bb0b85fed101750452008724c0008284504c05043b1d072440010284124405043b1d05047b10872480010284504805d4110005047b1d0504bb118724c0010284914c05d45200112451040254110005d43f0073640000095000007960800001aec5000910000101a43a0001a47e0007248001028ed04801a43b0005d4100011af50000920000101af9100098080000970000074af8000095000007960800001aec5000910000101a43a0001a47e0007248001028ed04801a43b0005d4100001af50000920000101af9100098080000970000074af800009500007f960800001aec5000910000301a43a0001a4790001a4be0005d4d00015d53f008104d35005d5100005d5500011b541540105145405fed40005d53f0085fed40011a53b0005057b02072580010285545805f4130015043b020504fb01072500010284d05005d413000724c0010284504c01af51000920000301af92000980800009700007f4af80000470000006d61696e00000000000000000000024800000000000000080000000000000004000000000000025000000000000004000100000000000000000000000000007b000000000000000a00000000000003c0' 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 index 45410e3e6c..fc0cb34b88 100644 --- a/packages/abi-typegen/test/fixtures/templates/predicate-with-configurable/factory.hbs +++ b/packages/abi-typegen/test/fixtures/templates/predicate-with-configurable/factory.hbs @@ -78,7 +78,7 @@ const _abi = { "type": 2, "typeArguments": null }, - "offset": 224 + "offset": 560 }, { "name": "ADDRESS", @@ -87,7 +87,7 @@ const _abi = { "type": 0, "typeArguments": null }, - "offset": 232 + "offset": 576 } ] } 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 index 5056d8c91c..3fc28762ed 100644 --- a/packages/abi-typegen/test/fixtures/templates/script-with-configurable/factory.hbs +++ b/packages/abi-typegen/test/fixtures/templates/script-with-configurable/factory.hbs @@ -86,7 +86,7 @@ const _abi = { "type": 0, "typeArguments": null }, - "offset": 496 + "offset": 536 } ] } diff --git a/packages/account/src/account.ts b/packages/account/src/account.ts index 9995d8d9a4..d62faa37dc 100644 --- a/packages/account/src/account.ts +++ b/packages/account/src/account.ts @@ -301,7 +301,6 @@ export class Account extends AbstractAccount { ); request.addResources(resources); - request.shiftPredicateData(); request.updatePredicateGasUsed(estimatedPredicates); const requestToReestimate = clone(request); @@ -340,7 +339,6 @@ export class Account extends AbstractAccount { fundingAttempts += 1; } - request.shiftPredicateData(); request.updatePredicateGasUsed(estimatedPredicates); const requestToReestimate = clone(request); diff --git a/packages/account/src/predicate/predicate.ts b/packages/account/src/predicate/predicate.ts index 8cf86a9840..c16d07f3f9 100644 --- a/packages/account/src/predicate/predicate.ts +++ b/packages/account/src/predicate/predicate.ts @@ -1,21 +1,13 @@ import type { JsonAbi, InputValue } from '@fuel-ts/abi-coder'; -import { - Interface, - INPUT_COIN_FIXED_SIZE, - WORD_SIZE, - calculateVmTxMemory, - SCRIPT_FIXED_SIZE, -} from '@fuel-ts/abi-coder'; +import { Interface } from '@fuel-ts/abi-coder'; import { Address } from '@fuel-ts/address'; import { ErrorCode, FuelError } from '@fuel-ts/errors'; import type { BytesLike } from '@fuel-ts/interfaces'; -import { ByteArrayCoder } from '@fuel-ts/transactions'; import { arrayify, hexlify } from '@fuel-ts/utils'; import { Account } from '../account'; import { transactionRequestify, - BaseTransactionRequest, isRequestInputResource, isRequestInputResourceFromOwner, } from '../providers'; @@ -90,8 +82,6 @@ export class Predicate extends Account { ) { const request = transactionRequestify(transactionRequestLike) as T; - const { policies } = BaseTransactionRequest.getPolicyMeta(request); - const placeholderIndex = this.getIndexFromPlaceholderWitness(request); if (placeholderIndex !== -1) { @@ -103,7 +93,7 @@ export class Predicate extends Account { // eslint-disable-next-line no-param-reassign input.predicate = hexlify(this.bytes); // eslint-disable-next-line no-param-reassign - input.predicateData = hexlify(this.getPredicateData(policies.length)); + input.predicateData = hexlify(this.getPredicateData()); // eslint-disable-next-line no-param-reassign input.witnessIndex = 0; } @@ -134,26 +124,13 @@ export class Predicate extends Account { return super.simulateTransaction(transactionRequest, { estimateTxDependencies: false }); } - private getPredicateData(policiesLength: number): Uint8Array { + private getPredicateData(): Uint8Array { if (!this.predicateData.length) { return new Uint8Array(); } const mainFn = this.interface?.functions.main; - const paddedCode = new ByteArrayCoder(this.bytes.length).encode(this.bytes); - - const VM_TX_MEMORY = calculateVmTxMemory({ - maxInputs: this.provider.getChain().consensusParameters.txParameters.maxInputs.toNumber(), - }); - const OFFSET = - VM_TX_MEMORY + - SCRIPT_FIXED_SIZE + - INPUT_COIN_FIXED_SIZE + - WORD_SIZE + - paddedCode.byteLength + - policiesLength * WORD_SIZE; - - return mainFn?.encodeArguments(this.predicateData, OFFSET) || new Uint8Array(); + return mainFn?.encodeArguments(this.predicateData) || new Uint8Array(); } /** @@ -215,7 +192,6 @@ export class Predicate extends Account { return resources.map((resource) => ({ ...resource, predicate: hexlify(this.bytes), - padPredicateData: (policiesLength: number) => hexlify(this.getPredicateData(policiesLength)), })); } diff --git a/packages/account/src/providers/coin.ts b/packages/account/src/providers/coin.ts index 1c71db35a7..ce7cffb774 100644 --- a/packages/account/src/providers/coin.ts +++ b/packages/account/src/providers/coin.ts @@ -13,5 +13,4 @@ export type Coin = { txCreatedIdx: BN; predicate?: BytesLike; predicateData?: BytesLike; - padPredicateData?: (policiesLenght: number) => BytesLike; }; diff --git a/packages/account/src/providers/message.ts b/packages/account/src/providers/message.ts index dcafe0abc0..886f68e4e1 100644 --- a/packages/account/src/providers/message.ts +++ b/packages/account/src/providers/message.ts @@ -27,7 +27,6 @@ export type MessageCoin = { daHeight: BN; predicate?: BytesLike; predicateData?: BytesLike; - padPredicateData?: (policiesLenght: number) => BytesLike; }; export type MerkleProof = { diff --git a/packages/account/src/providers/transaction-request/input.ts b/packages/account/src/providers/transaction-request/input.ts index 57ec20c7a0..3a3216058a 100644 --- a/packages/account/src/providers/transaction-request/input.ts +++ b/packages/account/src/providers/transaction-request/input.ts @@ -37,8 +37,6 @@ export type CoinTransactionRequestInput = { /** Predicate input data (parameters) */ predicateData?: BytesLike; - - padPredicateData?: (policiesLenght: number) => BytesLike; }; export type MessageTransactionRequestInput = { @@ -68,8 +66,6 @@ export type MessageTransactionRequestInput = { /** Predicate input data (parameters) */ predicateData?: BytesLike; - padPredicateData?: (policiesLenght: number) => BytesLike; - /** data of message */ data?: BytesLike; }; diff --git a/packages/account/src/providers/transaction-request/transaction-request.ts b/packages/account/src/providers/transaction-request/transaction-request.ts index 33b4e15da6..135c6db764 100644 --- a/packages/account/src/providers/transaction-request/transaction-request.ts +++ b/packages/account/src/providers/transaction-request/transaction-request.ts @@ -688,20 +688,4 @@ export abstract class BaseTransactionRequest implements BaseTransactionRequestLi } }); } - - shiftPredicateData() { - this.inputs.forEach((input) => { - // TODO: improve logic - if ( - 'predicateData' in input && - 'padPredicateData' in input && - typeof input.padPredicateData === 'function' - ) { - // eslint-disable-next-line no-param-reassign - input.predicateData = input.padPredicateData( - BaseTransactionRequest.getPolicyMeta(this).policies.length - ); - } - }); - } } diff --git a/packages/account/src/providers/transaction-summary/call.ts b/packages/account/src/providers/transaction-summary/call.ts index 4cf9cd24d8..f1aa0f9f22 100644 --- a/packages/account/src/providers/transaction-summary/call.ts +++ b/packages/account/src/providers/transaction-summary/call.ts @@ -1,6 +1,5 @@ -import { Interface, type JsonAbi, calculateVmTxMemory } from '@fuel-ts/abi-coder'; +import { Interface, type JsonAbi } from '@fuel-ts/abi-coder'; import type { BN } from '@fuel-ts/math'; -import { bn } from '@fuel-ts/math'; import type { ReceiptCall } from '@fuel-ts/transactions'; type GetFunctionCallProps = { @@ -10,51 +9,33 @@ type GetFunctionCallProps = { maxInputs: BN; }; -export const getFunctionCall = ({ abi, receipt, rawPayload, maxInputs }: GetFunctionCallProps) => { +export const getFunctionCall = ({ abi, receipt }: GetFunctionCallProps) => { const abiInterface = new Interface(abi); const callFunctionSelector = receipt.param1.toHex(8); const functionFragment = abiInterface.getFunction(callFunctionSelector); const inputs = functionFragment.jsonFn.inputs; - let encodedArgs; - - // if has more than 1 input or input type is bigger than 8 bytes, then it's a pointer to data - if (functionFragment.isInputDataPointer) { - if (rawPayload) { - // calculate offset to get function params from rawPayload. should also consider vm offset - const argsOffset = bn(receipt.param2) - .sub(calculateVmTxMemory({ maxInputs: maxInputs.toNumber() })) - .toNumber(); - - // slice(2) to remove first 0x, then slice again to remove offset and get only args - encodedArgs = `0x${rawPayload.slice(2).slice(argsOffset * 2)}`; - } - } else { - // for small inputs, param2 is directly the value - encodedArgs = receipt.param2.toHex(); - } - + const encodedArgs = receipt.param2.toHex(); let argumentsProvided; - if (encodedArgs) { - // use bytes got from rawPayload to decode function params - const data = functionFragment.decodeArguments(encodedArgs); - if (data) { - // put together decoded data with input names from abi - argumentsProvided = inputs.reduce((prev, input, index) => { - const value = data[index]; - const name = input.name; - - if (name) { - return { - ...prev, - // reparse to remove bn - [name]: JSON.parse(JSON.stringify(value)), - }; - } - return prev; - }, {}); - } + // use bytes got from rawPayload to decode function params + const data = functionFragment.decodeArguments(encodedArgs); + if (data) { + // put together decoded data with input names from abi + argumentsProvided = inputs.reduce((prev, input, index) => { + const value = data[index]; + const name = input.name; + + if (name) { + return { + ...prev, + // reparse to remove bn + [name]: JSON.parse(JSON.stringify(value)), + }; + } + + return prev; + }, {}); } const call = { diff --git a/packages/forc/VERSION b/packages/forc/VERSION index 25a153f0a9..a60476bfe1 100644 --- a/packages/forc/VERSION +++ b/packages/forc/VERSION @@ -1 +1 @@ -0.56.1 +0.58.0 diff --git a/packages/fuel-gauge/package.json b/packages/fuel-gauge/package.json index 479381836e..e371ca08c0 100644 --- a/packages/fuel-gauge/package.json +++ b/packages/fuel-gauge/package.json @@ -5,9 +5,8 @@ "description": "", "author": "Fuel Labs (https://fuel.network/)", "scripts": { - "pretest": "run-s build:forc build:forc-experimental build:process-predicates", + "pretest": "run-s build:forc build:process-predicates", "build:forc": "pnpm fuels-forc build -p test/fixtures/forc-projects --release", - "build:forc-experimental": "pnpm fuels-forc build -p test/fixtures/forc-projects-experimental --release", "build:process-predicates": "tsx ./scripts/process-predicates.ts" }, "license": "Apache-2.0", diff --git a/packages/fuel-gauge/src/experimental-contract.test.ts b/packages/fuel-gauge/src/experimental-contract.test.ts deleted file mode 100644 index ad4cfa96dc..0000000000 --- a/packages/fuel-gauge/src/experimental-contract.test.ts +++ /dev/null @@ -1,128 +0,0 @@ -import { readFileSync } from 'fs'; -import type { Contract } from 'fuels'; -import { ContractFactory, bn } from 'fuels'; -import { join } from 'path'; - -import { setup } from './utils'; - -let contractInstance: Contract; -let contractFactory: ContractFactory; - -const U8_MAX = 2 ** 8 - 1; -const U16_MAX = 2 ** 16 - 1; -const U32_MAX = 2 ** 32 - 1; -const U64_MAX = bn(2).pow(64).sub(1); -const U256_MAX = bn(2).pow(256).sub(1); -const B512 = - '0x8e9dda6f7793745ac5aacf9e907cae30b2a01fdf0d23b7750a85c6a44fca0c29f0906f9d1f1e92e6a1fb3c3dcef3cc3b3cdbaae27e47b9d9a4c6a4fce4cf16b2'; - -/** - * @group node - */ -describe('Experimental Contract', () => { - beforeAll(async () => { - const projectName = 'contract-echo'; - const path = join( - __dirname, - `../test/fixtures/forc-projects-experimental/${projectName}/out/release/${projectName}` - ); - const contractBytecode = readFileSync(`${path}.bin`); - const abi = JSON.parse(readFileSync(`${path}-abi.json`, 'utf8')); - - contractInstance = await setup({ contractBytecode, abi }); - contractFactory = new ContractFactory(contractBytecode, abi, contractInstance.account); - }); - - it('echos mixed struct with all types', async () => { - const struct = { - a: U8_MAX, - b: U16_MAX, - c: U32_MAX, - d: U64_MAX, - e: U256_MAX, - f: '0xbebd3baab326f895289ecbd4210cf886ce41952316441ae4cac35f00f0e882a6', - g: B512, - native: 'Pending', - mixed: { Value: true }, - grades: [1, 4, 6, 22], - fuel: 'fuel', - hello: 'Hello World', - opt: 42, - nada: undefined, - bytes: Uint8Array.from([40, 41, 42]), - tuple: [U8_MAX, U16_MAX, U32_MAX, 'fuel'], - vec_u8: [40, 41, 42], - str_slice: 'fuel', - deep: { - a: U8_MAX, - b: U16_MAX, - c: U32_MAX, - d: U64_MAX, - e: U256_MAX, - f: '0xbebd3baab326f895289ecbd4210cf886ce41952316441ae4cac35f00f0e882a6', - g: B512, - native: 'Pending', - mixed: { Value: true }, - grades: [1, 4, 6, 22], - fuel: 'fuel', - hello: 'Hello World', - opt: 42, - nada: undefined, - bytes: Uint8Array.from([40, 41, 42]), - tuple: [U8_MAX, U16_MAX, U32_MAX, 'fuel'], - vec_u8: [40, 41, 42], - even_deeper: { - nested_vec: [1, 2, 3, 4, 5], - nested_str: 'fuel labs', - nested_raw: [88, 89, 90, 100], - }, - }, - }; - - const { value } = await contractInstance.functions.echo_struct(struct).call(); - expect(value).toStrictEqual(struct); - }); - - it('extracts str slice from revert', async () => { - await expect(contractInstance.functions.test_revert().call()).rejects.toThrow( - 'The transaction reverted because a "require" statement has thrown "This is a revert error".' - ); - }); - - it('echos configurable (both encoding versions)', async () => { - const param = [1, 2, 3, 'four']; - const { value } = await contractInstance.functions.echo_configurable(param).call(); - - expect(value).toStrictEqual(param); - - const configurableParam = [5, 6, 7, 'fuel']; - const configurableConstants = { - CONF: configurableParam, - }; - const configurableContractInstance = await contractFactory.deployContract({ - configurableConstants, - }); - const { value: configurableValue } = await configurableContractInstance.functions - .echo_configurable(configurableParam) - .call(); - - expect(configurableValue).toStrictEqual(configurableParam); - }); - - it('multicalls', async () => { - const { value: firstResults } = await contractInstance - .multiCall([contractInstance.functions.first_call(255)]) - .call(); - - expect(firstResults).toStrictEqual([255]); - - const { value: secondResults } = await contractInstance - .multiCall([ - contractInstance.functions.first_call(255), - contractInstance.functions.second_call(555), - ]) - .call(); - - expect(secondResults).toStrictEqual([255, 555]); - }); -}); diff --git a/packages/fuel-gauge/src/experimental-logging.test.ts b/packages/fuel-gauge/src/experimental-logging.test.ts deleted file mode 100644 index b60dae82dc..0000000000 --- a/packages/fuel-gauge/src/experimental-logging.test.ts +++ /dev/null @@ -1,344 +0,0 @@ -import { readFileSync } from 'fs'; -import type { Contract } from 'fuels'; -import { bn, hexlify, randomBytes } from 'fuels'; -import { join } from 'path'; - -import { setup } from './utils'; - -let contractInstance: Contract; - -const U8_MAX = 2 ** 8 - 1; -const U16_MAX = 2 ** 16 - 1; -const U32_MAX = 2 ** 32 - 1; -const B256 = '0xd5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b'; -const B512 = - '0x8e9dda6f7793745ac5aacf9e907cae30b2a01fdf0d23b7750a85c6a44fca0c29f0906f9d1f1e92e6a1fb3c3dcef3cc3b3cdbaae27e47b9d9a4c6a4fce4cf16b2'; - -beforeAll(async () => { - const projectName = 'logging'; - const path = join( - __dirname, - `../test/fixtures/forc-projects-experimental/${projectName}/out/release/${projectName}` - ); - const contractBytecode = readFileSync(`${path}.bin`); - const abi = JSON.parse(readFileSync(`${path}-abi.json`, 'utf8')); - - contractInstance = await setup({ contractBytecode, abi }); -}); - -/** - * @group node - */ -describe('Experimental Logging', () => { - it('logs u8', async () => { - const expected = U8_MAX; - - const { logs } = await contractInstance.functions.log_u8(expected).call(); - - expect(logs).toStrictEqual([expected]); - }); - - it('logs u16', async () => { - const expected = U16_MAX; - - const { logs } = await contractInstance.functions.log_u16(expected).call(); - - expect(logs).toStrictEqual([expected]); - }); - - it('logs u32', async () => { - const expected = U32_MAX; - - const { logs } = await contractInstance.functions.log_u32(expected).call(); - - expect(logs).toStrictEqual([expected]); - }); - - it('logs u8 u16 u32 multiple params', async () => { - const expected = [U8_MAX, U16_MAX, U32_MAX]; - - const { value, logs } = await contractInstance.functions.log_u8_u16_u32(...expected).call(); - - expect(value).toEqual(expected); - expect(logs).toEqual(expected); - }); - - it('logs u64', async () => { - const expected = U32_MAX + 1; - - const { logs } = await contractInstance.functions.log_u64(expected).call(); - - expect(bn(logs[0]).toNumber()).toStrictEqual(expected); - }); - - it('logs u256', async () => { - const expected = U32_MAX + 1; - - const { logs } = await contractInstance.functions.log_u256(expected).call(); - - expect(bn(logs[0]).toNumber()).toStrictEqual(expected); - }); - - it('logs u64 u8 multiple params', async () => { - const expected = [U32_MAX + 1, U8_MAX]; - - const { logs } = await contractInstance.functions.log_u64_u8(...expected).call(); - - expect(bn(logs[0]).toNumber()).toStrictEqual(expected[0]); - expect(logs[1]).toEqual(expected[1]); - }); - - it('logs boolean', async () => { - const expected = true; - - const { logs } = await contractInstance.functions.log_boolean(expected).call(); - - expect(logs).toStrictEqual([expected]); - }); - - it('logs boolean boolean multiple params', async () => { - const expected = [true, false]; - - const { logs } = await contractInstance.functions.log_boolean_boolean(...expected).call(); - - expect(logs).toEqual(expected); - }); - - it('logs number boolean mixed params', async () => { - const expected = [U32_MAX, true]; - - const { logs } = await contractInstance.functions.log_number_boolean(...expected).call(); - - expect(logs).toEqual(expected); - }); - - it('logs b256', async () => { - const expected = B256; - - const { logs } = await contractInstance.functions.log_b256(expected).call(); - - expect(logs).toStrictEqual([expected]); - }); - - it('logs b256 vec', async () => { - const expected = [B256, B256]; - - const { logs } = await contractInstance.functions.log_vec_b256(expected).call(); - - expect(logs).toEqual([expected]); - }); - - it('logs b512', async () => { - const expected = B512; - - const { logs } = await contractInstance.functions.log_b512(expected).call(); - - expect(logs).toStrictEqual([expected]); - }); - - it('logs b512 vec', async () => { - const expected = [B512, B512]; - - const { logs } = await contractInstance.functions.log_vec_b512(expected).call(); - - expect(logs).toEqual([expected]); - }); - - it('logs b256 b512 multiple params', async () => { - const expected = [B256, B512]; - - const { logs } = await contractInstance.functions.log_b256_b512(...expected).call(); - - expect(logs).toEqual(expected); - }); - - it('logs u8 vec', async () => { - const expected = [U8_MAX, 1, U8_MAX, 5]; - - const { logs } = await contractInstance.functions.log_vec_u8(expected).call(); - - expect(logs).toEqual([expected]); - }); - - it('logs b256 vec', async () => { - const expected = [hexlify(randomBytes(32)), hexlify(randomBytes(32))]; - - const { logs } = await contractInstance.functions.log_vec_b256(expected).call(); - - expect(logs).toEqual([expected]); - }); - - it('logs bytes', async () => { - const expected = [40, 41, 42]; - - const { logs } = await contractInstance.functions.log_bytes(expected).call(); - - expect(logs).toEqual([Uint8Array.from(expected)]); - }); - - it('logs StdString', async () => { - const expected = 'fuel'; - - const { logs } = await contractInstance.functions.log_std_string(expected).call(); - - expect(logs).toEqual([expected]); - }); - - it('logs u16 bytes multiple params', async () => { - const expected = [U16_MAX, [40, 41, 42]]; - - const { logs } = await contractInstance.functions.log_u16_bytes(...expected).call(); - - expect(logs).toEqual([U16_MAX, Uint8Array.from([40, 41, 42])]); - }); - - it('logs u8 array', async () => { - const expected = [U8_MAX, 5, U8_MAX]; - - const { logs } = await contractInstance.functions.log_u8_array(expected).call(); - - expect(logs).toEqual([expected]); - }); - - it('logs u16 array', async () => { - const expected = [U16_MAX, 5, U16_MAX]; - - const { logs } = await contractInstance.functions.log_u16_array(expected).call(); - - expect(logs).toEqual([expected]); - }); - - it('log u16 u8 array multiple params', async () => { - const expected = [U16_MAX, [U8_MAX, 5, U8_MAX]]; - - const { logs } = await contractInstance.functions.log_u16_u8_array(...expected).call(); - - expect(logs).toEqual(expected); - }); - - it('logs string', async () => { - const expected = 'fuel'; - - const { logs } = await contractInstance.functions.log_str_4(expected).call(); - - expect(logs).toEqual([expected]); - }); - - it('logs u8 string multiple params', async () => { - const expected = [U8_MAX, 'at']; - - const { logs } = await contractInstance.functions.log_u8_str_2(...expected).call(); - - expect(logs).toEqual(expected); - }); - - it('logs u8 u16 tuple', async () => { - const expected = [U8_MAX, U16_MAX]; - - const { logs } = await contractInstance.functions.log_u8_u16_tuple(expected).call(); - - expect(logs).toEqual([expected]); - }); - - it('logs enum', async () => { - const expectedFoo = { Foo: U32_MAX }; - const expectedBar = { Bar: true }; - - const { logs: logsFoo } = await contractInstance.functions.log_enum(expectedFoo).call(); - - const { logs: logsBar } = await contractInstance.functions.log_enum(expectedBar).call(); - - expect(logsFoo).toEqual([expectedFoo]); - expect(logsBar).toEqual([expectedBar]); - }); - - it('logs native enum', async () => { - const expectedFoo = 'Foo'; - const expectedBar = 'Bar'; - - const { logs: logsFoo } = await contractInstance.functions.log_native_enum(expectedFoo).call(); - - const { logs: logsBar } = await contractInstance.functions.log_native_enum(expectedBar).call(); - - expect(logsFoo).toEqual([expectedFoo]); - expect(logsBar).toEqual([expectedBar]); - }); - - it('logs boolean enum multiple params', async () => { - const expected = [true, { Foo: U32_MAX }]; - - const { logs } = await contractInstance.functions.log_boolean_enum(...expected).call(); - - expect(logs).toEqual(expected); - }); - - it('logs struct', async () => { - const expected = { - a: U8_MAX, - b: U16_MAX, - }; - - const { logs } = await contractInstance.functions.log_struct(expected).call(); - - expect(logs).toEqual([expected]); - }); - - it('logs struct vec', async () => { - const expected = [ - { - a: U8_MAX, - b: U16_MAX, - }, - { - a: 1, - b: 2, - }, - ]; - - const { logs } = await contractInstance.functions.log_struct_vec(expected).call(); - - expect(logs).toEqual([expected]); - }); - - it('logs struct boolean multiple params', async () => { - const expected = [ - { - a: U8_MAX, - b: U16_MAX, - }, - true, - ]; - - const { logs } = await contractInstance.functions.log_struct_boolean(...expected).call(); - - expect(logs).toEqual(expected); - }); - - it('logs u8 option', async () => { - const expectedSome = U8_MAX; - const expectedNone = undefined; - - const { logs: logsSome } = await contractInstance.functions.log_option_u8(expectedSome).call(); - - const { logs: logsNone } = await contractInstance.functions.log_option_u8(expectedNone).call(); - - expect(logsSome).toEqual([expectedSome]); - expect(logsNone).toEqual([expectedNone]); - }); - - it('logs raw slice', async () => { - const expected = [40, 41, 42]; - - const { logs } = await contractInstance.functions.log_raw_slice(expected).call(); - - expect(logs).toEqual([expected]); - }); - - it('logs str slice', async () => { - const expected = 'fuel'; - - const { logs } = await contractInstance.functions.log_str_slice(expected).call(); - - expect(logs).toEqual([expected]); - }); -}); diff --git a/packages/fuel-gauge/src/experimental-predicate.test.ts b/packages/fuel-gauge/src/experimental-predicate.test.ts deleted file mode 100644 index f106476f87..0000000000 --- a/packages/fuel-gauge/src/experimental-predicate.test.ts +++ /dev/null @@ -1,99 +0,0 @@ -import { readFileSync } from 'fs'; -import type { JsonAbi, Provider, WalletLocked, WalletUnlocked } from 'fuels'; -import { Predicate, bn } from 'fuels'; -import { join } from 'path'; - -import { fundPredicate, setupWallets } from './predicate/utils/predicate'; - -const U8_MAX = 255; -const U16_MAX = 65535; -const U32_MAX = 4294967295; -const U64_MAX = bn(2).pow(64).sub(1); -const U256_MAX = bn(2).pow(256).sub(1); -const B512 = - '0x8e9dda6f7793745ac5aacf9e907cae30b2a01fdf0d23b7750a85c6a44fca0c29f0906f9d1f1e92e6a1fb3c3dcef3cc3b3cdbaae27e47b9d9a4c6a4fce4cf16b2'; - -/** - * @group node - */ -describe('Experimental Predicate', () => { - let wallet: WalletUnlocked; - let receiver: WalletLocked; - let bytecode: Buffer; - let abi: JsonAbi; - let provider: Provider; - let baseAssetId: string; - - beforeAll(async () => { - [wallet, receiver] = await setupWallets(); - baseAssetId = wallet.provider.getBaseAssetId(); - const name = 'predicate-echo'; - const path = join( - __dirname, - `../test/fixtures/forc-projects-experimental/${name}/out/release/${name}` - ); - bytecode = readFileSync(`${path}.bin`); - abi = JSON.parse(readFileSync(`${path}-abi.json`, 'utf8')); - provider = wallet.provider; - }); - - it('echos struct', async () => { - const struct = { - a: U8_MAX, - b: U16_MAX, - c: U32_MAX, - d: U64_MAX, - e: U256_MAX, - f: '0xbebd3baab326f895289ecbd4210cf886ce41952316441ae4cac35f00f0e882a6', - g: B512, - native: 'Pending', - mixed: { Value: true }, - grades: [1, 4, 6, 22], - fuel: 'fuel', - hello: 'Hello World', - opt: 42, - nada: undefined, - bytes: Uint8Array.from([40, 41, 42]), - tuple: [U8_MAX, U16_MAX, U32_MAX, 'fuel'], - vec_u8: [40, 41, 42], - deep: { - a: U8_MAX, - b: U16_MAX, - c: U32_MAX, - d: U64_MAX, - e: U256_MAX, - f: '0xbebd3baab326f895289ecbd4210cf886ce41952316441ae4cac35f00f0e882a6', - g: B512, - native: 'Pending', - mixed: { Value: true }, - grades: [1, 4, 6, 22], - fuel: 'fuel', - hello: 'Hello World', - opt: 42, - nada: undefined, - bytes: Uint8Array.from([40, 41, 42]), - tuple: [U8_MAX, U16_MAX, U32_MAX, 'fuel'], - vec_u8: [40, 41, 42], - }, - }; - - const predicate = new Predicate<[typeof struct]>({ - bytecode, - provider, - abi, - inputData: [struct], - }); - - const initialBalance = await receiver.getBalance(baseAssetId); - expect(initialBalance).toStrictEqual(bn(0)); - - const amountToReceiver = 100; - - await fundPredicate(wallet, predicate, 100_000); - const tx = await predicate.transfer(receiver.address, amountToReceiver, baseAssetId); - await tx.waitForResult(); - - const finalBalance = await receiver.getBalance(baseAssetId); - expect(finalBalance).toStrictEqual(bn(amountToReceiver)); - }); -}); diff --git a/packages/fuel-gauge/src/experimental-script.test.ts b/packages/fuel-gauge/src/experimental-script.test.ts deleted file mode 100644 index bd0534ed9b..0000000000 --- a/packages/fuel-gauge/src/experimental-script.test.ts +++ /dev/null @@ -1,122 +0,0 @@ -import { readFileSync } from 'fs'; -import { Script, bn } from 'fuels'; -import { join } from 'path'; - -import { createWallet } from './utils'; - -let echoScript: Script; -let printScript: Script; -const U8_MAX = 255; -const U16_MAX = 65535; -const U32_MAX = 4294967295; -const U64_MAX = bn(2).pow(64).sub(1); -const U256_MAX = bn(2).pow(256).sub(1); -const B512 = - '0x8e9dda6f7793745ac5aacf9e907cae30b2a01fdf0d23b7750a85c6a44fca0c29f0906f9d1f1e92e6a1fb3c3dcef3cc3b3cdbaae27e47b9d9a4c6a4fce4cf16b2'; - -const getScript = async (name: string) => { - const wallet = await createWallet(); - const path = join( - __dirname, - `../test/fixtures/forc-projects-experimental/${name}/out/release/${name}` - ); - const bytes = readFileSync(`${path}.bin`); - const abi = JSON.parse(readFileSync(`${path}-abi.json`, 'utf8')); - return new Script(bytes, abi, wallet); -}; - -beforeAll(async () => { - printScript = await getScript('script-print'); - echoScript = await getScript('script-echo'); -}); - -/** - * @group node - */ -describe('Experimental Script', () => { - it('prints mixed struct with all types', async () => { - const { value } = await printScript.functions.main(B512).call(); - expect(value).toStrictEqual({ - a: U8_MAX, - b: U16_MAX, - c: U32_MAX, - d: U64_MAX, - e: U256_MAX, - f: '0xbebd3baab326f895289ecbd4210cf886ce41952316441ae4cac35f00f0e882a6', - g: B512, - native: 'Pending', - mixed: { Value: true }, - grades: [1, 4, 6, 22], - fuel: 'fuel', - hello: 'Hello World', - opt: 42, - nada: undefined, - bytes: Uint8Array.from([40, 41, 42]), - tuple: [U8_MAX, U16_MAX, U32_MAX, 'fuel'], - vec_u8: [40, 41, 42], - deep: { - a: U8_MAX, - b: U16_MAX, - c: U32_MAX, - d: U64_MAX, - e: U256_MAX, - f: '0xbebd3baab326f895289ecbd4210cf886ce41952316441ae4cac35f00f0e882a6', - g: B512, - native: 'Pending', - mixed: { Value: true }, - grades: [1, 4, 6, 22], - fuel: 'fuel', - hello: 'Hello World', - opt: 42, - nada: undefined, - bytes: Uint8Array.from([40, 41, 42]), - tuple: [U8_MAX, U16_MAX, U32_MAX, 'fuel'], - vec_u8: [40, 41, 42], - }, - }); - }); - - it('echos number struct', async () => { - const struct = { - a: U8_MAX, - b: U16_MAX, - c: U32_MAX, - d: U64_MAX, - e: U256_MAX, - f: '0xbebd3baab326f895289ecbd4210cf886ce41952316441ae4cac35f00f0e882a6', - g: B512, - native: 'Pending', - mixed: { Value: true }, - grades: [1, 4, 6, 22], - fuel: 'fuel', - hello: 'Hello World', - opt: 42, - nada: undefined, - bytes: Uint8Array.from([40, 41, 42]), - tuple: [U8_MAX, U16_MAX, U32_MAX, 'fuel'], - vec_u8: [40, 41, 42], - deep: { - a: U8_MAX, - b: U16_MAX, - c: U32_MAX, - d: U64_MAX, - e: U256_MAX, - f: '0xbebd3baab326f895289ecbd4210cf886ce41952316441ae4cac35f00f0e882a6', - g: B512, - native: 'Pending', - mixed: { Value: true }, - grades: [1, 4, 6, 22], - fuel: 'fuel', - hello: 'Hello World', - opt: 42, - nada: undefined, - bytes: Uint8Array.from([40, 41, 42]), - tuple: [U8_MAX, U16_MAX, U32_MAX, 'fuel'], - vec_u8: [40, 41, 42], - }, - }; - - const { value } = await echoScript.functions.main(struct).call(); - expect(value).toStrictEqual(struct); - }); -}); diff --git a/packages/fuel-gauge/src/predicate-conditional-inputs.test.ts b/packages/fuel-gauge/src/predicate-conditional-inputs.test.ts index 3ed14f869d..73b4fd108e 100644 --- a/packages/fuel-gauge/src/predicate-conditional-inputs.test.ts +++ b/packages/fuel-gauge/src/predicate-conditional-inputs.test.ts @@ -46,7 +46,7 @@ describe('PredicateConditionalInputs', () => { await tx1.waitForResult(); // transfer base asset to Alice so she can pay the fees - const tx2 = await adminWallet.transfer(aliceWallet.address, 2_000, baseAssetId); + const tx2 = await adminWallet.transfer(aliceWallet.address, 2105, baseAssetId); await tx2.waitForResult(); diff --git a/packages/fuel-gauge/src/predicate/predicate-configurables.test.ts b/packages/fuel-gauge/src/predicate/predicate-configurables.test.ts index 3970c2702a..9e0cfbeaa0 100644 --- a/packages/fuel-gauge/src/predicate/predicate-configurables.test.ts +++ b/packages/fuel-gauge/src/predicate/predicate-configurables.test.ts @@ -180,6 +180,8 @@ describe('Predicate', () => { provider: wallet.provider, }); + await fundPredicate(wallet, predicate, amountToPredicate); + await expect( predicate.transfer(destination.address, 300, baseAssetId, { gasLimit: 1000 }) ).rejects.toThrow(/PredicateVerificationFailed/); diff --git a/packages/fuel-gauge/src/small-bytes.test.ts b/packages/fuel-gauge/src/small-bytes.test.ts deleted file mode 100644 index 953156c88c..0000000000 --- a/packages/fuel-gauge/src/small-bytes.test.ts +++ /dev/null @@ -1,234 +0,0 @@ -import { getForcProject } from '@fuel-ts/utils/test-utils'; -import type { Contract, JsonAbi } from 'fuels'; -import { bn, ContractFactory } from 'fuels'; -import { join } from 'path'; - -import { getSetupContract, createWallet } from './utils'; - -/** - * @group node - */ -describe('small-bytes', () => { - const smallBytesProjectDir = join(__dirname, '../test/fixtures/forc-projects/small-bytes'); - - const setupContract = getSetupContract('small-bytes'); - - let contract: Contract; - - beforeAll(async () => { - contract = await setupContract(); - }); - it('should successfully call contract and echo values', async () => { - const expected = [48, 63]; - const res1 = await contract.functions.echo_u8_array().simulate(); - expect(res1.value).toMatchObject(expected); - }); - - it('should successfully echo u8 array', async () => { - const expected = [48, 63]; - const res1 = await contract.functions.echo_u8_array_with_value(expected).simulate(); - expect(res1.value).toMatchObject(expected); - }); - - it('should echo boolean array', async () => { - const expected = [true, false]; - const res1 = await contract.functions.echo_boolean_array().simulate(); - expect(res1.value).toMatchObject(expected); - }); - - it('should echo boolean array with value', async () => { - const expected = [true, false]; - const res1 = await contract.functions.echo_boolean_array_with_value(expected).simulate(); - expect(res1.value).toMatchObject(expected); - }); - - it('echos a mixed tuple with value', async () => { - const expected = [73, true]; - const res1 = await contract.functions.echo_mixed_tuple_with_value(expected).simulate(); - expect(res1.value).toMatchObject(expected); - }); - - it('echos a mixed tuple', async () => { - const expected = [48, true]; - const res1 = await contract.functions.echo_mixed_tuple().simulate(); - expect(res1.value).toMatchObject(expected); - }); - - it('echos a bigger mixed tuple', async () => { - const expected = [48, true, bn(1337)]; - const res1 = await contract.functions.echo_tuple().simulate(); - expect(JSON.stringify(res1.value)).toEqual(JSON.stringify(expected)); - }); - - it('echos a mixed struct with value', async () => { - const expected = { a: 73, b: true }; - const res1 = await contract.functions.echo_mixed_struct_with_value(expected).simulate(); - expect(res1.value).toMatchObject(expected); - }); - - it('echos a mixed enum with value', async () => { - const expectedA = { a: 73 }; - const expectedB = { b: true }; - - const res1 = await contract.functions.echo_mixed_enum_with_value(expectedA).simulate(); - expect(res1.value).toMatchObject(expectedA); - - const res2 = await contract.functions.echo_mixed_enum_with_value(expectedB).simulate(); - expect(res2.value).toMatchObject(expectedB); - }); - - it('accepts native enum', async () => { - const res1 = await contract.functions.echo_native_enum('B').simulate(); - expect(res1.value).toEqual('C'); - }); - - it('echos a u8 vector with value', async () => { - const expected = [73, 23]; - const res1 = await contract.functions.echo_u8_vector_with_value(expected).simulate(); - expect(res1.value).toMatchObject(expected); - }); - - it('echos a u8 vector', async () => { - const expected = [23, 32, 78]; - const res1 = await contract.functions.echo_u8_vector().simulate(); - expect(res1.value).toMatchObject(expected); // [ 23 ] - }); - - it('echos a u64 vector', async () => { - const expected = [bn(1337), bn(1448), bn(1559)]; - const res1 = await contract.functions.echo_u64_vector().simulate(); - expect(JSON.stringify(res1.value)).toEqual(JSON.stringify(expected)); - }); - - it('echos a mixed struct', async () => { - const expected = { - a: true, - b: bn(1337), - }; - - const res1 = await contract.functions.echo_mixed_struct().simulate(); - expect(JSON.stringify(res1.value)).toEqual(JSON.stringify(expected)); - }); - - it('send and echos a mixed struct', async () => { - const expected = { - a: true, - b: bn(1337), - }; - - const res1 = await contract.functions.echo_received_mixed_struct(expected).simulate(); - expect(JSON.stringify(res1.value)).toEqual(JSON.stringify(expected)); - }); - - it('echos a u8 with configurable constant', async () => { - const expected = 23; - const configurableConstants = { - U8: expected, - }; - - const { binHexlified, abiContents } = getForcProject({ - projectDir: smallBytesProjectDir, - projectName: 'small-bytes', - build: 'release', - }); - - const wallet = await createWallet(); - const factory = new ContractFactory(binHexlified, abiContents, wallet); - const configurableContract = await factory.deployContract({ - configurableConstants, - }); - - const res1 = await configurableContract.functions.echo_configurable_u8().simulate(); - - expect(res1.value).toBe(expected); - }); - - it('echos a boolean with configurable constant', async () => { - const expected = true; - const configurableConstants = { - BOOLEAN: expected, - }; - - const { binHexlified, abiContents } = getForcProject({ - projectDir: smallBytesProjectDir, - projectName: 'small-bytes', - build: 'release', - }); - - const wallet = await createWallet(); - const factory = new ContractFactory(binHexlified, abiContents, wallet); - const configurableContract = await factory.deployContract({ - configurableConstants, - }); - - const res1 = await configurableContract.functions.echo_configurable_boolean().simulate(); - - expect(res1.value).toBe(expected); - }); - - it('echos a u8 literal', async () => { - const expected = 47; - const res1 = await contract.functions.echo_u8_literal().simulate(); - expect(res1.value).toBe(expected); - }); - - it('echos a u16', async () => { - const res1 = await contract.functions.echo_u16(30000).simulate(); - expect(res1.value).toBe(30000 * 2); - }); - - it('echos a u32', async () => { - const res1 = await contract.functions.echo_u32(100000).simulate(); - expect(res1.value).toBe(100000 * 2); - }); - - it('echos a boolean literal', async () => { - const expected = true; - const res1 = await contract.functions.echo_boolean_literal().simulate(); - expect(res1.value).toBe(expected); - }); - - it('echos a u8 value', async () => { - const expected = 47; - const res1 = await contract.functions.echo_u8(expected).simulate(); - expect(res1.value).toBe(expected); - }); - - it('accepts two u8 values', async () => { - const res1 = await contract.functions.echo_two_u8s(15, 255).simulate(); - expect(res1.value).toBe(255); - }); - - it('accepts two boolean values', async () => { - const res1 = await contract.functions.two_booleans(true, true).simulate(); - expect(res1.value).toBe(true); - }); - - it('accepts u8, u64, bool', async () => { - const res1 = await contract.functions.u8_u64_bool(255, 10000, true).simulate(); - expect(res1.value).toBe(55); - }); - - it('accepts struct and u8', async () => { - const res1 = await contract.functions - .struct_and_u8( - { - a: 254, - b: true, - }, - 230 - ) - .simulate(); - - expect(res1.value).toEqual({ - a: 230, - b: true, - }); - }); - - it('echos a boolean value', async () => { - const expected = true; - const res1 = await contract.functions.echo_boolean(expected).simulate(); - expect(res1.value).toBe(expected); - }); -}); diff --git a/packages/fuel-gauge/test/fixtures/forc-projects-experimental/Forc.toml b/packages/fuel-gauge/test/fixtures/forc-projects-experimental/Forc.toml deleted file mode 100644 index dc76225a68..0000000000 --- a/packages/fuel-gauge/test/fixtures/forc-projects-experimental/Forc.toml +++ /dev/null @@ -1,8 +0,0 @@ -[workspace] -members = [ - "predicate-echo", - "script-echo", - "script-print", - "logging", - "contract-echo", -] diff --git a/packages/fuel-gauge/test/fixtures/forc-projects-experimental/contract-echo/Forc.toml b/packages/fuel-gauge/test/fixtures/forc-projects-experimental/contract-echo/Forc.toml deleted file mode 100644 index 57b95ffcfe..0000000000 --- a/packages/fuel-gauge/test/fixtures/forc-projects-experimental/contract-echo/Forc.toml +++ /dev/null @@ -1,7 +0,0 @@ -[project] -authors = ["Fuel Labs "] -entry = "main.sw" -license = "Apache-2.0" -name = "contract-echo" - -[dependencies] diff --git a/packages/fuel-gauge/test/fixtures/forc-projects-experimental/contract-echo/src/main.sw b/packages/fuel-gauge/test/fixtures/forc-projects-experimental/contract-echo/src/main.sw deleted file mode 100644 index 61b48badd6..0000000000 --- a/packages/fuel-gauge/test/fixtures/forc-projects-experimental/contract-echo/src/main.sw +++ /dev/null @@ -1,109 +0,0 @@ -contract; - -use std::b512::B512; -use std::string::String; -use std::option::Option; -use std::bytes::Bytes; -use std::vec::Vec; - -enum NativeEnum { - Checked: (), - Pending: (), -} - -enum MixedEnum { - Value: bool, - Data: u16, -} - -struct EvenDeeperStruct { - nested_vec: Vec, - nested_str: str, - nested_raw: raw_slice, -} - -struct DeeperStruct { - a: u8, - b: u16, - c: u32, - d: u64, - e: u256, - f: b256, - g: B512, - native: NativeEnum, - mixed: MixedEnum, - grades: [u8; 4], - fuel: str[4], - hello: String, - opt: Option, - nada: Option, - bytes: Bytes, - tuple: (u8, u16, u32, str[4]), - vec_u8: Vec, - even_deeper: EvenDeeperStruct, -} - -struct MixedStruct { - a: u8, - b: u16, - c: u32, - d: u64, - e: u256, - f: b256, - g: B512, - native: NativeEnum, - mixed: MixedEnum, - grades: [u8; 4], - fuel: str[4], - hello: String, - opt: Option, - nada: Option, - bytes: Bytes, - tuple: (u8, u16, u32, str[4]), - vec_u8: Vec, - deep: DeeperStruct, - str_slice: str, -} - -configurable { - CONF: (u8, u16, u32, str[4]) = (1, 2, 3, __to_str_array("four")), -} - -abi MyContract { - fn echo_struct(param: MixedStruct) -> MixedStruct; - fn test_revert() -> bool; - fn echo_configurable(param: (u8, u16, u32, str[4])) -> (u8, u16, u32, str[4]); - fn first_call(param: u8) -> u8; - fn second_call(param: u16) -> u16; -} - -impl MyContract for Contract { - fn echo_struct(param: MixedStruct) -> MixedStruct { - param - } - - fn test_revert() -> bool { - require(false, "This is a revert error"); - true - } - - fn echo_configurable(param: (u8, u16, u32, str[4])) -> (u8, u16, u32, str[4]) { - assert_eq(param.0, CONF.0); - assert_eq(param.1, CONF.1); - assert_eq(param.2, CONF.2); - - let param_str: str = from_str_array(param.3); - let conf_str: str = from_str_array(CONF.3); - assert_eq(param_str, conf_str); - - CONF - } - - fn first_call(param: u8) -> u8 { - param - } - - fn second_call(param: u16) -> u16 { - param - } -} diff --git a/packages/fuel-gauge/test/fixtures/forc-projects-experimental/logging/Forc.toml b/packages/fuel-gauge/test/fixtures/forc-projects-experimental/logging/Forc.toml deleted file mode 100644 index 36fbc29bc3..0000000000 --- a/packages/fuel-gauge/test/fixtures/forc-projects-experimental/logging/Forc.toml +++ /dev/null @@ -1,7 +0,0 @@ -[project] -authors = ["Fuel Labs "] -entry = "main.sw" -license = "Apache-2.0" -name = "logging" - -[dependencies] diff --git a/packages/fuel-gauge/test/fixtures/forc-projects-experimental/logging/src/main.sw b/packages/fuel-gauge/test/fixtures/forc-projects-experimental/logging/src/main.sw deleted file mode 100644 index 0a2aa36878..0000000000 --- a/packages/fuel-gauge/test/fixtures/forc-projects-experimental/logging/src/main.sw +++ /dev/null @@ -1,267 +0,0 @@ -contract; - -use std::logging::log; -use std::b512::B512; -use std::vec::Vec; -use std::bytes::Bytes; -use std::string::String; -use std::option::Option; - -enum MyNativeEnum { - Foo: (), - Bar: (), -} - -enum MyEnum { - Foo: u32, - Bar: bool, -} - -struct MyStruct { - a: u8, - b: u16, -} - -abi LoggingContract { - fn log_u8(a: u8) -> u8; - fn log_u16(a: u16) -> u16; - fn log_u32(a: u32) -> u32; - fn log_u8_u16_u32(a: u8, b: u16, c: u32) -> (u8, u16, u32); - fn log_u64(a: u64) -> u64; - fn log_u256(a: u256) -> u256; - fn log_u64_u8(a: u64, b: u8) -> (u64, u8); - fn log_boolean(a: bool) -> bool; - fn log_boolean_boolean(a: bool, b: bool) -> (bool, bool); - fn log_number_boolean(a: u32, b: bool) -> (u32, bool); - fn log_b256(a: b256) -> b256; - fn log_b512(a: B512) -> B512; - fn log_b256_b512(a: b256, b: B512) -> (b256, B512); - fn log_vec_u8(a: Vec) -> Vec; - fn log_vec_b256(a: Vec); - fn log_vec_b512(a: Vec); - fn log_u16_vec_u8(a: u16, b: Vec) -> (u16, Vec); - fn log_bytes(a: Bytes) -> Bytes; - fn log_u16_bytes(a: u16, b: Bytes) -> (u16, Bytes); - fn log_std_string(a: String) -> String; - fn log_u16_std_string(a: u16, b: String) -> (u16, String); - fn log_raw_slice(a: raw_slice) -> raw_slice; - fn log_u8_array(a: [u8; 3]) -> [u8; 3]; - fn log_u16_array(a: [u16; 3]) -> [u16; 3]; - fn log_u16_u8_array(a: u16, b: [u8; 3]) -> (u16, [u8; 3]); - fn log_str_4(a: str[4]) -> str[4]; - fn log_u8_str_2(a: u8, b: str[2]) -> (u8, str[2]); - fn log_u8_u16_tuple(a: (u8, u16)) -> (u8, u16); - fn log_boolean_u8_vec_tuple(a: (bool, Vec)) -> (bool, Vec); - fn log_enum(a: MyEnum) -> MyEnum; - fn log_native_enum(a: MyNativeEnum) -> MyNativeEnum; - fn log_boolean_enum(a: bool, b: MyEnum) -> (bool, MyEnum); - fn log_struct(a: MyStruct) -> MyStruct; - fn log_struct_vec(a: Vec) -> Vec; - fn log_struct_boolean(a: MyStruct, b: bool) -> (MyStruct, bool); - fn log_option_u8(a: Option) -> Option; - fn log_option_vec_u16(a: Option>) -> Option>; - fn log_str_slice(a: str) -> str; -} - -impl LoggingContract for Contract { - fn log_u8(a: u8) -> u8 { - log(a); - a - } - - fn log_u16(a: u16) -> u16 { - log(a); - a - } - - fn log_u32(a: u32) -> u32 { - log(a); - a - } - - fn log_u8_u16_u32(a: u8, b: u16, c: u32) -> (u8, u16, u32) { - log(a); - log(b); - log(c); - (a, b, c) - } - - fn log_u64(a: u64) -> u64 { - log(a); - a - } - - fn log_u256(a: u256) -> u256 { - log(a); - a - } - - fn log_u64_u8(a: u64, b: u8) -> (u64, u8) { - log(a); - log(b); - (a, b) - } - - fn log_boolean(a: bool) -> bool { - log(a); - a - } - - fn log_boolean_boolean(a: bool, b: bool) -> (bool, bool) { - log(a); - log(b); - (a, b) - } - - fn log_number_boolean(a: u32, b: bool) -> (u32, bool) { - log(a); - log(b); - (a, b) - } - - fn log_b256(a: b256) -> b256 { - log(a); - a - } - - fn log_b512(a: B512) -> B512 { - log(a); - a - } - - fn log_b256_b512(a: b256, b: B512) -> (b256, B512) { - log(a); - log(b); - (a, b) - } - - fn log_vec_u8(a: Vec) -> Vec { - log(a); - a - } - - fn log_vec_b256(a: Vec) { - log(a); - } - - fn log_vec_b512(a: Vec) { - log(a); - } - - fn log_bytes(a: Bytes) -> Bytes { - log(a); - a - } - - fn log_std_string(a: String) -> String { - log(a); - a - } - - fn log_u16_vec_u8(a: u16, b: Vec) -> (u16, Vec) { - log(a); - log(b); - (a, b) - } - - fn log_u16_bytes(a: u16, b: Bytes) -> (u16, Bytes) { - log(a); - log(b); - (a, b) - } - - fn log_u16_std_string(a: u16, b: String) -> (u16, String) { - log(a); - log(b); - (a, b) - } - - fn log_raw_slice(a: raw_slice) -> raw_slice { - log(a); - a - } - - fn log_u8_array(a: [u8; 3]) -> [u8; 3] { - log(a); - a - } - - fn log_u16_array(a: [u16; 3]) -> [u16; 3] { - log(a); - a - } - - fn log_u16_u8_array(a: u16, b: [u8; 3]) -> (u16, [u8; 3]) { - log(a); - log(b); - (a, b) - } - - fn log_str_4(a: str[4]) -> str[4] { - log(a); - a - } - - fn log_u8_str_2(a: u8, b: str[2]) -> (u8, str[2]) { - log(a); - log(b); - (a, b) - } - - fn log_u8_u16_tuple(a: (u8, u16)) -> (u8, u16) { - log(a); - a - } - - fn log_boolean_u8_vec_tuple(a: (bool, Vec)) -> (bool, Vec) { - log(a); - a - } - - fn log_enum(a: MyEnum) -> MyEnum { - log(a); - a - } - - fn log_native_enum(a: MyNativeEnum) -> MyNativeEnum { - log(a); - a - } - - fn log_boolean_enum(a: bool, b: MyEnum) -> (bool, MyEnum) { - log(a); - log(b); - (a, b) - } - - fn log_struct(a: MyStruct) -> MyStruct { - log(a); - a - } - - fn log_struct_vec(a: Vec) -> Vec { - log(a); - a - } - - fn log_struct_boolean(a: MyStruct, b: bool) -> (MyStruct, bool) { - log(a); - log(b); - (a, b) - } - - fn log_option_u8(a: Option) -> Option { - log(a); - a - } - - fn log_option_vec_u16(a: Option>) -> Option> { - log(a); - a - } - - fn log_str_slice(a: str) -> str { - log(a); - a - } -} diff --git a/packages/fuel-gauge/test/fixtures/forc-projects-experimental/predicate-echo/Forc.toml b/packages/fuel-gauge/test/fixtures/forc-projects-experimental/predicate-echo/Forc.toml deleted file mode 100644 index a17df04822..0000000000 --- a/packages/fuel-gauge/test/fixtures/forc-projects-experimental/predicate-echo/Forc.toml +++ /dev/null @@ -1,7 +0,0 @@ -[project] -authors = ["Fuel Labs "] -entry = "main.sw" -license = "Apache-2.0" -name = "predicate-echo" - -[dependencies] diff --git a/packages/fuel-gauge/test/fixtures/forc-projects-experimental/predicate-echo/src/main.sw b/packages/fuel-gauge/test/fixtures/forc-projects-experimental/predicate-echo/src/main.sw deleted file mode 100644 index 2e13f3d402..0000000000 --- a/packages/fuel-gauge/test/fixtures/forc-projects-experimental/predicate-echo/src/main.sw +++ /dev/null @@ -1,65 +0,0 @@ -predicate; - -use std::b512::B512; -use std::string::String; -use std::option::Option; -use std::bytes::Bytes; -use std::vec::Vec; - -enum NativeEnum { - Checked: (), - Pending: (), -} - -enum MixedEnum { - Value: bool, - Data: u16, -} - -struct DeeperStruct { - a: u8, - b: u16, - c: u32, - d: u64, - e: u256, - f: b256, - g: B512, - native: NativeEnum, - mixed: MixedEnum, - grades: [u8; 4], - fuel: str[4], - hello: String, - opt: Option, - nada: Option, - bytes: Bytes, - tuple: (u8, u16, u32, str[4]), - vec_u8: Vec, -} - -struct MixedStruct { - a: u8, - b: u16, - c: u32, - d: u64, - e: u256, - f: b256, - g: B512, - native: NativeEnum, - mixed: MixedEnum, - grades: [u8; 4], - fuel: str[4], - hello: String, - opt: Option, - nada: Option, - bytes: Bytes, - tuple: (u8, u16, u32, str[4]), - vec_u8: Vec, - deep: DeeperStruct, -} - -fn main(param: MixedStruct) -> bool { - if (param.deep.d == 18446744073709551615) { - return true; - } - return false; -} diff --git a/packages/fuel-gauge/test/fixtures/forc-projects-experimental/script-echo/Forc.toml b/packages/fuel-gauge/test/fixtures/forc-projects-experimental/script-echo/Forc.toml deleted file mode 100644 index 34b6fef542..0000000000 --- a/packages/fuel-gauge/test/fixtures/forc-projects-experimental/script-echo/Forc.toml +++ /dev/null @@ -1,7 +0,0 @@ -[project] -authors = ["Fuel Labs "] -entry = "main.sw" -license = "Apache-2.0" -name = "script-echo" - -[dependencies] diff --git a/packages/fuel-gauge/test/fixtures/forc-projects-experimental/script-echo/src/main.sw b/packages/fuel-gauge/test/fixtures/forc-projects-experimental/script-echo/src/main.sw deleted file mode 100644 index 7a274d5535..0000000000 --- a/packages/fuel-gauge/test/fixtures/forc-projects-experimental/script-echo/src/main.sw +++ /dev/null @@ -1,62 +0,0 @@ -script; - -use std::b512::B512; -use std::string::String; -use std::option::Option; -use std::bytes::Bytes; -use std::vec::Vec; - -enum NativeEnum { - Checked: (), - Pending: (), -} - -enum MixedEnum { - Value: bool, - Data: u16, -} - -struct DeeperStruct { - a: u8, - b: u16, - c: u32, - d: u64, - e: u256, - f: b256, - g: B512, - native: NativeEnum, - mixed: MixedEnum, - grades: [u8; 4], - fuel: str[4], - hello: String, - opt: Option, - nada: Option, - bytes: Bytes, - tuple: (u8, u16, u32, str[4]), - vec_u8: Vec, -} - -struct MixedStruct { - a: u8, - b: u16, - c: u32, - d: u64, - e: u256, - f: b256, - g: B512, - native: NativeEnum, - mixed: MixedEnum, - grades: [u8; 4], - fuel: str[4], - hello: String, - opt: Option, - nada: Option, - bytes: Bytes, - tuple: (u8, u16, u32, str[4]), - vec_u8: Vec, - deep: DeeperStruct, -} - -fn main(param: MixedStruct) -> MixedStruct { - param -} diff --git a/packages/fuel-gauge/test/fixtures/forc-projects-experimental/script-print/Forc.toml b/packages/fuel-gauge/test/fixtures/forc-projects-experimental/script-print/Forc.toml deleted file mode 100644 index 647a1bd054..0000000000 --- a/packages/fuel-gauge/test/fixtures/forc-projects-experimental/script-print/Forc.toml +++ /dev/null @@ -1,7 +0,0 @@ -[project] -authors = ["Fuel Labs "] -entry = "main.sw" -license = "Apache-2.0" -name = "script-print" - -[dependencies] diff --git a/packages/fuel-gauge/test/fixtures/forc-projects-experimental/script-print/src/main.sw b/packages/fuel-gauge/test/fixtures/forc-projects-experimental/script-print/src/main.sw deleted file mode 100644 index 9b97833f77..0000000000 --- a/packages/fuel-gauge/test/fixtures/forc-projects-experimental/script-print/src/main.sw +++ /dev/null @@ -1,112 +0,0 @@ -script; - -use std::b512::B512; -use std::string::String; -use std::option::Option; -use std::bytes::Bytes; -use std::vec::Vec; - -enum NativeEnum { - Checked: (), - Pending: (), -} - -enum MixedEnum { - Value: bool, - Data: u16, -} - -struct DeeperStruct { - a: u8, - b: u16, - c: u32, - d: u64, - e: u256, - f: b256, - g: B512, - native: NativeEnum, - mixed: MixedEnum, - grades: [u8; 4], - fuel: str[4], - hello: String, - opt: Option, - nada: Option, - bytes: Bytes, - tuple: (u8, u16, u32, str[4]), - vec_u8: Vec, -} - -struct MixedStruct { - a: u8, - b: u16, - c: u32, - d: u64, - e: u256, - f: b256, - g: B512, - native: NativeEnum, - mixed: MixedEnum, - grades: [u8; 4], - fuel: str[4], - hello: String, - opt: Option, - nada: Option, - bytes: Bytes, - tuple: (u8, u16, u32, str[4]), - vec_u8: Vec, - deep: DeeperStruct, -} - -fn main(param_one: B512) -> MixedStruct { - let mut my_bytes = Bytes::new(); - - my_bytes.push(40u8); - my_bytes.push(41u8); - my_bytes.push(42u8); - - let mut my_vec_u8 = Vec::new(); - my_vec_u8.push(40u8); - my_vec_u8.push(41u8); - my_vec_u8.push(42u8); - - let my_struct = MixedStruct { - a: 255, - b: 65535, - c: 4294967295, - d: 18446744073709551615, - e: 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFu256, - f: 0xbebd3baab326f895289ecbd4210cf886ce41952316441ae4cac35f00f0e882a6, - g: param_one, - native: NativeEnum::Pending, - mixed: MixedEnum::Value(true), - grades: [1, 4, 6, 22], - fuel: __to_str_array("fuel"), - hello: String::from_ascii_str("Hello World"), - opt: Option::Some(42), - nada: Option::None, - bytes: my_bytes, - tuple: (255, 65535, 4294967295, __to_str_array("fuel")), - vec_u8: my_vec_u8, - deep: DeeperStruct { - a: 255, - b: 65535, - c: 4294967295, - d: 18446744073709551615, - e: 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFu256, - f: 0xbebd3baab326f895289ecbd4210cf886ce41952316441ae4cac35f00f0e882a6, - g: param_one, - native: NativeEnum::Pending, - mixed: MixedEnum::Value(true), - grades: [1, 4, 6, 22], - fuel: __to_str_array("fuel"), - hello: String::from_ascii_str("Hello World"), - opt: Option::Some(42), - nada: Option::None, - bytes: my_bytes, - tuple: (255, 65535, 4294967295, __to_str_array("fuel")), - vec_u8: my_vec_u8, - }, - }; - - my_struct -} diff --git a/packages/program/src/contract-call-script.ts b/packages/program/src/contract-call-script.ts index 7551d28188..1d892d65c7 100644 --- a/packages/program/src/contract-call-script.ts +++ b/packages/program/src/contract-call-script.ts @@ -1,13 +1,10 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -import type { EncodingVersion } from '@fuel-ts/abi-coder'; import { WORD_SIZE, B256Coder, ASSET_ID_LEN, BigNumberCoder, CONTRACT_ID_LEN, - ENCODING_V1, - ENCODING_V0, } from '@fuel-ts/abi-coder'; import type { CallResult, @@ -26,12 +23,7 @@ import * as asm from '@fuels/vm-asm'; import { InstructionSet } from './instruction-set'; import type { EncodedScriptCall, ScriptResult } from './script-request'; -import { - decodeCallResult, - ScriptRequest, - POINTER_DATA_OFFSET, - calculateScriptDataBaseOffset, -} from './script-request'; +import { decodeCallResult, ScriptRequest, calculateScriptDataBaseOffset } from './script-request'; import type { ContractCall, InvocationScopeLike } from './types'; type CallOpcodeParamsOffset = { @@ -41,17 +33,6 @@ type CallOpcodeParamsOffset = { assetIdOffset: number; }; -type CallOutputInfo = { - isHeap: boolean; - encodedLength: number; - encoding: EncodingVersion; -}; - -type ContractCallScriptFn = ( - call: ContractCall, - segmentOffset: number -) => { scriptData: Uint8Array[]; callParamOffsets: CallOpcodeParamsOffset }; - const DEFAULT_OPCODE_PARAMS: CallOpcodeParamsOffset = { assetIdOffset: 0, amountOffset: 0, @@ -72,10 +53,12 @@ const SCRIPT_WRAPPER_CONTRACT_ID = ZeroBytes32; // 0x13 Gas forwarded // // These are arbitrary non-reserved registers, no special meaning -const getSingleCallInstructions = ( - { callDataOffset, gasForwardedOffset, amountOffset, assetIdOffset }: CallOpcodeParamsOffset, - outputInfo: CallOutputInfo -): InstructionSet => { +const getSingleCallInstructions = ({ + callDataOffset, + gasForwardedOffset, + amountOffset, + assetIdOffset, +}: CallOpcodeParamsOffset): InstructionSet => { const inst = new InstructionSet( asm.movi(0x10, callDataOffset), asm.movi(0x11, amountOffset), @@ -93,36 +76,17 @@ const getSingleCallInstructions = ( inst.push(asm.call(0x10, 0x11, 0x12, asm.RegId.cgas().to_u8())); } - if (outputInfo.encoding === ENCODING_V0 && outputInfo.isHeap) { - inst.extend([ - // The RET register contains the pointer address of the `CALL` return (a stack - // address). - // The RETL register contains the length of the `CALL` return (=24 because the Vec/Bytes - // struct takes 3 WORDs). We don't actually need it unless the Vec/Bytes struct encoding - // changes in the compiler. - // Load the word located at the address contained in RET, it's a word that - // translates to a heap address. 0x15 is a free register. - asm.lw(0x15, asm.RegId.ret().to_u8(), 0), - // We know a Vec/Bytes struct has its third WORD contain the length of the underlying - // vector, so use a 2 offset to store the length in 0x16, which is a free register. - asm.lw(0x16, asm.RegId.ret().to_u8(), 2), - // The in-memory size of the type is (in-memory size of the inner type) * length - asm.muli(0x16, 0x16, outputInfo.encodedLength), - asm.retd(0x15, 0x16), - ]); - } - return inst; }; // Given a list of contract calls, create the actual opcodes used to call the contract -function getInstructions(offsets: CallOpcodeParamsOffset[], outputs: CallOutputInfo[]): Uint8Array { +function getInstructions(offsets: CallOpcodeParamsOffset[]): Uint8Array { if (!offsets.length) { return new Uint8Array(); } const multiCallInstructions = new InstructionSet(); for (let i = 0; i < offsets.length; i += 1) { - multiCallInstructions.extend(getSingleCallInstructions(offsets[i], outputs[i]).entries()); + multiCallInstructions.extend(getSingleCallInstructions(offsets[i]).entries()); } multiCallInstructions.push(asm.ret(0x01)); @@ -143,53 +107,42 @@ const getMainCallReceipt = ( type === ReceiptType.Call && from === SCRIPT_WRAPPER_CONTRACT_ID && to === contractId ); -const scriptResultDecoder = - (contractId: AbstractAddress, isOutputDataHeap: boolean) => (result: ScriptResult) => { - if (toNumber(result.code) !== 0) { - throw new FuelError(ErrorCode.SCRIPT_REVERTED, `Transaction reverted.`); - } +const scriptResultDecoder = (contractId: AbstractAddress) => (result: ScriptResult) => { + if (toNumber(result.code) !== 0) { + throw new FuelError(ErrorCode.SCRIPT_REVERTED, `Transaction reverted.`); + } - const mainCallResult = getMainCallReceipt( - result.receipts as TransactionResultCallReceipt[], - contractId.toB256() - ); - const mainCallInstructionStart = bn(mainCallResult?.is); - - const receipts = result.receipts as ReturnReceipt[]; - return receipts - .filter(({ type }) => isReturnType(type)) - .flatMap((receipt: ReturnReceipt, index, filtered) => { - if (!mainCallInstructionStart.eq(bn(receipt.is))) { - return []; - } - if (receipt.type === ReceiptType.Return) { - return [ - new BigNumberCoder('u64').encode((receipt as TransactionResultReturnReceipt).val), - ]; - } - if (receipt.type === ReceiptType.ReturnData) { - const encodedScriptReturn = arrayify(receipt.data); - if (isOutputDataHeap && isReturnType(filtered[index + 1]?.type)) { - const nextReturnData: TransactionResultReturnDataReceipt = filtered[ - index + 1 - ] as TransactionResultReturnDataReceipt; - return concat([encodedScriptReturn, arrayify(nextReturnData.data)]); - } - - return [encodedScriptReturn]; - } + const mainCallResult = getMainCallReceipt( + result.receipts as TransactionResultCallReceipt[], + contractId.toB256() + ); + const mainCallInstructionStart = bn(mainCallResult?.is); + + const receipts = result.receipts as ReturnReceipt[]; + return receipts + .filter(({ type }) => isReturnType(type)) + .flatMap((receipt: ReturnReceipt) => { + if (!mainCallInstructionStart.eq(bn(receipt.is))) { + return []; + } + if (receipt.type === ReceiptType.Return) { + return [new BigNumberCoder('u64').encode((receipt as TransactionResultReturnReceipt).val)]; + } + if (receipt.type === ReceiptType.ReturnData) { + const encodedScriptReturn = arrayify(receipt.data); - return [new Uint8Array()]; - }); - }; + return [encodedScriptReturn]; + } + + return [new Uint8Array()]; + }); +}; export const decodeContractCallScriptResult = ( callResult: CallResult, contractId: AbstractAddress, - isOutputDataHeap: boolean, logs: Array = [] -): Uint8Array[] => - decodeCallResult(callResult, scriptResultDecoder(contractId, isOutputDataHeap), logs); +): Uint8Array[] => decodeCallResult(callResult, scriptResultDecoder(contractId), logs); const getCallInstructionsLength = (contractCalls: ContractCall[]): number => contractCalls.reduce( @@ -198,156 +151,19 @@ const getCallInstructionsLength = (contractCalls: ContractCall[]): number => if (call.gas) { offset.gasForwardedOffset = 1; } - const output: CallOutputInfo = { - isHeap: call.isOutputDataHeap, - encodedLength: call.outputEncodedLength, - encoding: call.encoding ?? ENCODING_V0, - }; - return sum + getSingleCallInstructions(offset, output).byteLength(); + + return sum + getSingleCallInstructions(offset).byteLength(); }, asm.Instruction.size() // placeholder for single RET instruction which is added later ); -const getFunctionOutputInfos = (functionScopes: InvocationScopeLike[]): CallOutputInfo[] => - functionScopes.map((funcScope) => { - const { func } = funcScope.getCallConfig(); - return { - isHeap: func.outputMetadata.isHeapType, - encodedLength: func.outputMetadata.encodedLength, - encoding: func.encoding, - }; - }); - -/** - * Obtains script data for a contract call according to the V0 specification. - * - * @param call - the contract call to obtain for script data for. - * @param segmentOffset - the segment to generate pointers and offset data from. - * @returns the populated script data and call parameter offsets. - */ -export const getScriptDataV0: ContractCallScriptFn = ( - call: ContractCall, - segmentOffset: number -): { scriptData: Uint8Array[]; callParamOffsets: CallOpcodeParamsOffset } => { - const scriptData: Uint8Array[] = []; - let gasForwardedSize: number = 0; - - const callParamOffsets: CallOpcodeParamsOffset = { - amountOffset: segmentOffset, - assetIdOffset: segmentOffset + WORD_SIZE, - gasForwardedOffset: call.gas ? segmentOffset + WORD_SIZE + ASSET_ID_LEN : 0, - callDataOffset: segmentOffset + WORD_SIZE + ASSET_ID_LEN + gasForwardedSize, - }; - - // 1. Amount - scriptData.push(new BigNumberCoder('u64').encode(call.amount || 0)); - // 2. Asset ID - scriptData.push(new B256Coder().encode(call.assetId?.toString() || ZeroBytes32)); - // 3. Contract ID - scriptData.push(call.contractId.toBytes()); - // 4. Function selector - scriptData.push(new BigNumberCoder('u64').encode(call.fnSelector)); - // 5. Gas to be forwarded - if (call.gas) { - scriptData.push(new BigNumberCoder('u64').encode(call.gas)); - - gasForwardedSize = WORD_SIZE; - } - - // 6. Calldata offset - if (call.isInputDataPointer) { - const pointerInputOffset = segmentOffset + POINTER_DATA_OFFSET + gasForwardedSize; - scriptData.push(new BigNumberCoder('u64').encode(pointerInputOffset)); - } - - // 7. Encoded arguments (optional) (variable length) - const args = arrayify(call.data); - scriptData.push(args); - - return { - scriptData, - callParamOffsets, - }; -}; - -/** - * Obtains script data for a contract call according to the V1 specification. - * - * @param call - the contract call to obtain for script data for. - * @param segmentOffset - the segment to generate pointers and offset data from. - * @returns the populated script data and call parameter offsets. - */ -export const getScriptDataV1: ContractCallScriptFn = ( - call: ContractCall, - segmentOffset: number -): { scriptData: Uint8Array[]; callParamOffsets: CallOpcodeParamsOffset } => { - const scriptData: Uint8Array[] = []; - - const amountOffset = segmentOffset; - const assetIdOffset = amountOffset + WORD_SIZE; - const callDataOffset = assetIdOffset + ASSET_ID_LEN; - const encodedSelectorOffset = callDataOffset + CONTRACT_ID_LEN + WORD_SIZE + WORD_SIZE; - const encodedArgsOffset = encodedSelectorOffset + call.fnSelectorBytes.byteLength; - const encodedArgs = arrayify(call.data); - let gasForwardedOffset = 0; - - // 1. Amount - scriptData.push(new BigNumberCoder('u64').encode(call.amount || 0)); - // 2. Asset ID - scriptData.push(new B256Coder().encode(call.assetId?.toString() || ZeroBytes32)); - // 3. Contract ID - scriptData.push(call.contractId.toBytes()); - // 4. Function selector offset - scriptData.push(new BigNumberCoder('u64').encode(encodedSelectorOffset)); - // 5. Encoded argument offset - scriptData.push(new BigNumberCoder('u64').encode(encodedArgsOffset)); - // 6. Encoded function selector - scriptData.push(call.fnSelectorBytes); - // 7. Encoded arguments - scriptData.push(encodedArgs); - - // 8. Gas to be forwarded - if (call.gas) { - scriptData.push(new BigNumberCoder('u64').encode(call.gas)); - gasForwardedOffset = encodedArgsOffset + encodedArgs.byteLength; - } - - const callParamOffsets: CallOpcodeParamsOffset = { - amountOffset, - assetIdOffset, - gasForwardedOffset, - callDataOffset, - }; - - return { - scriptData, - callParamOffsets, - }; -}; - -/** - * Retrieves a script data function for a specific encoding version. - * - * @param encoding - the encoding version used for the contract call. - * @returns an appropriate script data function. - */ -export const getScriptDataForEncoding = (encoding?: string): ContractCallScriptFn => { - if (encoding === ENCODING_V1) { - return getScriptDataV1; - } - return getScriptDataV0; -}; - export const getContractCallScript = ( functionScopes: InvocationScopeLike[], maxInputs: BN ): ScriptRequest => new ScriptRequest( // Script to call the contract, start with stub size matching length of calls - getInstructions( - new Array(functionScopes.length).fill(DEFAULT_OPCODE_PARAMS), - getFunctionOutputInfos(functionScopes) - ), + getInstructions(new Array(functionScopes.length).fill(DEFAULT_OPCODE_PARAMS)), (contractCalls): EncodedScriptCall => { const TOTAL_CALLS = contractCalls.length; @@ -369,30 +185,55 @@ export const getContractCallScript = ( // The data for each call is ordered into segments const paramOffsets: CallOpcodeParamsOffset[] = []; // the data about the contract output - const outputInfos: CallOutputInfo[] = []; let segmentOffset = dataOffset; const scriptData: Uint8Array[] = []; for (let i = 0; i < TOTAL_CALLS; i += 1) { const call = contractCalls[i]; - const { scriptData: callScriptData, callParamOffsets } = getScriptDataForEncoding( - call.encoding - )(call, segmentOffset); - - // store output and param offsets for asm instructions later - outputInfos.push({ - isHeap: call.isOutputDataHeap, - encodedLength: call.outputEncodedLength, - encoding: call.encoding ?? ENCODING_V0, - }); - scriptData.push(concat(callScriptData)); + const amountOffset = segmentOffset; + const assetIdOffset = amountOffset + WORD_SIZE; + const callDataOffset = assetIdOffset + ASSET_ID_LEN; + const encodedSelectorOffset = callDataOffset + CONTRACT_ID_LEN + WORD_SIZE + WORD_SIZE; + const encodedArgsOffset = encodedSelectorOffset + call.fnSelectorBytes.byteLength; + const encodedArgs = arrayify(call.data); + let gasForwardedOffset = 0; + + // 1. Amount + scriptData.push(new BigNumberCoder('u64').encode(call.amount || 0)); + // 2. Asset ID + scriptData.push(new B256Coder().encode(call.assetId?.toString() || ZeroBytes32)); + // 3. Contract ID + scriptData.push(call.contractId.toBytes()); + // 4. Function selector offset + scriptData.push(new BigNumberCoder('u64').encode(encodedSelectorOffset)); + // 5. Encoded argument offset + scriptData.push(new BigNumberCoder('u64').encode(encodedArgsOffset)); + // 6. Encoded function selector + scriptData.push(call.fnSelectorBytes); + // 7. Encoded arguments + scriptData.push(encodedArgs); + + // 8. Gas to be forwarded + if (call.gas) { + scriptData.push(new BigNumberCoder('u64').encode(call.gas)); + gasForwardedOffset = encodedArgsOffset + encodedArgs.byteLength; + } + + const callParamOffsets: CallOpcodeParamsOffset = { + amountOffset, + assetIdOffset, + gasForwardedOffset, + callDataOffset, + }; + + // store param offsets for asm instructions later paramOffsets.push(callParamOffsets); segmentOffset = dataOffset + concat(scriptData).byteLength; } // get asm instructions - const script = getInstructions(paramOffsets, outputInfos); + const script = getInstructions(paramOffsets); const finalScriptData = concat(scriptData); return { data: finalScriptData, script }; }, diff --git a/packages/program/src/functions/base-invocation-scope.ts b/packages/program/src/functions/base-invocation-scope.ts index 8b94e63077..43affcdbed 100644 --- a/packages/program/src/functions/base-invocation-scope.ts +++ b/packages/program/src/functions/base-invocation-scope.ts @@ -19,7 +19,6 @@ import * as asm from '@fuels/vm-asm'; import { clone } from 'ramda'; import { getContractCallScript } from '../contract-call-script'; -import { POINTER_DATA_OFFSET } from '../script-request'; import type { ContractCall, InvocationScopeLike, TxParams } from '../types'; import { assert, getAbisFromAllCalls } from '../utils'; @@ -31,12 +30,9 @@ import { InvocationCallResult, FunctionInvocationResult } from './invocation-res * @param funcScope - The invocation scope containing the necessary information for the contract call. * @returns The contract call object. */ -function createContractCall(funcScope: InvocationScopeLike, offset: number): ContractCall { +function createContractCall(funcScope: InvocationScopeLike): ContractCall { const { program, args, forward, func, callParameters, externalAbis } = funcScope.getCallConfig(); - const DATA_POINTER_OFFSET = funcScope.getCallConfig().func.isInputDataPointer - ? POINTER_DATA_OFFSET - : 0; - const data = func.encodeArguments(args as Array, offset + DATA_POINTER_OFFSET); + const data = func.encodeArguments(args as Array); return { contractId: (program as AbstractContract).id, @@ -44,9 +40,6 @@ function createContractCall(funcScope: InvocationScopeLike, offset: number): Con fnSelectorBytes: func.selectorBytes, encoding: func.encoding, data, - isInputDataPointer: func.isInputDataPointer, - isOutputDataHeap: func.outputMetadata.isHeapType, - outputEncodedLength: func.outputMetadata.encodedLength, assetId: forward?.assetId, amount: forward?.amount, gas: callParameters?.gasLimit, @@ -97,11 +90,7 @@ export class BaseInvocationScope { 'Provider chain info cache is empty. Please make sure to initialize the `Provider` properly by running `await Provider.create()``' ); } - const maxInputs = consensusParams.consensusParameters.txParameters.maxInputs; - const script = getContractCallScript(this.functionInvocationScopes, maxInputs); - return this.functionInvocationScopes.map((funcScope) => - createContractCall(funcScope, script.getScriptDataOffset(maxInputs.toNumber())) - ); + return this.functionInvocationScopes.map((funcScope) => createContractCall(funcScope)); } /** diff --git a/packages/program/src/functions/invocation-results.ts b/packages/program/src/functions/invocation-results.ts index 64b94e765b..86927ec215 100644 --- a/packages/program/src/functions/invocation-results.ts +++ b/packages/program/src/functions/invocation-results.ts @@ -1,6 +1,5 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable max-classes-per-file */ -import { ENCODING_V0 } from '@fuel-ts/abi-coder'; import type { CallResult, JsonAbisFromAllCalls, @@ -98,14 +97,9 @@ export class InvocationResult { return callResultToInvocationResult(callResult, callConfig, logs); } - const outputAsIterableHeap = - (callConfig?.func.encoding === ENCODING_V0 && callConfig?.func.outputMetadata.isHeapType) || - false; - const encodedResults = decodeContractCallScriptResult( callResult, (callConfig?.program as AbstractContract).id, - outputAsIterableHeap, logs ); const returnValues = encodedResults.map((encodedResult, i) => { diff --git a/packages/program/src/functions/multicall-scope.ts b/packages/program/src/functions/multicall-scope.ts index 6672439cf9..0c7c9eae89 100644 --- a/packages/program/src/functions/multicall-scope.ts +++ b/packages/program/src/functions/multicall-scope.ts @@ -1,6 +1,4 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -import { ENCODING_V1 } from '@fuel-ts/abi-coder'; -import { ErrorCode, FuelError } from '@fuel-ts/errors'; import type { AbstractContract } from '@fuel-ts/interfaces'; import { BaseInvocationScope } from './base-invocation-scope'; @@ -21,9 +19,6 @@ export class MultiCallInvocationScope extends BaseInvocationScope constructor(contract: AbstractContract, funcScopes: Array) { super(contract, true); this.addCalls(funcScopes); - if (this.program.interface.jsonAbi.encoding !== ENCODING_V1) { - this.validateHeapTypeReturnCalls(); - } } /** @@ -45,34 +40,4 @@ export class MultiCallInvocationScope extends BaseInvocationScope addCalls(funcScopes: Array) { return super.addCalls(funcScopes); } - - private validateHeapTypeReturnCalls() { - let heapOutputIndex = -1; - let numberOfHeaps = 0; - - this.calls.forEach((call, callIndex) => { - const { isOutputDataHeap } = call; - - if (isOutputDataHeap) { - heapOutputIndex = callIndex; - - if (++numberOfHeaps > 1) { - throw new FuelError( - ErrorCode.INVALID_MULTICALL, - 'A multicall can have only one call that returns a heap type.' - ); - } - } - }); - - const hasHeapTypeReturn = heapOutputIndex !== -1; - const isOnLastCall = heapOutputIndex === this.calls.length - 1; - - if (hasHeapTypeReturn && !isOnLastCall) { - throw new FuelError( - ErrorCode.INVALID_MULTICALL, - 'In a multicall, the contract call returning a heap type must be the last call.' - ); - } - } } diff --git a/packages/program/src/types.ts b/packages/program/src/types.ts index 17d6a32338..7a7eff538c 100644 --- a/packages/program/src/types.ts +++ b/packages/program/src/types.ts @@ -14,9 +14,6 @@ export type ContractCall = { fnSelector: string; fnSelectorBytes: Uint8Array; encoding?: EncodingVersion; - isInputDataPointer: boolean; - isOutputDataHeap: boolean; - outputEncodedLength: number; amount?: BigNumberish; assetId?: BytesLike; gas?: BigNumberish; diff --git a/packages/script/src/script-invocation-scope.ts b/packages/script/src/script-invocation-scope.ts index c0edc84452..4d51a16a33 100644 --- a/packages/script/src/script-invocation-scope.ts +++ b/packages/script/src/script-invocation-scope.ts @@ -3,7 +3,6 @@ import type { Provider } from '@fuel-ts/account'; import { FuelError } from '@fuel-ts/errors'; import type { AbstractScript } from '@fuel-ts/interfaces'; import { ScriptRequest, FunctionInvocationScope } from '@fuel-ts/program'; -import { ByteArrayCoder } from '@fuel-ts/transactions'; export class ScriptInvocationScope< TArgs extends Array = Array, @@ -31,16 +30,9 @@ export class ScriptInvocationScope< ); } - const maxInputs = chainInfoCache.consensusParameters.txParameters.maxInputs.toNumber(); - - const byteLength = new ByteArrayCoder(programBytes.length).encodedLength; this.scriptRequest = new ScriptRequest( programBytes, - (args: TArgs) => - this.func.encodeArguments( - args, - ScriptRequest.getScriptDataOffsetWithScriptBytes(byteLength, maxInputs) - ), + (args: TArgs) => this.func.encodeArguments(args), () => [] as unknown as TReturn ); } diff --git a/packages/transactions/src/coders/input.ts b/packages/transactions/src/coders/input.ts index 366ea31590..a5a227e751 100644 --- a/packages/transactions/src/coders/input.ts +++ b/packages/transactions/src/coders/input.ts @@ -65,12 +65,12 @@ export class InputCoinCoder extends Coder { const parts: Uint8Array[] = []; parts.push(new B256Coder().encode(value.txID)); - parts.push(new NumberCoder('u16').encode(value.outputIndex)); + parts.push(new NumberCoder('u16', { padToWordSize: true }).encode(value.outputIndex)); parts.push(new B256Coder().encode(value.owner)); parts.push(new BigNumberCoder('u64').encode(value.amount)); parts.push(new B256Coder().encode(value.assetId)); parts.push(new TxPointerCoder().encode(value.txPointer)); - parts.push(new NumberCoder('u16').encode(value.witnessIndex)); + parts.push(new NumberCoder('u16', { padToWordSize: true }).encode(value.witnessIndex)); parts.push(new BigNumberCoder('u64').encode(value.predicateGasUsed)); parts.push(new BigNumberCoder('u64').encode(value.predicateLength)); parts.push(new BigNumberCoder('u64').encode(value.predicateDataLength)); @@ -88,7 +88,7 @@ export class InputCoinCoder extends Coder { [decoded, o] = new B256Coder().decode(data, o); const txID = decoded; - [decoded, o] = new NumberCoder('u16').decode(data, o); + [decoded, o] = new NumberCoder('u16', { padToWordSize: true }).decode(data, o); const outputIndex = decoded; [decoded, o] = new B256Coder().decode(data, o); const owner = decoded; @@ -98,7 +98,7 @@ export class InputCoinCoder extends Coder { const assetId = decoded; [decoded, o] = new TxPointerCoder().decode(data, o); const txPointer = decoded; - [decoded, o] = new NumberCoder('u16').decode(data, o); + [decoded, o] = new NumberCoder('u16', { padToWordSize: true }).decode(data, o); const witnessIndex = Number(decoded); [decoded, o] = new BigNumberCoder('u64').decode(data, o); const predicateGasUsed = decoded; @@ -163,7 +163,7 @@ export class InputContractCoder extends Coder { const parts: Uint8Array[] = []; parts.push(new B256Coder().encode(value.txID)); - parts.push(new NumberCoder('u16').encode(value.outputIndex)); + parts.push(new NumberCoder('u16', { padToWordSize: true }).encode(value.outputIndex)); parts.push(new B256Coder().encode(value.balanceRoot)); parts.push(new B256Coder().encode(value.stateRoot)); parts.push(new TxPointerCoder().encode(value.txPointer)); @@ -178,7 +178,7 @@ export class InputContractCoder extends Coder { [decoded, o] = new B256Coder().decode(data, o); const txID = decoded; - [decoded, o] = new NumberCoder('u16').decode(data, o); + [decoded, o] = new NumberCoder('u16', { padToWordSize: true }).decode(data, o); const outputIndex = decoded; [decoded, o] = new B256Coder().decode(data, o); const balanceRoot = decoded; @@ -277,7 +277,7 @@ export class InputMessageCoder extends Coder { parts.push(new ByteArrayCoder(32).encode(value.recipient)); parts.push(new BigNumberCoder('u64').encode(value.amount)); parts.push(new ByteArrayCoder(32).encode(value.nonce)); - parts.push(new NumberCoder('u16').encode(value.witnessIndex)); + parts.push(new NumberCoder('u16', { padToWordSize: true }).encode(value.witnessIndex)); parts.push(new BigNumberCoder('u64').encode(value.predicateGasUsed)); parts.push(new BigNumberCoder('u64').encode(data.length)); parts.push(new BigNumberCoder('u64').encode(value.predicateLength)); @@ -311,11 +311,11 @@ export class InputMessageCoder extends Coder { const amount = decoded; [decoded, o] = new B256Coder().decode(data, o); const nonce = decoded; - [decoded, o] = new NumberCoder('u16').decode(data, o); + [decoded, o] = new NumberCoder('u16', { padToWordSize: true }).decode(data, o); const witnessIndex = Number(decoded); [decoded, o] = new BigNumberCoder('u64').decode(data, o); const predicateGasUsed = decoded; - [decoded, o] = new NumberCoder('u32').decode(data, o); + [decoded, o] = new NumberCoder('u32', { padToWordSize: true }).decode(data, o); const dataLength = decoded; [decoded, o] = new BigNumberCoder('u64').decode(data, o); const predicateLength = decoded; @@ -359,7 +359,7 @@ export class InputCoder extends Coder { encode(value: Input): Uint8Array { const parts: Uint8Array[] = []; - parts.push(new NumberCoder('u8').encode(value.type)); + parts.push(new NumberCoder('u8', { padToWordSize: true }).encode(value.type)); const { type } = value; @@ -391,7 +391,7 @@ export class InputCoder extends Coder { let decoded; let o = offset; - [decoded, o] = new NumberCoder('u8').decode(data, o); + [decoded, o] = new NumberCoder('u8', { padToWordSize: true }).decode(data, o); const type = decoded as InputType; switch (type) { case InputType.Coin: { diff --git a/packages/transactions/src/coders/output.ts b/packages/transactions/src/coders/output.ts index fb086db054..8110df38f8 100644 --- a/packages/transactions/src/coders/output.ts +++ b/packages/transactions/src/coders/output.ts @@ -78,7 +78,7 @@ export class OutputContractCoder extends Coder { encode(value: OutputContract): Uint8Array { const parts: Uint8Array[] = []; - parts.push(new NumberCoder('u8').encode(value.inputIndex)); + parts.push(new NumberCoder('u8', { padToWordSize: true }).encode(value.inputIndex)); parts.push(new B256Coder().encode(value.balanceRoot)); parts.push(new B256Coder().encode(value.stateRoot)); @@ -89,7 +89,7 @@ export class OutputContractCoder extends Coder { let decoded; let o = offset; - [decoded, o] = new NumberCoder('u8').decode(data, o); + [decoded, o] = new NumberCoder('u8', { padToWordSize: true }).decode(data, o); const inputIndex = decoded; [decoded, o] = new B256Coder().decode(data, o); const balanceRoot = decoded; @@ -264,7 +264,7 @@ export class OutputCoder extends Coder { encode(value: Output): Uint8Array { const parts: Uint8Array[] = []; - parts.push(new NumberCoder('u8').encode(value.type)); + parts.push(new NumberCoder('u8', { padToWordSize: true }).encode(value.type)); const { type } = value; @@ -304,7 +304,7 @@ export class OutputCoder extends Coder { let decoded; let o = offset; - [decoded, o] = new NumberCoder('u8').decode(data, o); + [decoded, o] = new NumberCoder('u8', { padToWordSize: true }).decode(data, o); const type = decoded as OutputType; switch (type) { case OutputType.Coin: { diff --git a/packages/transactions/src/coders/policy.ts b/packages/transactions/src/coders/policy.ts index b7e4ae9a20..aeb7c03fb8 100644 --- a/packages/transactions/src/coders/policy.ts +++ b/packages/transactions/src/coders/policy.ts @@ -70,7 +70,7 @@ export class PoliciesCoder extends Coder { break; case PolicyType.Maturity: - parts.push(new NumberCoder('u32').encode(data)); + parts.push(new NumberCoder('u32', { padToWordSize: true }).encode(data)); break; default: { @@ -99,7 +99,10 @@ export class PoliciesCoder extends Coder { } if (policyTypes & PolicyType.Maturity) { - const [maturity, nextOffset] = new NumberCoder('u32').decode(data, o); + const [maturity, nextOffset] = new NumberCoder('u32', { padToWordSize: true }).decode( + data, + o + ); o = nextOffset; policies.push({ type: PolicyType.Maturity, data: maturity }); } diff --git a/packages/transactions/src/coders/receipt.ts b/packages/transactions/src/coders/receipt.ts index e883c85a61..19c4b1970f 100644 --- a/packages/transactions/src/coders/receipt.ts +++ b/packages/transactions/src/coders/receipt.ts @@ -709,7 +709,7 @@ export class ReceiptMessageOutCoder extends Coder { encode(value: Receipt): Uint8Array { const parts: Uint8Array[] = []; - parts.push(new NumberCoder('u8').encode(value.type)); + parts.push(new NumberCoder('u8', { padToWordSize: true }).encode(value.type)); const { type } = value; @@ -986,7 +986,7 @@ export class ReceiptCoder extends Coder { let decoded; let o = offset; - [decoded, o] = new NumberCoder('u8').decode(data, o); + [decoded, o] = new NumberCoder('u8', { padToWordSize: true }).decode(data, o); const type = decoded as ReceiptType; switch (type) { case ReceiptType.Call: { diff --git a/packages/transactions/src/coders/transaction.test.ts b/packages/transactions/src/coders/transaction.test.ts index c4ca284623..9f5d654b5b 100644 --- a/packages/transactions/src/coders/transaction.test.ts +++ b/packages/transactions/src/coders/transaction.test.ts @@ -319,7 +319,7 @@ describe('TransactionCoder', () => { const encoded = hexlify(new TransactionCoder().encode(transaction)); expect(encoded).toEqual( - '0x000000000000000300000000000000000000000000000001d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b000000000000000500000000000000000000000000000000000000000000000000000000000003e800000000000003e8' + '0x000000000000000300000000000000000000000000000001d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b0000000500000000000000000000000003e800000000000003e8' ); const [decoded, offset] = new TransactionCoder().decode(arrayify(encoded), 0); @@ -389,7 +389,7 @@ describe('TransactionCoder', () => { const encoded = hexlify(new TransactionCoder().encode(transaction)); expect(encoded).toEqual( - '0x00000000000000030000000000000001d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b000000000000000700000000000000010000000000000001000000000000000300000000000003e800000000000003e800000000000003e80000000000000001d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b0000000000000000d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930bd5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b00000000000000000000000000000000d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b0000000000000000d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b0000000000000001d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b000000000000000101000000000000000000000000000002010100000000000000000000000000030101010000000000' + '0x00000000000000030000000000000001d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b0000000700010001000300000000000003e800000000000003e800000000000003e80000000000000001d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b0000000000000000d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930bd5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b00000000000000000000000000000000d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b0000000000000000d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b0000000000000001d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b000000000000000101000000000000000000000000000002010100000000000000000000000000030101010000000000' ); const [decoded, offset] = new TransactionCoder().decode(arrayify(encoded), 0); @@ -426,7 +426,7 @@ describe('TransactionCoder', () => { const encoded = hexlify(new TransactionCoder().encode(transaction)); expect(encoded).toEqual( - '0x0000000000000004d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b00000000000003840000000000000384000000000000038400000000000000030000000000000007000000000000000000000000000000000000000000000000d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930bd5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930bd5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b00000000000003e800000000000003e800000000000003e8' + '0x0000000000000004d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b038403840384000300000007000000000000d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930bd5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930bd5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b00000000000003e800000000000003e800000000000003e8' ); const [decoded, offset] = new TransactionCoder().decode(arrayify(encoded), 0); @@ -521,7 +521,7 @@ describe('TransactionCoder', () => { const encoded = hexlify(new TransactionCoder().encode(transaction)); expect(encoded).toEqual( - '0x0000000000000004d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b0000000000000384000000000000038400000000000003840000000000000005000000000000000f000000000000000200000000000000020000000000000003d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930bd5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930bd5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930bd5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930bd5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b00000000000003e800000000000003e800000000000003e800000000000000200000000000000000d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b0000000000000000d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b0000000000000000d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b0000000000000000d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930bd5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b00000000000000000000000000000000d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b0000000000000000d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b0000000000000001d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b0000000000000002d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b0000000000000001d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b000000000000000101000000000000000000000000000002010100000000000000000000000000030101010000000000' + '0x0000000000000004d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b03840384038400050000000f000200020003d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930bd5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930bd5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930bd5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930bd5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b00000000000003e800000000000003e800000000000003e800000000000000200000000000000000d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b0000000000000000d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b0000000000000000d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b0000000000000000d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930bd5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b00000000000000000000000000000000d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b0000000000000000d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b0000000000000001d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b0000000000000002d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b0000000000000001d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b000000000000000101000000000000000000000000000002010100000000000000000000000000030101010000000000' ); const [decoded, offset] = new TransactionCoder().decode(arrayify(encoded), 0); diff --git a/packages/transactions/src/coders/transaction.ts b/packages/transactions/src/coders/transaction.ts index 740f778a2e..64f055603f 100644 --- a/packages/transactions/src/coders/transaction.ts +++ b/packages/transactions/src/coders/transaction.ts @@ -86,10 +86,10 @@ export class TransactionScriptCoder extends Coder { encode(value: Transaction): Uint8Array { const parts: Uint8Array[] = []; - parts.push(new NumberCoder('u8').encode(value.type)); + parts.push(new NumberCoder('u8', { padToWordSize: true }).encode(value.type)); const { type } = value; @@ -641,7 +641,7 @@ export class TransactionCoder extends Coder { let decoded; let o = offset; - [decoded, o] = new NumberCoder('u8').decode(data, o); + [decoded, o] = new NumberCoder('u8', { padToWordSize: true }).decode(data, o); const type = decoded as TransactionType; switch (type) { diff --git a/packages/transactions/src/coders/tx-pointer.ts b/packages/transactions/src/coders/tx-pointer.ts index 5e9f1dbffe..a4cd880f5c 100644 --- a/packages/transactions/src/coders/tx-pointer.ts +++ b/packages/transactions/src/coders/tx-pointer.ts @@ -14,8 +14,8 @@ export class TxPointerCoder extends StructCoder<{ }> { constructor() { super('TxPointer', { - blockHeight: new NumberCoder('u32'), - txIndex: new NumberCoder('u16'), + blockHeight: new NumberCoder('u32', { padToWordSize: true }), + txIndex: new NumberCoder('u16', { padToWordSize: true }), }); } } diff --git a/packages/transactions/src/coders/upgrade-purpose.test.ts b/packages/transactions/src/coders/upgrade-purpose.test.ts index 4bff302e37..9c40186179 100644 --- a/packages/transactions/src/coders/upgrade-purpose.test.ts +++ b/packages/transactions/src/coders/upgrade-purpose.test.ts @@ -23,7 +23,7 @@ describe('UpgradePurposeCoder', () => { }; const typeBytes = [0, 0, 0, 0, 0, 0, 0, UpgradePurposeTypeEnum.ConsensusParameters]; - const witnessIndexBytes = new NumberCoder('u8').encode(witnessIndex); + const witnessIndexBytes = new NumberCoder('u8', { padToWordSize: true }).encode(witnessIndex); const checksumBytes = new B256Coder().encode(checksum); const expectedEncoded = Uint8Array.from([...typeBytes, ...witnessIndexBytes, ...checksumBytes]); diff --git a/packages/transactions/src/coders/upgrade-purpose.ts b/packages/transactions/src/coders/upgrade-purpose.ts index 1544033e26..1b51e340ab 100644 --- a/packages/transactions/src/coders/upgrade-purpose.ts +++ b/packages/transactions/src/coders/upgrade-purpose.ts @@ -39,13 +39,13 @@ export class UpgradePurposeCoder extends Coder { const parts: Uint8Array[] = []; const { type } = upgradePurposeType; - parts.push(new NumberCoder('u8').encode(type)); + parts.push(new NumberCoder('u8', { padToWordSize: true }).encode(type)); switch (type) { case UpgradePurposeTypeEnum.ConsensusParameters: { const data = upgradePurposeType.data as ConsensusParameters; - parts.push(new NumberCoder('u16').encode(data.witnessIndex)); + parts.push(new NumberCoder('u16', { padToWordSize: true }).encode(data.witnessIndex)); parts.push(new B256Coder().encode(data.checksum)); break; } @@ -72,12 +72,12 @@ export class UpgradePurposeCoder extends Coder { let o = offset; let decoded; - [decoded, o] = new NumberCoder('u8').decode(data, o); + [decoded, o] = new NumberCoder('u8', { padToWordSize: true }).decode(data, o); const type = decoded as UpgradePurposeTypeEnum; switch (type) { case UpgradePurposeTypeEnum.ConsensusParameters: { - [decoded, o] = new NumberCoder('u16').decode(data, o); + [decoded, o] = new NumberCoder('u16', { padToWordSize: true }).decode(data, o); const witnessIndex = decoded; [decoded, o] = new B256Coder().decode(data, o); const checksum = decoded; diff --git a/packages/transactions/src/coders/utxo-id.ts b/packages/transactions/src/coders/utxo-id.ts index 08af089e19..c6b0688e93 100644 --- a/packages/transactions/src/coders/utxo-id.ts +++ b/packages/transactions/src/coders/utxo-id.ts @@ -14,7 +14,7 @@ export class UtxoIdCoder extends StructCoder<{ constructor() { super('UtxoId', { transactionId: new B256Coder(), - outputIndex: new NumberCoder('u8'), + outputIndex: new NumberCoder('u8', { padToWordSize: true }), }); } } diff --git a/packages/transactions/src/coders/witness.ts b/packages/transactions/src/coders/witness.ts index d56e28eafc..5121e60fc3 100644 --- a/packages/transactions/src/coders/witness.ts +++ b/packages/transactions/src/coders/witness.ts @@ -23,7 +23,7 @@ export class WitnessCoder extends Coder { encode(value: Witness): Uint8Array { const parts: Uint8Array[] = []; - parts.push(new NumberCoder('u32').encode(value.dataLength)); + parts.push(new NumberCoder('u32', { padToWordSize: true }).encode(value.dataLength)); parts.push(new ByteArrayCoder(value.dataLength).encode(value.data)); return concat(parts); @@ -33,7 +33,7 @@ export class WitnessCoder extends Coder { let decoded; let o = offset; - [decoded, o] = new NumberCoder('u32').decode(data, o); + [decoded, o] = new NumberCoder('u32', { padToWordSize: true }).decode(data, o); const dataLength = decoded; [decoded, o] = new ByteArrayCoder(dataLength).decode(data, o); const witnessData = decoded; diff --git a/packages/versions/src/lib/getBuiltinVersions.ts b/packages/versions/src/lib/getBuiltinVersions.ts index e95ad51795..ec5bb6768f 100644 --- a/packages/versions/src/lib/getBuiltinVersions.ts +++ b/packages/versions/src/lib/getBuiltinVersions.ts @@ -1,6 +1,6 @@ export function getBuiltinVersions() { return { - FORC: '0.56.1', + FORC: '0.58.0', FUEL_CORE: '0.26.0', FUELS: '0.85.0', };