Back to homepage

How to import local contracts in Solidity

Published

If you're building a big application and your logic is split into different smat contracts, you'll probably need to import them to use their methods.

Notice that in this article I'm fousing on local imports and not on imports from libraries like OpenZeppelin

When working with local imports we need to take into account the order in which your contracts are deployed to the blockchain. In this example I'll be using Hardhat so my deploy script will be adapted for this framework but if you're using Truffle or other framework, your script will probably be very similar.

Updated to add that Truffle has the deploy.link method which is very useful in these cases.

Solidity import statement

The import statement in Solidity is pretty simple, just point to the source file of the contract you want to import.

// File: Contract_A.sol

pragma solidity ^0.8.0;


import './Contract_B.sol';

contract ContractA {
  // contract code here...
}

Save imported contract address

In order to successfuly import another contract and use its methods we need to know the address where it's deployed. If we're deploying both contracts at the same time, we have to make sure they're deployed in the correct order.

In this example Contract_A is importing Contract_B so we'd need Contract_B to be deployed first. Then in the Contract_A constructor we need to receive the Contract_B address and save it in a state variable (in the example below this variable is contractB_ref).

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

import "./Contract_B.sol";

contract Contract_A {
    // Type / visibility / variable name
    Contract_B public contractB_ref;

    // receive address during deployment script
    constructor(Contract_B _addrContractB) {
        contractB_ref = _addrContractB;
    }

}

Deploy script to reference imported contracts

Now that we've defined a state variable to store the imported contract's address, we just need to prepare the deployment script to deploy our contracts in the correct order and pass the Contract_B deployment address to the Contract_A so it can be saved when the contructor function is invoked.

// File: deploy.js (by default Hardhat creates it as /scripts/sample-script.js)

const hre = require('hardhat');

async function main() {
  // Hardhat always runs the compile task when running scripts with its command
  // line interface.
  //
  // If this script is run directly using `node` you may want to call compile
  // manually to make sure everything is compiled
  // await hre.run('compile');

  // We get the contract to deploy
  const Contract_B = await hre.ethers.getContractFactory('Contract_B');
  const contractb = await Contract_B.deploy();

  await contractb.deployed();

  console.log('ContractB deployed to:', contractb.address);

  const Contract_A = await hre.ethers.getContractFactory('Contract_A');
  // pass contractA constructor the address where contractB was just deployed
  const contracta = await Contract_A.deploy(contractb.address);

  console.log('ContractA deployed to:', contracta.address);
}

// We recommend this pattern to be able to use async/await everywhere
// and properly handle errors.
main()
  .then(() => process.exit(0))
  .catch((error) => {
    console.error(error);
    process.exit(1);
  });

TAGS

If you enjoyed this article consider sharing it on social media or buying me a coffee ✌️

Buy Me A Coffee