標籤:port using 否則 factor 方法 ready balance change 繼承
基於
cryptozombies.ioZombieFactory
pragma solidity ^0.4.19;contract ZombieFactory { // 事件, web3.js 可以監控它 event NewZombie(uint zombieId, string name, uint dna); uint dnaDigits = 16; uint dnaModulus = 10 ** dnaDigits; // 乘方 // 定義結構體 struct Zombie { string name; uint dna; } // 定義數組 Zombie[] public zombies; // 定義 mapping 結構, 可理解為 python 裡面的 dict mapping (uint => address) public zombieToOwner; mapping (address => uint) ownerZombieCount; function _createZombie(string _name, uint _dna) internal { uint id = zombies.push(Zombie(_name, _dna)) - 1; // 擷取剛剛放到數組的元素的 id // msg.sender 為調用者的 地址。 zombieToOwner[id] = msg.sender; ownerZombieCount[msg.sender]++; // 觸發事件 NewZombie(id, _name, _dna); } function _generateRandomDna(string _str) private view returns (uint) { uint rand = uint(keccak256(_str)); return rand % dnaModulus; } function createRandomZombie(string _name) public { // 要求每個賬戶只能有一隻殭屍,否則退出 require(ownerZombieCount[msg.sender] == 0); uint randDna = _generateRandomDna(_name); randDna = randDna - randDna % 100; _createZombie(_name, randDna); }}
學到了
- 函數的定義
- 數組的使用
- mapping 的使用
- require的使用
- 事件的使用
ZombieFeeding
pragma solidity ^0.4.19;import "./zombiefactory.sol";// 定義一個合約介面,通過這種方式可以調用其他合約的公開方法contract KittyInterface { function getKitty(uint256 _id) external view returns ( bool isGestating, bool isReady, uint256 cooldownIndex, uint256 nextActionAt, uint256 siringWithId, uint256 birthTime, uint256 matronId, uint256 sireId, uint256 generation, uint256 genes );}// 繼承contract ZombieFeeding is ZombieFactory { KittyInterface kittyContract; // 使用了函數修飾符,確保只有 合約賬戶本身可以調用該方法 function setKittyContractAddress(address _address) external onlyOwner { // 通過 合約地址執行個體化介面,以後可以通過這個介面調用該合約的方法 kittyContract = KittyInterface(_address); } // 傳輸結構體指標 function _triggerCooldown(Zombie storage _zombie) internal { _zombie.readyTime = uint32(now + cooldownTime); } // 返回 bool 類型 function _isReady(Zombie storage _zombie) internal view returns (bool) { return (_zombie.readyTime <= now); } function feedAndMultiply(uint _zombieId, uint _targetDna, string species) internal { require(msg.sender == zombieToOwner[_zombieId]); Zombie storage myZombie = zombies[_zombieId]; require(_isReady(myZombie)); _targetDna = _targetDna % dnaModulus; uint newDna = (myZombie.dna + _targetDna) / 2; if (keccak256(species) == keccak256("kitty")) { // if 語句的使用 newDna = newDna - newDna % 100 + 99; } _createZombie("NoName", newDna); _triggerCooldown(myZombie); } function feedOnKitty(uint _zombieId, uint _kittyId) public { uint kittyDna; // 調用其他合約的方法 (,,,,,,,,,kittyDna) = kittyContract.getKitty(_kittyId); // 多個傳回值的擷取 feedAndMultiply(_zombieId, kittyDna, "kitty"); }}
學到了
- 調用其他合約的方法
- 結構體傳值
- 接收多個傳回值的方法
- 函數修飾符的使用
ZombieHelper
pragma solidity ^0.4.19;import "./zombiefeeding.sol";contract ZombieHelper is ZombieFeeding { uint levelUpFee = 0.001 ether; // 定義修飾函數,會在被修飾函數調用前調用 modifier aboveLevel(uint _level, uint _zombieId) { // 如果指定殭屍的 level 小於 _level 就會退出,否則繼續執行被修飾的函數 require(zombies[_zombieId].level >= _level); _; } // 用於提出 以太坊裡面的 eth function withdraw() external onlyOwner { owner.transfer(this.balance); } // function setLevelUpFee(uint _fee) external onlyOwner { levelUpFee = _fee; } // payable 修飾符表示,可以往這個方法發送 eth function levelUp(uint _zombieId) external payable { require(msg.value == levelUpFee); // 判斷 eth 的值 zombies[_zombieId].level++; } // 使用了修飾符,當層級大於 2 時才能修改名字 function changeName(uint _zombieId, string _newName) external aboveLevel(2, _zombieId) { require(msg.sender == zombieToOwner[_zombieId]); zombies[_zombieId].name = _newName; } function changeDna(uint _zombieId, uint _newDna) external aboveLevel(20, _zombieId) { require(msg.sender == zombieToOwner[_zombieId]); zombies[_zombieId].dna = _newDna; } // 返回一個列表 function getZombiesByOwner(address _owner) external view returns(uint[]) { // 定義 memory 數組,節省 gas uint[] memory result = new uint[](ownerZombieCount[_owner]); uint counter = 0; for (uint i = 0; i < zombies.length; i++) { if (zombieToOwner[i] == _owner) { result[counter] = i; counter++; } } return result; }}
學到了
- 定義修飾函數,以及往修飾函數傳參
- 接收,提取
eth
- 返回
uint[]
memory 變數, for 迴圈的使用
後面接著又瞭解了 SafeMath 的使用
pragma solidity ^0.4.19;import "./zombieattack.sol";import "./erc721.sol";import "./safemath.sol";contract ZombieOwnership is ZombieAttack, ERC721 { using SafeMath for uint256; mapping (uint => address) zombieApprovals; function balanceOf(address _owner) public view returns (uint256 _balance) { return ownerZombieCount[_owner]; } function ownerOf(uint256 _tokenId) public view returns (address _owner) { return zombieToOwner[_tokenId]; } function _transfer(address _from, address _to, uint256 _tokenId) private { ownerZombieCount[_to] = ownerZombieCount[_to].add(1); ownerZombieCount[msg.sender] = ownerZombieCount[msg.sender].sub(1); zombieToOwner[_tokenId] = _to; Transfer(_from, _to, _tokenId); } function transfer(address _to, uint256 _tokenId) public onlyOwnerOf(_tokenId) { _transfer(msg.sender, _to, _tokenId); } function approve(address _to, uint256 _tokenId) public onlyOwnerOf(_tokenId) { zombieApprovals[_tokenId] = _to; Approval(msg.sender, _to, _tokenId); } function takeOwnership(uint256 _tokenId) public { require(zombieApprovals[_tokenId] == msg.sender); address owner = ownerOf(_tokenId); _transfer(owner, msg.sender, _tokenId); }}
solidity 文法學習