Contract Deployment
Learn how to deploy smart contracts on Abstract.
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
, orcreate2Account
functionto
theContractDeployer
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.
Example contract factory contract deployment script
Example smart contract wallet factory deployment script
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:
Bootloader processes transaction
The bootloader receives an EIP-712 transaction that defines a contract deployment. This transaction must:
- Call the
create
orcreate2
function on theContractDeployer
system contract. - Provide a salt, the formatted hash of the contract bytecode, and the constructor calldata as arguments.
- 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).
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).
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.
Was this page helpful?