無知

갈 길이 먼 공부 일기

기술 공부/블록체인

스마트 컨트랙트 (5-5) | Solidity(솔리디티) Contracts, Inheritance, Interface

moozii 2022. 4. 18. 19:12

 

@Contracts in Solidity Doc https://docs.soliditylang.org/en/v0.8.13/contracts.html#

 

1. Contract

 

Contracts can be created “from outside” via Ethereum transactions or from within Solidity contracts. IDEs, such as Remix, make the creation process seamless using UI elements. One way to create contracts programmatically on Ethereum is via the JavaScript API web3.js. It has a function called web3.eth.Contract to facilitate contract creation.

When a contract is created, its constructor (a function declared with the constructor keyword) is executed once. A constructor is optional. Only one constructor is allowed, which means overloading is not supported. After the constructor has executed, the final code of the contract is stored on the blockchain. This code includes all public and external functions and all functions that are reachable from there through function calls. The deployed code does not include the constructor code or internal functions only called from the constructor. Internally, constructor arguments are passed ABI encoded after the code of the contract itself, but you do not have to care about this if you use web3.js. If a contract wants to create another contract, the source code (and the binary) of the created contract has to be known to the creator. This means that cyclic creation dependencies are impossible.

https://docs.soliditylang.org/en/v0.8.13/contracts.html#creating-contracts 

 

 

- constructor: contract 생성 시 트랜잭션에 의해 호출

- internal constructor: abstract contract 생성

- fallback function: 일반적으로 외부 계정에 의해 호출

- selfdestruct 함수: contract 삭제 및 잔여 이더리움 송금

- contract 사용은 신규 컨트랙트 생성 혹은 기존 컨트랙트 호출 2가지 방법으로 가능

 

pragma solidity >=0.4.0 <0.7.0;

contract Example{
	uint state_variable = 15;
    address payable owner;
    
    constructor() public {
    	// called by contract creation transaction
    	owner = msg.sender;
        
        // constructor can be either public or internal
        // if constructor is internal, we make abstract contract
    }
    
    function set(uint parameter) public modifer_ex {
    	state_variable = parameter;
    }
    
    function () external payable {
    	// if function has no name, it is a fallback function
    	// fallback function can also be called as default function
        
        // defined as external, since mostly called by external accounts
        // as the content is empty, it just receives ethers
    }
    
    function destroy() public modifier_ex {
    	// there is no destructor. only constructor exists
        // we can use selfdestruct function to destroy contract and send left ethers to the address
        selfdestruct(owner);
    }
    
    event event_ex(uint event_input);
    
    modifier modifier_ex(){
    	require(msg.sender == owner);
        _;
    }
    
    
}

contract HowToUseContract_1{
	// 1. create contract with new keyword
    function create() public returns (address) {
    	Example obj = new Example();
        obj.set(10);
        
        return address(obj);
    }
}

contract HowToUseContract_2{
	// 2. use the address of contract already deployed
    function call(address payable addr) public returns (uint) {
    	Example obj = Example(addr);
        return obj.get();
    }
}

 

 

 

- function visibility에 따라 호출 가능 여부 상이

 

pragma solidity >=0.4.0 <0.7.0;

contract VisibilityExample_1{
	uint private state_var;
    
    function private(uint input) private pure returns (uint) { return input }
    function public(uint input) public { state_var = input }
    function internal(uint input) internal pure returns (uint) { return input }
    function () external payable {}
}

contract VisibilityExample_2{
	function visibility_test() public {
    	VisibilityExample ex = new VisibilityExample();
        uint test_data = ex.private(0);
        // compile error since private function can not be called
        
        ex.public(0);
        
        test_data = ex.internal(0);
        // compile error since internal function can not be called
        // no error if VisibilityExample_2 inherited VisibilityExample_1
    }
}

 

 

 

- getter function

 

pragma solidity >=0.4.0 <0.7.0;

contract Getter_ex {
	uint public test_data;
}

contract Getter_ex_2{
	function getter_test() public returns (uint) {
    	Getter_ex ex = new Getter_ex();
        
        return ex.test_data()
        // compiler provides getter function with the name of state variable
        // returns the value of the state variable
    }
}

contract StateVarInArray {
	uint[] public test_array;
}

contract StateVarInArray_2{
	function getter_test() public returns (uint) {
    	StateVarInArray ex = new StateVarInArray();
        
        return ex.test_array()
        // Error: Getter method needs index when state var is an array
        // Do not return the whole array to prevent paying gas too much
        // If you want to get whole array returned, make a new custom function
    }
}

 

 

 

 

 

2. Function Overloading

- function overloading: contract 내 동명의 function이 서로 다른 parameter를 받을 경우.

파라미터 타입에 따라 어떤 함수를 호출하는지가 달라진다.

 

pragma solidity >=0.4.0 <0.7.0;

contract ContractEx{
	function f_overload(uint input_1) public pure returns (uint) {
    	return input_1
    }
    
    function f_overload(uint input_1, bool input_2) public pure returns (uint) {
    	return input_2 ? input_1 : input_1 * 2;
    }
}

 

 

 

 

 

3. Inherit

 

Inheritance: Solidity supports multiple inheritance including polymorphism. Polymorphism means that a function call (internal and external) always executes the function of the same name (and parameter types) in the most derived contract in the inheritance hierarchy. This has to be explicitly enabled on each function in the hierarchy using the virtual and override keywords. ... It is possible to call functions further up in the inheritance hierarchy internally by explicitly specifying the contract using ContractName.functionName() or using super.functionName() if you want to call the function one level higher up in the flattened inheritance hierarchy.

When a contract inherits from other contracts, only a single contract is created on the blockchain, and the code from all the base contracts is compiled into the created contract. This means that all internal calls to functions of base contracts also just use internal function calls (super.f(..) will use JUMP and not a message call). State variable shadowing is considered as an error. A derived contract can only declare a state variable x, if there is no visible state variable with the same name in any of its bases. The general inheritance system is very similar to Python’s, especially concerning multiple inheritance, but there are also some differences.


https://docs.soliditylang.org/en/v0.8.13/contracts.html#inheritance  

 

 

- Inheritance는 두 contract 간에 parent-child relation을 형성한다.

- parent contract에서 선언한 variable, function, modifier, event을 child contract에서도 사용 가능하다. 

- keyword “is”를 사용해 두 contract 간의 Inheritance 관계를 표현한다.

 

pragma solidity >=0.4.0 <0.7.0;

contract Parent {
	uint internal state_var;
    
    function set(uint x) public{
    	state_var = x;
    }
}

contract Child is Parent {
	function get() public view returns (uint) {
    	return state_var;
    }
}

contract Example {
	Child child = new Child();
    
    function f() public returns (uint) {
    	child.set(10);
        return child.get();
    }
}

 

 

 

- multiple inheritance의 경우 더 뒤에 상속하는 것을 우선으로 처리한다

 

pragma solidity >=0.4.0 <0.7.0;

contract Parent {
	address payable owner;
	constructor() public { owner = msg.sender; }
}

contract Child is Parent {
	function kill() public {
    	if (msg.sender == owner) selfdestruct(owner);
    }
}

contract GrandChild_1 is Child {
	function kill() public {
    	/* do cleanup procees for GrandChild */
        super.kill();
        // Child.kill(); will not be called since GrandChild2 is superior
        // But super.kill(); will call both
    }
}

contract GrandChild_2 is Child {
	function kill() public {
    	/* do cleanup procees for GrandChild */
        super.kill();
        // Child.kill(); will be called but not for 1, since 2 is superior
        // But super.kill(); will call both
    }
}

contract GrandGrandChild is GrandChild_1, GrandChild_2{
	// call 2 then 1 since the last one is the recent one
    // Be careful with the order to inherit
}

contract Client {
    function f() public {
    	Child obj = new GrandGrandChild();
        obj.kill();
        // call GrandChild_2 kill() first
    }
}

 

 

 

- 상속 컨트랙트를 생성할 때 인풋을 처리하는 방법 2가지

 

pragma solidity >=0.4.0 <0.7.0;

contract Parent {
	uint data;
	constructor(uint _input) public { data = _input; }
}

// 1. pass parameter with the parent class
contract Child_1 is Parent(1) {
	constructor() public { }
}

// 2. pass parameter with constuctor modifier
// use when we have to call with the input from child
contract Child_2 is Parent {
	constructor(uint _child_input) Parent(_child_input + 3) public { }
}

 

 

 

 

 

4. Abstract Contract & Interface

 

Abstract Contracts: Contracts need to be marked as abstract when at least one of their functions is not implemented. Contracts may be marked as abstract even though all functions are implemented. This can be done by using the abstract keyword as shown in the following example. Note that this contract needs to be defined as abstract, because the function utterance() was defined, but no implementation was provided (no implementation body { } was given).

Such abstract contracts can not be instantiated directly. This is also true, if an abstract contract itself does implement all defined functions. The usage of an abstract contract as a base class is shown in the following example:

(...)

Abstract contracts decouple the definition of a contract from its implementation providing better extensibility and self-documentation and facilitating patterns like the Template method and removing code duplication. Abstract contracts are useful in the same way that defining methods in an interface is useful. It is a way for the designer of the abstract contract to say “any child of mine must implement this method”.

https://docs.soliditylang.org/en/v0.8.13/contracts.html#abstract-contracts 

 

 

- Abstract contract는 contract가 제공하는 서비스와 이의 구현을 분리한다

- contract가 갖춰야 할 기본 구조를 정의한다

- 상속받는 child contract가 반드시 구현해야 할 메소드를 정의한다

 

pragma solidity >=0.4.0 <0.7.0;

contract Abstract {
	// create abstract contract since some functions are not developed.
    function completed_in_full() public returns (bytes32);
}

contract Full is Abstract{
	function completed_in_full() public returns (bytes32){
    	return "Completed";
    }
}

contract Normal {
	function example() public {
    	Abstract ex = new Abstract();
        // Error: Abstract Contract Cannot Make an Instance
        
        Abstract ex_2 = new Full();
        // No Error: Created an Instance
    }
}

 

 

 

Interfaces: Interfaces are similar to abstract contracts, but they cannot have any functions implemented. There are further restrictions:

1. They cannot inherit from other contracts, but they can inherit from other interfaces.
2. All declared functions must be external in the interface, even if they are public in the contract.
3. They cannot declare a constructor.
4. They cannot declare state variables.
5. They cannot declare modifiers.

https://docs.soliditylang.org/en/v0.8.13/contracts.html#abstract-contracts 

 

 

- Interface

- Abstract contract와 유사하다
- function declaration만 가질 수 있고 구현이나 state variable을 가질 수 없다
- 모든 function이 external로 선언되어야 한다

 

pragma solidity >=0.4.0 <0.7.0;

interface Interface {
	// interface is similar with abstract contract
    // interface only possess function definition with no implementation
    // interface cannot get state variable
    // all functions should be declared as external functions
    
    function getVal() external view returns (uint);
    function setVal(uint) external;
}

contract Contract is Interface {
	uint private data;
    
	function getVal() public view returns (uint) {
    	return data;
    }
    function setVal(uint x) public {
    	data = x;
    }
}

 

 

[출처] https://docs.soliditylang.org/en/v0.8.13/contracts.html#

 

Contracts — Solidity 0.8.13 documentation

Contracts Contracts in Solidity are similar to classes in object-oriented languages. They contain persistent data in state variables, and functions that can modify these variables. Calling a function on a different contract (instance) will perform an EVM f

docs.soliditylang.org