♦️
スマートコントラクトのアップグレード方法
Solidityスマートコントラクトで特定のfunctionの中身に修正が入った場合、いくつかの方法でアップグレードすることができます。
方法
1. インラインアップグレード
- 最もシンプルで、既存のコントラクトを変更せずに新しいfunctionを追加できます。
- ただし、既存のfunctionを変更することはできません。
- バージョン管理が難しく、複雑なアップグレードには適していません。
2. プロキシアップグレード
- 新しいコントラクトをデプロイし、既存のコントラクトへのプロキシとして設定します。
- 既存のfunctionを変更することもできます。
- バージョン管理が容易で、複雑なアップグレードにも適しています。
- いくつかの種類があり、それぞれに利点と欠点があります。
3. ダイヤモンドアップグレード
- プロキシアップグレードの一種で、より高度な機能を提供します。
- 複数のファセットと呼ばれるコントラクトを組み合わせることで、機能を拡張できます。
- 最も柔軟で拡張性の高いアップグレード方法ですが、複雑な実装が必要です。
4. トランスファーアップグレード
- 新しいコントラクトにデータを移行するアップグレード方法です。
- 既存のfunctionを変更することはできません。
- データ移行が必要な場合に適しています。
具体例
1. インラインアップグレード
例:
contract MyContract {
function add(uint256 a, uint256 b) public pure returns (uint256) {
return a + b;
}
// 新しいfunctionを追加
function subtract(uint256 a, uint256 b) public pure returns (uint256) {
return a - b;
}
}
解説:
- 既存のコントラクトを変更せずに、新しいfunction
subtract
を追加しています。 - 既存のfunction
add
は変更されていません。
2. プロキシアップグレード
例:
contract MyContract {
function add(uint256 a, uint256 b) public pure returns (uint256) {
return a + b;
}
}
contract MyProxy {
MyContract public implementation;
constructor(MyContract _implementation) {
implementation = _implementation;
}
function add(uint256 a, uint256 b) public payable returns (uint256) {
return implementation.add(a, b);
}
}
解説:
- 新しいコントラクト
MyProxy
をデプロイし、既存のコントラクトMyContract
へのプロキシとして設定します。 -
MyProxy
のadd
function は、MyContract
のadd
function を呼び出します。 - 将来、
MyContract
を新しいバージョンにアップグレードすることで、MyProxy
の機能を拡張することができます。
3. ダイヤモンドアップグレード
例:
contract MyFacet {
function add(uint256 a, uint256 b) public pure returns (uint256) {
return a + b;
}
}
contract MyDiamond {
// ファセットのアドレスを格納するマッピング
mapping(bytes4 => address) public facets;
constructor() {
// ファセットを追加
facets[bytes4(keccak256("add(uint256,uint256)"))] = address(new MyFacet());
}
// ファセットのfunctionを呼び出す
function add(uint256 a, uint256 b) public payable returns (uint256) {
return MyFacet(facets[bytes4(keccak256("add(uint256,uint256)"))]).add(a, b);
}
}
解説:
- ダイヤモンドアップグレードは、プロキシアップグレードの一種で、より高度な機能を提供します。
- 複数のファセットと呼ばれるコントラクトを組み合わせることで、機能を拡張できます。
- 上記の例では、
MyFacet
というファセットがadd
function を提供しています。 -
MyDiamond
コントラクトは、MyFacet
ファセットのadd
function を呼び出すことができます。 - 将来、新しいファセットを追加することで、
MyDiamond
コントラクトの機能を拡張することができます。
4. トランスファーアップグレード
例:
contract MyOldContract {
uint256 public balance;
function withdraw(uint256 amount) public {
balance -= amount;
msg.sender.transfer(amount);
}
}
contract MyNewContract {
uint256 public balance;
constructor(MyOldContract oldContract) {
// 既存のコントラクトからデータを移行
balance = oldContract.balance();
}
function withdraw(uint256 amount) public {
balance -= amount;
msg.sender.transfer(amount);
}
}
解説:
- トランスファーアップグレードは、新しいコントラクトにデータを移行するアップグレード方法です。
- 上記の例では、
MyNewContract
コントラクトはMyOldContract
コントラクトからbalance
データを移行しています。
選択基準
どの方法を選択するかは、以下の要素を考慮する必要があります。
- アップグレードの複雑性
- データ移行の必要性
- バージョン管理の必要性
- 将来の拡張性
各方法の詳細
各方法の詳細については、以下の情報をご覧ください。
- インラインアップグレード: https://habr.com/ru/sandbox/177574/
- プロキシアップグレード: https://docs.openzeppelin.com/upgrades-plugins/1.x/proxies
- ダイヤモンドアップグレード: https://www.quicknode.com/guides/ethereum-development/smart-contracts/the-diamond-standard-eip-2535-explained-part-1
- トランスファーアップグレード: https://docs.openzeppelin.com/learn/upgrading-smart-contracts
その他
- アップグレードを行う前に、必ずバックアップを取るようにしてください。
- テスト環境でアップグレードを十分にテストしてから、本番環境にデプロイするようにしてください。
- アップグレードに関する詳細は、Solidityの公式ドキュメントを参照してください。
参考情報
注意事項
- 上記の情報は一般的な情報であり、個々の状況によって異なる場合があります。
- アップグレードを行う前に、専門家に相談することをお勧めします。
Discussion