diff --git a/.changeset/tall-planes-nail.md b/.changeset/tall-planes-nail.md
new file mode 100644
index 00000000000..1419e9c50db
--- /dev/null
+++ b/.changeset/tall-planes-nail.md
@@ -0,0 +1,8 @@
+---
+"@fuel-ts/transactions": minor
+"@fuel-ts/contract": patch
+"@fuel-ts/account": minor
+"@fuel-ts/errors": minor
+---
+
+feat!: deploy contract validation
diff --git a/apps/docs/src/guide/contracts/deploying-contracts.md b/apps/docs/src/guide/contracts/deploying-contracts.md
index 1defa7265da..9e00beac37a 100644
--- a/apps/docs/src/guide/contracts/deploying-contracts.md
+++ b/apps/docs/src/guide/contracts/deploying-contracts.md
@@ -9,6 +9,8 @@
This guide walks you through deploying a contract using the SDK, covering loading contract artifacts, initializing a contract factory, and deploying the contract.
+> **Note:** The maximum contract deployment size supported by the SDK is 100 KB. The SDK will `throw` an [error](../errors/index.md) for contracts larger than this size.
+
## 1. Obtaining Contract Artifacts
After writing a contract in Sway and compiling it with `forc build` (read more on how to work with Sway), you will obtain two important artifacts: the compiled binary file and the JSON ABI file. These files are required for deploying a contract using the SDK.
diff --git a/apps/docs/src/guide/errors/index.md b/apps/docs/src/guide/errors/index.md
index 27b94c4c1ef..b84657a5d52 100644
--- a/apps/docs/src/guide/errors/index.md
+++ b/apps/docs/src/guide/errors/index.md
@@ -30,6 +30,12 @@ When converting a big number into an incompatible format.
Ensure that the value you've supplied to the big number is compatible with the value you are converting to.
+### `CONTRACT_SIZE_EXCEEDS_LIMIT`
+
+When the contract size exceeds the maximum contract size limit.
+
+Ensure that the contract size is less than the maximum contract size limit, of 100 KB. This can be validated by checking the bytecode length of the contract.
+
### `DUPLICATED_POLICY`
When there are more than policies with the same type, for a transaction.
@@ -174,9 +180,9 @@ When the transaction status received from the node is unexpected.
Check the status received is within `TransactionStatus`.
-### `INVALID_TRANSACTION_TYPE`
+### `UNSUPPORTED_TRANSACTION_TYPE`
-When the transaction type from the Fuel Node is _not_ valid.
+When the transaction type from the Fuel Node is _not_ supported.
The type is within [`TransactionType`](../../api/Account/TransactionType.md).
diff --git a/apps/docs/src/guide/fuels-cli/commands.md b/apps/docs/src/guide/fuels-cli/commands.md
index 0afb25e397d..5bdcaa9683e 100644
--- a/apps/docs/src/guide/fuels-cli/commands.md
+++ b/apps/docs/src/guide/fuels-cli/commands.md
@@ -95,6 +95,8 @@ npx fuels@{{fuels}} deploy
> [!NOTE] Note
> We recommend using the `fuels deploy` command only when you are deploying contracts to a local node.
> If you are deploying contracts to a live network like the Testnet, we recommend using the [`forc deploy`](https://docs.fuel.network/docs/intro/quickstart-contract/#deploy-to-testnet) command instead.
+>
+> Additionally, the maximum contract deployment size supported by the SDK is 100 KB. The SDK will `throw` an [error](../errors/index.md) for contracts larger than this size.
The `fuels deploy` command does two things:
diff --git a/packages/account/src/providers/transaction-request/transaction-request.test.ts b/packages/account/src/providers/transaction-request/transaction-request.test.ts
index d25feee64e3..738c46cb9e8 100644
--- a/packages/account/src/providers/transaction-request/transaction-request.test.ts
+++ b/packages/account/src/providers/transaction-request/transaction-request.test.ts
@@ -185,11 +185,13 @@ describe('transactionRequestify', () => {
expect(txRequest.witnesses).toEqual(txRequestLike.witnesses);
});
- it('should throw error if invalid transaction type', () => {
+ it('should throw error if unsupported transaction type', () => {
const txRequestLike = {
- type: 5,
+ type: 1234,
};
- expect(() => transactionRequestify(txRequestLike)).toThrow('Invalid transaction type: 5');
+ expect(() => transactionRequestify(txRequestLike)).toThrow(
+ 'Unsupported transaction type: 1234'
+ );
});
});
diff --git a/packages/account/src/providers/transaction-request/utils.ts b/packages/account/src/providers/transaction-request/utils.ts
index d89de4772cb..3aeac32e56a 100644
--- a/packages/account/src/providers/transaction-request/utils.ts
+++ b/packages/account/src/providers/transaction-request/utils.ts
@@ -21,7 +21,10 @@ export const transactionRequestify = (obj: TransactionRequestLike): TransactionR
return CreateTransactionRequest.from(obj);
}
default: {
- throw new FuelError(ErrorCode.INVALID_TRANSACTION_TYPE, `Invalid transaction type: ${type}.`);
+ throw new FuelError(
+ ErrorCode.UNSUPPORTED_TRANSACTION_TYPE,
+ `Unsupported transaction type: ${type}.`
+ );
}
}
};
diff --git a/packages/account/src/providers/transaction-summary/operations.test.ts b/packages/account/src/providers/transaction-summary/operations.test.ts
index 2cda7a660bb..cf20482aca0 100644
--- a/packages/account/src/providers/transaction-summary/operations.test.ts
+++ b/packages/account/src/providers/transaction-summary/operations.test.ts
@@ -936,7 +936,7 @@ describe('operations', () => {
expect(getTransactionTypeName(TransactionType.Script)).toBe(TransactionTypeName.Script);
expect(() => getTransactionTypeName('' as unknown as TransactionType)).toThrowError(
- 'Invalid transaction type: '
+ 'Unsupported transaction type: '
);
});
});
diff --git a/packages/account/src/providers/transaction-summary/operations.ts b/packages/account/src/providers/transaction-summary/operations.ts
index 55b4edd64b1..17e4f677302 100644
--- a/packages/account/src/providers/transaction-summary/operations.ts
+++ b/packages/account/src/providers/transaction-summary/operations.ts
@@ -57,8 +57,8 @@ export function getTransactionTypeName(transactionType: TransactionType): Transa
return TransactionTypeName.Script;
default:
throw new FuelError(
- ErrorCode.INVALID_TRANSACTION_TYPE,
- `Invalid transaction type: ${transactionType}.`
+ ErrorCode.UNSUPPORTED_TRANSACTION_TYPE,
+ `Unsupported transaction type: ${transactionType}.`
);
}
}
diff --git a/packages/contract/src/contract-factory.ts b/packages/contract/src/contract-factory.ts
index 362d0abf025..f24f03d1d7d 100644
--- a/packages/contract/src/contract-factory.ts
+++ b/packages/contract/src/contract-factory.ts
@@ -15,7 +15,12 @@ import { Contract } from '@fuel-ts/program';
import type { StorageSlot } from '@fuel-ts/transactions';
import { arrayify, isDefined } from '@fuel-ts/utils';
-import { getContractId, getContractStorageRoot, hexlifyWithPrefix } from './util';
+import {
+ MAX_CONTRACT_SIZE,
+ getContractId,
+ getContractStorageRoot,
+ hexlifyWithPrefix,
+} from './util';
/**
* Options for deploying a contract.
@@ -149,7 +154,15 @@ export default class ContractFactory {
async deployContract(
deployContractOptions: DeployContractOptions = {}
): Promise> {
+ if (this.bytecode.length > MAX_CONTRACT_SIZE) {
+ throw new FuelError(
+ ErrorCode.CONTRACT_SIZE_EXCEEDS_LIMIT,
+ 'Contract bytecode is too large. Max contract size is 100KB'
+ );
+ }
+
const { contractId, transactionRequest } = await this.prepareDeploy(deployContractOptions);
+
const account = this.getAccount();
const transactionResponse = await account.sendTransaction(transactionRequest, {
diff --git a/packages/contract/src/util.ts b/packages/contract/src/util.ts
index 610f7b73ff1..e540d55235f 100644
--- a/packages/contract/src/util.ts
+++ b/packages/contract/src/util.ts
@@ -4,6 +4,9 @@ import { calcRoot, SparseMerkleTree } from '@fuel-ts/merkle';
import type { StorageSlot } from '@fuel-ts/transactions';
import { chunkAndPadBytes, hexlify, concat, arrayify } from '@fuel-ts/utils';
+// Max contract size in bytes is 100KB
+export const MAX_CONTRACT_SIZE = 102400;
+
/**
* @hidden
*
diff --git a/packages/errors/src/error-codes.ts b/packages/errors/src/error-codes.ts
index 3a7927f71e1..4fc0c2f59d7 100644
--- a/packages/errors/src/error-codes.ts
+++ b/packages/errors/src/error-codes.ts
@@ -67,11 +67,12 @@ export enum ErrorCode {
INVALID_TRANSACTION_INPUT = 'invalid-transaction-input',
INVALID_TRANSACTION_OUTPUT = 'invalid-transaction-output',
INVALID_TRANSACTION_STATUS = 'invalid-transaction-status',
- INVALID_TRANSACTION_TYPE = 'invalid-transaction-type',
+ UNSUPPORTED_TRANSACTION_TYPE = 'unsupported-transaction-type',
TRANSACTION_ERROR = 'transaction-error',
INVALID_POLICY_TYPE = 'invalid-policy-type',
DUPLICATED_POLICY = 'duplicated-policy',
TRANSACTION_SQUEEZED_OUT = 'transaction-squeezed-out',
+ CONTRACT_SIZE_EXCEEDS_LIMIT = 'contract-size-exceeds-limit',
// receipt
INVALID_RECEIPT_TYPE = 'invalid-receipt-type',
diff --git a/packages/fuel-gauge/src/contract-factory.test.ts b/packages/fuel-gauge/src/contract-factory.test.ts
index 6d551a8ffb3..03e918c17ee 100644
--- a/packages/fuel-gauge/src/contract-factory.test.ts
+++ b/packages/fuel-gauge/src/contract-factory.test.ts
@@ -247,4 +247,22 @@ describe('Contract Factory', () => {
)
);
});
+
+ it('should not deploy contracts greater than 100KB', async () => {
+ using launched = await launchTestNode();
+ const {
+ wallets: [wallet],
+ } = launched;
+
+ const largeByteCode = `0x${'00'.repeat(112400)}`;
+ const factory = new ContractFactory(largeByteCode, StorageTestContractAbi__factory.abi, wallet);
+
+ await expectToThrowFuelError(
+ async () => factory.deployContract(),
+ new FuelError(
+ ErrorCode.CONTRACT_SIZE_EXCEEDS_LIMIT,
+ 'Contract bytecode is too large. Max contract size is 100KB'
+ )
+ );
+ });
});
diff --git a/packages/transactions/src/coders/transaction.ts b/packages/transactions/src/coders/transaction.ts
index 1aab7442bb4..efca5d0e472 100644
--- a/packages/transactions/src/coders/transaction.ts
+++ b/packages/transactions/src/coders/transaction.ts
@@ -628,8 +628,8 @@ export class TransactionCoder extends Coder {
}
default: {
throw new FuelError(
- ErrorCode.INVALID_TRANSACTION_TYPE,
- `Invalid transaction type: ${type}`
+ ErrorCode.UNSUPPORTED_TRANSACTION_TYPE,
+ `Unsupported transaction type: ${type}`
);
}
}
@@ -667,8 +667,8 @@ export class TransactionCoder extends Coder {
}
default: {
throw new FuelError(
- ErrorCode.INVALID_TRANSACTION_TYPE,
- `Invalid transaction type: ${type}`
+ ErrorCode.UNSUPPORTED_TRANSACTION_TYPE,
+ `Unsupported transaction type: ${type}`
);
}
}
diff --git a/packages/transactions/src/coders/upgrade-purpose.ts b/packages/transactions/src/coders/upgrade-purpose.ts
index 1b51e340abf..33db4b8d5ad 100644
--- a/packages/transactions/src/coders/upgrade-purpose.ts
+++ b/packages/transactions/src/coders/upgrade-purpose.ts
@@ -59,8 +59,8 @@ export class UpgradePurposeCoder extends Coder {
default: {
throw new FuelError(
- ErrorCode.INVALID_TRANSACTION_TYPE,
- `Invalid transaction type: ${type}`
+ ErrorCode.UNSUPPORTED_TRANSACTION_TYPE,
+ `Unsupported transaction type: ${type}`
);
}
}
@@ -94,8 +94,8 @@ export class UpgradePurposeCoder extends Coder {
default: {
throw new FuelError(
- ErrorCode.INVALID_TRANSACTION_TYPE,
- `Invalid transaction type: ${type}`
+ ErrorCode.UNSUPPORTED_TRANSACTION_TYPE,
+ `Unsupported transaction type: ${type}`
);
}
}