solidity - by - example

작홍분·2021년 9월 27일
0

solidity - by- example

목록 보기
1/1
post-custom-banner

Variables

3가지의 변수가 있음.

1) local

  • 함수 안에서 정의됨

- local 변수는 블록체인에 저장되지 않는다. (memory?)

2) state

  • 함수 밖에서 정의됨

- state 변수는 블록체인에 저장된다. (storage?)

3) global

  • 블록체인과 관련한 정보를 제공한다.
    ex) msg.sender, block.timestamp 등

    추가 구글링.

contract Variables{
    	function doSomething() public {
    		uint i = 456;
        //local 변수는 블록체인에 저장되지 않음
        	uint timestamp = block.timestamp ;
        //global 변수는 이미 저장된것을 말하는 것 같아.
        }

Reading and Writing to a State Variable

state 변수를 선언하거나 수정하려면, transaction을 전송해야 한다.(fee 사용)
하지만, 읽거나 불러오는(return) 건 transaction이 필요 없다.

Ether and Wei

trasaction은 ether 라는 비용을 지불한다.
1 ether == 10**18 wei

Gas and Gas Price

1) Gas

ether 비용

gas spent (쓴 가스) * gas price (가스 가격- 직접 설정, 높게 설정할수록 채굴자들이 블록에 먼저 넣으려고 할 것임.)

2) Gas limit

gas limit 이란,
"내가 설정하는 내 트랜잭션에서 사용할 최대 개스이다. "
block gas limit 이란,
"네트워크에서 정한, 블록에 허용된 최대 개스이다.

If / Else

문법은 자바스크립트와 같다.

function IfElse ( uint x) public pure returns (uint) {
		if(x<10) {
        	return 0;
        // x가 10보다 작으면 0을 반환
        }
        else if (x>=10){
        	return 1;
        } 
        // x가 10보다 크거나 같으면 1을 반환

For and While Loop

while 과 do while 은 잘 안쓰임. gas limit을 넘어 트랜잭션이 중단될 수 있기 때문.

1) for 문

문법 :

for ( 초기 상태, 조건, 조건확인후 초기상태를 변화시킬 함수){
		반복할 함수
        }

for (uint i =0; i <10; i++){
if(i==5){
break;
}
}

2) while 문

문법 :

while (조건){
	반복할 함수;
    }

Do while 과 차이 구글링

do ~ while 은 선실행 후평가문. 한번은 무조건 실행.

Mapping

문법 :

mapping( key값 => value값) mapping 이름

key 값은로는 uint, address bytes 등이 올수 있고,
value 값으로는 아무거나 와도 된다.

참고로 이중으로 사용이 된다.

ex)
mapping (address => mapping (uint => bool)) public nested;

Array

python에서 list과 같은 개념.

1) 선언방법
uint [] public array1;
혹은
uint [] public array2 =[ 1,2,3];

2) 특징
전체 array를 반환할 수 있음. 단, 길이가 정해진 array일 경우

3) 추가하기

array1.push(~);

4) pop 시키기
마지막 요소를 빼내고, array 길이가 1 준다.

array1.pop(~);

5) 길이 구하기
array1.length;

6) 삭제하기
방법 1 : delete array [삭제하려는 index];
방법 2: pop을 이용한 함수 만들기

uint[] public array1 = [1,2,3,4];
function remove(uint index) public {
	array1[index] = array1[array1.length -1]; 
    //삭제하려는 항목의 인덱스와 마지막 항목의 인덱스를 바꿈
    array.pop();
    }
    
 remove (1);
 // 
 [1,4,3]
 작동과정
 [1,2,3,4] ->index change-> [1,4,3,2]->pop! -> [1,4,3]

Enum

contract 밖에서도 선언될 수 있다.
열거할 때 사용.

1) 문법
enum 이름 {
element1,
element2,
element3
}

2) 좀 이해 안되는 부분

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.3;
contract Enum {
    // Enum representing shipping status
    enum Status~~이름이지?~~ {
        Pending,
        Shipped,
        Accepted,
        Rejected,
        Canceled
    }
    // Default value is the first element listed in
    // definition of the type, in this case "Pending"
    Status public status;
    // Returns uint
    // Pending  - 0
    // Shipped  - 1
    // Accepted - 2
    // Rejected - 3
    // Canceled - 4
    function get() public view returns (Status) {
        return status~~몬가 솔리디티 내부 변수인듯~~;
    }
    // Update status by passing uint into input
    function set(Status _status) public {
        status = _status;
    }
    // You can update to a specific enum like this
    function cancel() public {
        status = Status.Canceled; ~~이해안됨~~
    }
    // delete resets the enum to its first value, 0
    function reset() public {
        delete status;   ~~이해됨 ~~
    }    
}

Structs

struct을 만듦으로써 새로운 나만의 type를 만들 수 있다.
contract 밖에서 선언될 수 있고 다른 컨트랙트에서 import될 수 있다.

1) 문법
struct 이름 {
//예를들어
string text;
bool completed;
}

2) struct를 initialize(?)하는 3가지 방법

Todo struct의 array 형성
Todo[] public todos;

1. 함수처럼
todos.push(Todo(newText,false));

2. key- value 매핑
todos.push(Todo({text:newText, completed: false}));

3. 통째로 
Todo memory todo;
todo.text = newText;
todo.completed = false;
todos.push(todo);

언제쓰임?

Data Locations

변수들은 storage, memory, 혹은 call data의 위치에 저장된다.

  1. storage : 블록체인에 저장되어 있는 state 변수
  2. memory : 함수가 호출될 동안 존재하는 변수
  3. calldata : external 함수를 위한 인수를 포함한 특별한 데이타 저장소
pragma solidity ^0.8.3;

contract DataLocations {
    uint[] public arr; //**arr 라는 array 선언**
    mapping(uint=>address)map; // **map이라는 uint를 address값 									반환하는 mapping 선언**
    struct MyStruct {
        uint foo;
    } // ** MyStruct 라는 struct는 foo 라는 uint를 element로 가				진다.**
    mapping(uint => MyStruct) myStructs; // ** myStructs 라는 
    					 uint를 앞서 정의한 MyStruct로 
                         		반환하는 mapping 선언 **
                                            

    function f() public {
        
        _f(arr, map, myStructs[1]); //** 새로운 자료형 선언? 모지**

      
        MyStruct storage myStruct = myStructs[1];
        // myStruct라는 이름을 가진 MyStruct의 struct 타입을 myStruccts라는 매핑에 uint값 1을 넣어 대응시킨 것. 
        MyStruct memory myMemStruct = MyStruct(0);
    }
//**MyStruct는 인수가 없는디?**
    function _f(
        uint[] storage _arr,
        mapping(uint => address) storage _map,
        MyStruct storage _myStruct
    ) internal {
        // do something with storage variables
    }

    // You can return memory variables
    function g(uint[] memory _arr) public returns (uint[] memory) {
        // do something with memory array
    }
    
    function h(uint[] calldata _arr) external {
        // do something with calldata array
    }
}

Function

  1. 문법

function 이름 () public pure returns (uint){
함수 내용 ex) return (1)
}

  1. 반환 값들은 이름 매겨질 수 있다.

function named() public pure returns (
uint x, bool b, uint y)
{
return(1, false, 2);
}

각 이름에 할당 될 수 도 있다.
function named() public pure returns (
uint x, bool b, uint y)
{
x =1;
b= false;
y=2;
}
다른 함수로 지정할 수 있다.

View and Pure Functions

view 함수는 state 변화가 없을 것이라는 걸 의미
pure 함수는 어떤 state 변수를 읽거나 변경하지 않을 것이라는 걸 의미

contract ViewAndPure {
uint public x = 1; // state 변수 선언

// Promise not to modify the state.
function addToX(uint y) public view returns (uint) {
    return x + y;
}

// x의 값을 변화시키지 못함. x에다 y를 더한 값을 출력할 뿐.
// Promise not to modify or read from the state.
function add(uint i, uint j) public pure returns (uint) {
return i + j;
//x를 불러오지도, 변화시키지도 않음
}
}```

Error

에러는 트랜잭션 동안 이루어진 변화를 다시 되돌린다.

  1. require(조건,"이유");

조건을 만족하지 않으면 실행하지 않음.

  1. revert()

문법
if(조건){ revert("이유") };

  1. assert

confirm할 때 사용.

uint public balance;
uint public constant MAX_UINT = 2**256 - 1;
function deposit(uint _amount) public {
uint oldBalance = balance;
uint newBalance = balance + _amount;
// balance + _amount does not overflow if balance + _amount >= balance
require(newBalance >= oldBalance, "Overflow");
balance = newBalance;
assert(balance >= oldBalance);

Funciton Modifier

함수 호출 이전, 이후에 실행된다.

1) 제어 접근
2) input값 입증
3) 재진입 해킹으로부터 보호

선언 방법

modifier 이름 () {
내용
_;
}

_; 은 왜?

Constructor

contract 만들면서 실행되는 선택적 함수이다.
배포될 때 딱 한번밖에 실행이 안되는 함수.
ex) 컨트랙트의 주인을 선언할때, 혹은 기본적으로 가지고 있어야 하는 정보를 설정할 ㄸ

왜필요한거야

Inheritance

is를 사용하여 상속.

자녀 컨트랙트에 의해 override 된 함수 :virtual
부모 함수에 의해 override된 함수: override.

순서가 중요하다.?

pragma solidity ^0.8.3;

/* Graph of inheritance
    A
   / \
  B   C
 / \ /
F  D,E

*/

contract A {
    function foo() public pure virtual returns (string memory) {
        return "A";
    }
}

// Contracts inherit other contracts by using the keyword 'is'.
contract B is A {
    // Override A.foo() 
    function foo() public pure virtual override returns (string memory) {
        return "B";
    }
}
!!!!  A.foo는 B를 반환?

contract C is A {
    // Override A.foo()
    function foo() public pure virtual override returns (string memory) {
        return "C";
    }
}
!!!! A.foo는 C를 반환?

// Contracts can inherit from multiple parent contracts.
// When a function is called that is defined multiple times in
// different contracts, parent contracts are searched from
// right to left, and in depth-first manner.

contract D is B, C {
    // D.foo() returns "C"
    // since C is the right most parent contract with function foo()
    function foo() public pure override(B, C) returns (string memory) {
        return super.foo();
    }
}
!!!! 2개를 상속, 오른쪽 노드인 C를 상속, C를 반환
contract E is C, B {
    // E.foo() returns "B"
    // since B is the right most parent contract with function foo()
    function foo() public pure override(C, B) returns (string memory) {
        return super.foo();
    }
}'
!!!! 오른쪽 노드인 B를 상속, C 를 반환 
// Inheritance must be ordered from “most base-like” to “most derived”.
// Swapping the order of A and B will throw a compilation error.
contract F is A, B {
    function foo() public pure override(A, B) returns (string memory) {
        return super.foo();
    }
}

순서: 가장 기초적인 것 부터 파생된 것을 호출.

Visibility

다른 컨트랙트와 상호작용 상태 설정 가능

1) public- 모든 account, contract
2) private - 함수를 정의한 컨트랙트 안에서만- 상속한 contract에서는 호출 불가능.

3) internal - internal 함수를 상속한 contract 안에서만 ?

4) external 다른 컨트랙트나 어카운트?

-> state 변수는 external 로 불리지 못함.

Interface

다른 컨트랙트와 상호작용 가능한 새로운 자료형

interface

시행된 함수를 가질 수 없다?

다른 인터페이스로부터 상속 가능
interface에서 정의된 함수는 external이어야 함
constructor, state 변수를 선언할 수 없음

function 이 있는 construct 혹은 객체로 이해.

Payable

payable을 선언한 함수나 address는 그들의 컨트랙트로 ether을 받을 수 있다.

Sending Ether (transfer, send, call)

보내기
1) transfer
2) send-> true나 false를 반환
3) call -> true나 false를 반환

send call차이점?

받기
1) receive() external payable - > msg.data 에 아무것도 없을 때 사용
2) fallback() external payable-> msg.data에 무언가 있을 때.

what is msg.data?

fallback

어떠한 인수도 받지 않고, 아무것도 반환하지 않는 함수.

존재하지 않는 함수가 시행되었을 때나,
이더가 보내졌는데 그 컨트랙트에 receive()나 msg.data가 비었을 때.

Call

fallback함수를 통해 이더를 보낼때 사용.

Delegatecall :
A가 delegatcall을 B로 시행하면, A의 storage, msg.sender, msg.value를 가지고 B의 코드가 실행된다.

ragma solidity ^0.8.3;

// NOTE: Deploy this contract first
contract B {
    // NOTE: storage layout must be the same as contract A
    uint public num;
    address public sender;
    uint public value;

    function setVars(uint _num) public payable {
        num = _num;
        sender = msg.sender;
        value = msg.value;
    }
}

contract A {
    uint public num;
    address public sender;
    uint public value;

    function setVars(address _contract, uint _num) public payable {
        // A's storage is set, B is not modified.
        (bool success, bytes memory data) = _contract.delegatecall(
            abi.encodeWithSignature("setVars(uint256)", _num)
        );
    }
}

bool success, bytes memory data?

abi...?

Calling other Contract

1) A.함수(인수,인수,인수) 로 호출
2) call 사용 - 권장되지 않음.

Contract that Creates other Contracts

"new"키워드로 다른 컨트랙트를 만들 수 있다.

ex)

pragma solidity ^0.8.3;

contract Car {
    address public owner;
    string public model;
    address public carAddr;

    constructor(address _owner, string memory _model) payable {
        owner = _owner;
        model = _model;
        carAddr = address(this);
    }
}
contract CarFactory {
    Car[] public cars;
    function create(address _owner, string memory _model) public {
        Car car ***what does this means?*** = new Car(_owner, _model);
        cars.push(car);
    }
***만약 새로운 contract라면, Car 이라는 array 가 이미 있잫아. ***
    function createAndSendEther(address _owner, string memory _model) public payable {
        Car car***what does it means?*** = (new Car){value: msg.value}(_owner, _model);
        cars.push(car);
    }

    function getCar(uint _index)
        public
        view
        returns (
            address owner,
            string memory model,
            address carAddr,
            uint balance
        )
    {
        Car car = cars[_index];

        return (car.owner(), car.model(), car.carAddr(), address(car).balance);
    }
}

# Import

Local 파일 import

문법
import "./파일.sol";

깃허브에서 가져올 수도 있다. 

import "urllink.sol";

# Library

컨트랙트와 비슷하지만, state변수 선언이 불가능하고, 이더를 보낼 수 없다. 
library 내 함수들이 internal이면 contract에 내장할 수 있다. 그렇지 않다
그렇지 않다면 ㄴ먼저 시행되고 링크되어야 한다. 

글로벌 함수같은 건가?

사용법 
using 라이브러리명 for 자료형;
post-custom-banner

0개의 댓글