Skip to content
This repository has been archived by the owner on Feb 26, 2024. It is now read-only.

Migrating multiple contracts where a subsequent contract is deployed in a .then clause or after an await results in only first contract being deployed #650

Closed
1 task done
mhchu opened this issue Nov 1, 2017 · 12 comments · May be fixed by sgryphon/truffle#1

Comments

@mhchu
Copy link

mhchu commented Nov 1, 2017


Issue

When migrating more than one contract the following works:

deployer.deploy(contractA);
deployer.deploy(contractB);

but if the second contract needs information from the first contract to be deployed, then this:

await deployer.deploy(contractA);
const instanceA = await contractA.deployed();
const value = await instanceA.getValue();
deployer.deploy(contractB, value);

does not work. Only contractA is deployed to the network and truffle migrate ends after showing contractB's address and does not say "Saving successful migration to network..."

This is true even in the simplified example of:

await deployer.deploy(contractA);
deployer.deploy(contractB);

The use of .then() or deployer.then() results in the same behavior - only the first contract is saved to the network.

deployer.deploy(contractA).then( ()=>{ deployer.deploy(contractB); });
deployer.deploy(contractA);
deployer.then( ()=> deployer.deploy(contractB); );

In all cases, truffle migrate says Deploying contractB and provides contractB: <contractB address> but it does not say Saving successful migration to network...

Steps to Reproduce

Running truffle 3.4.11, node 7.10.1, and TestRPC 4.1.3 and simple contractA in contracts/contractA.sol and contractB in contracts/contractB.sol with migrations/2_deploy_contracts.js containing:

var contractA = artifacts.require("../contracts/contractA.sol");
var contractB = artifacts.require("../contracts/contractB.sol");

module.exports = async function(deployer, network, accounts) {
	await deployer.deploy(contractA);
	deployer.deploy(contractB);
}

contractA will be deployed on the network while contractB will not. (Obviously, this is not the use case, this is the simplest replication. The use case would be something closer to:

var contractA = artifacts.require("../contracts/contractA.sol");
var contractB = artifacts.require("../contracts/contractB.sol");

module.exports = async function(deployer, network, accounts) {
	const addr = accounts[0];

	await deployer.deploy(contractA, addr);
	const instance = await contractA.deployed();
	const value = await instance.getValue();
	console.log('DEBUG:', value); // provides an expected value
	deployer.deploy(contractB, value);
}

Expected Behavior

Both contracts should be on the network.

Actual Results

truffle network shows only the first contract. Using truffle console and trying to access contractB.deployed() results in a message that the contract is not deployed on the network.

@Velenir
Copy link

Velenir commented Nov 8, 2017

You need to return deployer.deploy(...) from inside .then(() => {...})
For me it works with

deployer.deploy(contractA).then( ()=> deployer.deploy(contractB) );

or

deployer.then( ()=> {
  ...
 return deployer.deploy(contractB);
);

async...await and any Promise.* don't work as per #501

@mhchu
Copy link
Author

mhchu commented Nov 8, 2017

I will give it a try and report back (probably in a couple days when I can return to my project).

@zcstarr
Copy link

zcstarr commented Dec 14, 2017

This is still an issue in 4.0.1 only .then and Promise chaining seems to work

@dzentota
Copy link

Tried every possible combination, async + await, then() and async+await+then(), it doesn't work. In fact it always save Artifacts before deploying second contract, that's why you do not see address of the second contract. In my case I see address of the second contract after saving artifacts:
Running step...
Deploying SampleCampaign...
... 0x68e6e16d86617689f9522e6dc9b56e0e9f66c7400e7c101fd3e0afaf5ffe8ca4
Saving artifacts...
... 0xdc7a4c7cdc7634c1b68fa254f863b2d54edbb475100f52fe87f084c63dcbd95d
SampleCampaign: 0xad89528ffe22aa057cfbec6c9ccf2367a638eb79

So if I run truffle console and then in console:
SampleCampaign.deployed()

I get:
SampleCampaign has not been deployed to detected network (network/artifact mismatch)
at /usr/lib/node_modules/truffle/build/cli.bundled.js:318327:17
at
at process._tickDomainCallback (internal/process/next_tick.js:228:7)

But if I check address "0xad89528ffe22aa057cfbec6c9ccf2367a638eb79" I see that contract is there:
SampleCampaign.at("0xad89528ffe22aa057cfbec6c9ccf2367a638eb79")

@ismaelbej
Copy link

This issue seems to be a duplicate of #501.

@cgewecke
Copy link
Contributor

cgewecke commented Feb 8, 2018

@ismaelbej Thank you for noting this, closing here in favor of #501..

@dzentota @mhchu
The deployer stages deployments rather than running them at the execution time of the migration function. It's possible to use async/await within its context but ultimately you also have to follow the deployer's interface by returning a promise to its .then property. More guidance on this at the other issue here

@cgewecke cgewecke closed this as completed Feb 8, 2018
@dzentota
Copy link

dzentota commented Feb 9, 2018

I saw #501 before and some similar. But approach mentioned in #501 doesn't work, output is the same

@cgewecke
Copy link
Contributor

cgewecke commented Feb 9, 2018

@dzentota Could you share the code from your migrations that's not working?

@dzentota
Copy link

Hi, unfortunately I don't have all the variants I've tried. Here is an example with then()

var Crowdsale = artifacts.require("./Crowdsale.sol");
var SampleCampaign = artifacts.require('./SampleCampaign.sol');

module.exports = function (deployer) {
    Crowdsale.deployed().then(function (_) {
        console.log(Crowdsale.address);
       return _.token.call();
    }).then(function(tokenAddress) {
        let crowdsaleAddress = Crowdsale.address;
        let minContribution = 1000000000000000000;
        let maxContribution = 10000000000000000000;
        let softCap = 5000000000000000000;
        let hardCap = 100000000000000000000;
        let startTime = Math.floor(Date.now() / 1000);
        let endTime = Math.floor(Date.now() / 1000) + 100000;
        let fee = 1;
        let bountyFee = 1;

        deployer.deploy(
            SampleCampaign,
            crowdsaleAddress,
            tokenAddress,
            minContribution,
            maxContribution,
            softCap,
            hardCap,
            startTime,
            endTime,
            fee,
            bountyFee
        );
    })

}

Output:

migrate -f 4
Using network 'develop'.

Running migration: 4_deploy_campaign.js
Saving successful migration to network...
  Replacing SampleCampaign...
  ... 0x87e580340a0fdff84559a1bb014f08f281476024af9f32a8036e4743f19f9f2d
Saving artifacts...
truffle(develop)>   ... 0x2606dfbc10b81afaa9d780e64c1612cea03e27dea943b48b2f3c40b4d03b3856
  SampleCampaign: 0xbaaa2a3237035a2c7fa2a33c76b44a8c6fe18e87

undefined

Actually, I see all this text except undefined. Undefined appears after I hit enter (otherwise it hangs)

@cgewecke
Copy link
Contributor

@dzentota The example @Velenir gives in this issue above is the model you should follow. If you want to run async logic in the migrations you must return it as a promise to the deployer method. In your case,

module.exports = function (deployer) {
  deployer.then( function() {
     return Crowdsale.deployed() .... etc ...
);

Additionally make sure you return everything async in the promise chain. For example the deployer.deploy in your final clause should also be prefaced with a return.

@dzentota
Copy link

Thanks @cgewecke now it works!!!

@benediamond
Copy link

Additionally make sure you return everything async in the promise chain

@dzentota @cgewecke yes, this part is key in a way I can't quite understand yet. Is this because the main deployment function "knows to wait" for the promise chain to finish executing when it depends on its return value?

Is the value returned from the deployment function actually used by truffle in any way...?

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants