1. สัญญาโรงงาน Sputnik-DAOSputnik-DAO ใช้รูปแบบการออกแบบโรงงานเชิงสร้างสรรค์ (Factory Pattern) เพื่อตระหนักถึงการสร้างและการจัดการแบบรวมศูนย์ขององค์กรปกครองตนเองแบบกระจายอำนาจ (DAO) ของแพลตฟอร์ม
บทความนี้จะแนะนำการออกแบบและการใช้งานรูปแบบโรงงานแพลตฟอร์ม Sputnik-DAO (sputnikdao-factory) โดยละเอียด
คลังซอร์สโค้ดของสัญญาที่เกี่ยวข้องอยู่ที่: https://github.com/near-daos/sputnik-dao-contract/tree/518ad1d97614fff4b945aba75b6c8bd2483187a2

ชื่อระดับแรก
2. การแนะนำฟังก์ชันโมดูล DAPP
เปิดหน้า DAPP ของแพลตฟอร์ม Sputnik DAO จะเห็นได้ว่าองค์กรอิสระแบบกระจายอำนาจจำนวนมากได้สร้างและปรับแต่งวัตถุอินสแตนซ์ DAO ของตนเอง (สัญญา Sputnikdaov2) บนแพลตฟอร์ม
ในเดือนมีนาคม 2022 DAO ที่มีการใช้งานมากที่สุดที่สร้างขึ้นภายใต้แพลตฟอร์มนี้คือ news.sputnik-dao.near ซึ่งมีข้อเสนอ 3051 รายการ (ข้อเสนอ) อยู่ในการลงคะแนนสาธารณะหรือสถานะถูกปิด

📄เพื่อความสะดวกของผู้อ่าน แผนภาพโครงสร้างของสัญญามีไว้ด้านบนเพื่อเป็นข้อมูลอ้างอิง

นั่นคือ สัญญาอินสแตนซ์ DAO ทั้งหมดที่สร้างขึ้นบนแพลตฟอร์ม Sputnik DAO จะถูกปรับใช้ภายใต้บัญชีย่อยของบัญชี NEAR ตัวอย่างเช่น:
pcp.sputnik-dao.near
test-dao-bro.sputnik-dao.near
blaqkstereo.sputnik-dao.near
octopode-dao.sputnik-dao.near
สำหรับคำจำกัดความของบัญชีย่อยใน NEAR Protocol คุณสามารถดูข้อมูลอ้างอิงได้ที่ https://docs.near.org/docs/concepts/account#subaccounts 🔗
ดังที่แสดงในรูปด้านล่าง องค์กรที่กระจายอำนาจสามารถเริ่มต้นการทำธุรกรรมอย่างเปิดเผยบนเครือข่ายหลัก NEAR และสร้างอินสแตนซ์ DAO ใหม่โดยเรียกเมธอด create() ที่ให้ไว้ในสัญญา sputnikdao-factory

3. การตีความรหัสสัญญาโรงงานสปุตนิกดาว
เพื่อช่วยให้คุณเข้าใจวิธีการเขียนสัญญาโหมดโรงงานสนิมได้ดีขึ้น บทความนี้จะตีความรหัสสัญญาของโรงงานสปุตนิกดาวอย่างลึกซึ้ง
3.1 การสร้าง DAO
สถานะสัญญาโรงงานสปุตนิกดาวส่วนใหญ่ประกอบด้วยสองส่วนต่อไปนี้:

factory_manager: การนำตรรกะของฟังก์ชันภายในหลักของสัญญาไปใช้ โดยมีชุดของวิธีการในการสร้าง/ลบ/อัปเดตอินสแตนซ์ DAO
daos: ใช้โครงสร้างข้อมูลคอลเลกชัน ซึ่งบันทึกที่อยู่บัญชี NEAR ของอินสแตนซ์ DAO ที่สร้างขึ้นทั้งหมดในประวัติของแพลตฟอร์ม
วิธีการสร้างสัญญาโรงงาน sputnikdao create() ที่ใช้สร้างอินสแตนซ์ DAO มีการกำหนดดังนี้:

ฟังก์ชันของบรรทัดที่ 3-5 ของโค้ดคือการกรอกชื่อผู้ใช้ที่ระบุโดยพารามิเตอร์ฟังก์ชันเมื่อเรียกเมธอด create() เพื่อให้ได้รับที่อยู่บัญชีย่อย NEAR สำหรับการปรับใช้สัญญา DAO ในอนาคต ที่นี่ env::current_account_id() หมายถึงที่อยู่ของสัญญา sputnikdao-factory ซึ่งก็คือ sputnik-dao.near
บรรทัดที่ 6-11 ของโค้ดสร้างพารามิเตอร์ฟังก์ชันของฟังก์ชันการเรียกกลับ on_create หลังจากเมธอด create() เรียก factory_manager.create_contract
บรรทัดที่ 12-19 ของรหัสเรียกอินเทอร์เฟซ create_contract ที่ Factory_manager ให้มาในสัญญาโรงงานเพื่อสร้างและปรับใช้สัญญาอินสแตนซ์ DAO ใหม่สำหรับผู้เรียกใช้เมธอด create() ในเวลาเดียวกัน สำหรับสัญญาอินสแตนซ์ DAO ที่ปรับใช้ใหม่ ข้อมูลการกำหนดค่าพื้นฐานของสัญญาสามารถส่งผ่านในรูปแบบของสตริง Base64 ผ่านอาร์กิวเมนต์พารามิเตอร์ create_contract
ต่อไปนี้เป็นธุรกรรมที่ใช้โดยองค์กรที่กระจายอำนาจใน NEAR mainnet เพื่อสร้างสัญญาอินสแตนซ์ DAO บนแพลตฟอร์ม Sputnik-DAO:
FyECaggFxATGaUMrRKkbotRWAPkhjw5SBnZfRHpzSiQ8🔗
ธุรกรรมนี้เรียกเมธอด create() ในรหัสสัญญา sputnikdao-factory ตระหนักถึงการสร้างบัญชีย่อย multicall.sputnik-dao.near และนำรหัสสัญญาของอินสแตนซ์ DAO ที่เกี่ยวข้องไปใช้ได้สำเร็จ (รายละเอียดการใช้งานเฉพาะจะเป็น ละเอียดในภายหลังขยายความ)


เนื้อหาเฉพาะของพารามิเตอร์ args หลังจากถอดรหัส Base64 คือ:
เนื้อหานี้เป็นข้อมูลการกำหนดค่าสัญญาที่จำเป็นเมื่อดำเนินการวิธีการเริ่มต้นสัญญาใหม่ () เมื่อปรับใช้สัญญา multicall.sputnik-dao.near
บทความต่อไปนี้จะวิเคราะห์การใช้งานเฉพาะของ factory_manager.create_contract อย่างละเอียด:

พารามิเตอร์ของฟังก์ชันนี้ระบุไว้ดังนี้:
code_hash: ค่าแฮชของโค้ดเทมเพลตสัญญาอินสแตนซ์ DAO มาตรฐานที่จัดทำโดยแพลตฟอร์ม Sputnik-DAO
account_id: บัญชีการปรับใช้ของสัญญาอินสแตนซ์ DAO ที่สร้างขึ้นใหม่ในอนาคต เช่น multicall.sputnik-dao.near เนื้อหาของพารามิเตอร์นี้ถูกสร้างขึ้นในฟังก์ชันด้านบน create() ของ create_contract()
new_method: ระบุฟังก์ชันการเริ่มต้นสัญญาในสัญญาอินสแตนซ์ DAO ที่สร้างขึ้นใหม่ โดยทั่วไปคือ new()
args: ข้อมูลการกำหนดค่าที่จำเป็นในการดำเนินการฟังก์ชันการเริ่มต้นสัญญาอินสแตนซ์ DAO new() รวมถึงสองด้านต่อไปนี้:
ข้อมูลพื้นฐานของ DAO ที่จัดทำโดยองค์กรปกครองตนเองแบบกระจายอำนาจ: Config

5. callback_method: ระบุฟังก์ชันการเรียกกลับหลังจากดำเนินการเมธอด create_contract() ซึ่งใช้เพื่อรักษาและประมวลผลข้อมูลของสัญญาอินสแตนซ์ DAO ใหม่ในสัญญาโรงงานนี้
6. callback_args: พารามิเตอร์ฟังก์ชันของฟังก์ชันการโทรกลับ
การดำเนินการของฟังก์ชันนี้แบ่งออกเป็นขั้นตอนต่อไปนี้เป็นหลัก:
บรรทัดที่ 15-22 ของโค้ดค้นหาและโหลดโค้ดเทมเพลตสัญญาอินสแตนซ์ DAO (รูปแบบ Wasm) ที่จัดทำโดยสัญญาจากโรงงานลงในทะเบียนหมายเลข 0 ตาม code_hash
บรรทัดที่ 23-25 ของโค้ดสร้าง Promise เพื่อติดตามผลการประมวลผลของขั้นตอนต่อไปนี้ทั้งหมด (3-6)
บรรทัดที่ 26-27 ของรหัสสร้างบัญชีสำหรับการปรับใช้สัญญาอินสแตนซ์ DAO
รหัส 28-29 โอนโทเค็น NEAR ไปยังบัญชีที่สร้างขึ้นใหม่ ซึ่งมาจากจำนวนเงินที่แนบ_ฝากโดยผู้เรียกของสัญญาโรงงานเดิม create() วิธีการ
บรรทัดที่ 30-31 ของโค้ดอ่านโค้ด wasm จาก register 0 และปรับใช้สัญญา
บรรทัดที่ 32-41 ของรหัสเรียกฟังก์ชันการเริ่มต้นใหม่ () ของรหัสสัญญาอินสแตนซ์ DAO
หลังจากปรับใช้สัญญาอินสแตนซ์ DAO ขั้นสุดท้ายแล้ว ฟังก์ชัน on_create() จะถูกเรียกกลับเมื่อสิ้นสุดโค้ดการดำเนินการของ
ต่อไปนี้คือการใช้โค้ดภายในของฟังก์ชันการเรียกกลับ on_create:
ตรรกะการประมวลผลเฉพาะของฟังก์ชันนี้คือ:
หากมีข้อผิดพลาดในขั้นตอนข้างต้น (3-6) และไม่สามารถดำเนินการได้ตามปกติ ผลลัพธ์ที่ส่งคืนของ Promise ที่ได้รับจากการเรียกใช้การค้นหา near_sdk::is_promise_success() ในฟังก์ชันการเรียกกลับ on_create() จะเป็นเท็จ ในเวลานี้ จำนวนของโทเค็น NEAR ที่แนบ_ฝากโดยผู้เรียกใช้เมธอด create() ของสัญญาโรงงานเดิมจะได้รับคืน
หากดำเนินการตามขั้นตอนข้างต้น (3-6) อย่างถูกต้อง หมายความว่าสัญญาอินสแตนซ์ DAO ใหม่ (Sputnikdaov2) ที่ผู้ใช้ร้องขอได้ถูกสร้างขึ้นตามปกติ ในขณะเดียวกัน สัญญาโรงงานจะบันทึกและติดตามที่อยู่บัญชีย่อยของสัญญาอินสแตนซ์ DAO
ชื่อเรื่องรอง

ข้อความ
ข้อความ
ข้อความ
รหัสตั้งอยู่ที่: sputnikdao-factory2/src/lib.rs # Line136-149
รายละเอียดการประมวลผลของ factory_manager.update_contract() มีดังนี้: อินเทอร์เฟซนี้สามารถรับรู้การเรียกใช้ฟังก์ชัน update() ในสัญญาอินสแตนซ์ DAO ที่สอดคล้องกัน
เป็นมูลค่าการกล่าวขวัญว่า:
ในระหว่างการวิเคราะห์รหัส Sputnik-DAO BlockSec พบปัญหาด้านความปลอดภัยที่ร้ายแรงในสัญญาโรงงาน ซึ่งจะส่งผลต่อสัญญาทั้งหมดที่ใช้ Sputnik-DAO หลังจากติดต่อฝ่ายโครงการ ในที่สุดปัญหาก็ได้รับการยืนยันและแก้ไขได้ทันเวลา
💡ช่องโหว่ด้านความปลอดภัยได้รับการอธิบายไว้โดยเฉพาะดังนี้:
ในโค้ดเวอร์ชันก่อนหน้า วิธีการอัพเดตสาธารณะ () ที่จัดทำโดยสัญญาโรงงาน sputinikdao ขาดการตรวจสอบการยืนยันคีย์ต่อไปนี้ ส่งผลให้ทุกคนสามารถเรียกใช้เมธอดนี้ได้
บังเอิญ สัญญาอินสแตนซ์ DAO (สัญญา Sputnikdaov2) อนุญาตให้อัปเกรดสัญญานี้โดย Sputnik-DAO Factory ผ่านการเรียกข้ามสัญญาโดยค่าเริ่มต้น
วิธี update() ที่ใช้ในสัญญาอินสแตนซ์ DAO มีดังต่อไปนี้ รหัสอยู่ใน sputnikdao2/src/upgrade.rs # บรรทัดที่ 62
ในบรรทัดที่ 9 ของโค้ดข้างต้น ค่าของ factory_info.auto_update จะถูกตั้งค่าเป็น True โดยค่าเริ่มต้นเมื่อสัญญาอินสแตนซ์ DAO ปรับใช้และเรียกเมธอด new() สำหรับการเริ่มต้น
วิธีการใหม่ () ของสัญญาอินสแตนซ์ DAO ถูกนำมาใช้ดังนี้: รหัสอยู่ใน sputnikdao2/src/lib.rs # บรรทัดที่ 83-104
โดยสรุป ผู้ใช้ทั่วไป (ไม่ใช่สัญญาโรงงานและสัญญา DAO เอง) สามารถอัปเกรด (แก้ไข) รหัสของสัญญา DAO ใดๆ ผ่านวิธีการ pub fn update() ที่จัดทำโดยสัญญาโรงงาน ซึ่งจะให้แพลตฟอร์ม Sputnik-DAO และ โครงการสัญญาทั้งหมดที่ใช้แพลตฟอร์ม Sputnik-DAO มีความเสี่ยงด้านความปลอดภัยสูง
🪴 โชคดีที่เมื่อพบปัญหานี้ รหัสของเวอร์ชันนี้ยังไม่ได้เปิดใช้งานบน NEAR mainnet ดังนั้นจึงไม่มีการสูญเสีย
เนื่องจากการตอบสนองอย่างรวดเร็วของฝ่ายโครงการ ช่องโหว่จึงได้รับการแก้ไขอย่างถูกต้องโดยการเพิ่มกลไกการตรวจสอบรายการที่อนุญาตพิเศษที่สมเหตุสมผล😊
ชื่อระดับแรก
ข้อความ
นอกจากช่องโหว่ที่ค้นพบและแก้ไขแล้วข้างต้น ความปลอดภัยของสัญญา 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🔗