Unlike Ethereum, Abstract does not store the bytecode of smart contracts directly; instead, it stores a hash of the bytecode and publishes the bytecode itself to Ethereum.

This adds several benefits to smart contract deployments on Abstract, including:

  • Inherited L1 Security: Smart contract bytecode is stored directly on Ethereum.
  • Increased Gas efficiency: Only unique contract bytecode needs to be published on Ethereum. If you deploy the same contract more than once (such as when using a factory), subsequent contract deployments are substantially cheaper.

How Contract Deployment Works

Contracts cannot be deployed on Abstract unless the bytecode of the smart contract to be deployed is published on Ethereum. If the bytecode of the contract has not been published, the deployment transaction will fail with the error the code hash is not known.

To publish bytecode before deployment, all contract deployments on Abstract are performed by calling the ContractDeployer system contract using one of it’s create, create2, createAccount, or create2Account functions.

The bytecode of your smart contract and any other smart contracts that it can deploy (such as when using a factory) must be included inside the factory dependencies (factoryDeps) of the deployment transaction.

Typically, this process occurs under the hood and is performed by the compiler and client libraries. This page will show you how to deploy smart contracts on Abstract by interacting with the ContractDeployer system contract.

Get Started Deploying Smart Contracts

Use the example repository below as a reference for creating smart contracts and scripts that can deploy smart contracts on Abstract using various libraries.

Contract Deployment Example Repo

See example code on how to build factory contracts and deployment scripts using Hardhat, Ethers, Viem, and more.

Deploying Smart Contracts

When building smart contracts, the zksolc and zkvyper compilers transform calls to the CREATE and CREATE2 opcodes into calls to the create and create2 functions on the ContractDeployer system contract.

In addition, when you call either of these opcodes, the compiler automatically detects what other contracts your contract is capable of deploying and includes them in the factoryDeps field of the generated artifacts.

Solidity

No Solidity changes are required to deploy smart contracts, as the compiler handles the transformation automatically. Note: address derivation via CREATE and CREATE2 is different from Ethereum. Learn more.

create

Below are examples of how to write a smart contract that deploys other smart contracts using the CREATE opcode. The compiler will automatically transform these calls into calls to the create function on the ContractDeployer system contract.

create2

Below are examples of how to write a smart contract that deploys other smart contracts using the CREATE2 opcode. The compiler will automatically transform these calls into calls to the create2 function on the ContractDeployer system contract.

createAccount

When deploying smart contract wallets on Abstract, manually call the createAccount or create2Account function on the ContractDeployer system contract. This is required because the contract needs to be flagged as a smart contract wallet by setting the fourth argument of the createAccount function to the account abstraction version.

View Example AccountFactory.sol using create

See an example of a factory contract that deploys smart contract wallets using createAccount.

create2Account

Similar to the createAccount function, the create2Account function on the ContractDeployer system contract must be called manually when deploying smart contract wallets on Abstract to flag the contract as a smart contract wallet by setting the fourth argument of the create2Account function to the account abstraction version.

View Example AccountFactory.sol using create2

See an example of a factory contract that deploys smart contract wallets using create2Account.

EIP-712 Transactions via Clients

Once your smart contracts are compiled and you have the bytecode(s), you can use various client libraries to deploy your smart contracts by creating EIP-712 transactions that:

  • Have the transaction type set to 113 (to indicate an EIP-712 transaction).
  • Call the create, create2, createAccount, or create2Account function to the ContractDeployer system contract address (0x0000000000000000000000000000000000008006).
  • Include the bytecode of the smart contract and any other contracts it can deploy in the customData.factoryDeps field of the transaction.

hardhat-zksync

Since the compiler automatically generates the factoryDeps field for you in the contract artifact (unless you are manually calling the ContractDeployer via createAccount or create2Account functions), load the artifact of the contract and use the Deployer class from the hardhat-zksync plugin to deploy the contract.

zksync-ethers

Use the ContractFactory class from the zksync-ethers library to deploy your smart contracts.

View Example zksync-ethers Contract Deployment Script

viem

Use Viem’s deployContract method to deploy your smart contracts.

View Example Viem Contract Deployment Script

How Bytecode Publishing Works

When a contract is deployed on Abstract, multiple system contracts work together to compress and publish the contract bytecode to Ethereum before the contract is deployed.

Once the bytecode is published, the hash of the bytecode is set to “known”; meaning the contract can be deployed on Abstract without needing to publish the bytecode again.

The process can be broken down into the following steps:

1

Bootloader processes transaction

The bootloader receives an EIP-712 transaction that defines a contract deployment. This transaction must:

  1. Call the create or create2 function on the ContractDeployer system contract.
  2. Provide a salt, the formatted hash of the contract bytecode, and the constructor calldata as arguments.
  3. Inside the factory_deps field of the transaction, include the bytecode of the smart contract being deployed as well as the bytecodes of any other contracts that this contract can deploy (such as if it is a factory contract).
2

Marking contract as known and publishing compressed bytedata

Under the hood, the bootloader informs the KnownCodesStorage system contract about the contract code hash. This is required for all contract deployments on Abstract.

The KnownCodesStorage then calls the Compressor, which subsequently calls the L1Messenger system contract to publish the hash of the compressed contract bytecode to Ethereum (assuming this contract code has not been deployed before).

3

Smart contract account execution

Once the bootloader finishes calling the other system contracts to ensure the contract code hash is known, and the contract code is published to Ethereum, it continues executing the transaction as described in the tranasction flow section.

This flow includes invoking the contract deployer account’s validateTransaction and executeTransaction functions; which will determine whether to deploy the contract and how to execute the deployment tranasction respectively.

Learn more about these functions on the smart contract wallets section, or view an example implementation in the DefaultAccount.