# Smart Contrct Develop: https://remix.ethereum.org/ 4/29 智能合約介紹 智能合約不只用在轉帳上面,還可以用在不同的客制化上。 智能合約是可以跑的程式碼,減少對中介者的需求 智能合約具有以下屬性: address Ether balance state and methods 智能合約的程式類似物件導向中的 class and object relationship # Solidity Language 程式語言介紹 這次所使用的語言是Solidity ## Contract Structure 1. **Pragma** define the Solidity version (E.G: pragma solidity ^0.8.0;) 2. **Import** Use another contract component or funtion, which likes javaScript's require or Python's import If you want to use another contract instance define, you need to define the contract address (E.G: import "./IERC20.sol";) 3. **Contract/Interface/Library** Language look likes javaScript It is like class, not void main() ## Data Type * **Value type**: uint/int, string, bool, address Address: can be 外部擁有地址(EOA) or 合約地址 Contract Address * **Reference** type(self:which is control the memory): struct, array, mapping Array: save with same type array Struct: hybird data type Enum: Not always use Mapping: Key-value ## Operators normal: -+*/% ## Control Structures if-else, for, while ## Function And Returms function name() public view returns (string memory) { return _name; } view => const, I can not change it returns (string memory) //Which instance return ## Rejecting Functions Assert => 不推薦使用 Require => 某特定條件會拒絕交易,在區塊鍵上拒絕,而if-else是logic reject(self:意味區塊鍵會接受) Revert ## Events 唯一可以與外界溝通的資料結構,跟全世界說今天我要轉帳出去,全世界都知道這事件發生 如何要跟交易所要資料,都要通過Event來做‧ ## Global Variable 每一筆交易都會有一個發起人 msg是載明交易的一些資訊 * msg.sender: sender address * msg.balance: sender LTE amount * msg.value: this transfer amount * msg.data: this transfer data ## Code ``` contract Your_Contract_Name{ uint _totalSupply; 0以上的一個數字 token的發行 uint _decimal; 小數點 is like 100 * 10^-6 string _name = "Input_Name"; token name string _symbol = "Symbol_Name"; 這是一個代號 token symbol address owner = owner_address(你的錢包address) struct TransferLog { address _sender; address _receiver; uint _amount; //Transcation amount uint _time; _balance[msg.sender] = totalSupply_;//建立這合約的人先充值進去 } /*The log which people I transfered before*/ Transferlog[] transferlog; /*Balance is save the token amount*/ mapping (address => uint) _balances; 這一個Mapping 是說每一個address對上一個uint /* 定義Transfer事件*/ event Transfer(address indexed _sender, address indexed _receiver, uint _amount); /*constructor for your smart contract*/ constructor (string memory name_, string memory symbol_, uint totalSupply_, uint decimal_) public{ _name = name_; _symbol = symbol_; _totalSupply = totalSupply_; _decimal = decimal_ } function name() public view returns (string memory) { return _name; } function symbol() public view returns (string memory) { return _symbol; } function balanceOf(address addr) public view returns (uint) { return _balance[addr]; } /* 轉帳 */ /** 從A轉到B * A的餘額要足夠 * 轉帳記錄要丟進去transferLog裡面 * 發送Transfer事件 */ function transfer(address _receiver, uint _amount) public { address _sender = msg.sender; /* cretical section */ require (_balance[_sender] >= _amount, "Insufficient Amount of sender"); //Check sender wallet whether Enough _balance[_sender] = _balance[_sender] - _amount; _balance[_receiver] = _balance[_receiver] + _amount; /* Transfer事件發送 */ emit Transfer(_sender, _receiver, _amount); /* TransferLog */ TransferLog memory log = TransferLog({ _sender: _sender, _receiver: _receiver, _amount: _amount, _time: block.timestamp }); transferLog.push(log); // Record this transfer } } ``` 開發概念解析 Provider: 可以想成是一個node,他可以幫你與區塊鏈進行溝通 5/03 Truffle: It is develop Environmet, which is use for testing ETH framework and deploy Ganache: 用於開發的人個人區塊鏈,可以用作測試,部署你的contract 會提供Virtual User # Contract Test in Remix **Step 1** Compile your contract: ![](https://i.imgur.com/bJOVTGm.png) **Step 2** Input the deploy information under the JavaScript Environment: ![](https://i.imgur.com/Z7Idxtj.png) **Step 3** If transaction is sucessfully, you can see the detial information of transaction. ![](https://i.imgur.com/oVPFArM.png) ##Use Truffle & Ganache run your contract Step for install: Download: Git and Node.js ``` npm install -g ganache-cli ganache-cli ``` ![](https://i.imgur.com/qdj3Cjo.png) ganache-cli 畫面 它會列出10 ELH錢包給你用作測試用 我們之後會選取第(0) 0xeFCeC35C6FDBDC1987296669377b6d16E79f16D2 (100 ETH)為owner 之後在YZTT.sol 檔案設定 address owner = 0xeFCeC35C6FDBDC1987296669377b6d16E79f16D2; ![](https://i.imgur.com/CEdOWpG.png) 安裝trufflesuite ``` npm install -g truffle truffle --version //用作檢查是否安裝成功 ``` 安裝成功會顯示: ![](https://i.imgur.com/scGA8VO.png) * 測試contract * 編譯所寫的合約 ``` truffle compile ``` 之後部署合約 ``` truffle migrate (--reset) ``` 結果如下: ![](https://i.imgur.com/542Gsa7.png) ## Truffle test ### migrations File 在migrationso內建立161892708_yzt.js ``` const YZT = artifacts.require("YZT") module.exports = function(deployer) { // Use deployer to state migration tasks. deployer.deploy(YZT, "YuenZe Token", "YZT", 6, 10000000000, ) }; ``` ### testFile write 建立一個test/yzt.js file用作測試contract Code: ``` const YZT = artifacts.require("YZTT"); /* * uncomment accounts to access the test accounts made available by the * Ethereum client * See docs: https://www.trufflesuite.com/docs/truffle/testing/writing-tests-in-javascript */ contract("YZTT", function (accounts) { let yztContract; before("Deploy YZT contract", async () => { console.log("deploying YZT contract...") yztContract = await YZT.deployed() //The test data in migrations assert.equal(await yztContract.owner(), accounts[0], "wrong contract owner"); //confirm the accounts is my supply amount assert.equal(await yztContract.name(), "YuenZe Token", "wrong contract name");//Test the name assert.equal(await yztContract.symbol(), "YZTT", "wrong contract symbol");//Test the symbol }) //confirm transfer doesn't have problem it("confirm transfter does not have problem", async () => { //test logic //test A transfer ot B //Whether A correct reduce amount //Whether B correct update amount //A -> accounts[0] //B -> accounts[1] //1. take the contract instance const yztContract = await YZT.deployed(); //2. run the contract, A transfer 1 dollers to B await yztContract.transfer( accounts[1], /* The receiver address*/ 100,//represent 1 dollers, because decimal is 2 { from: accounts[0] /* A send this transition */ } ) //3. Check the balance A and B const aBalance = yztContract.balanceOf(accounts[0]); const bBalance = yztContract.balanceOf(accounts[1]); assert.equal(aBalance, 9900, "A balance is error"); assert.equal(bBalance, 100, "B balance is error"); //4. Finish; return true; }); it("should have correct contract name", async function () { return await yztContract.name(), "YuenZe Token", "wrong contract name"; }); }); ``` 上面的test logic: Check owner, name, symbol 之後看contract跑完之後是否正確 test A transfer ot B Whether A correct reduce amount Whether B correct update amount 當中assert.equal(await yztContract.symbol(), "YZTT", "wrong contract symbol"); 是指yztContract.owner() == accounts[0],如果不等於,就輸出"wrong contract symbol" Error畫面: ![](https://i.imgur.com/WuDZrNm.png) 之後修正錯誤後成功的畫面: ![](https://i.imgur.com/d5gtl2V.png)