Deploy your first contract

Deploy a smart contract to a ZKsync chain in under 5 minutes

Choose between using testnet or a local node.

Review the smart contract code

The quickstart contract is a basic ERC-20 token built with OpenZeppelin. The entire code is as follows:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol";

contract QuickstartToken is ERC20, Ownable, ERC20Burnable {
    constructor(string memory name, string memory symbol) ERC20(name, symbol) Ownable(msg.sender) {
        _mint(msg.sender, 100 * 10 ** decimals());
    }

    function mint(address to, uint256 amount) public onlyOwner {
        _mint(to, amount);
    }
}

The contract:

  • imports helper contracts from @openzeppelin/contracts so that our contract is a standard ERC-20 contract, has an owner, and allows to tokens to be burned
  • sets the token name to the symbol using the constructor arguments
  • sets the deployer wallet as the owner
  • mints an initial supply of 100 tokens to the deployer
  • only allows the owner to mint additional tokens using the mint function
The ERC20 token code is provided “as is” without any express or implied warranties.
  • Regulations governing digital assets are still unclear in many jurisdictions.
  • ERC20 tokens may possess unique legal, tax, and market risks, so it is up to you to determine which, if any, laws apply to your deployment of ERC20 tokens.
  • The developers and publishers of this software disclaim any liability for any legal issues that may arise from its use.

Project setup

Choose between using Foundry or Hardhat.

If you don't already have forge installed, you can install it via foundryup.

  1. Create a new foundry project:
    forge init QuickstartToken
    
    cd QuickstartToken
    
  2. Install OpenZeppelin Contracts.
    forge install OpenZeppelin/openzeppelin-contracts
    

    Once installed, add a remappings.txt file and add this line:

    @openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/
    
  3. Create a new file in the src folder called QuickstartToken.sol.
  4. Copy and paste the QuickstartToken contract above into the QuickstartToken.sol file.
  5. Create a new file in the script folder called QuickstartToken.s.sol.
  6. Copy and paste the script below into QuickstartToken.s.sol. This script will be used to deploy the contract.
    // SPDX-License-Identifier: UNLICENSED
    pragma solidity ^0.8.13;
    
    import {Script} from "forge-std/Script.sol";
    import {QuickstartToken} from "../src/QuickstartToken.sol";
    
    contract QuickstartTokenScript is Script {
        QuickstartToken public quickstartToken;
    
        function setUp() public {}
    
        function run() public {
            vm.startBroadcast();
    
            quickstartToken = new QuickstartToken("Quickstart Token", "QKT");
    
            vm.stopBroadcast();
        }
    }
    
  7. Build the project.
    forge build
    
  8. Set your private key for deploying. Get this from your browser wallet for the same account where you bridged testnet ETH.
    export TESTNET_PRIVATE_KEY="0x..."
    
  9. Deploy the contract using the command below. Your contract address will be logged in the output.
    forge script script/QuickstartToken.s.sol --rpc-url https://zksync-os-testnet-alpha.zksync.dev --broadcast --skip-simulation --private-key $TESTNET_PRIVATE_KEY
    
  10. (Optional) Verify the contract. This will allow you to see the contract code in the block explorer. Replace 0x<YOUR_CONTRACT_ADDRESS> with your deployed contract address from the previous step.
    forge verify-contract \
    --chain-id 8022833 \
    --verifier custom \
    --verifier-url https://block-explorer-api.zksync-os-testnet-alpha.zksync.dev/api \
    0x<YOUR_CONTRACT_ADDRESS> \
    src/QuickstartToken.sol:QuickstartToken
    
  11. Verify if the contract was successfully verified by searching for your contract address on the testnet block explorer and clicking on the "Contract" tab.
  1. Create a new project folder
    mkdir hardhat-example
    cd hardhat-example
    
  2. Initialize a new Hardhat 3 project. You can choose to either use Mocha with Ethers.js or Node Test Runner with viem. Select y to install the dependencies.
    npx hardhat --init
    
  3. Install OpenZeppelin Contracts.
    npm install @openzeppelin/contracts
    
  4. Add ZKsync OS to the hardhat.config.ts file and configure the ignition required confirmations.
    hardhat.config.ts
      ignition: {
        requiredConfirmations: 1,
      },
      networks: {
        zksyncOS: {
          type: 'http',
          chainType: 'generic',
          url: 'https://zksync-os-testnet-alpha.zksync.dev',
          accounts: [configVariable('TESTNET_PRIVATE_KEY')],
        },
      },
    
  5. Add your private key to the Hardhat keystore as TESTNET_PRIVATE_KEY. If you've never used hardhat keystore before, you will be asked to set up a password. Get the private key from your browser wallet for the same account where you bridged testnet ETH.
    npx hardhat keystore set TESTNET_PRIVATE_KEY
    
  6. Create a new file in the contracts folder called QuickstartToken.sol.
  7. Copy and paste the QuickstartToken contract above into the QuickstartToken.sol file.
  8. Create a new file in the ignition/modules folder called QuickstartToken.ts.
  9. Copy and paste the ignition module below into QuickstartToken.ts. This will be used to deploy the contract.
    import { buildModule } from '@nomicfoundation/hardhat-ignition/modules';
    
    export default buildModule('QuickstartToken', (m) => {
      const quickstartToken = m.contract('QuickstartToken', ['Quickstart Token', 'QKT']);
    
      return { quickstartToken };
    });
    
  10. Compile and deploy the contract. Your contract address will be logged in the output.
    npx hardhat compile
    
    npx hardhat ignition deploy ignition/modules/QuickstartToken.ts --network zksyncOS
    

Verify the contract

You can optionally verify the contract so the code shows on the block explorer.

  1. Install the Hardhat verify SDK:
    npm install --save-dev @nomicfoundation/hardhat-verify
    
  2. Add hardhatVerify to the hardhat plugins and configure the verification endpoint:
    hardhat.config.ts
    import hardhatVerify from "@nomicfoundation/hardhat-verify";
    
    const config: HardhatUserConfig = {
    plugins: [
        hardhatVerify,
        // ...other plugins...
    ],
    // ...other config...
      chainDescriptors: {
        8022833: {
          name: 'zksyncOS',
          blockExplorers: {
            blockscout: {
              name: 'Testnet Explorer',
              url: 'https://zksync-os-testnet-alpha.staging-scan-v2.zksync.dev',
              apiUrl: 'https://block-explorer-api.zksync-os-testnet-alpha.zksync.dev/api',
            },
          },
        },
      },
    };
    
  3. Use your deployed contract address to verify using hardhat-verify:
    npx hardhat clean
    npx hardhat compile --build-profile production
    npx hardhat verify --build-profile production --network zksyncOS 0x<YOUR_CONTRACT_ADDRESS> "Quickstart Token" "QKT"
    
  4. Verify if the contract was successfully verified by searching for your contract address on the block explorer and clicking on the "Contract" tab.

Review the smart contract code

The quickstart contract is a basic ERC-20 token built with OpenZeppelin. The entire code is as follows:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol";

contract QuickstartToken is ERC20, Ownable, ERC20Burnable {
    constructor(string memory name, string memory symbol) ERC20(name, symbol) Ownable(msg.sender) {
        _mint(msg.sender, 100 * 10 ** decimals());
    }

    function mint(address to, uint256 amount) public onlyOwner {
        _mint(to, amount);
    }
}

The contract:

  • imports helper contracts from @openzeppelin/contracts so that our contract is a standard ERC-20 contract, has an owner, and allows to tokens to be burned
  • sets the token name to the symbol using the constructor arguments
  • sets the deployer wallet as the owner
  • mints an initial supply of 100 tokens to the deployer
  • only allows the owner to mint additional tokens using the mint function
The ERC20 token code is provided “as is” without any express or implied warranties.
  • Regulations governing digital assets are still unclear in many jurisdictions.
  • ERC20 tokens may possess unique legal, tax, and market risks, so it is up to you to determine which, if any, laws apply to your deployment of ERC20 tokens.
  • The developers and publishers of this software disclaim any liability for any legal issues that may arise from its use.

Project setup

Choose between using Foundry or Hardhat.

  1. Create a new foundry project. You should already have forge installed after installing foundryup in the previous setup.
    forge init QuickstartToken
    
    cd QuickstartToken
    
  2. Install OpenZeppelin Contracts.
    forge install OpenZeppelin/openzeppelin-contracts
    

    Once installed, add a remappings.txt file and add this line:

    @openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/
    
  3. Create a new file in the src folder called QuickstartToken.sol.
  4. Copy and paste the QuickstartToken contract above into the QuickstartToken.sol file.
  5. Create a new file in the script folder called QuickstartToken.s.sol.
  6. Copy and paste the script below into QuickstartToken.s.sol. This script will be used to deploy the contract.
    // SPDX-License-Identifier: UNLICENSED
    pragma solidity ^0.8.13;
    
    import {Script} from "forge-std/Script.sol";
    import {QuickstartToken} from "../src/QuickstartToken.sol";
    
    contract QuickstartTokenScript is Script {
        QuickstartToken public quickstartToken;
    
        function setUp() public {}
    
        function run() public {
            vm.startBroadcast();
    
            quickstartToken = new QuickstartToken("Quickstart Token", "QKT");
    
            vm.stopBroadcast();
        }
    }
    
  7. Build the project.
    forge build
    
  8. Deploy the contract using one of the test wallets provided by anvil. Your contract address will be logged in the output.
    forge script script/QuickstartToken.s.sol --rpc-url http://localhost:8545 --broadcast --skip-simulation --private-key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
    
  1. Create a new project folder
    mkdir hardhat-example
    cd hardhat-example
    
  2. Initialize a new Hardhat 3 project. You can choose to either use Mocha with Ethers.js or Node Test Runner with viem. Select y to install the dependencies.
    npx hardhat --init
    
  3. Install OpenZeppelin Contracts.
    npm install @openzeppelin/contracts
    
  4. Add the local node to the hardhat.config.ts file and configure the ignition required confirmations.
    hardhat.config.ts
      ignition: {
        requiredConfirmations: 1,
      },
      networks: {
        anvil: {
          type: 'http',
          chainType: 'generic',
          url: 'http://localhost:8545',
          accounts: ['0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80'],
        },
      },
    
  5. Create a new file in the contracts folder called QuickstartToken.sol.
  6. Copy and paste the QuickstartToken contract above into the QuickstartToken.sol file.
  7. Create a new file in the ignition/modules folder called QuickstartToken.ts.
  8. Copy and paste the ignition module below into QuickstartToken.ts. This will be used to deploy the contract.
    import { buildModule } from '@nomicfoundation/hardhat-ignition/modules';
    
    export default buildModule('QuickstartToken', (m) => {
      const quickstartToken = m.contract('QuickstartToken', ['Quickstart Token', 'QKT']);
    
      return { quickstartToken };
    });
    
  9. Compile and deploy the contract. Your contract address will be logged in the output.
    npx hardhat compile
    
    npx hardhat ignition deploy ignition/modules/QuickstartToken.ts --network anvil
    

Now your first contract is fully deployed! In the next section we'll interact with it using a script to mint and transfer some tokens.


Made with ❤️ by the ZKsync Community