I know that smart contracts are supposed to be immutable and that's the whole point, but to expect someone to implement a logic that never changes (no upgrade or no bugs) from day 1 is also unrealistic.
Therefore, I've been reading about several methods of working around this immutable state. A popular method seems to be using delegateCall with a Relay contract, but I'm struggling with how to actually use this method as I couldn't find any example.
Would someone be kind enough to look at that simple example I created, and tell me what I'm doing incorrectly?
https://gist.github.com/fabdarice/d513d620d9355312d085c7a68e6c6118
Relay.sol
contract Relay {
address public currentVersion;
address public owner;
mapping (address => uint) user_amounts;
modifier onlyOwner() {
if (msg.sender != owner) {
throw;
}
_;
}
function Relay(address initAddr) {
currentVersion = initAddr;
owner = msg.sender; // this owner may be another contract with multisig, not a single contract owner
}
function changeContract(address newVersion) public
onlyOwner()
{
currentVersion = newVersion;
}
function() {
if(!currentVersion.delegatecall(msg.data)) throw;
}
}
Donation.sol :
contract Donation {
mapping (address => uint) user_amounts;
/* DOES THIS METHODS MODIFY user_amounts of the Relay contract ??? */
function sendDonation(uint n) {
user_amounts[msg.sender] = user_amounts[msg.sender] + n
}
}
DonationNew.sol :
contract DonationNew {
mapping (address => uint) user_amounts;
function sendDonation(uint n) {
user_amounts[msg.sender] = user_amounts[msg.sender] + n
}
function cancelDonation() {
user_amounts[msg.sender] = 0
}
}
app.js :
// First, deploying Relay, then deploying Donation and retrieve Donation contract address in 'donation_contract_address'
// Then, linking Relay to my first version of my contract Donation
Relay.deployed().then(function(contractInstance) {
contractInstance.changeContract(donation_contract_address);
})
// Then, I want to call sendDonation from the Donation contract
// !!!!! I DON'T KNOW WHAT IS THE CORRECT WAY TO CALL THIS !!!!!!
Relay.deployed().then(function(contractInstance) {
contractInstance.sendDonation(5) ;
})
// OR
Relay.deployed().then(function(contractInstance) {
contractInstance.currentVersion.delegateCall(sendDonation(5)) ;
})
// Now I want to update the Donation contract to add the cancelDonation function
// First I deploy the new contract DonationNew and retrieve it's address in 'donation_new_contract_address'
Relay.deployed().then(function(contractInstance) {
contractInstance.changeContract(donation_new_contract_address);
})
// are the state variables still available from the old contract to the new one?
// Then if I want to call the new function :
Relay.deployed().then(function(contractInstance) {
contractInstance.cancelDonation() ;
})
P.S.: I know that this method above allow us to create an "upgradable contract" in the case we need to update our logic (functions etc..), however it doesn't allow us to modify/add our state variables structure. Is there a workaround this as well?
Thanks a lot, happy to be part of this community !