We're trying to figure out if migrations will work for our use case... We have one solidity contract (which creates a currency/tokens), which we deploy multiple instances of, often from the same ethereum account (owner). It doesn't seem to us like the migration system is set up to track multiple instances of the same solidity code. Is there a way this can work? Such that we can run migrations against multiple instances of a contact... Thanks for any help.
This is a good feature. On the list.
Excellent!
We need this as well
module.exports = function(deployer) {
deployer.deploy(MyToken, "Foo Token");
deployer.deploy(MyToken, "Bar Token");
};
https://gitter.im/ConsenSys/truffle?at=57a9a809ae838f6f569034c5
I post this comment not to dispute the need for this feature, instead to illustrate a potentially superior design which mitigates this issue.
If you are deploying multiple instances of the same contract, it may be in your best interest to use the 'factory' pattern. It allows you to compile and deploy a single contract which then performs the creation of further contracts. This provides consistency among contracts and provides easier deployment and testing in truffle.
pragma solidity ^0.4.8;
contract CarFactory {
function CarFactory() {
}
function newCar(string _color) public returns (address newCar) {
Car c = (new Car(_color));
return address(c);
}
}
contract Car {
string color;
function Car(string _color) {
color = _color;
}
function getColor() public constant returns (string color) {
return color;
}
}
I really think this is a good feature to have. I am trying to build a test environment that will facilitate a cross-transfer between 2 token types and ideally, I would want to deploy the 2 different token types from the same generalised token contract. I am not sure if using the factory method as suggested by @paulhauner will allow you to use contract abstractions when interacting with the newly spawned contract. What I have done so far is to make my 2 token types 2 different contracts that inherit from the same generalised token contract and deploying them explicitly.
Proposal:
deployer.deploy(ERC20Token, {as: 鈥淪ilverToken鈥潁);
deployer.deploy(ERC20Token, {as: 鈥淕oldToken鈥潁);
Triaging and looking for a good technical solution.
Following up on this feature, or what is the alternative to this approach in truffle deployment. Regards.
My solution to this was to create a container of multiple instances in the contracts folder. For example, if you have a MyERC20Token contract, and need to have a few of them deployed... you could create a container of them:
contract MyERC20TokenContainer {
address public a = new MyERC20Token(...);
address public b = new MyERC20Token(...);
}
Deploy that in a migration script (e.g. 2_deploy_MyERC20TokenContainer.js)
Then in your TestStuff.sol, you can grab them:
MyERC20Token tokenA = MyERC20Token(MyERC20TokenContainer(DeployedAddresses.MyERC20TokenContainer()).a());
MyERC20Token tokenB = MyERC20Token(MyERC20TokenContainer(DeployedAddresses.MyERC20TokenContainer()).b());
I had this exact use case and now the problem is that if you are using an ERC20 library like Zeppelin... the contracts are inheriting from Ownable... and the owner of the contract is txn.origin, not, your TestStuff.sol contract.
What I did is then created a child class of MyERC20Token that's solely for testing with some additional hooks. In this case, that hook is a way for your TestStuff contract to forcibly transfer ownership. So you need to implement a new function in your TestOnlyMyERC20Token to xfer the ownership to the TestStuff contract, and, call it from TestStuff.
contract TestOnlyMyERC20Token is MyERC20Token {
function forceTransferOwnership(address newOwner) external {
owner = newOwner;
}
}
This is not elegant but, it's the only workaround I could figure out.
Any update on that feature?
@k-misztal This is a key part of a refactor of the artifacts format we have scheduled for this summer, but work on that is just beginning. It will probably be a couple months before Migrations supports this.
+1
As a workaround to (for example) deploy multiple ERC20 tokens, I have created extra OneERC20.sol and TwoERC20.sol files which inherit ERC20, and deploy as individual entities. Not ideal but whatever, it works.
I ended up finding other solutions for my situation but one work-around I tried briefly might suit someone out there. Copies an existing artefact and hacks in network/address meta-data:
const fs = require('fs');
const cor = {
copy: (srcName, dstName, network, address) => {
const srcPath = __dirname + '/../build/contracts/' + srcName + '.json';
const dstPath = __dirname + '/../build/contracts/' + dstName + '.json';
const data = require(srcPath);
data.contractName = dstName;
// Save address when given
if (network && address) {
data.networks = {};
// Copy existing networks
if (fs.existsSync(dstPath)) {
const existing = require(dstPath);
data.networks = existing.networks;
}
data.networks[network.toString()] = {
//events: {},
//links: {},
address: address
//transactionHash: ''
};
}
fs.writeFileSync(dstPath, JSON.stringify(data, null, 2), { flag: 'w' });
}
};
module.exports = cor;
Thanks @mryellow this did the trick for me. I imagine this could be included in truffle to accompany the syntax @tcoulter mentioned?
This is part of a task on our roadmap. For more information, please see requirements listed the artifact-updates doc
One issue with the above hacky code is that it requires that a build already exists, so running in tests it gets those paths wrong and will fail unless a build directory full of artefacts has previously been created.
Copying proposal from duplicate issue:
deployer.deploy(A, {as: 'GoldToken'}); // => GoldToken.json
GoldToken = deployer.resolve(A, {from: 'GoldToken'})
deployer.deploy(B, GoldToken);
You can do like this:
module.exports = async function(deployer) {
const token1 = await deployer.deploy(MyToken);
const token2 = deployer.deploy(MyToken);
};
After migration, you'll have 2 addresses of your contracts, say 0x1 and 0x2
Then, on truffle console:
token1 = await MyToken.at(`0x1`)
token2 = await MyToken.at(`0x2`)
Any update now?
Is this resolved?
@captainheart Can you let me know more specifically which part you are referring to? You should be able to implement @CQBinh's solution above.
@eggplantzzz contractInstance.new() was just fine for my needs. No problem.
Is there anything else actionable here or can we close this issue?
Closing this for issue maintenance.
Most helpful comment
Proposal:
Triaging and looking for a good technical solution.