1. Sputnik-DAO 공장 계약Sputnik-DAO는 플랫폼의 분산형 자율 조직(DAO)의 통일된 생성 및 관리를 실현하기 위해 생성형 공장 설계 패턴(Factory Pattern)을 채택합니다.
이 기사에서는 Sputnik-DAO 플랫폼 팩토리 패턴(sputnikdao-factory)의 설계 및 구현을 자세히 소개합니다.
해당 계약의 소스 코드 웨어하우스는 다음 위치에 있습니다.

첫 번째 레벨 제목
2. DAPP 모듈 기능 소개
Sputnik DAO 플랫폼의 DAPP 페이지를 열면 많은 분산형 자율 조직이 플랫폼에서 자체 DAO 인스턴스 개체(Sputnikdaov2 계약)를 생성하고 사용자 정의한 것을 볼 수 있습니다.
2022년 3월 현재 이 플랫폼에서 생성된 가장 활발한 DAO는 news.sputnik-dao.near이며, 3051개의 제안(제안)이 공개 투표 중이거나 마감 상태입니다.

📄독자의 편의를 위해 계약의 구조도를 참조용으로 위에 제공합니다.

즉, Sputnik DAO 플랫폼을 기반으로 생성된 모든 DAO 인스턴스 계약은 NEAR 계정의 하위 계정에 배포됩니다. 예를 들면 다음과 같습니다.
pcp.sputnik-dao.near
test-dao-bro.sputnik-dao.near
blaqkstereo.sputnik-dao.near
octopode-dao.sputnik-dao.near
NEAR 프로토콜의 하위 계정 정의는 https://docs.near.org/docs/concepts/account#subaccounts 🔗에서 참조할 수 있습니다.
아래 그림과 같이 분산형 조직은 NEAR 메인 네트워크에서 공개적으로 거래를 개시할 수 있으며, sputnikdao-factory 컨트랙트에서 제공하는 create() 메서드를 호출하여 새로운 DAO 인스턴스를 생성할 수 있습니다.

3. sputnikdao-factory 계약 코드의 해석
Rust 팩토리 모드 컨트랙트의 작성 방법에 대한 이해를 돕기 위해 이 글에서는 sputnikdao-factory의 컨트랙트 코드를 깊이 있게 해석합니다.
3.1 DAO 생성
스푸트니크다오 공장 계약 상태는 주로 다음 두 부분으로 구성됩니다.

factory_manager: DAO 인스턴스를 생성/삭제/업데이트하는 일련의 메서드를 제공하는 계약의 주요 내부 함수 논리 구현입니다.
daos: 플랫폼 히스토리에 생성된 모든 DAO 인스턴스의 NEAR 계정 주소를 기록하는 컬렉션 데이터 구조를 채택합니다.
DAO 인스턴스를 생성하는 데 사용되는 sputnikdao-factory 계약 메서드 create()는 다음과 같이 정의됩니다.

코드의 3-5행의 기능은 create() 메서드를 호출할 때 함수 매개변수로 지정된 사용자 이름을 완성하여 향후 DAO 계약을 배포하기 위한 NEAR 하위 계정 주소를 얻는 것입니다. 여기서 env::current_account_id()는 sputnikdao-factory 계약의 주소, 즉 sputnik-dao.near를 나타냅니다.
코드의 6-11행은 create() 메서드가 factory_manager.create_contract를 호출한 후 콜백 함수 on_create의 함수 매개 변수를 구성합니다.
코드의 12-19행은 팩토리 계약에서 factory_manager가 제공하는 create_contract 인터페이스를 호출하여 create() 메서드 호출자를 위한 새 DAO 인스턴스 계약을 만들고 배포합니다. 동시에 새로 배포된 DAO 인스턴스 컨트랙트의 경우 create_contract 파라미터 args를 통해 컨트랙트의 기본 구성 정보를 Base64 문자열 형태로 전달할 수 있습니다.
다음은 Sputnik-DAO 플랫폼에서 DAO 인스턴스 계약을 생성하기 위해 NEAR 메인넷의 분산 조직에서 사용하는 트랜잭션입니다.
FyECaggFxATGaUMrRKkbotRWAPkhjw5SBnZfRHpzSiQ8🔗
이 트랜잭션은 sputnikdao-factory 계약 코드에서 create() 메서드를 호출하고 multicall.sputnik-dao.near 하위 계정 생성을 실현하며 해당 DAO 인스턴스의 계약 코드를 성공적으로 배포합니다(구체적인 구현 세부 사항은 자세한 내용은 나중에 설명을 확장하십시오).


Base64 디코딩 후 args 매개변수의 구체적인 내용은 다음과 같습니다.
이 내용은 바로 multicall.sputnik-dao.near 컨트랙트 배포 시 컨트랙트 초기화 메소드 new() 실행 시 필요한 컨트랙트 구성 정보입니다.
다음 기사에서는 factory_manager.create_contract의 특정 구현을 자세히 분석합니다.

이 함수의 매개변수는 다음과 같이 지정됩니다.
code_hash: Sputnik-DAO 플랫폼에서 제공하는 표준 DAO 인스턴스 계약 템플릿 코드의 해시 값입니다.
account_id: multicall.sputnik-dao.near와 같은 향후 새로 생성되는 DAO 인스턴스 컨트랙트의 배포 계정으로, 이 매개변수의 내용은 create_contract()의 상위 함수인 create()에 구성되어 있습니다.
new_method: 새로 생성된 DAO 인스턴스 컨트랙트에서 컨트랙트 초기화 기능을 지정합니다. 일반적으로 new()입니다.
args: 다음 두 가지 측면을 포함하여 DAO 인스턴스 계약 초기화 함수 new()를 실행하는 데 필요한 구성 정보입니다.
분산형 자율 조직에서 제공하는 DAO 기본 정보: Config

5. callback_method: create_contract() 메소드 실행 후 콜백 함수를 지정하며, 이 팩토리 컨트랙트에서 새로운 DAO 인스턴스 컨트랙트 정보를 유지 및 처리하는데 사용됩니다.
6. callback_args: 콜백 함수의 함수 매개변수.
이 기능의 실행은 주로 다음 단계로 나뉩니다.
코드의 15-22행은 팩토리 계약에서 제공하는 DAO 인스턴스 계약 템플릿 코드(wasm 형식)를 찾아 code_hash에 따라 0번 레지스터에 로드합니다.
코드의 23-25행은 다음 모든 단계(3-6)의 처리 결과를 추적하는 Promise를 구성합니다.
코드의 26-27행은 DAO 인스턴스 계약을 배포하기 위한 계정을 생성합니다.
코드 28-29는 NEAR 토큰을 새로 생성된 계정으로 전송합니다. 이 계정은 원래 공장 계약 create() 메서드의 호출자가 attach_deposited 금액에서 발생합니다.
코드의 30-31행은 레지스터 0에서 wasm 코드를 읽고 계약을 배포합니다.
코드의 32-41행은 DAO 인스턴스 계약 코드의 초기화 함수 new()를 호출합니다.
최종 DAO 인스턴스 컨트랙트가 배포된 후 on_create() 함수는 factory_manager.create_contract() 실행 코드 32-53 라인의 끝에서 다시 호출됩니다.
다음은 콜백 함수 on_create의 내부 코드 구현입니다.
이 함수의 특정 처리 논리는 다음과 같습니다.
위의 단계(3-6)에서 오류가 발생하여 정상적으로 실행되지 않는 경우 콜백 함수 on_create()에서 near_sdk::is_promise_success() 쿼리를 호출하여 얻은 Promise의 반환 결과는 false가 됩니다. 이때 원래 팩토리 컨트랙트 create() 메서드 호출자가 부착_예치한 NEAR 토큰의 양은 환불됩니다.
위의 단계(3-6)가 올바르게 수행되었다면 사용자가 요청한 새로운 DAO 인스턴스 컨트랙트(Sputnikdaov2)가 정상적으로 생성되었음을 의미합니다. 동시에 공장 계약은 DAO 인스턴스 계약의 하위 계정 주소를 기록하고 추적합니다.
보조 제목

텍스트
텍스트
텍스트
코드 위치: sputnikdao-factory2/src/lib.rs # Line136-149
factory_manager.update_contract()의 처리 세부 사항은 다음과 같습니다. 이 인터페이스는 해당 DAO 인스턴스 계약에서 update() 함수의 호출을 실현할 수 있습니다.
다음 사항을 언급할 가치가 있습니다.
Sputnik-DAO 코드를 분석하는 동안 BlockSec은 Factory 계약에서 Sputnik-DAO를 사용하는 모든 계약에 영향을 미칠 심각한 보안 문제를 발견했습니다. 프로젝트 당사자에게 연락한 후 문제가 최종적으로 확인되고 제 시간에 수정되었습니다.
💡보안 취약성은 구체적으로 다음과 같이 설명됩니다.
코드의 이전 버전에서 sputinikdao 팩토리 계약에서 제공하는 public update() 메서드에는 다음과 같은 키 어설션 검사가 없었습니다. 이로 인해 메서드는 누구나 호출할 수 있습니다.
공교롭게도 DAO 인스턴스 계약(Sputnikdaov2 계약)은 기본적으로 교차 계약 호출을 통해 Sputnik-DAO Factory에서 이 계약을 업그레이드할 수 있도록 합니다.
DAO 인스턴스 계약에 구현된 update() 메서드는 다음과 같으며 코드는 sputnikdao2/src/upgrade.rs에 있습니다. # Line 62
위 코드의 9행에서 factory_info.auto_update 값은 DAO 인스턴스 계약이 배포되고 초기화를 위해 new() 메서드를 호출할 때 기본적으로 True로 설정됩니다.
DAO 인스턴스 계약의 new() 메서드는 다음과 같이 구현됩니다. 코드는 sputnikdao2/src/lib.rs에 있습니다. # Line 83-104
요약하면 일반 사용자(Factory 계약 및 DAO 계약 자체가 아님)는 Factory 계약에서 제공하는 pub fn update() 메서드를 통해 모든 DAO 계약의 코드를 업그레이드(변조)할 수 있으며, 이는 Sputnik-DAO 플랫폼 및 Sputnik-DAO 플랫폼에 의존하는 모든 계약 프로젝트는 큰 보안 위험을 초래합니다.
🪴 다행히 이 문제가 발견되었을 때 이 버전의 코드는 NEAR 메인넷에 아직 런칭되지 않았기 때문에 손실은 없었습니다.
프로젝트 당사자의 빠른 대응으로 인해 합리적인 화이트리스트 검증 메커니즘을 추가하여 취약점을 올바르게 수정했습니다😊
첫 번째 레벨 제목
텍스트
위에서 발견 및 수정된 취약점 외에도 Sputnik-DAO Factory 계약의 보안은 주로 다음 측면에서 보장됩니다.
다음 함수는 상태 변수를 수정하지 않습니다.
get_owner(&self)
get_number_daos(&self)
get_default_version(&self)
get_default_code_hash(&self)
get_daos(&self, from_index: u64, limit: u64)
get_dao_list(&self)
get_contracts_metadata(&self)
get_code(&self, code_hash: Base58CryptoHash)
[액세스 제어] 계약에 의해 열린 권한 있는 기능, 이러한 기능은 계약 소유자(또는 DAO 계약 계정)만 실행할 수 있으며 메소드에 해당 주장이 있습니다. 예를 들면 다음과 같습니다.

프로젝트 당사자의 빠른 대응으로 인해 합리적인 화이트리스트 검증 메커니즘을 추가하여 취약점을 올바르게 수정했습니다😊
커밋 수정 참조: 518ad1d97614fff4b945aba75b6c8bd2483187a2🔗