From 9a18682c8121cc77142486b2e7cdd6f4a844b89c Mon Sep 17 00:00:00 2001 From: chad Date: Wed, 21 Aug 2024 22:17:36 -0500 Subject: [PATCH 01/12] feat: added support for unknown txn types --- packages/account/src/account.ts | 6 +- packages/account/src/predicate/predicate.ts | 6 +- packages/account/src/providers/provider.ts | 6 +- .../providers/transaction-request/index.ts | 1 + .../transaction-request.ts | 7 +- .../providers/transaction-request/types.ts | 10 +- .../unknown-transaction-request.ts | 57 +++++ .../transaction-request/utils.test.ts | 20 +- .../providers/transaction-request/utils.ts | 16 +- .../transaction-summary/operations.ts | 2 + .../providers/transaction-summary/types.ts | 1 + .../src/wallet/base-wallet-unlocked.ts | 6 +- packages/fuel-gauge/src/transaction.test.ts | 34 ++- .../transactions/src/coders/transaction.ts | 241 +++++++++--------- 14 files changed, 270 insertions(+), 143 deletions(-) create mode 100644 packages/account/src/providers/transaction-request/unknown-transaction-request.ts diff --git a/packages/account/src/account.ts b/packages/account/src/account.ts index 522faefdee1..f4ef4930fa3 100644 --- a/packages/account/src/account.ts +++ b/packages/account/src/account.ts @@ -18,7 +18,6 @@ import type { ExcludeResourcesOption, Provider, ScriptTransactionRequestLike, - TransactionResponse, TransactionCost, EstimateTransactionParams, CursorPaginationArgs, @@ -36,6 +35,8 @@ import { ScriptTransactionRequest, transactionRequestify, addAmountToCoinQuantities, + isTransactionTypeUnknown, + TransactionResponse, } from './providers'; import { cacheRequestInputsResourcesFromOwner, @@ -632,6 +633,9 @@ export class Account extends AbstractAccount { ); } const transactionRequest = transactionRequestify(transactionRequestLike); + if (isTransactionTypeUnknown(transactionRequest)) { + return new TransactionResponse(transactionRequest, this.provider); + } if (estimateTxDependencies) { await this.provider.estimateTxDependencies(transactionRequest); } diff --git a/packages/account/src/predicate/predicate.ts b/packages/account/src/predicate/predicate.ts index 8121d0a3567..23e3b59273e 100644 --- a/packages/account/src/predicate/predicate.ts +++ b/packages/account/src/predicate/predicate.ts @@ -11,6 +11,8 @@ import { transactionRequestify, isRequestInputResource, isRequestInputResourceFromOwner, + isTransactionTypeUnknown, + TransactionResponse, } from '../providers'; import type { CallResult, @@ -20,7 +22,6 @@ import type { Resource, TransactionRequest, TransactionRequestLike, - TransactionResponse, } from '../providers'; import { getPredicateRoot } from './utils'; @@ -117,6 +118,9 @@ export class Predicate< */ sendTransaction(transactionRequestLike: TransactionRequestLike): Promise { const transactionRequest = transactionRequestify(transactionRequestLike); + if (isTransactionTypeUnknown(transactionRequest)) { + return Promise.resolve(new TransactionResponse(transactionRequest, this.provider)); + } return super.sendTransaction(transactionRequest, { estimateTxDependencies: false }); } diff --git a/packages/account/src/providers/provider.ts b/packages/account/src/providers/provider.ts index c19359886b6..9684ee9c1d2 100644 --- a/packages/account/src/providers/provider.ts +++ b/packages/account/src/providers/provider.ts @@ -46,6 +46,7 @@ import type { import { isTransactionTypeCreate, isTransactionTypeScript, + isTransactionTypeUnknown, transactionRequestify, } from './transaction-request'; import type { TransactionResultReceipt } from './transaction-response'; @@ -739,12 +740,15 @@ Supported fuel-core version: ${supportedVersion}.` * @param sendTransactionParams - The provider send transaction parameters (optional). * @returns A promise that resolves to the transaction response object. */ - // #region Provider-sendTransaction async sendTransaction( transactionRequestLike: TransactionRequestLike, { estimateTxDependencies = true }: ProviderSendTxParams = {} ): Promise { const transactionRequest = transactionRequestify(transactionRequestLike); + if (isTransactionTypeUnknown(transactionRequest)) { + return new TransactionResponse(transactionRequest, this); + } + // #region Provider-sendTransaction if (estimateTxDependencies) { await this.estimateTxDependencies(transactionRequest); } diff --git a/packages/account/src/providers/transaction-request/index.ts b/packages/account/src/providers/transaction-request/index.ts index 37116d65685..808dc1eed8a 100644 --- a/packages/account/src/providers/transaction-request/index.ts +++ b/packages/account/src/providers/transaction-request/index.ts @@ -4,6 +4,7 @@ export * from './transaction-request'; export * from './blob-transaction-request'; export * from './create-transaction-request'; export * from './script-transaction-request'; +export * from './unknown-transaction-request'; export * from './errors'; export * from './scripts'; export * from './types'; diff --git a/packages/account/src/providers/transaction-request/transaction-request.ts b/packages/account/src/providers/transaction-request/transaction-request.ts index 64c631ef46a..9b1a249b51b 100644 --- a/packages/account/src/providers/transaction-request/transaction-request.ts +++ b/packages/account/src/providers/transaction-request/transaction-request.ts @@ -11,6 +11,7 @@ import type { Policy, TransactionCreate, TransactionBlob, + TransactionUnknown, } from '@fuel-ts/transactions'; import { PolicyType, @@ -192,7 +193,11 @@ export abstract class BaseTransactionRequest implements BaseTransactionRequestLi }; } - abstract toTransaction(): TransactionCreate | TransactionScript | TransactionBlob; + abstract toTransaction(): + | TransactionCreate + | TransactionScript + | TransactionBlob + | TransactionUnknown; /** * Converts the transaction request to a byte array. diff --git a/packages/account/src/providers/transaction-request/types.ts b/packages/account/src/providers/transaction-request/types.ts index 10569374f0c..e05bb599a7a 100644 --- a/packages/account/src/providers/transaction-request/types.ts +++ b/packages/account/src/providers/transaction-request/types.ts @@ -13,15 +13,21 @@ import type { ScriptTransactionRequest, ScriptTransactionRequestLike, } from './script-transaction-request'; +import type { + UnknownTransactionRequestLike, + UnknownTransactionRequest, +} from './unknown-transaction-request'; export type TransactionRequest = | ScriptTransactionRequest | CreateTransactionRequest - | BlobTransactionRequest; + | BlobTransactionRequest + | UnknownTransactionRequest; export type TransactionRequestLike = | ({ type: TransactionType.Script } & ScriptTransactionRequestLike) | ({ type: TransactionType.Create } & CreateTransactionRequestLike) - | ({ type: TransactionType.Blob } & BlobTransactionRequestLike); + | ({ type: TransactionType.Blob } & BlobTransactionRequestLike) + | ({ type: TransactionType.Unknown } & UnknownTransactionRequestLike); export type JsonAbisFromAllCalls = { main: JsonAbi; diff --git a/packages/account/src/providers/transaction-request/unknown-transaction-request.ts b/packages/account/src/providers/transaction-request/unknown-transaction-request.ts new file mode 100644 index 00000000000..f93c376833f --- /dev/null +++ b/packages/account/src/providers/transaction-request/unknown-transaction-request.ts @@ -0,0 +1,57 @@ +import type { BytesLike } from '@fuel-ts/interfaces'; +import type { TransactionUnknown } from '@fuel-ts/transactions'; + +import { hashTransaction } from './hash-transaction'; +import type { BaseTransactionRequestLike } from './transaction-request'; +import { BaseTransactionRequest, TransactionType } from './transaction-request'; + +/** + * @hidden + */ +export interface UnknownTransactionRequestLike extends BaseTransactionRequestLike { + data?: BytesLike; +} + +export class UnknownTransactionRequest extends BaseTransactionRequest { + static from(obj: UnknownTransactionRequestLike) { + if (obj instanceof this) { + return obj; + } + return new this(obj); + } + + /** Type of the transaction */ + type = TransactionType.Unknown as const; + + /** Data of the transaction */ + data?: BytesLike; + + constructor({ data, ...rest }: UnknownTransactionRequestLike = {}) { + super(rest); + this.data = data; + } + + /** + * Gets the Transaction Request by hashing the transaction. + * + * @param chainId - The chain ID. + * + * @returns - A hash of the transaction, which is the transaction ID. + */ + getTransactionId(chainId: number): string { + return hashTransaction(this, chainId); + } + + /** + * Converts the transaction request to a `TransactionBlob`. + * + * @returns The transaction create object. + */ + toTransaction(): TransactionUnknown { + return { + ...this.getBaseTransaction(), + type: TransactionType.Unknown, + data: this.data, + }; + } +} diff --git a/packages/account/src/providers/transaction-request/utils.test.ts b/packages/account/src/providers/transaction-request/utils.test.ts index 35c89e49715..135a6bf4acb 100644 --- a/packages/account/src/providers/transaction-request/utils.test.ts +++ b/packages/account/src/providers/transaction-request/utils.test.ts @@ -1,7 +1,13 @@ import { BlobTransactionRequest } from './blob-transaction-request'; import { CreateTransactionRequest } from './create-transaction-request'; import { ScriptTransactionRequest } from './script-transaction-request'; -import { isTransactionTypeBlob, isTransactionTypeCreate, isTransactionTypeScript } from './utils'; +import { UnknownTransactionRequest } from './unknown-transaction-request'; +import { + isTransactionTypeBlob, + isTransactionTypeCreate, + isTransactionTypeScript, + isTransactionTypeUnknown, +} from './utils'; /** * @group node @@ -42,3 +48,15 @@ describe('isTransactionTypeBlob', () => { expect(isTransactionTypeCreate(request)).toBe(false); }); }); + +describe('isTransactionTypeUnknown', () => { + it('should return true if the request is an unknown transaction', () => { + const request = new UnknownTransactionRequest({ data: '0x' }); + expect(isTransactionTypeUnknown(request)).toBe(true); + }); + + it('should return false if the request is not an unknown transaction', () => { + const request = new ScriptTransactionRequest(); + expect(isTransactionTypeUnknown(request)).toBe(false); + }); +}); diff --git a/packages/account/src/providers/transaction-request/utils.ts b/packages/account/src/providers/transaction-request/utils.ts index 3aec3e92f2b..3f84172c418 100644 --- a/packages/account/src/providers/transaction-request/utils.ts +++ b/packages/account/src/providers/transaction-request/utils.ts @@ -1,10 +1,10 @@ -import { ErrorCode, FuelError } from '@fuel-ts/errors'; import { TransactionType } from '@fuel-ts/transactions'; import { BlobTransactionRequest } from './blob-transaction-request'; import { CreateTransactionRequest } from './create-transaction-request'; import { ScriptTransactionRequest } from './script-transaction-request'; import type { TransactionRequestLike, TransactionRequest } from './types'; +import { UnknownTransactionRequest } from './unknown-transaction-request'; /** @hidden */ export const transactionRequestify = (obj: TransactionRequestLike): TransactionRequest => { @@ -16,8 +16,6 @@ export const transactionRequestify = (obj: TransactionRequestLike): TransactionR return obj; } - const { type } = obj; - switch (obj.type) { case TransactionType.Script: { return ScriptTransactionRequest.from(obj); @@ -29,10 +27,11 @@ export const transactionRequestify = (obj: TransactionRequestLike): TransactionR return BlobTransactionRequest.from(obj); } default: { - throw new FuelError( - ErrorCode.UNSUPPORTED_TRANSACTION_TYPE, - `Unsupported transaction type: ${type}.` + // eslint-disable-next-line no-console + console.warn( + 'This transaction type is not supported in this SDK version, it will be ignored, if you believe this is an error, please upgrade your SDK' ); + return UnknownTransactionRequest.from(obj); } } }; @@ -51,3 +50,8 @@ export const isTransactionTypeCreate = ( export const isTransactionTypeBlob = ( request: TransactionRequestLike ): request is BlobTransactionRequest => request.type === TransactionType.Blob; + +/** @hidden */ +export const isTransactionTypeUnknown = ( + request: TransactionRequestLike +): request is UnknownTransactionRequest => request.type === TransactionType.Unknown; diff --git a/packages/account/src/providers/transaction-summary/operations.ts b/packages/account/src/providers/transaction-summary/operations.ts index 4ef7d3fc816..713e36f5a5d 100644 --- a/packages/account/src/providers/transaction-summary/operations.ts +++ b/packages/account/src/providers/transaction-summary/operations.ts @@ -61,6 +61,8 @@ export function getTransactionTypeName(transactionType: TransactionType): Transa return TransactionTypeName.Script; case TransactionType.Blob: return TransactionTypeName.Blob; + case TransactionType.Unknown: + return TransactionTypeName.Unknown; default: throw new FuelError( ErrorCode.UNSUPPORTED_TRANSACTION_TYPE, diff --git a/packages/account/src/providers/transaction-summary/types.ts b/packages/account/src/providers/transaction-summary/types.ts index 012d1982491..7dfec1e8ac1 100644 --- a/packages/account/src/providers/transaction-summary/types.ts +++ b/packages/account/src/providers/transaction-summary/types.ts @@ -36,6 +36,7 @@ export enum TransactionTypeName { Upgrade = 'Upgrade', Upload = 'Upload', Blob = 'Blob', + Unknown = 'Unknown', } /** diff --git a/packages/account/src/wallet/base-wallet-unlocked.ts b/packages/account/src/wallet/base-wallet-unlocked.ts index 0774a584e35..5a84e5c62fc 100644 --- a/packages/account/src/wallet/base-wallet-unlocked.ts +++ b/packages/account/src/wallet/base-wallet-unlocked.ts @@ -3,9 +3,8 @@ import type { BytesLike } from '@fuel-ts/interfaces'; import { hexlify } from '@fuel-ts/utils'; import { Account } from '../account'; -import { transactionRequestify } from '../providers'; +import { isTransactionTypeUnknown, transactionRequestify, TransactionResponse } from '../providers'; import type { - TransactionResponse, TransactionRequestLike, CallResult, Provider, @@ -115,6 +114,9 @@ export class BaseWalletUnlocked extends Account { { estimateTxDependencies = false }: ProviderSendTxParams = {} ): Promise { const transactionRequest = transactionRequestify(transactionRequestLike); + if (isTransactionTypeUnknown(transactionRequest)) { + return new TransactionResponse(transactionRequest, this.provider); + } if (estimateTxDependencies) { await this.provider.estimateTxDependencies(transactionRequest); } diff --git a/packages/fuel-gauge/src/transaction.test.ts b/packages/fuel-gauge/src/transaction.test.ts index 564510d5611..357d4c82491 100644 --- a/packages/fuel-gauge/src/transaction.test.ts +++ b/packages/fuel-gauge/src/transaction.test.ts @@ -1,4 +1,4 @@ -import { TransactionType } from 'fuels'; +import { TransactionType, UnknownTransactionRequest, Wallet } from 'fuels'; import { launchTestNode } from 'fuels/test-utils'; /** @@ -21,4 +21,36 @@ describe('Transaction', () => { expect(tx.type).toBe(TransactionType.Mint); }); + + it('Should log a warning when the transaction type is unknown', async () => { + using launched = await launchTestNode(); + const { + provider, + wallets: [wallet], + } = launched; + + // Check if a warning was logged to the console + const consoleWarnSpy = vi.spyOn(console, 'warn'); + + const amountToTransfer = 120; + + const receipient = Wallet.generate({ provider }); + + const request = new UnknownTransactionRequest({ + data: '0x', + }); + + request.addCoinOutput(receipient.address, amountToTransfer, provider.getBaseAssetId()); + + await wallet.sendTransaction(request); + + expect(consoleWarnSpy).toHaveBeenCalledWith( + expect.stringContaining( + 'This transaction type is not supported in this SDK version, it will be ignored, if you believe this is an error, please upgrade your SDK' + ) + ); + + // Clean up the spy + consoleWarnSpy.mockRestore(); + }); }); diff --git a/packages/transactions/src/coders/transaction.ts b/packages/transactions/src/coders/transaction.ts index dbb94fe9446..7b71b67357d 100644 --- a/packages/transactions/src/coders/transaction.ts +++ b/packages/transactions/src/coders/transaction.ts @@ -2,6 +2,7 @@ import { Coder, ArrayCoder, B256Coder, NumberCoder, BigNumberCoder } from '@fuel-ts/abi-coder'; import { ErrorCode, FuelError } from '@fuel-ts/errors'; +import type { BytesLike } from '@fuel-ts/interfaces'; import { type BN } from '@fuel-ts/math'; import { concat } from '@fuel-ts/utils'; @@ -27,22 +28,26 @@ export enum TransactionType /* u8 */ { Upgrade = 3, Upload = 4, Blob = 5, + Unknown = 6, } -export type TransactionScript = { - type: TransactionType.Script; +type BaseTransaction = { + /** The type of the transaction */ + type: TransactionType; + /** List of witnesses (Witness[]) */ + witnesses: Witness[]; - /** Gas limit for transaction (u64) */ - scriptGasLimit: BN; + /** Number of witnesses (u16) */ + witnessesCount: number; - /** Merkle root of receipts (b256) */ - receiptsRoot: string; + /** List of outputs (Output[]) */ + outputs: Output[]; - /** Script length, in instructions (u64) */ - scriptLength: BN; + /** List of inputs (Input[]) */ + inputs: Input[]; - /** Length of script input data, in bytes (u64) */ - scriptDataLength: BN; + /** List of policies. */ + policies: Policy[]; /** Bitfield of used policy types (u32) */ policyTypes: number; @@ -52,27 +57,28 @@ export type TransactionScript = { /** Number of outputs (u16) */ outputsCount: number; +}; - /** Number of witnesses (u16) */ - witnessesCount: number; +export type TransactionScript = BaseTransaction & { + type: TransactionType.Script; - /** Script to execute (byte[]) */ - script: string; + /** Gas limit for transaction (u64) */ + scriptGasLimit: BN; - /** Script input data (parameters) (byte[]) */ - scriptData: string; + /** Merkle root of receipts (b256) */ + receiptsRoot: string; - /** List of policies, sorted by PolicyType. */ - policies: Policy[]; + /** Script length, in instructions (u64) */ + scriptLength: BN; - /** List of inputs (Input[]) */ - inputs: Input[]; + /** Length of script input data, in bytes (u64) */ + scriptDataLength: BN; - /** List of outputs (Output[]) */ - outputs: Output[]; + /** Script to execute (byte[]) */ + script: string; - /** List of witnesses (Witness[]) */ - witnesses: Witness[]; + /** Script input data (parameters) (byte[]) */ + scriptData: string; }; export class TransactionScriptCoder extends Coder { @@ -156,7 +162,7 @@ export class TransactionScriptCoder extends Coder { @@ -348,35 +330,11 @@ export class TransactionMintCoder extends Coder { @@ -441,7 +399,7 @@ export class TransactionUpgradeCoder extends Coder { @@ -569,7 +503,7 @@ export class TransactionUploadCoder extends Coder { @@ -669,13 +579,79 @@ export class TransactionBlobCoder extends Coder { + constructor() { + super('TransactionUnknown', 'struct TransactionUnknown', 0); + } + + encode(value: TransactionUnknown): Uint8Array { + const parts: Uint8Array[] = []; + + parts.push(new NumberCoder('u32', { padToWordSize: true }).encode(value.policyTypes)); + parts.push(new NumberCoder('u16', { padToWordSize: true }).encode(value.inputsCount)); + parts.push(new NumberCoder('u16', { padToWordSize: true }).encode(value.outputsCount)); + parts.push(new NumberCoder('u16', { padToWordSize: true }).encode(value.witnessesCount)); + parts.push(new PoliciesCoder().encode(value.policies)); + parts.push(new ArrayCoder(new InputCoder(), value.inputsCount).encode(value.inputs)); + parts.push(new ArrayCoder(new OutputCoder(), value.outputsCount).encode(value.outputs)); + parts.push(new ArrayCoder(new WitnessCoder(), value.witnessesCount).encode(value.witnesses)); + + return concat(parts); + } + + decode(data: Uint8Array, offset: number): [TransactionUnknown, number] { + let decoded; + let o = offset; + + [decoded, o] = new NumberCoder('u32', { padToWordSize: true }).decode(data, o); + const policyTypes = decoded; + [decoded, o] = new NumberCoder('u16', { padToWordSize: true }).decode(data, o); + const inputsCount = decoded; + [decoded, o] = new NumberCoder('u16', { padToWordSize: true }).decode(data, o); + const outputsCount = decoded; + [decoded, o] = new NumberCoder('u16', { padToWordSize: true }).decode(data, o); + const witnessesCount = decoded; + [decoded, o] = new PoliciesCoder().decode(data, o, policyTypes); + const policies = decoded; + [decoded, o] = new ArrayCoder(new InputCoder(), inputsCount).decode(data, o); + const inputs = decoded; + [decoded, o] = new ArrayCoder(new OutputCoder(), outputsCount).decode(data, o); + const outputs = decoded; + [decoded, o] = new ArrayCoder(new WitnessCoder(), witnessesCount).decode(data, o); + const witnesses = decoded; + + return [ + { + type: TransactionType.Unknown, + policyTypes, + inputsCount, + outputsCount, + witnessesCount, + policies, + inputs, + outputs, + witnesses, + }, + o, + ]; + } +} + type PossibleTransactions = | TransactionScript | TransactionCreate | TransactionMint | TransactionUpgrade | TransactionUpload - | TransactionBlob; + | TransactionBlob + | TransactionUnknown; export type Transaction = TTransactionType extends TransactionType ? Extract @@ -684,7 +660,8 @@ export type Transaction = TTransactionType extends Tran Partial> & Partial> & Partial> & - Partial> & { + Partial> & + Partial> & { type: TransactionType; }; @@ -733,6 +710,12 @@ export class TransactionCoder extends Coder { parts.push(new TransactionBlobCoder().encode(value as Transaction)); break; } + case TransactionType.Unknown: { + parts.push( + new TransactionUnknownCoder().encode(value as Transaction) + ); + break; + } default: { throw new FuelError( ErrorCode.UNSUPPORTED_TRANSACTION_TYPE, @@ -776,6 +759,10 @@ export class TransactionCoder extends Coder { [decoded, o] = new TransactionBlobCoder().decode(data, o); return [decoded, o]; } + case TransactionType.Unknown: { + [decoded, o] = new TransactionUnknownCoder().decode(data, o); + return [decoded, o]; + } default: { throw new FuelError( ErrorCode.UNSUPPORTED_TRANSACTION_TYPE, From 74953029cc5e7d1115ac9e0950c638760592bc91 Mon Sep 17 00:00:00 2001 From: chad Date: Wed, 21 Aug 2024 22:18:51 -0500 Subject: [PATCH 02/12] docs: add changeset --- .changeset/honest-toes-pump.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changeset/honest-toes-pump.md diff --git a/.changeset/honest-toes-pump.md b/.changeset/honest-toes-pump.md new file mode 100644 index 00000000000..128c5b5ad75 --- /dev/null +++ b/.changeset/honest-toes-pump.md @@ -0,0 +1,6 @@ +--- +"@fuel-ts/transactions": patch +"@fuel-ts/account": patch +--- + +feat: added support for unknown txn types From dd5cb42c7a03bbcd0105a1649eb21fe14cbd8b98 Mon Sep 17 00:00:00 2001 From: chad Date: Thu, 22 Aug 2024 16:19:21 -0500 Subject: [PATCH 03/12] fix: ensure base transaction type is distinguished from unsupported --- .../providers/transaction-request/utils.ts | 37 ++++++++++++++++--- .../transactions/src/coders/transaction.ts | 15 ++++---- 2 files changed, 40 insertions(+), 12 deletions(-) diff --git a/packages/account/src/providers/transaction-request/utils.ts b/packages/account/src/providers/transaction-request/utils.ts index 3f84172c418..f5c042ecaf0 100644 --- a/packages/account/src/providers/transaction-request/utils.ts +++ b/packages/account/src/providers/transaction-request/utils.ts @@ -1,4 +1,5 @@ -import { TransactionType } from '@fuel-ts/transactions'; +import { ErrorCode, FuelError } from '@fuel-ts/errors'; +import { TransactionType, type BaseTransactionType } from '@fuel-ts/transactions'; import { BlobTransactionRequest } from './blob-transaction-request'; import { CreateTransactionRequest } from './create-transaction-request'; @@ -6,6 +7,23 @@ import { ScriptTransactionRequest } from './script-transaction-request'; import type { TransactionRequestLike, TransactionRequest } from './types'; import { UnknownTransactionRequest } from './unknown-transaction-request'; +/** @hidden */ +const isBaseTransaction = (obj: TransactionRequestLike): boolean => { + const baseTransactionKeys: Array = [ + 'type', + 'witnesses', + 'witnessesCount', + 'outputs', + 'inputs', + 'policies', + 'policyTypes', + 'inputsCount', + 'outputsCount', + ]; + + return baseTransactionKeys.every((prop) => prop in obj); +}; + /** @hidden */ export const transactionRequestify = (obj: TransactionRequestLike): TransactionRequest => { if ( @@ -27,11 +45,20 @@ export const transactionRequestify = (obj: TransactionRequestLike): TransactionR return BlobTransactionRequest.from(obj); } default: { - // eslint-disable-next-line no-console - console.warn( - 'This transaction type is not supported in this SDK version, it will be ignored, if you believe this is an error, please upgrade your SDK' + if (isBaseTransaction(obj)) { + // eslint-disable-next-line no-console + console.warn( + 'This transaction type is not supported in this SDK version, it will be ignored, if you believe this is an error, please upgrade your SDK' + ); + return UnknownTransactionRequest.from({ + ...obj, + }); + } + + throw new FuelError( + ErrorCode.UNSUPPORTED_TRANSACTION_TYPE, + `Unsupported transaction type: ${obj.type}` ); - return UnknownTransactionRequest.from(obj); } } }; diff --git a/packages/transactions/src/coders/transaction.ts b/packages/transactions/src/coders/transaction.ts index 7b71b67357d..3c1977915c2 100644 --- a/packages/transactions/src/coders/transaction.ts +++ b/packages/transactions/src/coders/transaction.ts @@ -31,7 +31,8 @@ export enum TransactionType /* u8 */ { Unknown = 6, } -type BaseTransaction = { +/** @hidden */ +export type BaseTransactionType = { /** The type of the transaction */ type: TransactionType; /** List of witnesses (Witness[]) */ @@ -59,7 +60,7 @@ type BaseTransaction = { outputsCount: number; }; -export type TransactionScript = BaseTransaction & { +export type TransactionScript = BaseTransactionType & { type: TransactionType.Script; /** Gas limit for transaction (u64) */ @@ -162,7 +163,7 @@ export class TransactionScriptCoder extends Coder Date: Thu, 22 Aug 2024 16:41:35 -0500 Subject: [PATCH 04/12] fix: update property check --- .../account/src/providers/transaction-request/utils.ts | 7 ++----- packages/fuel-gauge/src/transaction.test.ts | 2 +- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/packages/account/src/providers/transaction-request/utils.ts b/packages/account/src/providers/transaction-request/utils.ts index f5c042ecaf0..cde24ae1be7 100644 --- a/packages/account/src/providers/transaction-request/utils.ts +++ b/packages/account/src/providers/transaction-request/utils.ts @@ -12,13 +12,9 @@ const isBaseTransaction = (obj: TransactionRequestLike): boolean => { const baseTransactionKeys: Array = [ 'type', 'witnesses', - 'witnessesCount', 'outputs', 'inputs', - 'policies', - 'policyTypes', - 'inputsCount', - 'outputsCount', + 'witnesses', ]; return baseTransactionKeys.every((prop) => prop in obj); @@ -44,6 +40,7 @@ export const transactionRequestify = (obj: TransactionRequestLike): TransactionR case TransactionType.Blob: { return BlobTransactionRequest.from(obj); } + case TransactionType.Unknown: default: { if (isBaseTransaction(obj)) { // eslint-disable-next-line no-console diff --git a/packages/fuel-gauge/src/transaction.test.ts b/packages/fuel-gauge/src/transaction.test.ts index 357d4c82491..4309edb602a 100644 --- a/packages/fuel-gauge/src/transaction.test.ts +++ b/packages/fuel-gauge/src/transaction.test.ts @@ -22,7 +22,7 @@ describe('Transaction', () => { expect(tx.type).toBe(TransactionType.Mint); }); - it('Should log a warning when the transaction type is unknown', async () => { + it.only('Should log a warning when the transaction type is unknown', async () => { using launched = await launchTestNode(); const { provider, From 552ca6c191dc3081a03de639b667e7965d71085b Mon Sep 17 00:00:00 2001 From: chad Date: Thu, 22 Aug 2024 16:50:01 -0500 Subject: [PATCH 05/12] test: remove unnecessary only --- packages/fuel-gauge/src/transaction.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/fuel-gauge/src/transaction.test.ts b/packages/fuel-gauge/src/transaction.test.ts index 4309edb602a..357d4c82491 100644 --- a/packages/fuel-gauge/src/transaction.test.ts +++ b/packages/fuel-gauge/src/transaction.test.ts @@ -22,7 +22,7 @@ describe('Transaction', () => { expect(tx.type).toBe(TransactionType.Mint); }); - it.only('Should log a warning when the transaction type is unknown', async () => { + it('Should log a warning when the transaction type is unknown', async () => { using launched = await launchTestNode(); const { provider, From 6b88425ace21222e2ef45d5b7adfb8d77211a23e Mon Sep 17 00:00:00 2001 From: chad Date: Fri, 23 Aug 2024 15:22:56 -0500 Subject: [PATCH 06/12] fix: remove transaction encoding and decoding + hide UnknowTransactionRequest class --- .../providers/transaction-request/types.ts | 7 +- .../unknown-transaction-request.ts | 19 ++--- .../transaction-request/utils.test.ts | 2 +- .../providers/transaction-request/utils.ts | 5 +- packages/fuel-gauge/src/transaction.test.ts | 2 +- .../transactions/src/coders/transaction.ts | 70 +------------------ 6 files changed, 16 insertions(+), 89 deletions(-) diff --git a/packages/account/src/providers/transaction-request/types.ts b/packages/account/src/providers/transaction-request/types.ts index e05bb599a7a..4ac562e46ec 100644 --- a/packages/account/src/providers/transaction-request/types.ts +++ b/packages/account/src/providers/transaction-request/types.ts @@ -13,10 +13,7 @@ import type { ScriptTransactionRequest, ScriptTransactionRequestLike, } from './script-transaction-request'; -import type { - UnknownTransactionRequestLike, - UnknownTransactionRequest, -} from './unknown-transaction-request'; +import type { UnknownTransactionRequest } from './unknown-transaction-request'; export type TransactionRequest = | ScriptTransactionRequest @@ -27,7 +24,7 @@ export type TransactionRequestLike = | ({ type: TransactionType.Script } & ScriptTransactionRequestLike) | ({ type: TransactionType.Create } & CreateTransactionRequestLike) | ({ type: TransactionType.Blob } & BlobTransactionRequestLike) - | ({ type: TransactionType.Unknown } & UnknownTransactionRequestLike); + | ({ type: TransactionType.Unknown } & UnknownTransactionRequest); export type JsonAbisFromAllCalls = { main: JsonAbi; diff --git a/packages/account/src/providers/transaction-request/unknown-transaction-request.ts b/packages/account/src/providers/transaction-request/unknown-transaction-request.ts index f93c376833f..af5e9dc1687 100644 --- a/packages/account/src/providers/transaction-request/unknown-transaction-request.ts +++ b/packages/account/src/providers/transaction-request/unknown-transaction-request.ts @@ -1,7 +1,6 @@ import type { BytesLike } from '@fuel-ts/interfaces'; import type { TransactionUnknown } from '@fuel-ts/transactions'; -import { hashTransaction } from './hash-transaction'; import type { BaseTransactionRequestLike } from './transaction-request'; import { BaseTransactionRequest, TransactionType } from './transaction-request'; @@ -9,9 +8,11 @@ import { BaseTransactionRequest, TransactionType } from './transaction-request'; * @hidden */ export interface UnknownTransactionRequestLike extends BaseTransactionRequestLike { - data?: BytesLike; + bytes?: BytesLike; } - +/** + * @hidden + */ export class UnknownTransactionRequest extends BaseTransactionRequest { static from(obj: UnknownTransactionRequestLike) { if (obj instanceof this) { @@ -24,11 +25,11 @@ export class UnknownTransactionRequest extends BaseTransactionRequest { type = TransactionType.Unknown as const; /** Data of the transaction */ - data?: BytesLike; + bytes?: BytesLike; - constructor({ data, ...rest }: UnknownTransactionRequestLike = {}) { + constructor({ bytes, ...rest }: UnknownTransactionRequestLike = {}) { super(rest); - this.data = data; + this.bytes = bytes; } /** @@ -38,8 +39,8 @@ export class UnknownTransactionRequest extends BaseTransactionRequest { * * @returns - A hash of the transaction, which is the transaction ID. */ - getTransactionId(chainId: number): string { - return hashTransaction(this, chainId); + getTransactionId(): string { + return ''; } /** @@ -51,7 +52,7 @@ export class UnknownTransactionRequest extends BaseTransactionRequest { return { ...this.getBaseTransaction(), type: TransactionType.Unknown, - data: this.data, + bytes: this.bytes, }; } } diff --git a/packages/account/src/providers/transaction-request/utils.test.ts b/packages/account/src/providers/transaction-request/utils.test.ts index 135a6bf4acb..f07bead75bd 100644 --- a/packages/account/src/providers/transaction-request/utils.test.ts +++ b/packages/account/src/providers/transaction-request/utils.test.ts @@ -51,7 +51,7 @@ describe('isTransactionTypeBlob', () => { describe('isTransactionTypeUnknown', () => { it('should return true if the request is an unknown transaction', () => { - const request = new UnknownTransactionRequest({ data: '0x' }); + const request = new UnknownTransactionRequest({ bytes: '0x' }); expect(isTransactionTypeUnknown(request)).toBe(true); }); diff --git a/packages/account/src/providers/transaction-request/utils.ts b/packages/account/src/providers/transaction-request/utils.ts index cde24ae1be7..854b95b9c96 100644 --- a/packages/account/src/providers/transaction-request/utils.ts +++ b/packages/account/src/providers/transaction-request/utils.ts @@ -47,11 +47,8 @@ export const transactionRequestify = (obj: TransactionRequestLike): TransactionR console.warn( 'This transaction type is not supported in this SDK version, it will be ignored, if you believe this is an error, please upgrade your SDK' ); - return UnknownTransactionRequest.from({ - ...obj, - }); + return new UnknownTransactionRequest({ ...obj }); } - throw new FuelError( ErrorCode.UNSUPPORTED_TRANSACTION_TYPE, `Unsupported transaction type: ${obj.type}` diff --git a/packages/fuel-gauge/src/transaction.test.ts b/packages/fuel-gauge/src/transaction.test.ts index 357d4c82491..8bfa9538e59 100644 --- a/packages/fuel-gauge/src/transaction.test.ts +++ b/packages/fuel-gauge/src/transaction.test.ts @@ -37,7 +37,7 @@ describe('Transaction', () => { const receipient = Wallet.generate({ provider }); const request = new UnknownTransactionRequest({ - data: '0x', + bytes: '0x', }); request.addCoinOutput(receipient.address, amountToTransfer, provider.getBaseAssetId()); diff --git a/packages/transactions/src/coders/transaction.ts b/packages/transactions/src/coders/transaction.ts index 3c1977915c2..8233ad1b538 100644 --- a/packages/transactions/src/coders/transaction.ts +++ b/packages/transactions/src/coders/transaction.ts @@ -584,67 +584,9 @@ export type TransactionUnknown = BaseTransactionType & { type: TransactionType.Unknown; /** Data of the transaction */ - data?: BytesLike; + bytes?: BytesLike; }; -export class TransactionUnknownCoder extends Coder { - constructor() { - super('TransactionUnknown', 'struct TransactionUnknown', 0); - } - - encode(value: TransactionUnknown): Uint8Array { - const parts: Uint8Array[] = []; - - parts.push(new NumberCoder('u32', { padToWordSize: true }).encode(value.policyTypes)); - parts.push(new NumberCoder('u16', { padToWordSize: true }).encode(value.inputsCount)); - parts.push(new NumberCoder('u16', { padToWordSize: true }).encode(value.outputsCount)); - parts.push(new NumberCoder('u16', { padToWordSize: true }).encode(value.witnessesCount)); - parts.push(new PoliciesCoder().encode(value.policies)); - parts.push(new ArrayCoder(new InputCoder(), value.inputsCount).encode(value.inputs)); - parts.push(new ArrayCoder(new OutputCoder(), value.outputsCount).encode(value.outputs)); - parts.push(new ArrayCoder(new WitnessCoder(), value.witnessesCount).encode(value.witnesses)); - - return concat(parts); - } - - decode(data: Uint8Array, offset: number): [TransactionUnknown, number] { - let decoded; - let o = offset; - - [decoded, o] = new NumberCoder('u32', { padToWordSize: true }).decode(data, o); - const policyTypes = decoded; - [decoded, o] = new NumberCoder('u16', { padToWordSize: true }).decode(data, o); - const inputsCount = decoded; - [decoded, o] = new NumberCoder('u16', { padToWordSize: true }).decode(data, o); - const outputsCount = decoded; - [decoded, o] = new NumberCoder('u16', { padToWordSize: true }).decode(data, o); - const witnessesCount = decoded; - [decoded, o] = new PoliciesCoder().decode(data, o, policyTypes); - const policies = decoded; - [decoded, o] = new ArrayCoder(new InputCoder(), inputsCount).decode(data, o); - const inputs = decoded; - [decoded, o] = new ArrayCoder(new OutputCoder(), outputsCount).decode(data, o); - const outputs = decoded; - [decoded, o] = new ArrayCoder(new WitnessCoder(), witnessesCount).decode(data, o); - const witnesses = decoded; - - return [ - { - type: TransactionType.Unknown, - policyTypes, - inputsCount, - outputsCount, - witnessesCount, - policies, - inputs, - outputs, - witnesses, - }, - o, - ]; - } -} - type PossibleTransactions = | TransactionScript | TransactionCreate @@ -711,12 +653,6 @@ export class TransactionCoder extends Coder { parts.push(new TransactionBlobCoder().encode(value as Transaction)); break; } - case TransactionType.Unknown: { - parts.push( - new TransactionUnknownCoder().encode(value as Transaction) - ); - break; - } default: { throw new FuelError( ErrorCode.UNSUPPORTED_TRANSACTION_TYPE, @@ -760,10 +696,6 @@ export class TransactionCoder extends Coder { [decoded, o] = new TransactionBlobCoder().decode(data, o); return [decoded, o]; } - case TransactionType.Unknown: { - [decoded, o] = new TransactionUnknownCoder().decode(data, o); - return [decoded, o]; - } default: { throw new FuelError( ErrorCode.UNSUPPORTED_TRANSACTION_TYPE, From 28849bf4dd7cb2cedb3a6f0a78c37eb92955cdd3 Mon Sep 17 00:00:00 2001 From: Chad Nehemiah Date: Mon, 26 Aug 2024 12:59:13 -0500 Subject: [PATCH 07/12] fix: update transaction code Co-authored-by: Peter Smith --- packages/transactions/src/coders/transaction.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/transactions/src/coders/transaction.ts b/packages/transactions/src/coders/transaction.ts index 8233ad1b538..65142eb294e 100644 --- a/packages/transactions/src/coders/transaction.ts +++ b/packages/transactions/src/coders/transaction.ts @@ -28,7 +28,7 @@ export enum TransactionType /* u8 */ { Upgrade = 3, Upload = 4, Blob = 5, - Unknown = 6, + Unknown = -1, } /** @hidden */ From 606bae5c66d95468f5a9bd43c9ad0c0b9f1ffc12 Mon Sep 17 00:00:00 2001 From: chad Date: Tue, 27 Aug 2024 13:56:04 -0500 Subject: [PATCH 08/12] fix: ensure retrieval of unknown txns return a warning --- .../account/src/providers/provider.test.ts | 71 +++++++++++++++++++ packages/account/src/providers/provider.ts | 17 ++++- .../test/fixtures/transaction-summary.ts | 2 + .../transactions/src/coders/transaction.ts | 3 +- 4 files changed, 89 insertions(+), 4 deletions(-) diff --git a/packages/account/src/providers/provider.test.ts b/packages/account/src/providers/provider.test.ts index 57ae650b050..4721aae735b 100644 --- a/packages/account/src/providers/provider.test.ts +++ b/packages/account/src/providers/provider.test.ts @@ -16,6 +16,10 @@ import { MESSAGE_PROOF_RAW_RESPONSE, MESSAGE_PROOF, } from '../../test/fixtures'; +import { + MOCK_TX_UNKNOWN_RAW_PAYLOAD, + MOCK_TX_SCRIPT_RAW_PAYLOAD, +} from '../../test/fixtures/transaction-summary'; import { setupTestProviderAndWallets, launchNode, TestMessage } from '../test-utils'; import type { Coin } from './coin'; @@ -56,6 +60,73 @@ const getCustomFetch = * @group node */ describe('Provider', () => { + it('should throw an error when retrieving a transaction with an unknown transaction type', async () => { + using launched = await setupTestProviderAndWallets(); + const { provider } = launched; + + const mockProvider = await Provider.create(provider.url, { + fetch: getCustomFetch('getTransaction', { + transaction: { + id: '0x1234567890abcdef', + rawPayload: MOCK_TX_UNKNOWN_RAW_PAYLOAD, // Unknown transaction type + }, + }), + }); + + await expectToThrowFuelError( + () => mockProvider.getTransaction('0x1234567890abcdef'), + new FuelError(ErrorCode.UNSUPPORTED_TRANSACTION_TYPE, 'Unsupported transaction type: 6') + ); + }); + + it('should log a warning when retrieving batch transactions with an unknown transaction type', async () => { + using launched = await setupTestProviderAndWallets(); + const { provider: nodeProvider } = launched; + + // Create a mock provider with custom getTransactions operation + const mockProvider = await Provider.create(nodeProvider.url, { + fetch: getCustomFetch('getTransactions', { + transactions: { + edges: [ + { + node: { + id: '0x1234567890abcdef', + rawPayload: MOCK_TX_UNKNOWN_RAW_PAYLOAD, + }, + }, + { + node: { + id: '0xabcdef1234567890', + rawPayload: MOCK_TX_SCRIPT_RAW_PAYLOAD, + }, + }, + ], + pageInfo: { + hasNextPage: false, + hasPreviousPage: false, + startCursor: null, + endCursor: null, + }, + }, + }), + }); + + // Spy on console.warn + const consoleWarnSpy = vi.spyOn(console, 'warn'); + + // Verify that only one transaction was returned (the known type) + const { transactions } = await mockProvider.getTransactions(); + expect(transactions.length).toBe(1); + + // Check if warning was logged + expect(consoleWarnSpy).toHaveBeenCalledWith( + expect.stringContaining('Unsupported transaction type encountered:') + ); + + // Clean up + consoleWarnSpy.mockRestore(); + }); + it('can getVersion()', async () => { using launched = await setupTestProviderAndWallets(); const { provider } = launched; diff --git a/packages/account/src/providers/provider.ts b/packages/account/src/providers/provider.ts index 9684ee9c1d2..1362989848c 100644 --- a/packages/account/src/providers/provider.ts +++ b/packages/account/src/providers/provider.ts @@ -1458,9 +1458,20 @@ Supported fuel-core version: ${supportedVersion}.` } = await this.operations.getTransactions(paginationArgs); const coder = new TransactionCoder(); - const transactions = edges.map( - ({ node: { rawPayload } }) => coder.decode(arrayify(rawPayload), 0)[0] - ); + const transactions = edges + .map(({ node: { rawPayload } }) => { + try { + return coder.decode(arrayify(rawPayload), 0)[0]; + } catch (error) { + if (error instanceof FuelError && error.code === ErrorCode.UNSUPPORTED_TRANSACTION_TYPE) { + // eslint-disable-next-line no-console + console.warn('Unsupported transaction type encountered:'); + return null; + } + throw error; + } + }) + .filter((tx): tx is Transaction => tx !== null); return { transactions, pageInfo }; } diff --git a/packages/account/test/fixtures/transaction-summary.ts b/packages/account/test/fixtures/transaction-summary.ts index 04660b3b57e..9e954446590 100644 --- a/packages/account/test/fixtures/transaction-summary.ts +++ b/packages/account/test/fixtures/transaction-summary.ts @@ -325,3 +325,5 @@ export const MOCK_TX_CREATE_RAW_PAYLOAD = '0x00000000000000010000000000000000b100016b3e4e6c6ec572832e5cd9b5bd9162d1371f932ee28c5a61f5a8607f7e0000000000000000000000000000000900000000000000010000000000000002000000000000000200000000000000000000000000000754000000000000000002cc837ec4516621729d615acb83b4871b34b59772c9ad42674f24cbf232f25b0000000000000000a1bfd8f997bb7654af676f6d8a9ebda7eb1ab63426d7f3e5745fdc1672f0031000000000004c4b4000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000e00000000000000010000000000000000000000000000000000000000000000000000000000000004181c794f94f71f983a1cb57b18ee43be3d1d3a74aa2e3ed4c9e50687a18f015600000000000000000000000000000000000000000000000000000000000000000000000000000002a1bfd8f997bb7654af676f6d8a9ebda7eb1ab63426d7f3e5745fdc1672f0031000000000004c43ec00000000000000000000000000000000000000000000000000000000000000000000000000000594740000034700000000000000000003945dfcc00110fff3005d4060495d47f03213490440764800085d47f033134904407648007c5d47f03413490440764800bf72f0007b36f000001aec5000910001405d43f035104103005fec00005047b00f5e4410005d47f03610451300504bb010724c0020284914c05053b0505fec000a5045400f5e4410005057b03072440020285504405043b0605fec100c5045000f5c4bf0905e4520005047b0705e440000504910085c4ff0985e493000504910105c4ff0a05e4930005d4bf0155fed201150491020724c0010284944c050491030724c0020284954c05045105072480010284504805d43f0371041030072440010340004117240001034001ed05d43f038104103005d47f01672480010340114125043b0105d47f01772480020340114125d43f039104103005d47f01872480008340114125043b0705d47f01972480060340114125d43f03a104103005d47f01a72480010340114125043b0705c4100005d47f01b334110005d43f03b104103005d47f01c72480010340114125043b0105047b0d05d4bf0165fed201a5049100f5c4ff0905e493000504bb0e05c4ff0e85e493000504d20085c53f0f05e4d4000504d20105c53f0f85e4d40005d4ff0205fed301f504d202072500010284fb500504d203072500020284d05005041205072480010284114805043b0e05d47f02172480060340114125d43f03c104103005d47f02272480008340114125c43f090244000001aec5000910001305d40604a5d4900005d4d00015d43f035104103005fec00005047b00f5e4410005047b120725000102847b5005047b0305fec00065051100f5e5010005053b01072540020285105405057b0405fec10085041500f5c5bf0905e416000505bb0505e580000504160085c5ff0985e417000504160105c5ff0a05e4170005d43f0155fed000d50416020725c0010284115c0504160307244002028414440504160507244001028415440134124c05047b050134100007640000e5d43f03d104103005d4bf025724c0010340124135043b120504bb110724c0010284904c05d43f026724c0010340104935c43f090244000005043b0b072480060284114805d47f02772480060340114125d43f028364000001aec5000910000305d40604a5c450000504100085d4bf03e104923005d4ff03072500018340134947248002028ed04805d43f0315fed00045fed10055d43f03f104103001a44a0002dec04115c43f0902440000047000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00fffffffffffffffffffffffffffff47616d65205374617465000000000000436f6e7472616374204964000000000047616d652052656647616d65205265662053636f726500004469726563742047616d6500000000005761732054727565010000000000000064000000000000000a000000000000000000000000018af8000000000000000200000000000000030000000000000004000000000000000500000000000000060000000000000007000000000000000865000000000000000c00000000000000030000000000000000000000000201570000000000000009000000000000000a48656c6c6f2054657374657200000000000000000000000d000000000000000e000000000000000cffffffffffff000048656c6c6f2066726f6d206d61696e20436f6e74726163740000000000000000000000000000000000000000000000000000000000000000000000000000000f00000000b1abb86f000000002151bd4b00000000fdbf0f6a0000000045b1551100000000000003b4000000000000039400000000000003d400000000000003e400000000000003f400000000000003fc000000000000040c000000000000041c00000000000004ac00000000000004dc00000000000004f400000000000000000000004041836759e99b4bd0b1a8d9a622e091bf15cbfe9f975dacc38334dfb084ced1c55d58b4e5b4072d22fd3279bf90b1f3bf6429ce4096626905037cccbc05bec7e4'; export const MOCK_TX_MINT_RAW_PAYLOAD = '0x0000000000000002000000000000000500000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001'; +export const MOCK_TX_UNKNOWN_RAW_PAYLOAD = + '0x0000000000000006000000000000000500000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001'; diff --git a/packages/transactions/src/coders/transaction.ts b/packages/transactions/src/coders/transaction.ts index 65142eb294e..7515df19f20 100644 --- a/packages/transactions/src/coders/transaction.ts +++ b/packages/transactions/src/coders/transaction.ts @@ -28,7 +28,7 @@ export enum TransactionType /* u8 */ { Upgrade = 3, Upload = 4, Blob = 5, - Unknown = -1, + Unknown = 6, } /** @hidden */ @@ -696,6 +696,7 @@ export class TransactionCoder extends Coder { [decoded, o] = new TransactionBlobCoder().decode(data, o); return [decoded, o]; } + case TransactionType.Unknown: default: { throw new FuelError( ErrorCode.UNSUPPORTED_TRANSACTION_TYPE, From e7daa0515d54e3317ecbc9a9830b2f52875ed1a2 Mon Sep 17 00:00:00 2001 From: chad Date: Tue, 27 Aug 2024 14:06:16 -0500 Subject: [PATCH 09/12] chore: clean up message and throw warning for single case --- .../account/src/providers/provider.test.ts | 18 ++++++++++++---- packages/account/src/providers/provider.ts | 21 ++++++++++++++----- 2 files changed, 30 insertions(+), 9 deletions(-) diff --git a/packages/account/src/providers/provider.test.ts b/packages/account/src/providers/provider.test.ts index 4721aae735b..c40cee101ed 100644 --- a/packages/account/src/providers/provider.test.ts +++ b/packages/account/src/providers/provider.test.ts @@ -73,10 +73,20 @@ describe('Provider', () => { }), }); - await expectToThrowFuelError( - () => mockProvider.getTransaction('0x1234567890abcdef'), - new FuelError(ErrorCode.UNSUPPORTED_TRANSACTION_TYPE, 'Unsupported transaction type: 6') + // Spy on console.warn + const consoleWarnSpy = vi.spyOn(console, 'warn'); + + // Verify that only one transaction was returned (the known type) + const transaction = await mockProvider.getTransaction('0x1234567890abcdef'); + + expect(transaction).toBeNull(); + + expect(consoleWarnSpy).toHaveBeenCalledWith( + expect.stringContaining('Unsupported transaction type encountered') ); + + // Clean up + consoleWarnSpy.mockRestore(); }); it('should log a warning when retrieving batch transactions with an unknown transaction type', async () => { @@ -120,7 +130,7 @@ describe('Provider', () => { // Check if warning was logged expect(consoleWarnSpy).toHaveBeenCalledWith( - expect.stringContaining('Unsupported transaction type encountered:') + expect.stringContaining('Unsupported transaction type encountered') ); // Clean up diff --git a/packages/account/src/providers/provider.ts b/packages/account/src/providers/provider.ts index 1362989848c..5c5f6688761 100644 --- a/packages/account/src/providers/provider.ts +++ b/packages/account/src/providers/provider.ts @@ -1438,13 +1438,24 @@ Supported fuel-core version: ${supportedVersion}.` transactionId: string ): Promise | null> { const { transaction } = await this.operations.getTransaction({ transactionId }); + if (!transaction) { return null; } - return new TransactionCoder().decode( - arrayify(transaction.rawPayload), - 0 - )?.[0] as Transaction; + + try { + return new TransactionCoder().decode( + arrayify(transaction.rawPayload), + 0 + )?.[0] as Transaction; + } catch (error) { + if (error instanceof FuelError && error.code === ErrorCode.UNSUPPORTED_TRANSACTION_TYPE) { + // eslint-disable-next-line no-console + console.warn('Unsupported transaction type encountered'); + return null; + } + throw error; + } } /** @@ -1465,7 +1476,7 @@ Supported fuel-core version: ${supportedVersion}.` } catch (error) { if (error instanceof FuelError && error.code === ErrorCode.UNSUPPORTED_TRANSACTION_TYPE) { // eslint-disable-next-line no-console - console.warn('Unsupported transaction type encountered:'); + console.warn('Unsupported transaction type encountered'); return null; } throw error; From 14500a85d337e5b37b64ab4cb36aad866ad3708c Mon Sep 17 00:00:00 2001 From: chad Date: Thu, 29 Aug 2024 09:58:33 -0500 Subject: [PATCH 10/12] chore: remove unknown transaction type --- packages/account/src/account.ts | 6 +- packages/account/src/predicate/predicate.ts | 7 +-- packages/account/src/providers/provider.ts | 4 -- .../providers/transaction-request/index.ts | 1 - .../providers/transaction-request/types.ts | 7 +-- .../unknown-transaction-request.ts | 58 ------------------- .../transaction-request/utils.test.ts | 20 +------ .../providers/transaction-request/utils.ts | 33 ++--------- .../src/wallet/base-wallet-unlocked.ts | 6 +- packages/fuel-gauge/src/transaction.test.ts | 34 +---------- 10 files changed, 13 insertions(+), 163 deletions(-) delete mode 100644 packages/account/src/providers/transaction-request/unknown-transaction-request.ts diff --git a/packages/account/src/account.ts b/packages/account/src/account.ts index f4ef4930fa3..70474d4df0f 100644 --- a/packages/account/src/account.ts +++ b/packages/account/src/account.ts @@ -29,14 +29,13 @@ import type { GetBalancesResponse, Coin, TransactionCostParams, + TransactionResponse, } from './providers'; import { withdrawScript, ScriptTransactionRequest, transactionRequestify, addAmountToCoinQuantities, - isTransactionTypeUnknown, - TransactionResponse, } from './providers'; import { cacheRequestInputsResourcesFromOwner, @@ -633,9 +632,6 @@ export class Account extends AbstractAccount { ); } const transactionRequest = transactionRequestify(transactionRequestLike); - if (isTransactionTypeUnknown(transactionRequest)) { - return new TransactionResponse(transactionRequest, this.provider); - } if (estimateTxDependencies) { await this.provider.estimateTxDependencies(transactionRequest); } diff --git a/packages/account/src/predicate/predicate.ts b/packages/account/src/predicate/predicate.ts index 23e3b59273e..5c7762db5dc 100644 --- a/packages/account/src/predicate/predicate.ts +++ b/packages/account/src/predicate/predicate.ts @@ -11,8 +11,6 @@ import { transactionRequestify, isRequestInputResource, isRequestInputResourceFromOwner, - isTransactionTypeUnknown, - TransactionResponse, } from '../providers'; import type { CallResult, @@ -22,6 +20,7 @@ import type { Resource, TransactionRequest, TransactionRequestLike, + TransactionResponse, } from '../providers'; import { getPredicateRoot } from './utils'; @@ -118,9 +117,7 @@ export class Predicate< */ sendTransaction(transactionRequestLike: TransactionRequestLike): Promise { const transactionRequest = transactionRequestify(transactionRequestLike); - if (isTransactionTypeUnknown(transactionRequest)) { - return Promise.resolve(new TransactionResponse(transactionRequest, this.provider)); - } + return super.sendTransaction(transactionRequest, { estimateTxDependencies: false }); } diff --git a/packages/account/src/providers/provider.ts b/packages/account/src/providers/provider.ts index 5c5f6688761..f9409828f61 100644 --- a/packages/account/src/providers/provider.ts +++ b/packages/account/src/providers/provider.ts @@ -46,7 +46,6 @@ import type { import { isTransactionTypeCreate, isTransactionTypeScript, - isTransactionTypeUnknown, transactionRequestify, } from './transaction-request'; import type { TransactionResultReceipt } from './transaction-response'; @@ -745,9 +744,6 @@ Supported fuel-core version: ${supportedVersion}.` { estimateTxDependencies = true }: ProviderSendTxParams = {} ): Promise { const transactionRequest = transactionRequestify(transactionRequestLike); - if (isTransactionTypeUnknown(transactionRequest)) { - return new TransactionResponse(transactionRequest, this); - } // #region Provider-sendTransaction if (estimateTxDependencies) { await this.estimateTxDependencies(transactionRequest); diff --git a/packages/account/src/providers/transaction-request/index.ts b/packages/account/src/providers/transaction-request/index.ts index 808dc1eed8a..37116d65685 100644 --- a/packages/account/src/providers/transaction-request/index.ts +++ b/packages/account/src/providers/transaction-request/index.ts @@ -4,7 +4,6 @@ export * from './transaction-request'; export * from './blob-transaction-request'; export * from './create-transaction-request'; export * from './script-transaction-request'; -export * from './unknown-transaction-request'; export * from './errors'; export * from './scripts'; export * from './types'; diff --git a/packages/account/src/providers/transaction-request/types.ts b/packages/account/src/providers/transaction-request/types.ts index 4ac562e46ec..10569374f0c 100644 --- a/packages/account/src/providers/transaction-request/types.ts +++ b/packages/account/src/providers/transaction-request/types.ts @@ -13,18 +13,15 @@ import type { ScriptTransactionRequest, ScriptTransactionRequestLike, } from './script-transaction-request'; -import type { UnknownTransactionRequest } from './unknown-transaction-request'; export type TransactionRequest = | ScriptTransactionRequest | CreateTransactionRequest - | BlobTransactionRequest - | UnknownTransactionRequest; + | BlobTransactionRequest; export type TransactionRequestLike = | ({ type: TransactionType.Script } & ScriptTransactionRequestLike) | ({ type: TransactionType.Create } & CreateTransactionRequestLike) - | ({ type: TransactionType.Blob } & BlobTransactionRequestLike) - | ({ type: TransactionType.Unknown } & UnknownTransactionRequest); + | ({ type: TransactionType.Blob } & BlobTransactionRequestLike); export type JsonAbisFromAllCalls = { main: JsonAbi; diff --git a/packages/account/src/providers/transaction-request/unknown-transaction-request.ts b/packages/account/src/providers/transaction-request/unknown-transaction-request.ts deleted file mode 100644 index af5e9dc1687..00000000000 --- a/packages/account/src/providers/transaction-request/unknown-transaction-request.ts +++ /dev/null @@ -1,58 +0,0 @@ -import type { BytesLike } from '@fuel-ts/interfaces'; -import type { TransactionUnknown } from '@fuel-ts/transactions'; - -import type { BaseTransactionRequestLike } from './transaction-request'; -import { BaseTransactionRequest, TransactionType } from './transaction-request'; - -/** - * @hidden - */ -export interface UnknownTransactionRequestLike extends BaseTransactionRequestLike { - bytes?: BytesLike; -} -/** - * @hidden - */ -export class UnknownTransactionRequest extends BaseTransactionRequest { - static from(obj: UnknownTransactionRequestLike) { - if (obj instanceof this) { - return obj; - } - return new this(obj); - } - - /** Type of the transaction */ - type = TransactionType.Unknown as const; - - /** Data of the transaction */ - bytes?: BytesLike; - - constructor({ bytes, ...rest }: UnknownTransactionRequestLike = {}) { - super(rest); - this.bytes = bytes; - } - - /** - * Gets the Transaction Request by hashing the transaction. - * - * @param chainId - The chain ID. - * - * @returns - A hash of the transaction, which is the transaction ID. - */ - getTransactionId(): string { - return ''; - } - - /** - * Converts the transaction request to a `TransactionBlob`. - * - * @returns The transaction create object. - */ - toTransaction(): TransactionUnknown { - return { - ...this.getBaseTransaction(), - type: TransactionType.Unknown, - bytes: this.bytes, - }; - } -} diff --git a/packages/account/src/providers/transaction-request/utils.test.ts b/packages/account/src/providers/transaction-request/utils.test.ts index f07bead75bd..35c89e49715 100644 --- a/packages/account/src/providers/transaction-request/utils.test.ts +++ b/packages/account/src/providers/transaction-request/utils.test.ts @@ -1,13 +1,7 @@ import { BlobTransactionRequest } from './blob-transaction-request'; import { CreateTransactionRequest } from './create-transaction-request'; import { ScriptTransactionRequest } from './script-transaction-request'; -import { UnknownTransactionRequest } from './unknown-transaction-request'; -import { - isTransactionTypeBlob, - isTransactionTypeCreate, - isTransactionTypeScript, - isTransactionTypeUnknown, -} from './utils'; +import { isTransactionTypeBlob, isTransactionTypeCreate, isTransactionTypeScript } from './utils'; /** * @group node @@ -48,15 +42,3 @@ describe('isTransactionTypeBlob', () => { expect(isTransactionTypeCreate(request)).toBe(false); }); }); - -describe('isTransactionTypeUnknown', () => { - it('should return true if the request is an unknown transaction', () => { - const request = new UnknownTransactionRequest({ bytes: '0x' }); - expect(isTransactionTypeUnknown(request)).toBe(true); - }); - - it('should return false if the request is not an unknown transaction', () => { - const request = new ScriptTransactionRequest(); - expect(isTransactionTypeUnknown(request)).toBe(false); - }); -}); diff --git a/packages/account/src/providers/transaction-request/utils.ts b/packages/account/src/providers/transaction-request/utils.ts index 854b95b9c96..3aec3e92f2b 100644 --- a/packages/account/src/providers/transaction-request/utils.ts +++ b/packages/account/src/providers/transaction-request/utils.ts @@ -1,24 +1,10 @@ import { ErrorCode, FuelError } from '@fuel-ts/errors'; -import { TransactionType, type BaseTransactionType } from '@fuel-ts/transactions'; +import { TransactionType } from '@fuel-ts/transactions'; import { BlobTransactionRequest } from './blob-transaction-request'; import { CreateTransactionRequest } from './create-transaction-request'; import { ScriptTransactionRequest } from './script-transaction-request'; import type { TransactionRequestLike, TransactionRequest } from './types'; -import { UnknownTransactionRequest } from './unknown-transaction-request'; - -/** @hidden */ -const isBaseTransaction = (obj: TransactionRequestLike): boolean => { - const baseTransactionKeys: Array = [ - 'type', - 'witnesses', - 'outputs', - 'inputs', - 'witnesses', - ]; - - return baseTransactionKeys.every((prop) => prop in obj); -}; /** @hidden */ export const transactionRequestify = (obj: TransactionRequestLike): TransactionRequest => { @@ -30,6 +16,8 @@ export const transactionRequestify = (obj: TransactionRequestLike): TransactionR return obj; } + const { type } = obj; + switch (obj.type) { case TransactionType.Script: { return ScriptTransactionRequest.from(obj); @@ -40,18 +28,10 @@ export const transactionRequestify = (obj: TransactionRequestLike): TransactionR case TransactionType.Blob: { return BlobTransactionRequest.from(obj); } - case TransactionType.Unknown: default: { - if (isBaseTransaction(obj)) { - // eslint-disable-next-line no-console - console.warn( - 'This transaction type is not supported in this SDK version, it will be ignored, if you believe this is an error, please upgrade your SDK' - ); - return new UnknownTransactionRequest({ ...obj }); - } throw new FuelError( ErrorCode.UNSUPPORTED_TRANSACTION_TYPE, - `Unsupported transaction type: ${obj.type}` + `Unsupported transaction type: ${type}.` ); } } @@ -71,8 +51,3 @@ export const isTransactionTypeCreate = ( export const isTransactionTypeBlob = ( request: TransactionRequestLike ): request is BlobTransactionRequest => request.type === TransactionType.Blob; - -/** @hidden */ -export const isTransactionTypeUnknown = ( - request: TransactionRequestLike -): request is UnknownTransactionRequest => request.type === TransactionType.Unknown; diff --git a/packages/account/src/wallet/base-wallet-unlocked.ts b/packages/account/src/wallet/base-wallet-unlocked.ts index 5a84e5c62fc..58240df9ae0 100644 --- a/packages/account/src/wallet/base-wallet-unlocked.ts +++ b/packages/account/src/wallet/base-wallet-unlocked.ts @@ -3,7 +3,7 @@ import type { BytesLike } from '@fuel-ts/interfaces'; import { hexlify } from '@fuel-ts/utils'; import { Account } from '../account'; -import { isTransactionTypeUnknown, transactionRequestify, TransactionResponse } from '../providers'; +import { transactionRequestify } from '../providers'; import type { TransactionRequestLike, CallResult, @@ -11,6 +11,7 @@ import type { ProviderSendTxParams, EstimateTransactionParams, TransactionRequest, + TransactionResponse, } from '../providers'; import { Signer } from '../signer'; @@ -114,9 +115,6 @@ export class BaseWalletUnlocked extends Account { { estimateTxDependencies = false }: ProviderSendTxParams = {} ): Promise { const transactionRequest = transactionRequestify(transactionRequestLike); - if (isTransactionTypeUnknown(transactionRequest)) { - return new TransactionResponse(transactionRequest, this.provider); - } if (estimateTxDependencies) { await this.provider.estimateTxDependencies(transactionRequest); } diff --git a/packages/fuel-gauge/src/transaction.test.ts b/packages/fuel-gauge/src/transaction.test.ts index 8bfa9538e59..005b94f0de2 100644 --- a/packages/fuel-gauge/src/transaction.test.ts +++ b/packages/fuel-gauge/src/transaction.test.ts @@ -1,4 +1,4 @@ -import { TransactionType, UnknownTransactionRequest, Wallet } from 'fuels'; +import { TransactionType, Wallet } from 'fuels'; import { launchTestNode } from 'fuels/test-utils'; /** @@ -21,36 +21,4 @@ describe('Transaction', () => { expect(tx.type).toBe(TransactionType.Mint); }); - - it('Should log a warning when the transaction type is unknown', async () => { - using launched = await launchTestNode(); - const { - provider, - wallets: [wallet], - } = launched; - - // Check if a warning was logged to the console - const consoleWarnSpy = vi.spyOn(console, 'warn'); - - const amountToTransfer = 120; - - const receipient = Wallet.generate({ provider }); - - const request = new UnknownTransactionRequest({ - bytes: '0x', - }); - - request.addCoinOutput(receipient.address, amountToTransfer, provider.getBaseAssetId()); - - await wallet.sendTransaction(request); - - expect(consoleWarnSpy).toHaveBeenCalledWith( - expect.stringContaining( - 'This transaction type is not supported in this SDK version, it will be ignored, if you believe this is an error, please upgrade your SDK' - ) - ); - - // Clean up the spy - consoleWarnSpy.mockRestore(); - }); }); From af4f051eb1728383cc0147984c713f7786f509f2 Mon Sep 17 00:00:00 2001 From: chad Date: Thu, 29 Aug 2024 10:09:37 -0500 Subject: [PATCH 11/12] chore: remove other unused types --- .../transaction-request/transaction-request.ts | 7 +------ .../providers/transaction-summary/operations.ts | 2 -- .../src/providers/transaction-summary/types.ts | 1 - packages/transactions/src/coders/transaction.ts | 15 ++------------- 4 files changed, 3 insertions(+), 22 deletions(-) diff --git a/packages/account/src/providers/transaction-request/transaction-request.ts b/packages/account/src/providers/transaction-request/transaction-request.ts index 9b1a249b51b..64c631ef46a 100644 --- a/packages/account/src/providers/transaction-request/transaction-request.ts +++ b/packages/account/src/providers/transaction-request/transaction-request.ts @@ -11,7 +11,6 @@ import type { Policy, TransactionCreate, TransactionBlob, - TransactionUnknown, } from '@fuel-ts/transactions'; import { PolicyType, @@ -193,11 +192,7 @@ export abstract class BaseTransactionRequest implements BaseTransactionRequestLi }; } - abstract toTransaction(): - | TransactionCreate - | TransactionScript - | TransactionBlob - | TransactionUnknown; + abstract toTransaction(): TransactionCreate | TransactionScript | TransactionBlob; /** * Converts the transaction request to a byte array. diff --git a/packages/account/src/providers/transaction-summary/operations.ts b/packages/account/src/providers/transaction-summary/operations.ts index 713e36f5a5d..4ef7d3fc816 100644 --- a/packages/account/src/providers/transaction-summary/operations.ts +++ b/packages/account/src/providers/transaction-summary/operations.ts @@ -61,8 +61,6 @@ export function getTransactionTypeName(transactionType: TransactionType): Transa return TransactionTypeName.Script; case TransactionType.Blob: return TransactionTypeName.Blob; - case TransactionType.Unknown: - return TransactionTypeName.Unknown; default: throw new FuelError( ErrorCode.UNSUPPORTED_TRANSACTION_TYPE, diff --git a/packages/account/src/providers/transaction-summary/types.ts b/packages/account/src/providers/transaction-summary/types.ts index 7dfec1e8ac1..012d1982491 100644 --- a/packages/account/src/providers/transaction-summary/types.ts +++ b/packages/account/src/providers/transaction-summary/types.ts @@ -36,7 +36,6 @@ export enum TransactionTypeName { Upgrade = 'Upgrade', Upload = 'Upload', Blob = 'Blob', - Unknown = 'Unknown', } /** diff --git a/packages/transactions/src/coders/transaction.ts b/packages/transactions/src/coders/transaction.ts index 7515df19f20..e11a23119fe 100644 --- a/packages/transactions/src/coders/transaction.ts +++ b/packages/transactions/src/coders/transaction.ts @@ -28,7 +28,6 @@ export enum TransactionType /* u8 */ { Upgrade = 3, Upload = 4, Blob = 5, - Unknown = 6, } /** @hidden */ @@ -580,21 +579,13 @@ export class TransactionBlobCoder extends Coder = TTransactionType extends TransactionType ? Extract @@ -603,8 +594,7 @@ export type Transaction = TTransactionType extends Tran Partial> & Partial> & Partial> & - Partial> & - Partial> & { + Partial> & { type: TransactionType; }; @@ -696,7 +686,6 @@ export class TransactionCoder extends Coder { [decoded, o] = new TransactionBlobCoder().decode(data, o); return [decoded, o]; } - case TransactionType.Unknown: default: { throw new FuelError( ErrorCode.UNSUPPORTED_TRANSACTION_TYPE, From 347ff9bebc0c5f898fec40183f9f2357fa22038c Mon Sep 17 00:00:00 2001 From: chad Date: Thu, 29 Aug 2024 10:10:44 -0500 Subject: [PATCH 12/12] linting --- packages/fuel-gauge/src/transaction.test.ts | 2 +- packages/transactions/src/coders/transaction.ts | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/fuel-gauge/src/transaction.test.ts b/packages/fuel-gauge/src/transaction.test.ts index 005b94f0de2..564510d5611 100644 --- a/packages/fuel-gauge/src/transaction.test.ts +++ b/packages/fuel-gauge/src/transaction.test.ts @@ -1,4 +1,4 @@ -import { TransactionType, Wallet } from 'fuels'; +import { TransactionType } from 'fuels'; import { launchTestNode } from 'fuels/test-utils'; /** diff --git a/packages/transactions/src/coders/transaction.ts b/packages/transactions/src/coders/transaction.ts index e11a23119fe..5c6e2355cc6 100644 --- a/packages/transactions/src/coders/transaction.ts +++ b/packages/transactions/src/coders/transaction.ts @@ -2,7 +2,6 @@ import { Coder, ArrayCoder, B256Coder, NumberCoder, BigNumberCoder } from '@fuel-ts/abi-coder'; import { ErrorCode, FuelError } from '@fuel-ts/errors'; -import type { BytesLike } from '@fuel-ts/interfaces'; import { type BN } from '@fuel-ts/math'; import { concat } from '@fuel-ts/utils';