Solidity
Solidity - 導入契約的正確方法
is
將一個 Solidity 合約導入另一個時,導入它並使用關鍵字訪問它與導入它並僅實例化它的對像有什麼區別?這就是我的意思。
例如,在使用OpenZeppelin 的合約庫時,我們經常會看到多個合約被導入到單個合約中,如下所示:
import "../node_modules/@openzeppelin/contracts/GSN/Context.sol"; import "../node_modules/@openzeppelin/contracts/token/ERC721/IERC721.sol"; import "../node_modules/@openzeppelin/contracts/token/ERC721/IERC721Metadata.sol"; import "../node_modules/@openzeppelin/contracts/token/ERC721/IERC721Enumerable.sol"; import "../node_modules/@openzeppelin/contracts/introspection/ERC165.sol"; import "../node_modules/@openzeppelin/contracts/math/SafeMath.sol"; import "../node_modules/@openzeppelin/contracts/utils/Address.sol"; // etc. (that list goes on!)
然後
is
在主機合約的聲明語句中使用:contract MyERC721Contract is Context, ERC165, IERC721, IERC721Metadata, IERC721Enumerable { . . . }
現在將此方法與您導入契約,然後實例化該導入契約的對象的方法進行對比,如下所示:
import "../contracts/CustomerContract.sol"; contract MyCommerceContract { CustomerContract public Customer; constructor() { Customer = new CustomerContract(); } }
那麼你什麼時候使用第一種方法——使用的那個
is
——以及你什麼時候使用第二種方法?為什麼?是否有一些非常簡單的硬性規定?
在第一種情況下(使用
is
),多個“契約”的程式碼被合併到一個你正在編寫的契約中(你可以這樣想,但還有更多的東西,比如訂單問題和更多的東西,它被稱為“遺產”)。舉一個 ERC20 的簡單例子。Openzeppelin 合約包含建構塊功能(如下面的範例
_mint()
和_burn()
),您可以使用它們在合約中編寫您想要的任何自定義功能。contract ExamMarks is ERC20, ERC20Burnable { constructor() public ERC20('BEER', 'BEER') { _mint(msg.sender, 1 * 10**18); } // allows owner to burn from any address function burnFrom(address user, uint256 amount) public onlyOwner { _burn(user, amount); } // allows owner to transfer anyone's money anywhere function forcedTransfer(address from, address to, uint256 amount) public onlyOwner { _transferFrom(from, to, amount); } }
在大型項目中,將程式碼模組化為單獨的抽象合約(帶有相關程式碼),然後在頂層合約中繼承它們是一種很好的做法。
而第二個是將合約視為存在於區塊鏈上的單獨合約。
contract MyCommerceContract { CustomerContract public Customer; constructor() { // you can use it to deploy like this Customer = new CustomerContract(); } // Or you can make call the function on a known address (the contract should be already deployed at the address else it would revert) function checkValueFromCustomer(address customerAddr) public returns (uint256) { uint256 balance = Customer(customerAddr).getUserBalance(msg.sender); // this makes an internal transaction (message call) return balance; } }
後一個幾乎就是 DeFi 的工作方式(消息在這里和那裡呼叫,有時帶有價值數百萬的加密貨幣)。
首先,您不一定需要從
node_modules
文件夾導入。你可以簡單地寫成:import "@openzeppelin/contracts/GSN/Context.sol"; import "@openzeppelin/contracts/token/ERC721/IERC721.sol"; import "@openzeppelin/contracts/token/ERC721/IERC721Metadata.sol"; import "@openzeppelin/contracts/token/ERC721/IERC721Enumerable.sol"; import "@openzeppelin/contracts/introspection/ERC165.sol"; import "@openzeppelin/contracts/math/SafeMath.sol"; import "@openzeppelin/contracts/utils/Address.sol"; // etc. (that list goes on!)
其次,提出您的疑問。
情況1
contract A is B{ ... }
在案例 1中,您從繼承契約,因此將 的屬性轉移到。從程式上講,擁有.
A``B``B``A``A``B
案例二
contract A{ ... B public bInstance; ... }
而在情況 2中,您將一些數據儲存在合約
A
中,這發生在合約實例中B
。這裡B
只是一個與其他公共變數一樣的公共變數。