在上一篇文章中(傳送門:區塊鏈研究實驗室 | 手把手教你使用Solidity開發智慧合約(五)),我們瞭解瞭如何使用函式,並應用了到目前為止所學到的一切來構建一個多功能簽名錢包。
在本文中,我們將看到如何從另一個合同中建立一個合同,以及如何定義抽象合同和介面。
合同建立
可以透過以太坊交易或在Solidity合約中使用new關鍵字建立合約,該關鍵字將部署該合約的新例項並返回其地址。
透過檢查Solidity文件中給出的示例,讓我們仔細看一下它是如何工作的。我建立了name變數,public以便我們可以檢查其值並建立一個事件以讀取該createToken函式的返回值(我們將在事件的另一篇文章中介紹):
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.22 <0.8.0;
contract OwnedToken {
TokenCreator creator;
address owner;
bytes32 public name;
constructor(bytes32 _name) {
owner = msg.sender;
creator = TokenCreator(msg.sender);
name = _name;
}
functionchangeName(bytes32 newName) public{
if (msg.sender == address(creator))
name = newName;
}
functiontransfer(address newOwner) public{
if (msg.sender != owner) return;
if (creator.isTokenTransferOK(owner, newOwner))
owner = newOwner;
}
}
contract TokenCreator {
event TokenCreated(bytes32 name, address tokenAddress);
functioncreateToken(bytes32 name)
public
returns (OwnedToken tokenAddress)
{
tokenAddress = new OwnedToken(name);
emit TokenCreated(name, address(tokenAddress));
}
functionchangeName(OwnedToken tokenAddress, bytes32 name) public{
tokenAddress.changeName(name);
}
functionisTokenTransferOK(address currentOwner, address newOwner)
public
pure
returns (bool ok)
{
return keccak256(abi.encodePacked(currentOwner, newOwner))[0] == 0x7f;
}
}
這次,我將使用Tuffle框架——您可以按照他們製作的快速入門指南對其進行學習。
首先,我們將建立一個新專案並透過執行以下命令對其進行初始化:
> mkdir token
>cd token
> truffle init
開啟專案,然後更新truffle-config.js檔案以使用您將在其中部署合同的網路IP和埠以及您正在使用的Solidity編譯器的版本。就我而言,我正在使用Ganache執行網路。
現在,我們可以在contracts資料夾中建立合同。複製並貼上程式碼後,您需要在migrations資料夾中建立一個遷移檔案以部署TokenCreator合同。將其命名為2_deploy_token.js,然後複製並貼上以下程式碼。
const TokenCreator = artifacts.require("TokenCreator");
module.exports = function (deployer) {
deployer.deploy(TokenCreator);
};
現在返回命令列,然後鍵入truffle console以啟動Truffle控制檯-您可以在其中編譯和部署合同:
我們現在要做的是檢索TokenCreator已部署例項的例項。然後,我們將呼叫該createToken函式兩次,並儲存每個新建立合約的地址。
如果使用的是Ganache,則可以看到兩個代表合同呼叫的交易新增到了交易列表中,其中資料欄位設定為函式選擇器的四個位元組,並傳遞了引數。如果您想知道真正發生了什麼以及如何建立這些合同,請繼續關注我。
正如我們所知,合同只是另一種型別的帳戶,那麼到底發生了什麼,當我們所謂的createToken功能狀態資料庫進行了更新,包括與四個變數,每個帳戶儲存(新建立的帳戶nonce,balance,storage_root,code_hash)正確初始化。
如果現在返回到Truffle控制檯,則可以檢查每個事務的日誌以獲取每個合同的地址,然後可以呼叫名稱getter來驗證它們確實是兩個單獨的實體。
建設者宣言
合同的建構函式在建立合同時被呼叫,並且不會與其餘的合同程式碼一起儲存在區塊鏈上。
建構函式是可選的。只允許一個建構函式,這意味著不支援過載。
使用constructor關鍵字宣告建構函式:
contractA {
uinta;
boolb;
constructor(uint_a, bool _b){
a = _a;
b = _b;
}
...
}
抽象合約
需要將合同標記為abstract未執行其至少一項功能時。abstract即使實現了所有功能,合同也可能被標記為。
這可以使用abstract合同的關鍵字來完成,未實現的功能應具有virtual允許多型的關鍵字。
abstract contract A {
function f() public pure virtual;
}
即使所有功能都已實現,抽象協定也無法直接例項化。它們可以用作定義其他合同繼承的特定行為的基本合同。已實現的功能應具有override關鍵字。
abstract contract A {
function f() public pure virtual;
}
abstract contract B is A {
function f() public pure override {
//function body
}
}
如果派生合同未實現所有未實現的功能,則也需要對其進行標記abstract。
介面
介面類似於抽象協定,但是不能實現任何功能。還有其他限制:
它們不能從其他合同繼承,但是可以從其他介面繼承
所有宣告的函式必須是外部的
他們不能宣告建構函式
他們不能宣告狀態變數
介面使用interface關鍵字宣告。
interfaceA{
functionf()externalpure;
}
介面中宣告的所有函式都是隱式的virtual。
結論
至此,我們對智慧合約的建立與繼承講完了。下次,我們將研究工廠模式以及如何在Solidity中使用它們。
作者:鏈三豐,來源:區塊鏈研究實驗室