체인의정석

하나의 컨트렉트를 여러개로 분리해서 만들 때의 주의 사항 본문

블록체인/Solidity

하나의 컨트렉트를 여러개로 분리해서 만들 때의 주의 사항

체인의정석 2022. 7. 7. 17:41
728x90
반응형

컨트렉트의 가독성을 높이기 위해서 opensea의 seaport 코드를 참고하여 분석을 진행하였다.

먼저 오픈씨의 메인 컨트렉트가 상속 받는 Consideration 컨트렉트이다.

https://github.com/ProjectOpenSea/seaport/blob/main/contracts/lib/Consideration.sol

 

GitHub - ProjectOpenSea/seaport: Seaport is a marketplace protocol for safely and efficiently buying and selling NFTs.

Seaport is a marketplace protocol for safely and efficiently buying and selling NFTs. - GitHub - ProjectOpenSea/seaport: Seaport is a marketplace protocol for safely and efficiently buying and sell...

github.com

이 컨트렉트를 보면 생성자가 들어있는 것을 볼 수 있다.

OrderComiber의 생성자인 address형태의 conduitController가 있다.

    constructor(address conduitController) OrderCombiner(conduitController) {}

그럼 OrderComiber.sol에 들어가 보겠다.

contract OrderFulfiller is
    BasicOrderFulfiller,
    CriteriaResolution,
    AmountDeriver
{
    /**
     * @dev Derive and set hashes, reference chainId, and associated domain
     *      separator during deployment.
     *
     * @param conduitController A contract that deploys conduits, or proxies
     *                          that may optionally be used to transfer approved
     *                          ERC20/721/1155 tokens.
     */
    constructor(address conduitController)
        BasicOrderFulfiller(conduitController)
    {}

보면 받은 consturcotr를 BasicOrderFulfiller로 넘겨준다.

    constructor(address conduitController) OrderValidator(conduitController) {}

BasicOrderFulfiller는 또다시 OrderValidator로 넘겨주고

  constructor(address conduitController) Executor(conduitController) {}

OrderValidator는 또다시 Executor로 넘겨주고

    constructor(address conduitController) Verifiers(conduitController) {}

요건 다시  Verifiers에서 Assertions로

    constructor(address conduitController) Assertions(conduitController) {}

이런식으로 정말 계속계속 들어간다.

 

난 constants로 변수를 뺀 뒤 최하단 경로에서 한번 설정해주면 될 줄 알았는데 그게 아니고 위에서 부터 아래로 쭉쭉 넣어줘야 하나보다. 여기에 맞춰 생성자 함수를 다시 수정해서 초기에 생성자 변수를 받으면 상속받은 애도 쭉 타고 내려와서 사용하는 식으로 하였다.

 

이렇게 한 이유는 EIP712 오픈제플린 코드를 상속하는 커스터마이징 EIP721 컨트렉트를 사용하기 때문이였는데, 오픈씨도 저렇게 쭉쭉 보내버리는걸 보니 나도 그냥 쭉쭉 보내버리고 상수는 그냥 내버려 두었다.

 

그런데 계속 발생하는 에러.

사실 여태까지 코드의 가독성을 높이려고 분리하려는 시도를 해본 적이 없었다.

 

그러다 분석 후 알게 된 사실

Ownable과 같은 추상 컨트렉트는 퍼블릭 함수를 써서 호출 바로 가능하지만

일반 컨트렉트의 경우 public으로 되어 있는것은 호출 되지 않는것을 확인 할 수 있었다.

=> 알고보니 단순히 internal 함수를 직접 호출하려 해서 되지 않는 에러였다. ㅋㅋㅋㅋ 잘못된 가설.. 강의하다가 큰일 날 수 있기 때문에 잘못된건 바로바로 이해하고 수정해야 한다.

 

아무튼 분석 결과 코드를 효과적으로 분리하는 스타일은 2가지 케이스로 좁혀졌다.

일반 컨트렉트로 두고 상속하는 애들을 internal로 두어서 코드를 간결히 만들거나

추상 컨트렉트로 두고 퍼블릭을 그대로 사용한 후 상속 받아서 갈결히 만들거나.

 

결국 최상단 컨트렉트가 메인이기 때문에 추상 컨트렉트와 internal을 적절히 섞여 써야 된다는게 포인트 인거 같다.

일단 코딩 스타일도 추상 & public으로 하는것이 깔끔 하기 때문에 그렇게 하기로 결정!

 

기왕 착각한 김에 결국 직접 배포되는 애 빼고는 다 추상 컨트렉트로 바꿔 버렸다.

그리고 맘편이 public 함수로 쓰고

 

앞으로  아래 2가지 중 택 1을 해서 코드의 가독성을 높이는 것으로!

일반 컨트렉트로 두고 상속하는 애들을 internal로 두어서 코드를 간결히 만들거나

추상 컨트렉트로 두고 퍼블릭을 그대로 사용한 후 상속 받아서 간결히 만들거나.

728x90
반응형
Comments