INTRODUCE
해당 프로젝트는 블록체인을 Stake 서비스로 ProofOfStake(PoS) 와 비슷하다가 착각할 수 있지만 엄연히 다른 서비스입니다. PoS는 새로운 블록을 쌓기 위해 연산을 하고 그에 대한 보상을 지급하는 서비스인 반면, 해당 Stake 서비스는 블록체인 재화를 예치하고, 이를 통해 보상을 지급하는 서비스입니다. 즉, 은행 예치에 대한 이자와 비슷하다고 보시면 될거 같습니다.
프로젝트에서는 블록체인 Contract 를 제작하고 테스트 및 검증 배포와 함께 B.E 서비스를 통해 블록체인 실시간 데이터를 API를 통해 제공하였으며, Admin 서비스로는 Grafana를 통해 데이터 모니터링 및 BackOffice API 를 제작하였습니다.
※프로젝트에서 블록체인과 B.E 개발을 담당하여 포트폴리오를 2개로 분할합니다.
프로젝트 목표
- 기획에 맞는 Contract 설계
- 블록체인 계약의 로직과 안전성 검증
- 백앤드 서비스를 통한 Portal 연동 기능 구현
- Admin 제공용 Grafana 데이터 수집 기능 구현
Stake란?
Stake 서비스가 독자적인 서비스는 아닙니다. 여러 블록체인 거래소와 플랫폼 서비스에서 이미 서비스중이며, 비슷한 서비스는 아래 링크로 확인할 수 있습니다.
빗썸 : https://www.bithumb.com/react/staking
업비트 : https://upbit.com/staking/items
클레이스왑 : https://klayswap.com/ko/pool
바이낸스 : https://www.binance.com/en/earn
등 다양한 거래소 & 플랫폼에서 스테이킹 서비스를 제공하고 있습니다. 그렇다면 왜 PoS 채굴이 아닌데 스테이킹 서비스를 출시하고 이를 통해 보상을 지급할까? 라는 의문이 있을 겁니다. 그에 대한 간단한 설명으로 여러 사이트에서 설명해주고 있습니다.
스테이킹에 대한 설명 : https://www.coinex.com/ko/academy/detail/1207-staking-pool?pId=1

즉, 블록체인 Node를 직접 띄워서 해당 네트워크에 직접 PoS 를 참여할 수 없는 이용자들에게 자산을 예치받고 대신 PoS에 참여하고 이를 기반으로 보상을 지급하기 위해 Stake 서비스를 제공하는 것입니다.
뿐만 아니라 Uniswap 서비스를 이용하면 여러 토큰을 묶어 DEX 토큰을 발행이 가능합니다. 이를 통해 새로운 토큰을 유통하거나 시장에 풀 수 있습니다.
SKILL
블록체인
Language : Solidity, TypeScript
Library: Openzeppelin, Hardhat, Mocha
Infrastructure: Remix, Ganache, Hardhat
BackEnd
Language : Golang
FrameWork : Native
Infrastructure: Gorm, MemoryCache, HTTP, goRoutine
담당 업무
담당 업무
블록체인
- Contract 기능 추가 및 역할 리펙토링
- 테스트 코드를 통한 검증
- 배포 스크립트 작성
BackEnd
- 메타 데이터 API 구현
- 실시간 블록체인 데이터 프로파일링
- 데이터 수집 기능 구현
- Garafana DB 연동 및 데이터 저장

블록체인 Contract에는 다양한 기능이 요구되었다. 해당 기능들을 추가함에 따라 Contract의 용량은 자연스럽게 거대해지며 EIP-170 규약에 의해 블록체인에 배포하기 위한 24.000KIB를 초과하게 되었다. 이로 인하여 Contract를 역할별로 분할하게
1. 확장을 위한 Router Contract
2. 자금을 관리하는 Contract
3. 데이터를 관리하는 Contract
이렇게 기능 별 Contract로 나누고 보안적인 요소를 위해 여러가지 기능을 추가하였습니다. OpenZeppelin의 ReentrancyGuard를 활용하여 Contract의 재진입을 방지하였으며, AccessControl을 통해 권한 관리를 통해 Contract에 권한을 추가하여 기능을 제한하였습니다. 이 외에도 Pausable, SafeMath, EnumerableSet 등을 활용하여 Contract를 개발하였습니다.
Contract를 개발하고 TypeScript와 Hardhat, Mocha를 사용한 테스트 코드를 통해 개발한 Contract를 검증하고 테스트하였습니다. 테스트 코드 작성으로 인하여 100%에 해당하는 Coverage를 달성하였습니다.
Contract 개발 당시 용량으로 인하여 최적화와 기능의 분할에 대해서 많은 고민이 있었습니다. 필수적으로 필요한 기능을 남기고 Contract를 개발하였음에도 24.000KIB 를 초과하는 상황에서 Optimization도 최대로 한 상태였습니다. 이러한 상황에서 CrossChain Contract를 개발하는 팀원에게 도움을 요청하여 Router Contract를 사용할 것을 조언 받았으며, Delegate Call을 통해 작업하려 했지만, 해당 기능을 구현 시 보안적인 문제로 인하여 잠재적으로 보류 되었습니다.
이후, 다른 서비스의 Contract 지속적으로 개발 및 리펙토링 하면서 여러 기능을 추가하여 해당 서비스를 리펙토링 할 수 있을거라 생각하였지만, 한번 배포되면 수정이 불가능한 Contract의 특성상 리펙토링을 하기 위해서는 대규모 작업이 필요로 했습니다.
프로젝트 후기 및 문제 해결
해당 프로젝트는 가장 힘들었고 노력했던 프로젝트로 가장 애착이 있는 프로젝트입니다.
1. 컨트랙트 용량 최적화 및 기능 분리
- 기능 단위로 컨트랙트를 분리하고, Router Contract를 통해 기능들을 연결하는 구조 설계
- AccessControl을 도입하여 Router Contract는 인증된 주소만 접근 가능하도록 보안 설정
2. 예치 Token 확장 대응
- 다양한 예치 Token 지원을 위해 Factory Contract 도입
- Salt + new 키워드를 활용해 특정 조건에 따라 동적으로 Contract를 배포할 수 있도록 구성
3. 예치 자산 보호 및 보안 강화
- Contract 해킹 및 오류 발생에 대비해, 예치된 재화를 분리하여 관리하는 전용 재화 관리 Contract를 설계
- 사용자 자산을 직접 다루는 구조에서 보안 이슈를 고려한 안정성 중심의 설계 적용
4. 다양한 보상 분배 구조
- 여러 종류의 보상을 효율적으로 분배하기 위해 Mapping 구조를 활용
- 보상별 조건 및 대상에 따라 유연하게 접근 가능한 구조로 설계
적용하지 않은 기술 & 이유
- DelegateCall
delegatecall은 호출한 컨트랙트의 데이터를 사용하여 외부 컨트랙트의 코드를 실행하는 방식이지만, 데이터 저장소(Storage)가 호출한 컨트랙트에서 관리되기 때문에 이 프로젝트의 구조 및 보안 요구 사항과 맞지 않았습니다. 따라서, 유지 보수성과 보안상의 이유로 사용을 지양하였습니다. - tx.origin 사용
msg.sender 대신 tx.origin을 사용하는 방식은 외부 호출 체인의 최초 송신자를 가져올 수 있지만, 피싱 공격 등에 취약한 보안 문제가 존재합니다. 실제 해킹 사례에서도 자주 악용되는 기법이기 때문에, 보안성을 고려하여 사용하지 않기로 결정하였습니다.