Skip to content

Instantly share code, notes, and snippets.

@sbin0819
Last active July 6, 2022 07:28
Show Gist options
  • Save sbin0819/2029990c459ed676d09af4a1df27788a to your computer and use it in GitHub Desktop.
Save sbin0819/2029990c459ed676d09af4a1df27788a to your computer and use it in GitHub Desktop.
# Chapter 1
Web3.js
## basic
### ์ปจํŠธ๋ž™ํŠธ
```solidity
pragma solidity ^0.4.19;
contract HelloWorld {
}
```
### ๊ตฌ์กฐ์ฒด
```solidity
struct Person {
uint age;
string name;
}
```
### ํ•จ์ˆ˜
```solidity
uint[] numbers;
function _addToArray(uint _number) private {
numbers.push(_number);
}
```
### ํ•จ์ˆ˜ ์ œ์–ด์ž
- ์ƒํƒœ๋ฅผ ๋ณ€ํ™”์‹œํ‚ค์ง€ ์•Š์Œ `view`
- ํ•จ์ˆ˜๊ฐ€ ์•ฑ์—์„œ ์–ด๋–ค ๋ฐ์ดํ„ฐ๋„ ์ ‘๊ทผํ•˜์ง€ ์•Š๋Š” ๊ฒƒ `pure`
### ์ด๋ฒคํŠธ
```solidity
event IntegersAdded(uint x, uint y, uint result);
function add(uint _x, uint _y) public {
uint result = _x + _y;
// ์ด๋ฒคํŠธ๋ฅผ ์‹คํ–‰ํ•˜์—ฌ ์•ฑ์—๊ฒŒ add ํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰๋˜์—ˆ์Œ์„ ์•Œ๋ฆฐ๋‹ค:
IntegersAdded(_x, _y, result);
return result;
}
```
```js
YourContract.IntegersAdded(function(error, result) {
// ๊ฒฐ๊ณผ์™€ ๊ด€๋ จ๋œ ํ–‰๋™์„ ์ทจํ•œ๋‹ค
})
```
# Chapter 2
## ๋งคํ•‘๊ณผ ์ฃผ์†Œ
`mapping`, `adress`
- ์ฃผ์†Œ
์ด๋”๋ฆฌ์›€ ๋ธ”๋ก์ฒด์ธ์˜ ์ฃผ์†Œ
- ๋งคํ•‘
๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜๋Š” ๋˜๋‹ค๋ฅธ ๋ฐฉ๋ฒ•
```solidity
// ๊ธˆ์œต ์•ฑ์šฉ์œผ๋กœ, ์œ ์ €์˜ ๊ณ„์ขŒ ์ž”์•ก์„ ๋ณด์œ ํ•˜๋Š” uint๋ฅผ ์ €์žฅํ•œ๋‹ค:
mapping (address => uint) public accountBalance;
// ํ˜น์€ userID๋กœ ์œ ์ € ์ด๋ฆ„์„ ์ €์žฅ/๊ฒ€์ƒ‰ํ•˜๋Š” ๋ฐ ๋งคํ•‘์„ ์“ธ ์ˆ˜๋„ ์žˆ๋‹ค
mapping (uint => string) userIdToName;
```
๋งคํ•‘์€ ๊ธฐ๋ณธ์ ์œผ๋กœ ํ‚ค-๊ฐ’ (key-value) ์ €์žฅ์†Œ๋กœ, ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜๊ณ  ๊ฒ€์ƒ‰ํ•˜๋Š” ๋ฐ ์ด์šฉ๋œ๋‹ค. ์ฒซ๋ฒˆ์งธ ์˜ˆ์‹œ์—์„œ ํ‚ค๋Š” address์ด๊ณ  ๊ฐ’์€ uint์ด๋‹ค. ๋‘๋ฒˆ์งธ ์˜ˆ์‹œ์—์„œ ํ‚ค๋Š” uint์ด๊ณ  ๊ฐ’์€ string์ด๋‹ค.
## msg.sender
์†”๋ฆฌ๋””ํ‹ฐ์—๋Š” ๋ชจ๋“  ํ•จ์ˆ˜์—์„œ ์ด์šฉ ๊ฐ€๋Šฅํ•œ ํŠน์ • ์ „์—ญ ๋ณ€์ˆ˜๋“ค์ด ์žˆ์ง€. ๊ทธ ์ค‘์˜ ํ•˜๋‚˜๊ฐ€ ํ˜„์žฌ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•œ ์‚ฌ๋žŒ (ํ˜น์€ ์Šค๋งˆํŠธ ์ปจํŠธ๋ž™ํŠธ)์˜ ์ฃผ์†Œ๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” msg.sender์ด์ง€.
์ฐธ๊ณ : ์†”๋ฆฌ๋””ํ‹ฐ์—์„œ ํ•จ์ˆ˜ ์‹คํ–‰์€ ํ•ญ์ƒ ์™ธ๋ถ€ ํ˜ธ์ถœ์ž๊ฐ€ ์‹œ์ž‘ํ•˜๋„ค. ์ปจํŠธ๋ž™ํŠธ๋Š” ๋ˆ„๊ตฐ๊ฐ€๊ฐ€ ์ปจํŠธ๋ž™ํŠธ์˜ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ๊นŒ์ง€ ๋ธ”๋ก์ฒด์ธ ์ƒ์—์„œ ์•„๋ฌด ๊ฒƒ๋„ ์•ˆ ํ•˜๊ณ  ์žˆ์„ ๊ฒƒ์ด๋„ค. ๊ทธ๋Ÿฌ๋‹ˆ ํ•ญ์ƒ msg.sender๊ฐ€ ์žˆ์–ด์•ผ ํ•˜๋„ค.
```solidity
mapping (address => uint) favoriteNumber;
function setMyNumber(uint _myNumber) public {
// `msg.sender`์— ๋Œ€ํ•ด `_myNumber`๊ฐ€ ์ €์žฅ๋˜๋„๋ก `favoriteNumber` ๋งคํ•‘์„ ์—…๋ฐ์ดํŠธํ•œ๋‹ค `
favoriteNumber[msg.sender] = _myNumber;
// ^ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜๋Š” ๊ตฌ๋ฌธ์€ ๋ฐฐ์—ด๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•  ๋–„์™€ ๋™์ผํ•˜๋‹ค
}
function whatIsMyNumber() public view returns (uint) {
// sender์˜ ์ฃผ์†Œ์— ์ €์žฅ๋œ ๊ฐ’์„ ๋ถˆ๋Ÿฌ์˜จ๋‹ค
// sender๊ฐ€ `setMyNumber`์„ ์•„์ง ํ˜ธ์ถœํ•˜์ง€ ์•Š์•˜๋‹ค๋ฉด ๋ฐ˜ํ™˜๊ฐ’์€ `0`์ด ๋  ๊ฒƒ์ด๋‹ค
return favoriteNumber[msg.sender];
}
```
์ด ๊ฐ„๋‹จํ•œ ์˜ˆ์‹œ์—์„œ ๋ˆ„๊ตฌ๋‚˜ setMyNumber์„ ํ˜ธ์ถœํ•˜์—ฌ ๋ณธ์ธ์˜ ์ฃผ์†Œ์™€ ์—ฐ๊ฒฐ๋œ ์šฐ๋ฆฌ ์ปจํŠธ๋ž™ํŠธ ๋‚ด์— uint๋ฅผ ์ €์žฅํ•  ์ˆ˜ ์žˆ์ง€.
msg.sender๋ฅผ ํ™œ์šฉํ•˜๋ฉด ์ž๋„ค๋Š” ์ด๋”๋ฆฌ์›€ ๋ธ”๋ก์ฒด์ธ์˜ ๋ณด์•ˆ์„ฑ์„ ์ด์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์ง€. ์ฆ‰, ๋ˆ„๊ตฐ๊ฐ€ ๋‹ค๋ฅธ ์‚ฌ๋žŒ์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณ€๊ฒฝํ•˜๋ ค๋ฉด ํ•ด๋‹น ์ด๋”๋ฆฌ์›€ ์ฃผ์†Œ์™€ ๊ด€๋ จ๋œ ๊ฐœ์ธํ‚ค๋ฅผ ํ›”์น˜๋Š” ๊ฒƒ ๋ฐ–์—๋Š” ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์ด ์—†๋‹ค๋Š” ๊ฒƒ์ด๋„ค.
## require
```solidity
function sayHiToVitalik(string _name) public returns (string) {
// _name์ด "Vitalik"์ธ์ง€ ๋น„๊ตํ•œ๋‹ค. ์ฐธ์ด ์•„๋‹ ๊ฒฝ์šฐ ์—๋Ÿฌ ๋ฉ”์‹œ์ง€๋ฅผ ๋ฐœ์ƒํ•˜๊ณ  ํ•จ์ˆ˜๋ฅผ ๋ฒ—์–ด๋‚œ๋‹ค
// (์ฐธ๊ณ : ์†”๋ฆฌ๋””ํ‹ฐ๋Š” ๊ณ ์œ ์˜ ์ŠคํŠธ๋ง ๋น„๊ต ๊ธฐ๋Šฅ์„ ๊ฐ€์ง€๊ณ  ์žˆ์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์—
// ์ŠคํŠธ๋ง์˜ keccak256 ํ•ด์‹œ๊ฐ’์„ ๋น„๊ตํ•˜์—ฌ ์ŠคํŠธ๋ง ๊ฐ’์ด ๊ฐ™์€์ง€ ํŒ๋‹จํ•œ๋‹ค)
require(keccak256(_name) == keccak256("Vitalik"));
// ์ฐธ์ด๋ฉด ํ•จ์ˆ˜ ์‹คํ–‰์„ ์ง„ํ–‰ํ•œ๋‹ค:
return "Hi!";
}
```
## ์ƒ์†
`is`
```solidity
contract Doge {
function catchphrase() public returns (string) {
return "So Wow CryptoDoge";
}
}
contract BabyDoge is Doge {
function anotherCatchphrase() public returns (string) {
return "Such Moon BabyDoge";
}
}
```
## import
## storage vs memory
Storage๋Š” ๋ธ”๋ก์ฒด์ธ ์ƒ์— ์˜๊ตฌ์ ์œผ๋กœ ์ €์žฅ๋˜๋Š” ๋ณ€์ˆ˜๋ฅผ ์˜๋ฏธํ•˜์ง€. Memory๋Š” ์ž„์‹œ์ ์œผ๋กœ ์ €์žฅ๋˜๋Š” ๋ณ€์ˆ˜๋กœ, ์ปจํŠธ๋ž™ํŠธ ํ•จ์ˆ˜์— ๋Œ€ํ•œ ์™ธ๋ถ€ ํ˜ธ์ถœ๋“ค์ด ์ผ์–ด๋‚˜๋Š” ์‚ฌ์ด์— ์ง€์›Œ์ง€์ง€. ๋‘ ๋ณ€์ˆ˜๋Š” ๊ฐ๊ฐ ์ปดํ“จํ„ฐ ํ•˜๋“œ ๋””์Šคํฌ์™€ RAM๊ณผ ๊ฐ™์ง€.
`์ƒํƒœ ๋ณ€์ˆ˜(ํ•จ์ˆ˜ ์™ธ๋ถ€์— ์„ ์–ธ๋œ ๋ณ€์ˆ˜)`๋Š” ์ดˆ๊ธฐ ์„ค์ •์ƒ `storage`๋กœ ์„ ์–ธ๋˜์–ด ๋ธ”๋ก์ฒด์ธ์— ์˜๊ตฌ์ ์œผ๋กœ ์ €์žฅ๋˜๋Š” ๋ฐ˜๋ฉด, `ํ•จ์ˆ˜ ๋‚ด์— ์„ ์–ธ๋œ ๋ณ€์ˆ˜`๋Š” `memory`๋กœ ์ž๋™ ์„ ์–ธ๋˜์–ด์„œ ํ•จ์ˆ˜ ํ˜ธ์ถœ์ด ์ข…๋ฃŒ๋˜๋ฉด ์‚ฌ๋ผ์ง€์ง€.
*ํ•˜์ง€๋งŒ ์ด ํ‚ค์›Œ๋“œ๋“ค์„ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋Š” ๋•Œ๊ฐ€ ์žˆ์ง€. ๋ฐ”๋กœ ํ•จ์ˆ˜ ๋‚ด์˜ ๊ตฌ์กฐ์ฒด์™€ _๋ฐฐ์—ด_์„ ์ฒ˜๋ฆฌํ•  ๋•Œ์ง€:*
```solidity
contract SandwichFactory {
struct Sandwich {
string name;
string status;
}
Sandwich[] sandwiches;
function eatSandwich(uint _index) public {
// Sandwich mySandwich = sandwiches[_index];
// ^ ๊ฝค ๊ฐ„๋‹จํ•ด ๋ณด์ด๋‚˜, ์†”๋ฆฌ๋””ํ‹ฐ๋Š” ์—ฌ๊ธฐ์„œ
// `storage`๋‚˜ `memory`๋ฅผ ๋ช…์‹œ์ ์œผ๋กœ ์„ ์–ธํ•ด์•ผ ํ•œ๋‹ค๋Š” ๊ฒฝ๊ณ  ๋ฉ”์‹œ์ง€๋ฅผ ๋ฐœ์ƒํ•œ๋‹ค.
// ๊ทธ๋Ÿฌ๋ฏ€๋กœ `storage` ํ‚ค์›Œ๋“œ๋ฅผ ํ™œ์šฉํ•˜์—ฌ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์„ ์–ธํ•ด์•ผ ํ•œ๋‹ค:
Sandwich storage mySandwich = sandwiches[_index];
// ...์ด ๊ฒฝ์šฐ, `mySandwich`๋Š” ์ €์žฅ๋œ `sandwiches[_index]`๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” ํฌ์ธํ„ฐ์ด๋‹ค.
// ๊ทธ๋ฆฌ๊ณ 
mySandwich.status = "Eaten!";
// ...์ด ์ฝ”๋“œ๋Š” ๋ธ”๋ก์ฒด์ธ ์ƒ์—์„œ `sandwiches[_index]`์„ ์˜๊ตฌ์ ์œผ๋กœ ๋ณ€๊ฒฝํ•œ๋‹ค.
// ๋‹จ์ˆœํžˆ ๋ณต์‚ฌ๋ฅผ ํ•˜๊ณ ์ž ํ•œ๋‹ค๋ฉด `memory`๋ฅผ ์ด์šฉํ•˜๋ฉด ๋œ๋‹ค:
Sandwich memory anotherSandwich = sandwiches[_index + 1];
// ...์ด ๊ฒฝ์šฐ, `anotherSandwich`๋Š” ๋‹จ์ˆœํžˆ ๋ฉ”๋ชจ๋ฆฌ์— ๋ฐ์ดํ„ฐ๋ฅผ ๋ณต์‚ฌํ•˜๋Š” ๊ฒƒ์ด ๋œ๋‹ค.
// ๊ทธ๋ฆฌ๊ณ 
anotherSandwich.status = "Eaten!";
// ...์ด ์ฝ”๋“œ๋Š” ์ž„์‹œ ๋ณ€์ˆ˜์ธ `anotherSandwich`๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ๊ฒƒ์œผ๋กœ
// `sandwiches[_index + 1]`์—๋Š” ์•„๋ฌด๋Ÿฐ ์˜ํ–ฅ์„ ๋ผ์น˜์ง€ ์•Š๋Š”๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค:
sandwiches[_index + 1] = anotherSandwich;
// ...์ด๋Š” ์ž„์‹œ ๋ณ€๊ฒฝํ•œ ๋‚ด์šฉ์„ ๋ธ”๋ก์ฒด์ธ ์ €์žฅ์†Œ์— ์ €์žฅํ•˜๊ณ ์ž ํ•˜๋Š” ๊ฒฝ์šฐ์ด๋‹ค.
}
}
```
## ํ•จ์ˆ˜ ์ ‘๊ทผ ์ œ์–ด์ž ๋” ์•Œ์•„๋ณด๊ธฐ
- internal
- external
```solidity
contract Sandwich {
uint private sandwichesEaten = 0;
function eat() internal {
sandwichesEaten++;
}
}
contract BLT is Sandwich {
uint private baconSandwichesEaten = 0;
function eatWithBacon() public returns (string) {
baconSandwichesEaten++;
// eat ํ•จ์ˆ˜๊ฐ€ internal๋กœ ์„ ์–ธ๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ์—ฌ๊ธฐ์„œ ํ˜ธ์ถœ์ด ๊ฐ€๋Šฅํ•˜๋‹ค
eat();
}
}
```
## ์ธํ„ฐํŽ˜์ด์Šค
```solidity
contract LuckyNumber {
mapping(address => uint) numbers;
function setNum(uint _num) public {
numbers[msg.sender] = _num;
}
function getNum(address _myAddress) public view returns (uint) {
return numbers[_myAddress];
}
}
```
```solidity
contract NumberInterface {
function getNum(address _myAddress) public view returns (uint);
}
```
## ์ธํ„ฐํŽ˜์ด์Šค ํ™œ์šฉ
```solidity
contract MyContract {
address NumberInterfaceAddress = 0xab38...
// ^ ์ด๋”๋ฆฌ์›€์ƒ์˜ FavoriteNumber ์ปจํŠธ๋ž™ํŠธ ์ฃผ์†Œ์ด๋‹ค
NumberInterface numberContract = NumberInterface(NumberInterfaceAddress)
// ์ด์ œ `numberContract`๋Š” ๋‹ค๋ฅธ ์ปจํŠธ๋ž™ํŠธ๋ฅผ ๊ฐ€๋ฆฌํ‚ค๊ณ  ์žˆ๋‹ค.
function someFunction() public {
// ์ด์ œ `numberContract`๊ฐ€ ๊ฐ€๋ฆฌํ‚ค๊ณ  ์žˆ๋Š” ์ปจํŠธ๋ž™ํŠธ์—์„œ `getNum` ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ๋‹ค:
uint num = numberContract.getNum(msg.sender);
// ...๊ทธ๋ฆฌ๊ณ  ์—ฌ๊ธฐ์„œ `num`์œผ๋กœ ๋ฌด์–ธ๊ฐ€๋ฅผ ํ•  ์ˆ˜ ์žˆ๋‹ค
}
}
```
## ๋‹ค์ˆ˜์˜ ๋ฐ˜ํ™˜๊ฐ’ ์ฒ˜๋ฆฌํ•˜๊ธฐ
```solidity
function multipleReturns() internal returns(uint a, uint b, uint c) {
return (1, 2, 3);
}
function processMultipleReturns() external {
uint a;
uint b;
uint c;
// ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋‹ค์ˆ˜ ๊ฐ’์„ ํ• ๋‹นํ•œ๋‹ค:
(a, b, c) = multipleReturns();
}
// ํ˜น์€ ๋‹จ ํ•˜๋‚˜์˜ ๊ฐ’์—๋งŒ ๊ด€์‹ฌ์ด ์žˆ์„ ๊ฒฝ์šฐ:
function getLastReturnValue() external {
uint c;
// ๋‹ค๋ฅธ ํ•„๋“œ๋Š” ๋นˆ์นธ์œผ๋กœ ๋†“๊ธฐ๋งŒ ํ•˜๋ฉด ๋œ๋‹ค:
(,,c) = multipleReturns();
}
```
```solidity
contract ZombieFeeding is ZombieFactory {
address ckAddress = 0x06012c8cf97BEaD5deAe237070F9587f8E7A266d;
KittyInterface kittyContract = KittyInterface(ckAddress);
// ์—ฌ๊ธฐ์— ์žˆ๋Š” ํ•จ์ˆ˜ ์ •์˜๋ฅผ ๋ณ€๊ฒฝ:
function feedAndMultiply(uint _zombieId, uint _targetDna) public {
require(msg.sender == zombieToOwner[_zombieId]);
Zombie storage myZombie = zombies[_zombieId];
_targetDna = _targetDna % dnaModulus;
uint newDna = (myZombie.dna + _targetDna) / 2;
// ์—ฌ๊ธฐ์— if ๋ฌธ ์ถ”๊ฐ€
_createZombie("NoName", newDna);
}
function feedOnKitty(uint _zombieId, uint _kittyId) public {
uint kittyDna;
(,,,,,,,,,kittyDna) = kittyContract.getKitty(_kittyId);
// ์—ฌ๊ธฐ์— ์žˆ๋Š” ํ•จ์ˆ˜ ํ˜ธ์ถœ์„ ๋ณ€๊ฒฝ:
feedAndMultiply(_zombieId, kittyDna);
}
}
```
## if ๋ฌธ
์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ if ๋ฌธ๊ณผ ๋™์ผ
```solidity
function eatBLT(string sandwich) public {
// ์ŠคํŠธ๋ง ๊ฐ„์˜ ๋™์ผ ์—ฌ๋ถ€๋ฅผ ํŒ๋‹จํ•˜๊ธฐ ์œ„ํ•ด keccak256 ํ•ด์‹œ ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•ด์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์„ ๊ธฐ์–ตํ•˜์ž
if (keccak256(sandwich) == keccak256("BLT")) {
eat();
}
}
```
# ์†”๋ฆฌ๋””ํ‹ฐ ๊ณ ๊ธ‰๊ฐœ๋…
## ๊ฐ€์Šค(Gas)
### ๊ฐ€์Šค - ์ด๋”๋ฆฌ์›€ DApp์ด ์‚ฌ์šฉํ•˜๋Š” ์—ฐ๋ฃŒ
ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•˜๋Š” ๋ฐ์— ์–ผ๋งˆ๋‚˜ ๋งŽ์€ ๊ฐ€์Šค๊ฐ€ ํ•„์š”ํ•œ์ง€๋Š” ๊ทธ ํ•จ์ˆ˜์˜ ๋กœ์ง(๋…ผ๋ฆฌ ๊ตฌ์กฐ)์ด ์–ผ๋งˆ๋‚˜ ๋ณต์žกํ•œ์ง€์— ๋”ฐ๋ผ ๋‹ฌ๋ผ์ง€๋„ค. ๊ฐ๊ฐ์˜ ์—ฐ์‚ฐ์€ ์†Œ๋ชจ๋˜๋Š” ๊ฐ€์Šค ๋น„์šฉ(gas cost)์ด ์žˆ๊ณ , ๊ทธ ์—ฐ์‚ฐ์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ฐ์— ์†Œ๋ชจ๋˜๋Š” ์ปดํ“จํŒ… ์ž์›์˜ ์–‘์ด ์ด ๋น„์šฉ์„ ๊ฒฐ์ •ํ•˜๋„ค. ์˜ˆ๋ฅผ ๋“ค์–ด, storage์— ๊ฐ’์„ ์“ฐ๋Š” ๊ฒƒ์€ ๋‘ ๊ฐœ์˜ ์ •์ˆ˜๋ฅผ ๋”ํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ํ›จ์”ฌ ๋น„์šฉ์ด ๋†’๋„ค. ์ž๋„ค ํ•จ์ˆ˜์˜ ์ „์ฒด ๊ฐ€์Šค ๋น„์šฉ์€ ๊ทธ ํ•จ์ˆ˜๋ฅผ ๊ตฌ์„ฑํ•˜๋Š” ๊ฐœ๋ณ„ ์—ฐ์‚ฐ๋“ค์˜ ๊ฐ€์Šค ๋น„์šฉ์„ ๋ชจ๋‘ ํ•ฉ์นœ ๊ฒƒ๊ณผ ๊ฐ™๋„ค.
### ๊ฐ€์Šค๋Š” ์™œ ํ•„์š”ํ•œ๊ฐ€?
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment