因為學長是 portto 的實習生,加上也在區塊鏈圈子打滾許久,因此我自然而然有了 Blocto 的錢包(?)。Blocto 的錢包是一種合約錢包,藉此來滿足一些設計(例如代替使用者發起交易等等)。部署這樣的一個合約錢包,從交易紀錄可以看到他花費了 0.02 ETH 左右,在撰文當下就是 26.64 美金,這樣的成本對營運者顯然是過高,轉交給消費者也不是很實際,有沒有辦法處理呢?有的,透過 Minimal Proxy Contract 就可以達成。
什麼是 Minimal Proxy ?
對於在網路世界遨遊許久的人,Proxy 應該不會是一個陌生的名詞,簡單來說,Proxy 可以理解成轉送者,它基本上不會篩選或對收到的訊息做處理,只會轉送給預先定義好的對象。
而在 EIP-1167 中,提出了 Minimal Proxy。當使用者呼叫 Proxy 合約時,這個合約將把呼叫轉送到另一個合約,稱之為 Implementation Contract(Proxy 合約則稱作 Redirecting Contract)。
因此若是需要建立多個相同功能,但地址、狀態需要獨立的合約,那 Minimal Proxy 或許就可以派上用場。例如前文提到的 Blocto 合約錢包,必須要讓每個使用者都有獨立的地址,也需要獨立儲存各種狀態。
由於 Redirecting Contract 本身沒有功能,因此在建立合約時就可以降低合約所需的儲存空間大小,藉此省下手續費。但在未來每次呼叫也都會額外經過一層合約,因此也會提高後面交易的手續費。這個手續費主要取決於函數參數的大小。
Minimal Proxy 的好壞
如前文所說,Minimal Proxy 可以降低相同合約部署的費用,但也會提高未來呼叫時的手續費。因此在選用 Minimal Proxy 時,應考慮未來的使用狀況,例如若每個函數都有大量的參數,並且可以預期會經常呼叫,那就需要斟酌是否直接部署完整合約較為合適。
使用 Minimal Proxy 的方法
在使用 Minimal Proxy 時,需要針對原始的合約做調整,最重要的部分是不能在函數外或在 constructor 指派需要隔離的變數值。例如這個合約:
contract People {
string public name = "Default";
function setName (string memory name_) public {
name = name_;
}
}
以及
contract People {
string public name;
constructor (string memory name_) {
name = name_;
}
}
中,複製出來的合約將會共用 name 變數,這是由於在函數外部或在 constructor 指派的變數(概念上)和合約程式碼放在一起,無論誰呼叫都將使用相同的儲存位置。而在函數內指派的就不會與合約程式碼放一起,因此可以達到隔離。
接著,我們開始部署 CloneFactory,提案者已經提供一份程式碼可利用了,只需要導入使用即可。
contract CloneFactory {
// 略過
}
contract PeopleFactory is CloneFactory {
address public template;
constructor (address template_) {
template = template_;
}
function create (string memory name) public returns (People result) {
result = People(createClone(template));
result.setName(name);
}
}
contract People {
string public name;
function setName(string memory name_) public {
name = name_;
}
}