A contract instance represents a deployed contract in a particular network. Using a contract abstraction instance, we need to create a contract instance. There are three methods to create a contract instance:
- SampleContract.new([arg1, arg2, ...], [tx params]): This function takes whatever constructor parameters your contract requires and deploys a new instance of the contract to the network to which the contract abstraction is set to use. There's an optional last argument, which you can use to pass transaction parameters, including the transaction from address, gas limit, and gas price. This function returns a promise that resolves into a new instance of the contract abstraction at the newly deployed address when the transaction is mined. This method doesn't make any changes to the artifacts object the contract abstraction represents. Before using this method, make sure that it can find the libraries' addresses that the byte code is dependent on for the network it's set to use.
- SampleContract.at(address): This function creates a new instance of the contract abstraction representing the contract at the passed-in address. It returns a "thenable" object (not yet an actual promise for backward compatibility). It resolves to a contract abstraction instance after ensuring that the code exists at the specified address in the network it's set to use.
- SampleContract.deployed(): This is just like at(), but the address is retrieved from the artifacts object. Like at(), deployed() is tenable and will resolve to a contract instance representing the deployed contract after ensuring that the code exists at that location and that the address exists on the network that the contract abstraction is set to use.
Let's deploy and get a contract instance of the Sample contract. In network ID 10, we need to use new() to deploy the StringLib library first and then add the deployed address of the StringLib library to the StringLib abstraction, link the StringLib abstraction to the SampleContract abstraction, and then deploy the Sample contract using new() to get an instance of the Sample contract. But in network ID 1, we just need to deploy SampleContract and get its instance, as we already have StringLib deployed there. Here is the code to do all this:
web3.version.getNetwork(function(err, network_id) {
if(network_id == 1)
{
var SampleContract_Instance = null;
SampleContract.new().then(function(instance){
SampleContract.networks[SampleContract.network_id]
["address"] = instance.address;
SampleContract_Instance = instance;
})
}
else if(network_id == 10)
{
var StringLib_Instance = null;
var SampleContract_Instance = null;
StringLib.new().then(function(instance){
StringLib_Instance = instance;
}).then(function(){
StringLib.networks[StringLib.network_id] = {};
StringLib.networks[StringLib.network_id]["address"] =
StringLib_Instance.address;
SampleContract.link(StringLib);
}).then(function(result){
return SampleContract.new();
}).then(function(instance){
SampleContract.networks[SampleContract.network_id]
["address"] = instance.address;
SampleContract_Instance = instance;
})
}
});
This is how the preceding code works:
- At first, we detect the network ID. If the network ID is 10, then we deploy both the contract and library, and if the network ID is 10, then we only deploy the contract.
- In network ID 10, we deploy the StringLib contract and get the contract instance of it.
- Then, we update the StringLib abstraction so that it knows about the address of the contract in the current network it represents. The interface to update the abstraction is similar to updating the artifacts object directly. If you are connected to network ID 1, then it will override the StringLib address, which is already set.
- Then, we link the deployed StringLib to the SampleContract abstraction. Linking updates the links and copies the events of the library to the SampleContract abstraction's current network it represents. Libraries can be linked multiple times and will overwrite their previous linkage.
- We deploy SampleContract to the current network.
- We update the SampleContract abstraction to store the address of the contract in the current network it's representing so that we can use deployed() to get the instance later on.
- In the case of network ID 1, we just deploy SampleContract and that's it.
- Now you can simply change the network that your node is connected to and restart your app, and your app will behave accordingly. So for example, on a developer's machine, the app will be connected to a development network and on a production server, it will be connected to the main network. Obviously, you may not want to deploy the contracts every time the preceding file is run, so you can actually update the artifacts objects once the contracts are deployed and in the code you can check whether the contract is deployed or not. If not deployed, only then should you deploy it. Instead of updating the artifacts object manually, you can store the artifacts in a DB or in a file and write code to update them automatically after the contract deployment is done.