Solidity
智能合約設計:託管/控制器合約
我將如何創建以下內容:
託管/控制器合約 A 能夠接受來自合約 B 的 ERC20 代幣和來自 C 方的 ETH,並在滿足某些條件時進行交換。同樣的合約 A 也應該能夠從合約 D 接收 ERC20 代幣,從合約 E 接收 ETH,並在滿足某些條件時進行交換。
問題的關鍵/相關性是,如何設計合約 A 以能夠處理不同類型的 ERC20 代幣輸入,例如 Walton(WTC) 和 FUSION(FSN) ERC20 代幣?
這就是介面的用武之地。太好了,因為 ERC-20 實際上是一個介面!下面我給你舉個例子。如您所見,
TokenSwapper
甚至不需要知道TokenA
andTokenB
,只需它們實現ERC20
介面即可。哦,在開始開發之前,您應該首先熟悉 ERC20 介面的基礎知識。閱讀此維基
pragma solidity ^0.4.23; /* Declaring the ERC20 interface. This tells other contracts how to handle ERC-20 tokens */ interface ERC20 { function allowance(address owner, address spender) external view returns (uint256); function transferFrom(address from, address to, uint256 value) external returns (bool); function approve(address spender, uint256 value) external returns (bool); function totalSupply() external view returns (uint256); function balanceOf(address who) external view returns (uint256); function transfer(address to, uint256 value) external returns (bool); } /* a simple base ERC token contract for testing */ /* DO NOT USE FOR PRODUCTION AS IT IS NOT SAFE */ contract ERC20Token is ERC20 { uint256 totalSupply_; mapping (address => mapping (address => uint256)) internal allowed; mapping(address => uint256) balances; function totalSupply() public view returns (uint256) { return totalSupply_; } function transfer(address _to, uint256 _value) external returns (bool) { require(_to != address(0)); require(_value <= balances[msg.sender]); balances[msg.sender] -= _value; balances[_to] += _value; return true; } function balanceOf(address _owner) public view returns (uint256) { return balances[_owner]; } function transferFrom( address _from, address _to, uint256 _value ) public returns (bool) { require(_to != address(0)); require(_value <= balances[_from]); require(_value <= allowed[_from][msg.sender]); balances[_from] -= _value; balances[_to] += _value; allowed[_from][msg.sender] -= _value; return true; } function approve(address _spender, uint256 _value) public returns (bool) { allowed[msg.sender][_spender] = _value; return true; } function allowance( address _owner, address _spender ) public view returns (uint256) { return allowed[_owner][_spender]; } } /* The tokens inherit their functionality from ERC20Token */ contract TokenA is ERC20Token { } contract TokenB is ERC20Token { } contract TokenC is ERC20Token { } contract TokenD is ERC20Token { } /* DO NOT USE IN PRODUCTION AS IT DOESN'T CHECK FOR UNDERFLOW/OVERFLOW */ contract TokenSwapper { // Keeps track of the tokens users have mapping(address => mapping(address => uint256)) tokenBalances_; function tokenBalances(address _owner, ERC20 _token) public view returns (uint256 balance) { return balance = tokenBalances_[_owner][_token]; } function deposit(ERC20 _token, uint256 _amount) public { _token.transferFrom(msg.sender, address(this), _amount); tokenBalances_[msg.sender][_token] += _amount; } function swap(ERC20 _fromToken, ERC20 _toToken, uint256 _amount) public { tokenBalances_[msg.sender][_fromToken] -= _amount; tokenBalances_[msg.sender][_toToken] += _amount; } function withdraw(ERC20 _token, uint256 _amount) public { require(tokenBalances_[msg.sender][_token] >= _amount); _token.transfer(msg.sender, _amount); } }