3

I'm deploying two contracts, one of which depends on another, plus they depend on a number of other contracts via the import statements. However, although in my deployment script I haven't included any link statements, all my tests pass.

Why does it work without linking, and should I add the link statements before deploying to a live net?

Here's what I have in my .sol file:

pragma solidity ^0.4.18;
import '../node_modules/zeppelin-solidity/contracts/token/StandardToken.sol';
import '../node_modules/zeppelin-solidity/contracts/math/Math.sol';
import '../node_modules/zeppelin-solidity/contracts/math/SafeMath.sol';
import '../node_modules/zeppelin-solidity/contracts/ownership/Ownable.sol';

contract NppToken is StandardToken, Ownable {...}

contract CrowdSale is Ownable {
  NppToken private token;
...
}

Here's my migrations file:

var NppToken = artifacts.require("./NppToken.sol");
var CrowdSale = artifacts.require("./CrowdSale.sol");

module.exports = function(deployer, network, accounts) {
  deployer.deploy(NppToken);
  deployer.deploy(CrowdSale, NppToken.address);
};

3 Answers 3

1

What does the inheritance of your contracts look like? Link is used to link libraries that are already deployed on the network, see here. But if you are not linking libraries and are just inheriting things like your SafeMath.sol and Ownable.sol then that is why their code is available to you and your tests are passing.

3
  • I inherit from StandardToken which inherits from BasicToken which uses SafeMath: contract BasicToken is ERC20Basic { using SafeMath for uint256;...
    – ulu
    Jan 23, 2018 at 15:16
  • When you say BasicToken uses SafeMath, how? Are you importing? When you import, two contracts are created, the library address will be linked. See here (ethereum.stackexchange.com/questions/10187/…). For best practices for deployment though, I believe it is best to create a library and then link the address.
    – Karen S
    Jan 23, 2018 at 15:34
  • BasicToken is a token by Zeppelin, github.com/OpenZeppelin/zeppelin-solidity/blob/master/contracts/…. It has import "../math/SafeMath.sol"; at the top and uses SafeMath's functions in the code. The link you provide references Remix, and I'm using Truffle.
    – ulu
    Jan 23, 2018 at 20:02
5

Calling library functions declared as internal, such as those in SafeMath and Math above do not require the calling contract to be linked to the library contract as they will be copied into the calling contract's bytecode during compilation.

Calling library functions declared as public or external will require the calling contract to be linked to the library contract, using deployer.link() in Truffle, as they are not copied into the calling contract. They will live in a separate, library contract.

Note I haven't discussed private functions here as they can't be called from another contract.

Ultimately, for your code, there's no need to add the link statements for live deployment. Note that the deployment script should be the same for testrpc and live nets for all approaches to linking in Truffle.

See the Solidity doc on libraries for more info.

1
  • Your and Karen's answers complement each other: I have both a base contract and a library with internal methods. I marked her answer as the correct one because she was first, sorry :( you got +1.
    – ulu
    Jan 23, 2018 at 20:06
0

Linking is basically assigning an address of a library to a contract. If you have e.g.:

library A{
   function doNothing(){}
}

contract B{
   function doSomething(){
       A.doNothing();
   }
}

then during compilation, A.doNothing is replaced with delegatecall(, ...). In order for the deployer to know the address of the deployed library, you have to do the linking - which do nothing else as replace all the references to library A in the delegatecall with its actual address.

However, if you do something like this:

contract A{}
contract B{
   A a;
}

the address of 'a' remains initialised unless you explicitly initialise it (e.g. through assignment or new() call), e.g.

contract A{}
contract B{
   A a;
   function setA(address _a){
      a = A(_a);
   }

   function createA(){
      a = new A();
   }
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.