# 區塊鏈 16,23,30-Sep-2022,
###### tags: `blockchain`
### jamboard
## https://jamboard.google.com/d/1s5ImoKlKkBXVWlap3UAz3SANHHAIth0VQbnU6QQc2rU/edit?usp=sharing
## 下載ganache的戰機
### https://trufflesuite.com/ganache/
### `10:30-10:40` break
## https://chrome.google.com/webstore/detail/metamask/nkbihfbeogaeaoehlefnkodbefgpgknn
## https://metamask.io/
## https://github.com/ipfs/ipfs
## https://blockcast.it/2022/03/21/what-to-expect-after-the-ethereum-merge/
## 0x ba c5 2F 94 C4 67 85 07 88 4F 26 50 c9 10 43 e0 f3 3F 42 42
## https://github.com/ethereum/solidity
## http://remix.ethereum.org/

# 4_Demo1.sol
```solidity=
// SPDX-License-Identifier: GPL-3.0
pragma solidity = 0.6.8;
contract Demo1 {
}
```

# Demo1.sol
```solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.7.4;
contract Demo1 {
string public message;
constructor(string memory initMessage) {
message = initMessage;
}
function setMessage(string memory newMessage) public {
message = newMessage;
}
function getMessage() public view returns(string memory) {
return message;
}
}
```

# break 3:40-3:50
# https://iancoleman.io/bip39/#english
# Demo2
```solidity=
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.7.4;
contract Demo2 {
function getrResult(uint a, uint b) public pure returns (string memory){
return integerToString(a+b);
}
function integerToString(uint i) internal pure returns(string memory){
if (i==0){
return "0";
}
// 算出有幾位數
uint j=i;
uint len;
while (j!=0){
len++;
j/=10;
}
bytes memory bstr = new bytes(len);
uint k = len-1;
while(i != 0){
bstr[k--]=bytes1(uint8(48+(i%10)));
i /= 10;
}
return string(bstr);
}
}
```

# Demo3
```solidity=
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.7.4;
contract Demo3 {
function arrayDemo1() public pure returns (uint256){
uint len= 7;
uint[] memory a = new uint[](len);
return a.length;
}
}
```
# download node.JS if not
## https://nodejs.org/en/
# download visual studio code if not
## https://code.visualstudio.com/
## 16.16, 16.17 or 18.X 都可以
## 打開http://remix.ethereum.org/
# 6_demo3.sol
```solidity!
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.7.4;
contract Demo3 {
function arrayDemo1() public pure returns (uint256){
uint len= 7;
uint[] memory a = new uint[](len);
return a.length;
}
function arrayDemo2(uint length) public pure returns(uint256) {
uint[] memory a = new uint[](length);
return a.length;
}
function arrayDemo3() public pure returns(uint256) {
uint[7] memory a;
return a.length;
}
function arrayDemo4(uint index) public pure returns(uint256) {
uint[] memory a = new uint[](7);
a[6]=7;
a[5]=6;
a[4]=5;
a[3]=4;
a[2]=3;
a[1]=2;
a[0]=1;
return a[index];
}
function arrayDemo5(uint index) public pure returns(uint256) {
uint[7] memory a;
a[6]=7;
a[5]=6;
a[4]=5;
a[3]=4;
a[2]=3;
a[1]=2;
a[0]=1;
return a[index];
}
function arrayDemo6() public pure returns(uint[7] memory) {
uint[7] memory a;
a[6]=7;
a[5]=6;
a[4]=5;
a[3]=4;
a[2]=3;
a[1]=2;
a[0]=1;
return a;
}
function arrayDemo7() public pure returns(uint[] memory) {
uint[] memory a = new uint[](7);
a[6]=7;
a[5]=6;
a[4]=5;
a[3]=4;
a[2]=3;
a[1]=2;
a[0]=1;
return a;
}
}
```

# 7_Demo4.sol
```solidity!
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.7.4;
contract Demo4 {
uint256[] members1 = new uint256[](5);
function arrayTest1() public {
members1[0]=2;
members1[1]=4;
members1[2]=6;
members1[3]=8;
members1[4]=10;
}
function arrayTest2() public view returns(uint256[] memory){
return members1;
}
function arrayTest3(uint d) public {
members1.push(d);
}
}
```
# 8_Demo5.sol
```solidity!
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.7.4;
contract Demo5 {
enum StarbuckSize {SHORT, TALL, GRANDE, VENTI, TRENTA}
StarbuckSize size;
StarbuckSize constant defaultSize=StarbuckSize.TALL;
StarbuckSize size2 = StarbuckSize.GRANDE;
function getSize1() public view returns (StarbuckSize) {
return size;
}
function getSize2() public pure returns (StarbuckSize) {
return defaultSize;
}
function getSize3() public view returns (StarbuckSize) {
return size2;
}
function setSize1(StarbuckSize s)public {
size = s;
}
// function setSize2(StarbuckSize s) public {
// defaultSize = s;
// }
function getSize4() public view returns (uint8){
return uint8(size);
}
}
```

# 9_Demo6.sol
```solidity!
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.7.4;
contract Demo7 {
mapping(address=>uint)public balances;
function updateBalance(uint newBalance) public {
balances[msg.sender] = newBalance;
}
function getBalance() public view returns (uint) {
return balances[address(this)];
}
function setContractBalance(uint v) public {
balances[address(this)]=v;
}
}
```



# 11_demo8.sol
```solidity=
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.7.4;
contract Demo8{
function getMultiReturn() public pure returns(uint256 product, uint256 sum) {
uint a=3;
uint b=5;
return (a*b, a+b);
}
function getMultiReturn2() public pure returns(uint256 product, uint256 sum){
uint a=3;
uint b=5;
product = a*b;
sum = a+b;
}
}
```
# 12_demo9.sol
```solidity!
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.7.4;
contract Demo9 {
address owner;
constructor() {
owner = msg.sender;
}
modifier onlyOwner {
require(msg.sender==owner);
_;
}
modifier costs(uint256 price) {
if (msg.value >= price) {
_;
}
}
}
contract Register is Demo9 {
mapping(address => bool) public registeredAddress;
uint public price;
constructor(uint initPrice) {
price = initPrice;
}
function register() public payable costs(price) {
registeredAddress[msg.sender] = true;
}
function changePrice(uint256 _price) public onlyOwner {
price = _price;
}
}
```






# 13_Demo10.sol
```solidity=
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.7.4;
pragma experimental ABIEncoderV2;
contract Demo10 {
string[] public myArray;
constructor() {
myArray.push("Hi");
myArray.push("Hello world");
}
function getArray() public view returns (string[] memory) {
return myArray;
}
}
```
# truffle install
# https://github.com/git-for-windows/git/releases/download/v2.37.3.windows.1/Git-2.37.3-64-bit.exe
```
npm uninstall -g truffle
npm uninstall -g ganache-cli
npm install -g truffle
npm install -g npm@8.19.2
npm list -g
npm install -g ganache-cli
truffle --version
ganache-cli --version
```
# 參考的結果是
```
C:\Users\user>truffle --version
Truffle v5.5.31 (core: 5.5.31)
Ganache v7.4.3
Solidity v0.5.16 (solc-js)
Node v16.16.0
Web3.js v1.7.4
C:\Users\user>ganache-cli --version
Ganache CLI v6.12.2 (ganache-core: 2.13.2)
```
```
code .
```
ctrl+k,o
# https://github.com/github/gitignore/blob/main/Node.gitignore
# Extensions
* Name: Git Graph
Id: mhutchie.git-graph
Description: View a Git Graph of your repository, and perform Git actions from the graph.
Version: 1.30.0
Publisher: mhutchie
VS Marketplace Link: https://marketplace.visualstudio.com/items?itemName=mhutchie.git-graph
* Name: solidity
Id: JuanBlanco.solidity
Description: Ethereum Solidity Language for Visual Studio Code
Version: 0.0.140
Publisher: Juan Blanco
VS Marketplace Link: https://marketplace.visualstudio.com/items?itemName=JuanBlanco.solidity

```
npm init -y
truffle init -y
```
# template的樣本
```
Try our scaffold commands to get started:
$ truffle create contract YourContractName # scaffold a contract
$ truffle create test YourTestName # scaffold a test
http://trufflesuite.com/docs
```
# https://trufflesuite.com/ganache/
```javascript!
compilers: {
solc: {
version: "0.5.16", // Fetch exact version from solc-bin (default: truffle's version)
// docker: true, // Use "0.5.1" you've installed locally with docker (default: false)
settings: { // See the solidity docs for advice about optimization and evmVersion
optimizer: {
enabled: false,
runs: 200
},
// evmVersion: "byzantium"
}
}
},
```
# 完整的
```javascript=
/**
* Use this file to configure your truffle project. It's seeded with some
* common settings for different networks and features like migrations,
* compilation, and testing. Uncomment the ones you need or modify
* them to suit your project as necessary.
*
* More information about configuration can be found at:
*
* https://trufflesuite.com/docs/truffle/reference/configuration
*
* Hands-off deployment with Infura
* --------------------------------
*
* Do you have a complex application that requires lots of transactions to deploy?
* Use this approach to make deployment a breeze 🏖️:
*
* Infura deployment needs a wallet provider (like @truffle/hdwallet-provider)
* to sign transactions before they're sent to a remote public node.
* Infura accounts are available for free at 🔍: https://infura.io/register
*
* You'll need a mnemonic - the twelve word phrase the wallet uses to generate
* public/private key pairs. You can store your secrets 🤐 in a .env file.
* In your project root, run `$ npm install dotenv`.
* Create .env (which should be .gitignored) and declare your MNEMONIC
* and Infura PROJECT_ID variables inside.
* For example, your .env file will have the following structure:
*
* MNEMONIC = <Your 12 phrase mnemonic>
* PROJECT_ID = <Your Infura project id>
*
* Deployment with Truffle Dashboard (Recommended for best security practice)
* --------------------------------------------------------------------------
*
* Are you concerned about security and minimizing rekt status 🤔?
* Use this method for best security:
*
* Truffle Dashboard lets you review transactions in detail, and leverages
* MetaMask for signing, so there's no need to copy-paste your mnemonic.
* More details can be found at 🔎:
*
* https://trufflesuite.com/docs/truffle/getting-started/using-the-truffle-dashboard/
*/
// require('dotenv').config();
// const { MNEMONIC, PROJECT_ID } = process.env;
// const HDWalletProvider = require('@truffle/hdwallet-provider');
module.exports = {
/**
* Networks define how you connect to your ethereum client and let you set the
* defaults web3 uses to send transactions. If you don't specify one truffle
* will spin up a managed Ganache instance for you on port 9545 when you
* run `develop` or `test`. You can ask a truffle command to use a specific
* network from the command line, e.g
*
* $ truffle test --network <network-name>
*/
networks: {
// Useful for testing. The `development` name is special - truffle uses it by default
// if it's defined here and no other network is specified at the command line.
// You should run a client (like ganache, geth, or parity) in a separate terminal
// tab if you use this network and you must also set the `host`, `port` and `network_id`
// options below to some value.
//
development: {
host: "127.0.0.1", // Localhost (default: none)
port: 7545, // Standard Ethereum port (default: none)
network_id: "*", // Any network (default: none)
},
//
// An additional network, but with some advanced options…
// advanced: {
// port: 8777, // Custom port
// network_id: 1342, // Custom network
// gas: 8500000, // Gas sent with each transaction (default: ~6700000)
// gasPrice: 20000000000, // 20 gwei (in wei) (default: 100 gwei)
// from: <address>, // Account to send transactions from (default: accounts[0])
// websocket: true // Enable EventEmitter interface for web3 (default: false)
// },
//
// Useful for deploying to a public network.
// Note: It's important to wrap the provider as a function to ensure truffle uses a new provider every time.
// goerli: {
// provider: () => new HDWalletProvider(MNEMONIC, `https://goerli.infura.io/v3/${PROJECT_ID}`),
// network_id: 5, // Goerli's id
// confirmations: 2, // # of confirmations to wait between deployments. (default: 0)
// timeoutBlocks: 200, // # of blocks before a deployment times out (minimum/default: 50)
// skipDryRun: true // Skip dry run before migrations? (default: false for public nets )
// },
//
// Useful for private networks
// private: {
// provider: () => new HDWalletProvider(MNEMONIC, `https://network.io`),
// network_id: 2111, // This network is yours, in the cloud.
// production: true // Treats this network as if it was a public net. (default: false)
// }
},
// Set default mocha options here, use special reporters, etc.
mocha: {
// timeout: 100000
},
// Configure your compilers
compilers: {
solc: {
version: "0.5.16", // Fetch exact version from solc-bin (default: truffle's version)
// docker: true, // Use "0.5.1" you've installed locally with docker (default: false)
settings: { // See the solidity docs for advice about optimization and evmVersion
optimizer: {
enabled: false,
runs: 200
},
// evmVersion: "byzantium"
}
}
},
// Truffle DB is currently disabled by default; to enable it, change enabled:
// false to enabled: true. The default storage location can also be
// overridden by specifying the adapter settings, as shown in the commented code below.
//
// NOTE: It is not possible to migrate your contracts to truffle DB and you should
// make a backup of your artifacts to a safe location before enabling this feature.
//
// After you backed up your artifacts you can utilize db by running migrate as follows:
// $ truffle migrate --reset --compile-all
//
// db: {
// enabled: false,
// host: "127.0.0.1",
// adapter: {
// name: "sqlite",
// settings: {
// directory: ".db"
// }
// }
// }
};
```
# lab1.sol
```solidity=
pragma solidity ^0.5.16;
contract GMR {
address public manager;
constructor() public {
manager = msg.sender;
}
}
```
# build with command line
```
truffle compile
```


```
truffle create migration GMR
```
# 1_g_m_r.js
```javascript=
const GMR = artifacts.require("GMR")
module.exports = function (_deployer) {
_deployer.deploy(GMR);
};
```
# 部署
```
truffle deploy
```
# 檢視solcjs
# 進入到contracts的目錄
```
solcjs --version
solcjs --abi lab1.sol
```
# mkdir lab2_solidity_test
```
copy lab1_solidity_intro\.gitignore lab2_solidity_test
```
# 打開vs code後
```
npm init -y
truffle init -y
```
# Call.sol
```solidity
pragma solidity ^0.5.16;
contract Chat {
string public message;
constructor (string memory initMessage) public {
message = initMessage;
}
function setMessage(string memory newMessage) public {
message = newMessage;
}
function getMessage() public view returns (string memory) {
return message;
}
}
```
# 2_call.js
```javascript=
const Chat = artifacts.require("Chat");
module.exports = function (_deployer) {
_deployer.deploy(Chat, "Hi, I am truffle")
};
```
# npm install mocha
# .\Room.js
```javascript=
class Room {
constructor() {
console.log("**創建了一個Room**")
}
open() {
return "door open, welcome"
}
close() {
return "door close,bye bye"
}
}
module.exports = Room
```
# .\test\Room.test.js
https://mochajs.org/
```javascript
const Room = require("../Room")
const assert = require("assert")
it("this is my first test", () => {
console.log("要執行第一個測試~!")
})
it("this is my second test", () => {
console.log("這是我的第二個測試")
})
```
# node_modules\.bin\mocha test
```javascript=
"scripts": {
"test": "mocha"
},
```
# npm run test
# alt+shift+F 排列程式碼
# BC.test.js
```javascript
it("寫在其它的檔的測試", () => {
console.log("test something else...")
})
```
# Room.test.js
```javascript
const Room = require("../Room")
const assert = require("assert")
before("準備工作", () => {
console.log("準備資料")
})
beforeEach("派送資料", () => {
console.log("[p]指派該份資料到測試")
})
afterEach("收集資料", () => {
console.log("[c]收集資料並且清理環境")
})
after("最後收尾", () => {
console.log("最後收尾")
})
it("this is my first test", () => {
console.log("要執行第一個測試~!")
})
it("this is my second test", () => {
console.log("這是我的第二個測試")
})
describe("測試Room的這個類別", () => {
let r1;
before("prepare r1",()=>{
r1 = new Room();
})
it("test1, 測試門會開", () => {
assert.strictEqual(r1.open(), "door open, welcome")
})
it("test2, 測試門會關", () => {
assert.strictEqual(r1.close(), "door close,bye bye")
})
})
```
# day2的程式碼請見:
## https://drive.google.com/file/d/1VwJMoBEAs91iqLl9OkZILDBLYvHbHQ_7/view?usp=sharing
# day3
```
cd lab2_solidity_test
```
## npm run test
## node_modules\.bin\mocha test
## 執行某一個特定的檔案
### `npm run test -- test\BC.test.js`
# `my.test.web3.js`
```javascript=
describe("test web3 alone", () => {
it("get web3 environment", () => {
})
})
```
## npm install 連至區塊鏈需要的內容
```
npm install web3
npm install ganache-cli
```
## 修改my.test.web3.js
```javascript
const assert = require("assert")
const ganache = require("ganache-cli")
const Web3 = require("web3")
const web3 = new Web3(ganache.provider())
beforeEach(() => {
//console.log("web3=", web3)
web3.eth.getAccounts().then((accounts)=>{
console.log("帳號這時候才來")
console.log(accounts)
})
//console.log("result=", result)
})
describe("test web3 alone", () => {
it("get web3 environment", () => {
console.log("執行測試")
})
})
```
## npm run test -- test\my.web3.test.js
# my2.web3.test.js
```javascript
const assert = require("assert")
const ganache = require("ganache-cli")
const Web3 = require("web3")
const web3 = new Web3(ganache.provider())
let accounts;
beforeEach(async () => {
accounts = await web3.eth.getAccounts();
})
describe("test web3 alone", () => {
it("get web3 environment", () => {
console.log("執行測試")
console.log("取得第一個帳號", accounts[0])
})
})
```
## npm run test -- test\my2.web3.test.js
### npm install chai chai-as-promised
## contract.test.js
```javascript=
const { default: Web3 } = require("web3")
contract("測試合約", accounts => {
it("1.取得帳戶", () => {
console.log("第一個帳戶是:", accounts[0])
})
it("2.取得餘額", async () => {
// 直接送一個web3
const balance = await web3.eth.getBalance(accounts[0]);
console.log("餘額是:", balance)
})
})
```
## truffle test -- .\test\contract.test.js
## !!
## 修改Call.sol ==> Chat.sol
```javascript=
const Chat = artifacts.require("../contracts/Chat.sol")
let chat;
beforeEach(async () => {
chat = await Chat.deployed()
console.log("部署好合約:")
})
contract("與合約互動", accounts => {
it("取得初始化的值", async () => {
console.log("作測試")
const message = await chat.getMessage();
console.log("合約初始值是:", message)
})
it("設值再把值取回", async () => {
await chat.setMessage("修改到其它值")
const m1 = await chat.getMessage();
console.log("修改完的結果是", m1)
const m2 = await chat.message();
console.log("使用變數生成的函數結果是", m2)
})
})
```
```
mkdir lab3_metacoin
cd lab3_metacoin
truffle unbox metacoin
```
# README.md
```
truffle test .\test\TestMetaCoin.sol
```



```javascript=
development: {
host: "127.0.0.1", // Localhost (default: none)
port: 7545, // Standard Ethereum port (default: none)
network_id: "5777", // Any network (default: none)
},
```
# commands
```
accounts
accounts[0]
```

```
web3
web3.eth
```
```
deploy
let instance = await MetaCoin.deployed()
typeof instance
let accounts = await web3.eth.getAccounts()
accounts[0]
let balance = await instance.getBalance(accounts[0])
balance
balance+balance
balance.toNumber()+balance.toNumber()
let balanceInEther = await instance.getBalanceInEth(accounts[0])
typeof balanceInEther
balanceInEther.toNumber()
balanceInEther.toNumber()*5
instance.sendCoin(accounts[1],500)
let b1 = await instance.getBalance(accounts[0])
b1.toNumber()
let b2 = await instance.getBalance(accounts[1])
b2.toNumber()
```
# https://drive.google.com/file/d/1yvxxHuBTgjD6INyZbhz3q4w45I_uDnAx/view?usp=sharing
```solidity
pragma solidity ^0.5.16;
contract GMR {
address public manager;
address[] public players;
constructor() public {
manager = msg.sender;
}
function enterGame() public payable {
players.push(msg.sender);
}
}
```


# 修改程式加上限制
```javascript=
pragma solidity ^0.5.16;
contract GMR {
address public manager;
address[] public players;
constructor() public {
manager = msg.sender;
}
function enterGame() public payable {
require(msg.value>0.01 ether);
players.push(msg.sender);
}
}
```

# https://eth-converter.com/

```solidity
pragma solidity ^0.5.16;
contract GMR {
address public manager;
address payable[] public players;
constructor() public {
manager = msg.sender;
}
function enterGame() public payable {
require(msg.value>0.01 ether);
players.push(msg.sender);
}
function getContractBalance() public view returns (uint) {
return address(this).balance;
}
modifier restricted() {
require(msg.sender==manager);
_;
}
function payMoneyToPlayer() public restricted {
//require(msg.sender==manager);
uint winnerIndex = chooseByTime();
players[winnerIndex].transfer(getContractBalance());
players = new address payable[](0);
}
function chooseByTime() private view returns (uint) {
uint result = block.timestamp%players.length;
return result;
}
function getCurrentPlayers() public view returns (address payable[] memory) {
return players;
}
}
```

# npm install mocha chai chai-as-promised
## GMR.test.js
```javascript
const GMR = artifacts.require("../contracts/GMR.sol");
let gmr;
beforeEach(() => {
})
contract("lab1 GMR testing:", accounts => {
it("部署完檢查帳號", () => {
console.log("accounts=",accounts[0]);
})
})
```
# npm list -g

```javascript=
test: {
host: "127.0.0.1", // Localhost (default: none)
port: 8545, // Standard Ethereum port (default: none)
network_id: "*", // Any network (default: none)
},
development: {
host: "127.0.0.1", // Localhost (default: none)
port: 7545, // Standard Ethereum port (default: none)
network_id: "*", // Any network (default: none)
},
```
## `truffle test --network test test\GMR.test.js`
```javascript
const GMR = artifacts.require("../contracts/GMR.sol");
const assert = require("assert");
let gmr;
beforeEach(async () => {
//gmr = await GMR.deployed();
gmr = await GMR.new();
console.log("GMR is fresh deployed");
})
contract("lab1 GMR testing:", accounts => {
it("部署完檢查合約地址", () => {
//console.log("accounts=", accounts[0]);
assert.ok(gmr.address);
})
it("管理者應該是第一個帳戶", async () => {
console.log("accounts[0]=", accounts[0]);
const manager = await gmr.manager();
console.log("manager=", manager);
assert.strictEqual(accounts[0], manager);
})
it("進入遊戲", async () => {
await gmr.enterGame({
from: accounts[0],
value: web3.utils.toWei("0.02", "ether")
});
const players = await gmr.getCurrentPlayers();
console.log("目前使用者是:", players);
assert.strictEqual(players[0], accounts[0]);
assert.strictEqual(1, players.length);
})
it("多筆玩家", async () => {
const joiningPlayers = [accounts[1], accounts[2], accounts[3], accounts[4]];
for (let p of joiningPlayers) {
await gmr.enterGame({ from: p, value: web3.utils.toWei("0.02", "ether") })
}
const players = await gmr.getCurrentPlayers();
console.log("目前使用者是:", players);
assert.strictEqual(4, players.length);
assert.strictEqual(accounts[1], players[0]);
assert.strictEqual(accounts[2], players[1]);
assert.strictEqual(accounts[3], players[2]);
assert.strictEqual(accounts[4], players[3]);
})
})
```
# GMR.fail.test.js
```javascript
const GMR = artifacts.require("../contracts/GMR.sol");
//const assert = require("assert");
let gmr;
beforeEach(async () => {
gmr = await GMR.deployed();
//gmr = await GMR.new();
console.log("GMR is fresh deployed");
})
contract("GMR不正確時的檢查", accounts => {
it("入場費不夠", async () => {
try {
await gmr.enterGame({
from: accounts[0],
value: 300
})
assert(false);
} catch (err) {
assert.isAbove(err.message.search("VM Exception while processing transaction"),
-1, "應該要發生的是VM的錯誤");
}
})
})
```

## mkdir lab4_cac
## cd lab4_cac
## copy ..\lab1_solidity_intro\.gitignore .
## code .
```
npm init -y
truffle init -y
git init
```
# cac.sol
```solidity=
// SPDX-License-Identifier: MIT
pragma solidity ^0.5.16;
contract CAC {
address public manager;
uint256 public minimumFund;
address[] public approvers;
constructor(uint256 minimum) public {
manager = msg.sender;
minimumFund = minimum;
}
function join() public payable {
require(msg.value > minimumFund);
approvers.push(msg.sender);
}
}
```
# 1_init_cac.js
```javascript
const CAC = artifacts.require("CAC")
module.exports = function(deployer){
deployer.deploy(CAC, 500);
}
```
```javascript
development: {
host: "127.0.0.1", // Localhost (default: none)
port: 9545, // Standard Ethereum port (default: none)
network_id: "*", // Any network (default: none)
},
```
# truffle develop
## truffle deploy
## truffle develop --network development
## deploy
## deploy --reset
```
let cac1 = await CAC.deployed()
typeof cac1
cac1
cac1.manager()
await cac1.manager()
cac1.minimumFund()
await cac1.minimumFund()
let cac1_mf = await cac1.minimumFund()
cac1_mf.toNumber()
(await cac1.minimumFund()).toNumber()
```

## day3 完成的code
# https://drive.google.com/file/d/1L7A7GL-kL-7mvNLlhdpzqY0xrxLs7Dzu/view?usp=sharing
# Day4開始
## 使用LAB4_CAC
## 使用truffle-cli
## truffle develop
### 在truffle>
```
deploy
accounts
let cac1 = await CAC.deployed()
(await cac1.minimumFund()).toNumber()
```
## not enough
```
cac1.join({from:accounts[1], value:450})
```
## enough
```
cac1.join({from:accounts[1], value:550})
cac1.approvers(1)
accounts[1]
```
## CAC.sol
```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.5.16;
contract CAC {
struct SpendingRequest {
string description;
uint value;
address vendorAccount;
bool complete;
}
SpendingRequest[] public requests;
address public manager;
uint256 public minimumFund;
address[] public approvers;
modifier restricted() {
require(msg.sender == manager);
_;
}
constructor(uint256 minimum) public {
manager = msg.sender;
minimumFund = minimum;
}
function join() public payable {
require(msg.value > minimumFund);
approvers.push(msg.sender);
}
}
```
# http://remix.ethereum.org/
## 16_Demo12.sol
```solidity=
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.4;
contract Demo13 {
int[] public myArray;
constructor() {
myArray.push(100);
}
function addSomething() public {
myArray.push(200);
myArray.push(300);
int[] storage myArray2 = myArray;
myArray2[0]=555;
}
}
```
## 19_Demo15.sol
```solidity=
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.4;
contract Demo14 {
int[] public myArray;
constructor() {
myArray.push(100);
}
function addSomething() public {
myArray.push(200);
myArray.push(300);
int[] memory myArray2 = myArray;
myArray2[0]=555;
}
}
```
## CAC.sol
```solidity=
// SPDX-License-Identifier: MIT
pragma solidity ^0.5.16;
contract CAC {
struct SpendingRequest {
string description;
uint value;
address vendorAccount;
bool complete;
}
SpendingRequest[] public requests;
address public manager;
uint256 public minimumFund;
address[] public approvers;
function createRequest(string memory des,
uint value, address vendor) public restricted {
SpendingRequest memory req = SpendingRequest({
description:des,
value:value,
vendorAccount:vendor,
complete:false
});
requests.push(req);
}
modifier restricted() {
require(msg.sender == manager);
_;
}
constructor(uint256 minimum) public {
manager = msg.sender;
minimumFund = minimum;
}
function join() public payable {
require(msg.value > minimumFund);
approvers.push(msg.sender);
}
}
```

```
migrate --reset
```
```
cac1.createRequest()
cac1 = await CAC.deployed()
cac1.createRequest("wash outer wall",1000,accounts[0])
cac1.requests(0)
cac1.createRequest("wash outer wall",1000,accounts[0],{from:accounts[1]})
```
# CAC.sol
```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.5.16;
contract CAC {
struct SpendingRequest {
string description;
uint value;
address vendorAccount;
bool complete;
// change to mapping
uint approvalCount;
mapping(address=>bool) approvedUsers;
}
SpendingRequest[] public requests;
address public manager;
uint256 public minimumFund;
// change to mapping
mapping(address=>bool) public approvers;
uint public approversCount;
function createRequest(string memory des,
uint value, address vendor) public restricted {
SpendingRequest memory req = SpendingRequest({
description:des,
value:value,
vendorAccount:vendor,
complete:false,
approvalCount:0
});
requests.push(req);
}
modifier restricted() {
require(msg.sender == manager);
_;
}
constructor(uint256 minimum) public {
manager = msg.sender;
minimumFund = minimum;
}
function join() public payable {
require(msg.value > minimumFund);
//approvers.push(msg.sender);
approvers[msg.sender] = true;
}
}
```
# 重新檢驗
```
migrate --reset
cac1 = await CAC.deployed()
cac1.createRequest("wash outer wall",1000,accounts[0])
cac1.requests(0)
cac1.createRequest("wash outer wall",1000,accounts[0],{from:accounts[1]})
```

# CAC.sol
## 相容於0.76版
```solidity=
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.4;
contract CAC {
struct SpendingRequest {
string description;
uint256 value;
address vendorAccount;
bool complete;
// change to mapping
uint256 approvalCount;
mapping(address => bool) approvedUsers;
}
uint256 numRequests;
mapping(uint256 => SpendingRequest) public requests;
address public manager;
uint256 public minimumFund;
// change to mapping
mapping(address => bool) public approvers;
uint256 public approversCount;
function createRequest(
string memory des,
uint256 value,
address vendor
) public restricted {
SpendingRequest storage spendingRequest = requests[numRequests++];
spendingRequest.description = des;
spendingRequest.value = value;
spendingRequest.vendorAccount = vendor;
}
modifier restricted() {
require(msg.sender == manager);
_;
}
constructor(uint256 minimum) {
manager = msg.sender;
minimumFund = minimum;
}
function join() public payable {
require(msg.value > minimumFund);
//approvers.push(msg.sender);
approvers[msg.sender] = true;
approversCount++;
}
function approvalRequest(uint256 index) public {
SpendingRequest storage request = requests[index];
require(approvers[msg.sender]);
require(!request.approvedUsers[msg.sender]);
request.approvalCount++;
request.approvedUsers[msg.sender] = true;
}
}
```
```
compile
migrate --reset
cac1 = await CAC.deployed()
cac1.createRequest("wash outer wall",1000,accounts[9])
cac1.requests(0)
```






```
npm install mocha chai chai-as-promised
```
## package.json
```json
"scripts": {
"test": "mocha"
},
```
## truffle develop
```javascript=
const assert = require("chai").assert;
const CAC = artifacts.require("CAC.sol");
let cac
const VM_ERROR_STRING = "VM Exception while processing transaction:"
beforeEach(async () => {
//cac = await CAC.deployed();
cac = await CAC.new(500);
})
contract("test CAC", (accounts) => {
it("contract exist", async () => {
assert(cac != null, "array should not be null")
//console.log("cac address=", cac.address)
})
it("get minimum fund", async () => {
const minimumFund = await cac.minimumFund();
const v = minimumFund.toNumber();
//console.log("type is", typeof v);
// strict equal ===
// equal ==
assert.strictEqual(v, 500, "minimum fund should be 500");
})
it("get manager", async () => {
const mgr = await cac.manager();
console.log("mgr", typeof mgr);
assert.strictEqual(mgr, accounts[0], "manager should be first account");
})
it("join, make request, and approve", async () => {
await cac.join({ from: accounts[0], value: 550 });
await cac.createRequest("clean floor", 1000, accounts[9]);
await cac.approvalRequest(0, { from: accounts[0] });
})
it("join, make request, and approve twice", async () => {
await cac.join({ from: accounts[0], value: 550 });
await cac.join({ from: accounts[1], value: 550 });
await cac.join({ from: accounts[2], value: 550 });
await cac.createRequest("clean floor", 1000, accounts[9]);
await cac.approvalRequest(0, { from: accounts[0] });
try {
await cac.approvalRequest(0, { from: accounts[0] });
assert(false)
} catch (e) {
assert.isAbove(e.message.search(VM_ERROR_STRING), -1, "VM exception should happen")
}
})
it("not enough fee", async () => {
try {
await cac.join({ from: accounts[0], value: 450 });
assert(false)
} catch (e) {
assert.isAbove(e.message.search(VM_ERROR_STRING), -1, "VM exception should happen")
}
})
it("not approvers", async () => {
await cac.createRequest("clean floor", 1000, accounts[9]);
try{
await cac.approvalRequest(0, { from: accounts[5] });
assert(false)
} catch(e){
assert.isAbove(e.message.search(VM_ERROR_STRING), -1, "VM exception should happen")
}
})
})
```
# CAC (with payable vendor)
```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.4;
contract CAC {
struct SpendingRequest {
string description;
uint256 value;
address payable vendorAccount;
bool complete;
// change to mapping
uint256 approvalCount;
mapping(address => bool) approvedUsers;
}
uint256 numRequests;
mapping(uint256 => SpendingRequest) public requests;
address public manager;
uint256 public minimumFund;
// change to mapping
mapping(address => bool) public approvers;
uint256 public approversCount;
function createRequest(
string memory des,
uint256 value,
address payable vendor
) public restricted {
SpendingRequest storage spendingRequest = requests[numRequests++];
spendingRequest.description = des;
spendingRequest.value = value;
spendingRequest.vendorAccount = vendor;
}
modifier restricted() {
require(msg.sender == manager);
_;
}
constructor(uint256 minimum) {
manager = msg.sender;
minimumFund = minimum;
}
function join() public payable {
require(msg.value > minimumFund);
//approvers.push(msg.sender);
approvers[msg.sender] = true;
approversCount++;
}
function approvalRequest(uint256 index) public {
SpendingRequest storage request = requests[index];
require(approvers[msg.sender]);
require(!request.approvedUsers[msg.sender]);
request.approvalCount++;
request.approvedUsers[msg.sender] = true;
}
function executeRequest(uint256 index) public restricted {
SpendingRequest storage request = requests[index];
require(!request.complete);
require(request.approvalCount > (approversCount / 2));
request.vendorAccount.transfer(request.value);
request.complete = true;
}
}
```
# CAC2.test.js
```javascript=
const assert = require("chai").assert;
const CAC = artifacts.require("CAC.sol");
let cac
const VM_ERROR_STRING = "VM Exception while processing transaction:"
beforeEach(async () => {
//cac = await CAC.deployed();
cac = await CAC.new(500);
})
contract("test more CAC", (accounts) => {
it("付款失敗", async () => {
await cac.join({ from: accounts[0], value: 1000 });
await cac.join({ from: accounts[1], value: 1000 });
await cac.join({ from: accounts[2], value: 1000 });
await cac.createRequest("clean floor", 888, accounts[9]);
await cac.approvalRequest(0, { from: accounts[0] });
try {
await cac.executeRequest(0);
assert(false);
} catch (e) {
assert.isAbove(e.message.search(VM_ERROR_STRING), -1, "VM exception should happen")
}
})
it("取得帳戶餘額", async () => {
const amount1 = await web3.eth.getBalance(accounts[0]);
console.log("餘額是", typeof amount1, amount1);
const value = BigInt(amount1);
console.log("value=", typeof value, value);
console.log("轉成bigint可以作加減", value + 100n);
console.log("轉成bigint可以作加減", value - 100n);
})
it("付款成功", async () => {
await cac.join({ from: accounts[0], value: 1000 });
await cac.join({ from: accounts[1], value: 1000 });
await cac.join({ from: accounts[2], value: 1000 });
await cac.createRequest("clean floor", 888, accounts[9]);
await cac.approvalRequest(0, { from: accounts[0] });
await cac.approvalRequest(0, { from: accounts[1] });
const origBalance = await web3.eth.getBalance(accounts[9]);
console.log("原本accounts[9]的餘額是", origBalance);
await cac.executeRequest(0);
const newBalance = await web3.eth.getBalance(accounts[9]);
console.log("新accounts[9]的餘額是", newBalance);
const remaining = BigInt(newBalance) - BigInt(origBalance);
console.log("值是:", remaining);
assert.strictEqual(BigInt(888), remaining, `值應該是${remaining}`);
})
})
```
## 修改完的CAC.sol
```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.4;
contract CAC {
struct SpendingRequest {
string description;
uint256 value;
address payable vendorAccount;
bool complete;
// change to mapping
uint256 approvalCount;
mapping(address => bool) approvedUsers;
}
uint256 numRequests;
mapping(uint256 => SpendingRequest) public requests;
address public manager;
uint256 public minimumFund;
// change to mapping
mapping(address => bool) public approvers;
uint256 public approversCount;
function createRequest(
string memory des,
uint256 value,
address payable vendor
) public restricted {
SpendingRequest storage spendingRequest = requests[numRequests++];
spendingRequest.description = des;
spendingRequest.value = value;
spendingRequest.vendorAccount = vendor;
}
modifier restricted() {
require(msg.sender == manager);
_;
}
constructor(uint256 minimum,address creator) {
manager = creator;
minimumFund = minimum;
}
function join() public payable {
require(msg.value > minimumFund);
//approvers.push(msg.sender);
approvers[msg.sender] = true;
approversCount++;
}
function approvalRequest(uint256 index) public {
SpendingRequest storage request = requests[index];
require(approvers[msg.sender]);
require(!request.approvedUsers[msg.sender]);
request.approvalCount++;
request.approvedUsers[msg.sender] = true;
}
function executeRequest(uint256 index) public restricted {
SpendingRequest storage request = requests[index];
require(!request.complete);
require(request.approvalCount > (approversCount / 2));
request.vendorAccount.transfer(request.value);
request.complete = true;
}
}
```
## CommitteeCreator.sol
```solidity=
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.4;
import "./CAC.sol";
contract CommitteeCreator {
CAC[] public deployedCommittee;
function createCommittee(uint256 minimum) public {
CAC c = new CAC(minimum, msg.sender);
deployedCommittee.push(c);
}
function getDeployedCommittee() public view returns(CAC[] memory){
return deployedCommittee;
}
}
```





# `1_initial_creator.js`
```javascript!
const cc = artifacts.require("CommitteeCreator")
module.exports = function(deployer){
deployer.deploy(cc);
}
```
## 在truffle>
```
deploy --reset
let cc = await CommitteeCreator.deployed()
cc.address
cc
```
## 更新的CAC.test.js
```javascript
const assert = require("chai").assert;
const CAC = artifacts.require("CAC.sol");
let cac
const VM_ERROR_STRING = "VM Exception while processing transaction:"
contract("test CAC", (accounts) => {
beforeEach(async () => {
//cac = await CAC.deployed();
cac = await CAC.new(500, accounts[0]);
})
it("contract exist", async () => {
assert(cac != null, "array should not be null")
//console.log("cac address=", cac.address)
})
it("get minimum fund", async () => {
const minimumFund = await cac.minimumFund();
const v = minimumFund.toNumber();
//console.log("type is", typeof v);
// strict equal ===
// equal ==
assert.strictEqual(v, 500, "minimum fund should be 500");
})
it("get manager", async () => {
const mgr = await cac.manager();
console.log("mgr", typeof mgr);
assert.strictEqual(mgr, accounts[0], "manager should be first account");
})
it("join, make request, and approve", async () => {
await cac.join({ from: accounts[0], value: 550 });
await cac.createRequest("clean floor", 1000, accounts[9]);
await cac.approvalRequest(0, { from: accounts[0] });
})
it("join, make request, and approve twice", async () => {
await cac.join({ from: accounts[0], value: 550 });
await cac.join({ from: accounts[1], value: 550 });
await cac.join({ from: accounts[2], value: 550 });
await cac.createRequest("clean floor", 1000, accounts[9]);
await cac.approvalRequest(0, { from: accounts[0] });
try {
await cac.approvalRequest(0, { from: accounts[0] });
assert(false)
} catch (e) {
assert.isAbove(e.message.search(VM_ERROR_STRING), -1, "VM exception should happen")
}
})
it("not enough fee", async () => {
try {
await cac.join({ from: accounts[0], value: 450 });
assert(false)
} catch (e) {
assert.isAbove(e.message.search(VM_ERROR_STRING), -1, "VM exception should happen")
}
})
it("not approvers", async () => {
await cac.createRequest("clean floor", 1000, accounts[9]);
try {
await cac.approvalRequest(0, { from: accounts[5] });
assert(false)
} catch (e) {
assert.isAbove(e.message.search(VM_ERROR_STRING), -1, "VM exception should happen")
}
})
})
```
## 更新過的CAC2.test.js
```javascript!
const assert = require("chai").assert;
const CAC = artifacts.require("CAC.sol");
let cac
const VM_ERROR_STRING = "VM Exception while processing transaction:"
contract("test more CAC", (accounts) => {
beforeEach(async () => {
//cac = await CAC.deployed();
cac = await CAC.new(500,accounts[0]);
})
it("付款失敗", async () => {
await cac.join({ from: accounts[0], value: 1000 });
await cac.join({ from: accounts[1], value: 1000 });
await cac.join({ from: accounts[2], value: 1000 });
await cac.createRequest("clean floor", 888, accounts[9]);
await cac.approvalRequest(0, { from: accounts[0] });
try {
await cac.executeRequest(0);
assert(false);
} catch (e) {
assert.isAbove(e.message.search(VM_ERROR_STRING), -1, "VM exception should happen")
}
})
it("取得帳戶餘額", async () => {
const amount1 = await web3.eth.getBalance(accounts[0]);
console.log("餘額是", typeof amount1, amount1);
const value = BigInt(amount1);
console.log("value=", typeof value, value);
console.log("轉成bigint可以作加減", value + 100n);
console.log("轉成bigint可以作加減", value - 100n);
})
it("付款成功", async () => {
await cac.join({ from: accounts[0], value: 1000 });
await cac.join({ from: accounts[1], value: 1000 });
await cac.join({ from: accounts[2], value: 1000 });
await cac.createRequest("clean floor", 888, accounts[9]);
await cac.approvalRequest(0, { from: accounts[0] });
await cac.approvalRequest(0, { from: accounts[1] });
const origBalance = await web3.eth.getBalance(accounts[9]);
console.log("原本accounts[9]的餘額是", origBalance);
await cac.executeRequest(0);
const newBalance = await web3.eth.getBalance(accounts[9]);
console.log("新accounts[9]的餘額是", newBalance);
const remaining = BigInt(newBalance) - BigInt(origBalance);
console.log("值是:", remaining);
assert.strictEqual(BigInt(888), remaining, `值應該是${remaining}`);
})
})
```
## `CC.test.js`
```javascript!
const CommitteeCreator = artifacts.require("CommitteeCreator.sol");
const CAC = artifacts.require("CAC.sol");
const assert = require("chai").assert;
require('chai').use(require("chai-as-promised")).should();
let cc;
beforeEach(async () => {
cc = await CommitteeCreator.new();
console.log("cc部署完成")
})
contract("Committee Creator測試", accounts => {
it("用第一個帳號創建應該是第一個帳號作管理者", async () => {
await cc.createCommittee(500);
const cac1Addr = await cc.deployedCommittee(0);
console.log(`cac的實例會在${cac1Addr}`)
const allArray = await cc.getDeployedCommittee();
console.log(`array在${allArray}`)
const cac1 = await CAC.at(cac1Addr)
const manager = await cac1.manager();
assert.strictEqual(manager, accounts[0], "管理應該是第一個帳號")
})
it("用第二個帳號創建應該是第二個帳號作管理者", async () => {
await cc.createCommittee(500, { from: accounts[1] });
const cac1Addr = await cc.deployedCommittee(0);
const cac = await CAC.at(cac1Addr)
const manager = await cac.manager();
assert.strictEqual(manager, accounts[1], "管理應該是第個二帳號")
})
})
```
## CC2.test.js
```javascript!
const assert = require("chai").assert;
const CAC = artifacts.require("CAC.sol");
const CommitteeCreator = artifacts.require("CommitteeCreator.sol");
let cac
let cc
const VM_ERROR_STRING = "VM Exception while processing transaction:"
beforeEach(async () => {
cc = await CommitteeCreator.new();
console.log("cc部署完成")
})
contract("test CAC", (accounts) => {
beforeEach(async () => {
//cac = await CAC.new(500, accounts[0]);
await cc.createCommittee(500, { from: accounts[0] })
const cac1Addr = await cc.deployedCommittee(0);
cac = await CAC.at(cac1Addr);
})
it("contract exist", async () => {
assert(cac != null, "array should not be null")
//console.log("cac address=", cac.address)
})
it("get minimum fund", async () => {
const minimumFund = await cac.minimumFund();
const v = minimumFund.toNumber();
//console.log("type is", typeof v);
// strict equal ===
// equal ==
assert.strictEqual(v, 500, "minimum fund should be 500");
})
it("get manager", async () => {
const mgr = await cac.manager();
console.log("mgr", typeof mgr);
assert.strictEqual(mgr, accounts[0], "manager should be first account");
})
it("join, make request, and approve", async () => {
await cac.join({ from: accounts[0], value: 550 });
await cac.createRequest("clean floor", 1000, accounts[9]);
await cac.approvalRequest(0, { from: accounts[0] });
})
it("join, make request, and approve twice", async () => {
await cac.join({ from: accounts[0], value: 550 });
await cac.join({ from: accounts[1], value: 550 });
await cac.join({ from: accounts[2], value: 550 });
await cac.createRequest("clean floor", 1000, accounts[9]);
await cac.approvalRequest(0, { from: accounts[0] });
try {
await cac.approvalRequest(0, { from: accounts[0] });
assert(false)
} catch (e) {
assert.isAbove(e.message.search(VM_ERROR_STRING), -1, "VM exception should happen")
}
})
it("not enough fee", async () => {
try {
await cac.join({ from: accounts[0], value: 450 });
assert(false)
} catch (e) {
assert.isAbove(e.message.search(VM_ERROR_STRING), -1, "VM exception should happen")
}
})
it("not approvers", async () => {
await cac.createRequest("clean floor", 1000, accounts[9]);
try {
await cac.approvalRequest(0, { from: accounts[5] });
assert(false)
} catch (e) {
assert.isAbove(e.message.search(VM_ERROR_STRING), -1, "VM exception should happen")
}
})
})
```
## 使用
```
truffle develop
deploy --reset
let cc =await CommitteeCreator.deployed()
cc.createCommittee(500)
let cacAddr1 = await cc.deployedCommittee(0)
let inst1 = await CAC.at(cacAddr1)
inst1.manager()
accounts[0]
inst1.minimumFund()
(await inst1.minimumFund()).toNumber()
```
# 所有的程式碼
1. vs code:
* https://drive.google.com/file/d/1gwoYAXI_kmCr1zknd4LtlzXRD-d3JvSd/view?usp=sharing
1. remix code:
* https://drive.google.com/file/d/1UAgEi_MI_OX8I3TzXsiOzGUoSbyI4Jpw/view?usp=sharing