How to deploy an Ethereum smart contract using Aurora

In this tutorial, we’ll walk through the flow for deploying a smart contract to Aurora, and discuss how Ethereum and NEAR can be used to interact with this smart contract.

In this tutorial, we are going to deploy an ERC-721 smart contract to Aurora testnet, and will be reproducing some of the steps used in the Deploying a Contract using Truffle Aurora Tutorial. Parts of this tutorial will be modified to use the Aurora testnet endpoints available via Infura.

Once the smart contract is deployed, we can bridge ETH or NEAR to Aurora, and use that bridged ETH and NEAR to pay for gas costs associated with minting tokens using the ERC-721 contract we have created. This example meant to illustrate how Aurora can be used to cheaply deploy a smart contract. Similar patterns could be used for DeFi applications (if using an ERC-20 token), DAO membership, gaming, and other use cases.

At this time, tokens that are minted on Ethereum can use the Rainbow Bridge to move to Aurora. Tokens minted on NEAR can also be bridged to Aurora using the Rainbow Bridge. At this time, tokens created on Aurora cannot yet be bridged to Ethereum or NEAR, but this is on the roadmap for Aurora.

Tokens minted on Aurora are not able to bridged to Ethereum or NEAR at this time.

Deploy an ERC-721 smart contract to Aurora testnet

This tutorial assumes familiarity and prior usage of the smart contract development suite Truffle. If this is your first use of Truffle, we recommend completing the “Pet Shop” tutorial in the Truffle documentation first before starting on this tutorial.

1. Create a project directory and initialize a Truffle project
In your terminal, create a new folder called aurora-721-example and initialize a truffle project within that directory

           mkdir aurora-721-example
           cd aurora-721-example
           truffle init

2. Download the OpenZeppelin contracts
Within the aurora-721-example directory, download the OpenZeppelin contracts, as the smart contract we will deploy will import some of these contracts.

           npm install @openzeppelin/contracts

3. Create an account to sign transactions
In order to sign transactions, we’ll need an account to sign with. There are multiple ways to generate a wallet, and if this is your first time doing so, we encourage you to follow Step 3 of the ConsenSys Developer Portal. Alternatively, you can use Truffle Dashboard to connect an existing wallet and sign transactions without needing to put your mnemonic in a .env file.

4. Create the .env file
As we are using a .env file to store our Infura project ID, run following command in your terminal:

           npm install --save dotenv

Create a file in the root level of your directory called .env and inside this file enter the following information, providing your Infura API key (without quotations), and, if needed, your mnemonic (with quotations):


NEVER PUSH A .env FILE TO GITHUB OR ANY PUBLIC LOCATION. For best practices on using a .env file and protecting your secrets as it relates to Infura please read How to Use .env to Enhance Basic Security Within Your DApp. General advice on protecting your secrets can found by reading at How to Avoid Uploading Your Private Keys to GitHub.

5. Create your smart contract
Navigate to the Contracts folder and create a new contract called ClubToken.sol. Within that file, paste the following code:

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

        import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
        import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
        import "@openzeppelin/contracts/utils/Counters.sol";

        contract ClubToken is ERC721URIStorage {
            uint256 private _tokensCount = 0;
            address public minter = address(0);

            modifier onlyMinter(){
                    minter == msg.sender,
                    'Invalid Minter'

            constructor() ERC721("ClubToken", "CT") {
                minter = msg.sender;

            function mint(address to) external onlyMinter {
                uint256 tokenId = _tokensCount + 1;
                _mint(to, tokenId);
                _tokensCount = tokenId;

            function burn(uint256 tokenId) external {
                _tokensCount -= 1;

            function safeTransferFrom(address from, address to, uint256 tokenId) public virtual override {
                require(minter == msg.sender || to == minter, 'Invalid Transfer');
                safeTransferFrom(from, to, tokenId, "");

            function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory _data) public virtual override {
                require(minter == msg.sender || to == minter, 'Invalid Transfer');
                require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");
                _safeTransfer(from, to, tokenId, _data);

6. Create the migrations script
Navigate to the migrations folder and create a file named 2_deploy_contracts.js and paste in the following code:

        const ClubToken = artifacts.require("ClubToken.sol");

        module.exports = function(deployer) {

7. Configure the Truffle settings
Now navigate to the truffle-config.js file and put the following information at the top of the file, assuming you are using a .env to store your Infura project ID and wallet mnemonic:

    const HDWalletProvider = require("@truffle/hdwallet-provider");

Under the networks section of truffle-config.js paste in the following code:

    auroratestnet: {
        provider: () =>
          new HDWalletProvider(
        network_id: 0x4e454153, // Aurora testnet ID
        gas: 10000000

8. Compile and deploy the smart contract to Aurora testnet
In your terminal, run the command:

    truffle migrate --network auroratestnet

This will compile and migrate the smart contract to the Aurora testnet, and you will be able to see the deployed code using the testnet version of Aurorascan. We now have deployed a smart contract to Aurora testnet.

    Compiling your contracts...
            > Compiling ./contracts/ClubToken.sol
            > Artifacts written to /Users/Code/aurora-721-example/build/contracts
            > Compiled successfully using:
            - solc: 0.8.11+commit.d7f03943.Emscripten.clang

            Starting migrations...
            > Network name:    'auroratestnet'
            > Network id:      1313161555
            > Block gas limit: 0 (0x0)


            Deploying 'ClubToken'
            > transaction hash:    0xe999cf28b54d11985f61d33aeb8cd11c269a45bdd28f389ad0ebb83101fddc4e
            > Blocks: 11           Seconds: 8
            > contract address:    0x12820Dc1283354CbB9f2478b6c044d4260E95e15
            > block number:        84998829
            > block timestamp:     1647289263
            > account:             0xc94C5473073878FAFd500aFfb5495aDb2230Eeea
            > balance:             0.001
            > gas used:            2685442 (0x28fa02)
            > gas price:           0 gwei
            > value sent:          0 ETH
            > total cost:          0 ETH

            > Saving migration to chain.
            > Saving artifacts
            > Total cost:                   0 ETH

            > Total deployments:   1
            > Final cost:          0 ETH

this, you complete this workshop successfully!!