I have a smart contract which I might want to modify in future. Should I use self-destruct to destruct that contract and then deploy a new one? Or, should I make that contract upgradable to make changes in future? Which one is most feasible solution in terms of cost and other factors?
The cost is theoretically the same. It's really up to your own preference if you want the old contract to continue existing or not.
One benefit to using an upgrade-able contract is that it can store a reference to the new contract which could make it easier for someone to find the newer contract.
One downside to using an upgrade-able contract is that people may continue trying to use the old contract (which you may or may not have disabled functionality for) and that could be quite frustrating as a user.
This is how the contract updation would work if you used
Deploy a new version of the contract.
Manually migrate all state from the old one contract to the new one (which can be very expensive in terms of gas fees!)
Update all contracts that interacted with the old contract to use the address of the new one
Reach out to all your users and convince them to start using the new deployment (and handle both contracts being used simultaneously, as users are slow to migrate)
selfdestructthe old contract.
But if you use upgradable contracts, you can upgrade your contracts, keeping(preserving) the contract state (storage & balance) while keeping the same contract address.
So, in this sense, I think using
selfdestruct approach WILL COST YOU MUCH MORE than using upgradable contracts.
In case you would like to know how upgradable contracts work, and how you can wtite one easily, you can check out this post on smart contract versioning.
selfdestruct will remove all storage from the state, which isn't ideal if you might ever need it in future.
Upgradeable contracts can be established with a version flag and a pointer to the address of any new contracts after they are deprecated - you could also include a 'pause' function in your contract (with an
onlyOwner modifier to make sure nobody else pauses it) so once it has been deprecated the functions within the original contract no longer work.
We use a contract register on our private chain to keep an eye on the latest version of each contract - when updates are made the original contract is paused, its
latestVersion bool is set to false and
successorAddress is added to their register mapping entry to point towards the correct new version. Our contract register is also upgradeable, for additional resilience :)
There is plenty of in-depth coverage on this topic in this question