智能公器

智能公器(Smart Common)是遵循 SCC0 許可協議、擁有自己的估值通證、能夠讓其開發者基於 PoV 價值證明獲得獎勵的智能創造公共物(包括dApp、EIPs、AI、論文、技術標準等)。

在道易程網站上,為簡化應用,菜單“智能公器”同時也是開發者對其公器的版本及其所獲獎金進行管理的入口。

{
    {
        string name; // Smart Common 名稱,唯一,不能與其它Smart Common同名.
        string symbol; // Smart Common 代幣名稱,唯一,不能與其它Smart Common代幣同名
        string desc; // Smart Common 描述
        address manager; // Smart Common 管理員
        uint16 version; // Smart Common 版本號,mint 時從1開始
        string SC_Type // Smart Common 的類型
    },
    address[] calldata _members, //成員列表
    uint16[] calldata _dividendRights, // 成員票權(分紅權),與_members 一一對應
    uint16 _strategy,  //提案投票通過率.百分之百(全票通過)是2的16次方減1(65535), 可以通過提案更改此值
    uint32 _lifetime, //提案存活時間,以秒為單位,提案從創建開始計時,經過該時間後沒有完成的就作廢
    uint32 _coolingPeriod // 提案冷卻時間,單位是秒,從提案創建開始計時,要經過該數值的時間後才能建新的提案.特別註意:冷卻時間必須大於存活時間
    {
        string filetype  // logo 的後綴名, 只能是svg
        string fileContent // svg 的純文本內容
    }
}

如果你的智能合約是一個 EIP 或者一篇論文,可先閱讀《將 PoV 價值證明應用到 EIPs 或者 AI 等領域》了解PoV價值證明帶來的獎勵機製。並且:

  • 我們建議將 EIP 或論文以 HTML 源碼寫在智能合約裏:
    function eipContent() external view returns(string memory);
  • 如果是一個已經通過github發表了的EIP,譬如ERC-2569,可以不要以上 EIP 的 HTML 源碼而以一個鏈接替代 EIP 的內容。如這個地址可以是https://eips.ethereum.org/EIPS/erc-2569。同時,請作者在原EIP裏補充一個和寫在智能合約裏的owner地址完全相同的地址。如下:
    owner = 這裏寫入一個以太坊帳戶(地址)
  • 非dApp類的智能公器,在Mint時都要註意其專屬的估值通證的命名方法。相關內容在本文底部

如何在道易程上Mint一個智能公器

  • 只有 智能合約 的所有者(owner)才能 mint 智能公器,所以 mint 智能公器前,要先部署好自己的智能合約。
  • Mint 智能公器的合約可以是某個 dApp 中的任何你指定的智能合約。需要特別註意的是,每個合約地址僅有權限創建一個智能公器。
  • Mint 智能公器時,你還可以同時 Mint 任意套數的榮譽通證(一種紀念你的智能公器誕生的NFT)。所謂套數,是指其數量可以是你的智能公器分紅成員的N倍。請註意你的智能合約裏,要事先寫好調用相關接口的合約代碼。

請註意:因以太坊gas非常昂貴,建議 logo 在2K以下,並且只能為 SVG 矢量圖形。

智能公器的合約示例

// SPDX-License-Identifier: MIT 
pragma solidity ^0.8.0;

import "../interfaces/IDAismInterface.sol";

contract ThreeDapp {
    
    address public daismRegistrar;
    address public nftAddress;
    address public owner;

    constructor(address daismRegistrar_,address nftAddress_){
        require(daismRegistrar==address(0)&&nftAddress==address(0));
        daismRegistrar = daismRegistrar_;
        nftAddress = nftAddress_;
        owner = tx.origin;
    }
    function ownerOf() public view returns(address){
        return owner;
    }
    function mintSCandNFT(
        IDAismInterface.SCInfo memory _SCInfo,
        address[] calldata _members,
        uint16[] calldata _dividendRights,
        uint16 _strategy,
        uint32 _lifetime,
        uint32 _coolingPeriod,
        IDAismInterface.File memory _logo,
        uint256 _num
    ) public returns(uint256[][] memory){
       uint256 scId = IDAismInterface(daismRegistrar).createSC(_SCInfo, _members, _dividendRights, _strategy, _lifetime, _coolingPeriod, _logo);
       return IDAismInterface(nftAddress).mintBatch(scId, _members, _num);
    }
    function createSC(
        IDAismInterface.SCInfo memory _SCInfo,
        address[] calldata _members,
        uint16[] calldata _dividendRights,
        uint16 _strategy,
        uint32 _lifetime,
        uint32 _coolingPeriod,
        IDAismInterface.File memory _logo
    ) external returns(uint) {
        return IDAismInterface(daismRegistrar).createSC(_SCInfo, _members, _dividendRights, _strategy, _lifetime, _coolingPeriod, _logo);
    }
}

//IDAismInterface 接口
// SPDX-License-Identifier: MIT 
pragma solidity ^0.8.20;
interface IDAismInterface {
    struct SCInfo {
        string name; // The name of the SC.
        string symbol; // The symbol of the SC.
        string desc; // The description of the SC.
        address manager; // The address of the SC manager.
        uint16 version; // The version of the SC.
        string SC_Type;
    }
    struct File{
     string fileType;
     string fileContent;
    }
    function creator(uint256 _scId) external view returns (address);
    function SCLogo() external view returns(address);
    function SCInfos(uint SC_id) external view returns (SCInfo memory);
    function getLogo(uint SC_id) external view returns (File memory);
    function ownerOf() external view returns(address);
    function toProxy(uint256 _scId) external view returns (address);
    function createSC(
        SCInfo memory _SCInfo,
        address[] calldata _members,
        uint16[] calldata _dividendRights,
        uint16 _strategy,
        uint32 _lifetime,
        uint32 _coolingPeriod,
        File memory _logo
    ) external returns(uint) ;
    function mintBatch(uint256 _scId, address[] calldata _to, uint256 _num) external returns(uint256[][] memory);
}

利用hardhat發布並 mint Smart Common 示例

const fs=require('fs')
const { ethers } = require('hardhat')

async function main(){
    await hre.run('compile');
    const [owner] = await ethers.getSigners();

    // 合約名稱 /請換成你的合約
    const contractName = 'ThreeDapp';

    //請換成最新的地址,當前使用的地址在mint 智能公器窗口的示例代碼中
    const daismRegistrar_='0x4E0430f2ad966861846245340b1bA64b829AA069' ;

    //請換成最新的地址,當前使用的地址在mint 智能公器窗口的示例代碼中
    const nftAddress_ ='0xDcf063A9E95318e0Abf8dAAAC1f146ad83C844d8';

    //發布合約
    const contractObj1 = await daism_deploy(owner,contractName,[daismRegistrar_,nftAddress_]);

    // mint 道易程的 Smart Common
    let res= await contractObj1.createSC(
        ['名稱1', '代幣名稱1','描述1', owner.address,1,'dApp'],  //道易程的SC(見上面的結構描述), 註:名稱和代幣名稱 不允許重復
        [owner.address],  //成員列表
        [10],   // 成員票權(分紅權),不能為1,2,3,因為這三個數有特殊用途
        (2 ** 16-1), //提案投票通過率,百分之分(全票)
        7 * 24 * 3600,  //壽命期為7天
        9 * 24 * 3600,  //冷卻期九天
        ['svg','<svg fill="#f7861c" height="24" viewBox="113.789 0 24.088 24" width="24.088" xmlns="http://www.w3.org/2000/svg"><path d="M134.613 6.85h-3.499l-2.035-2.009-.006-.006-.004-.003a1.698 1.698 0 00-1.189-.482h-4.23c-.491 0-.93.209-1.238.539l-.003-.005-1.991 1.966h-3.571c-.935 0-1.691.747-1.691 1.667v10c0 .92.757 1.668 1.691 1.668h17.768a1.68 1.68 0 001.691-1.668v-10a1.682 1.682 0 00-1.693-1.667zm.846 11.668a.843.843 0 01-.846.834h-17.768a.841.841 0 01-.846-.834v-10c0-.459.38-.833.846-.833h3.922l.248-.245 1.024-1.011.021.062.971-1.035a.843.843 0 01.618-.271h4.23c.223 0 .435.086.602.247l2.033 2.008.247.245H134.613c.465 0 .846.374.846.833z"/><path d="M125.729 9.351c-2.104 0-3.808 1.678-3.808 3.749 0 2.072 1.703 3.752 3.808 3.752 2.104 0 3.808-1.68 3.808-3.752s-1.704-3.749-3.808-3.749zm0 6.667c-1.633 0-2.962-1.31-2.962-2.918s1.329-2.916 2.962-2.916 2.961 1.307 2.961 2.916-1.328 2.918-2.961 2.918z"/></svg>']
    );

    console.log('createSC hash: '+res.hash)
    await res.wait()
    console.log("createSC success")

    //註:一個dApp 只能mint 一次, 所以在此需要重新發布一個新的dApp
    const contractObj2 = await daism_deploy(owner,contractName,[daismRegistrar_,nftAddress_]);
    res=await contractObj2.mintSCandNFT(  
        ['名稱2', '代幣名稱2','描述2', owner.address,1,'dApp'],  //道易程的SC(見上面的結構描述), 註:名稱和代幣名稱 不允許重復
        [owner.address],  //成員列表
        [10],   // 成員票權(分紅權),不能為1,2,3,因為這三個數有特殊用途
        (2 ** 16-1), //提案投票通過率,百分之分(全票)
        7 * 24 * 3600,  //壽命期為7天
        9 * 24 * 3600,  //冷卻期九天
        ['svg','<svg fill="#f7861c" height="24" viewBox="113.789 0 24.088 24" width="24.088" xmlns="http://www.w3.org/2000/svg"><path d="M134.613 6.85h-3.499l-2.035-2.009-.006-.006-.004-.003a1.698 1.698 0 00-1.189-.482h-4.23c-.491 0-.93.209-1.238.539l-.003-.005-1.991 1.966h-3.571c-.935 0-1.691.747-1.691 1.667v10c0 .92.757 1.668 1.691 1.668h17.768a1.68 1.68 0 001.691-1.668v-10a1.682 1.682 0 00-1.693-1.667zm.846 11.668a.843.843 0 01-.846.834h-17.768a.841.841 0 01-.846-.834v-10c0-.459.38-.833.846-.833h3.922l.248-.245 1.024-1.011.021.062.971-1.035a.843.843 0 01.618-.271h4.23c.223 0 .435.086.602.247l2.033 2.008.247.245H134.613c.465 0 .846.374.846.833z"/><path d="M125.729 9.351c-2.104 0-3.808 1.678-3.808 3.749 0 2.072 1.703 3.752 3.808 3.752 2.104 0 3.808-1.68 3.808-3.752s-1.704-3.749-3.808-3.749zm0 6.667c-1.633 0-2.962-1.31-2.962-2.918s1.329-2.916 2.962-2.916 2.961 1.307 2.961 2.916-1.328 2.918-2.961 2.918z"/></svg>'],
        2 // 每個成員mint兩份榮譽通證
    );

    console.log('threeDapp.mintScAndNFT hash: '+res.hash);
    await res.wait();
    console.log("mintScAndNFT success")
    console.log("--------------END--------------")
}

//發布合約
async function daism_deploy(signer,contractName,paras=[]){
    const factory = await ethers.getContractFactory(contractName,signer)
    const product = await factory.deploy.apply(factory,paras)
    await product.waitForDeployment()
    const contract_address=await product.getAddress()
    console.log('部署: '+contractName+' : '+contract_address)
    return await ethers.getContractAt(contractName,contract_address,signer)
}

main()
  .then(() => process.exit(0))
  .catch((error) => {
    console.error(error);
    process.exit(1);
  });

網頁 Mint 智能公器示例

首先發布能夠調用 mint 智能公器的合約的智能合約(如你的dApp)。 並取提該智能合約或dApp的發布地址。

網頁上填寫相應信息並mint, 見下圖:

估值通證的命名

我們借鑒了Unix操作系統和Windows裏通用的方法(相關文檔可查閱微軟的「命名文件、路徑和命名空間」),即:

  • 智能公器的分類體現在估值通證的擴展名上。
  • 估值通證的命名部分借鑒電腦操作系統的方法,即以」.「分成兩部分:
    1. 估值通證的命名規則,為」XXXX.擴展名「。如:UL.eip(表明其智能公器是一個 EIP)。或者:ALOHA.ai(表明其為一個 AI 項目😂)。擴展名建議小寫,以使得前面的名稱更突出。任何人都可以任意設置其智能公器的擴展名——這是一種去中心化的命名規範。當然,如果其他人已經對某個分類做了沒有瑕疵的命名,那麽希望後面的開發者們能夠沿用。
    2. 文件名是大小寫不敏感。但前端會顯示大小寫。
    3. 擴展名不可為空。
    4. 擴展名只增加,不刪除。
    5. 擴展名的修改,實際可能是新增,也可能是另選已經存在的另一個擴展名。
    6. 誰主張修改,誰遷移——如果某個智能公器的開發者決定修改其估值通證的擴展名,實際上是他新增了一個擴展名,或者是遷移到另一個已經存在的擴展名,然後他的智能公器就被劃分到新的分類裏。但原擴展名並沒有被刪除。這樣之前主動加入到原分類(原擴展名)裏的其它智能公器,就完全沒有受到影響。
    7. 擴展名的調整,要通過提案來表決。
    8. (前端)已經存在的擴展名,在用戶填寫時,自動成為可選項。一旦選擇,就會出現該擴展名的描述。這樣就能避免不同的分類使用同一擴展名。
    9. (前端)擴展名的命名是去中心化的,沒有限製。但考慮到越容易記住越好,還是要建議用戶盡量使用簡單易記的名稱,即盡量使用英文字母和數字來命名估值通證。一般不建議在文件名中包含特殊字符。