We can create a Dao contract for an user using the DaoRegister contract deployed by Relation Protocol. A dao contract can provide a Dao with member management functions. Both the DaoRegister contract and the Dao contract implement the contract interface defined by the Contract Standard.
Construct a Contract object
Via Relation Protocol's resource list, you can acquire the contract address and abi file of DaoRegister and DaoWithSign, and the abi file of Dao contract. As for the address of a Dao contract, you need to query it through DaoRegister.
The administrator of a Dao can assign description and avatar for a Dao, with the description and avatar stored on Arweave. We use the data format for this as follows:
{"avatar":"${The avatar of DAO}","description":"${The description of DAO}"}
The transaction hash of the upload will be stored in the contract as DaoURI
You can get a whole list of Dao members with a traversal process to find all the token owners of said Dao.
constdaoContractAddress='0x000...';constdaoContract=getDaoContractInstance(daoContractAddress)constmemberCount=awaitdaoContractAddress.totalSupply();var memberList = [];for(var i =0; i < memberCount;i++){consttokenId=awaitdaoContract.tokenByIndex(i);constmember=awaitdaoContract.ownerOf(tokenId);memberList.push(member);}
Configure the DaoURI(Gas fee can be paid by someone else)
The administrator of a Dao can assign description and avatar to a Dao, with the content stored on Arweave. The format of the content should be:
{"avatar":"${The avatar of DAO}","description":"${The description of DAO}"}
The administrator signs against the transaction hash and constructs a parameter to be posted on the blockchain. Any address can use this parameter to initiate a transaction on the blockchain, with the gas fee paid by said address.
import { Bytes } from'@ethersproject/bytes'constdaoURI='hX_Mne1...';constdaoContractAddress='0x000...';constdaoContract=getDaoContractInstance(daoContractAddress)constdaoWithSignContract=getDaoWithSignContractInstance(daoContractAddress)constaccounts=awaitethereum.request({ method:'eth_requestAccounts' })let name =awaitdaoWithSignContract.name();let nonce =awaitdaoWithSignContract.nonces(accounts[0]);//The time when the signature expires(Unit: second). The following example means the signature will expire 100 seconds after the current time.let deadline =Date.parse(newDate()) /1000+100;let sign =awaitgetSign(awaitbuildSetDaoURIParam( name,daoWithSignContract.address.toLowerCase(),daoContract.address.toLowerCase(), daoURI,parseInt(nonce), deadline), accounts[0]);let param = {"sig": {"v":sign.v,"r":sign.r,"s":sign.s,"deadline": deadline},"target":daoContract.address,"addr": accounts[0],"daoURI": daoURI}//In reality, this method will be called by the address paying the gas fee.awaitdaoWithSignContract.connect(accounts[1]).setDaoURIWithSign(param);asyncfunctiongetSign(msgParams, signerAddress) {constparams= [signerAddress, msgParams];consttrace=awaithre.network.provider.send("eth_signTypedData_v4", params);returnBytes.splitSignature(trace);}asyncfunctiongetChainId() {returnawaitethereum.request({ method:'eth_chainId', });}asyncfunctionbuildSetDaoURIParam(name, contractAddress,daoContractAddress, daoURI, nonce, deadline) {return { domain: { chainId:awaitgetChainId(), name: name, verifyingContract: contractAddress, version:'1', },// Defining the message signing data content. message: { target: daoContractAddress, daoURI: daoURI, nonce: nonce, deadline: deadline, },// Refers to the keys of the *types* object below. primaryType:'SetDaoURIWithSign', types: { EIP712Domain: [ {name:'name', type:'string'}, {name:'version', type:'string'}, {name:'chainId', type:'uint256'}, {name:'verifyingContract', type:'address'}, ], SetDaoURIWithSign: [ {name:'target', type:'address'}, {name:'daoURI', type:'string'}, {name:'nonce', type:'uint256'}, {name:'deadline', type:'uint256'}, ], }, };}
When an administrator adds a member to a Dao(Gas fee can be paid by someone else)
An administrator can add specific addresses to a Dao.
import { Bytes } from'@ethersproject/bytes'constdaoContractAddress='0x000...';constdaoContract=getDaoContractInstance(daoContractAddress)constdaoWithSignContract=getDaoWithSignContractInstance(daoContractAddress)constaccounts=awaitethereum.request({ method:'eth_requestAccounts' })constmembers= ['0x001...','0x002...','0x003...'];let name =awaitdaoWithSignContract.name();let nonce =awaitdaoWithSignContract.nonces(accounts[0]);//The time when the signature expires(Unit: second). The following example means the signature will expire 100 seconds after the current time.let deadline =Date.parse(newDate()) /1000+100;let sign =awaitgetSign(awaitbuildAddMemberParam( name,daoWithSignContract.address.toLowerCase(),daoContract.address.toLowerCase(), members,parseInt(nonce), deadline), accounts[0]);let param = {"sig": {"v":sign.v,"r":sign.r,"s":sign.s,"deadline": deadline},"target":daoContract.address,"addr": accounts[0],"members": members}//In reality, this method will be called by the address paying the gas fee.awaitexpect(daoWithSignContract.connect(accounts[1]).addMemberWithSign(param));asyncfunctiongetSign(msgParams, signerAddress) {constparams= [signerAddress, msgParams];consttrace=awaithre.network.provider.send("eth_signTypedData_v4", params);returnBytes.splitSignature(trace);}asyncfunctiongetChainId() {returnawaitethereum.request({ method:'eth_chainId', });}asyncfunctionbuildAddMemberParam(name, contractAddress, daoContractAddress,members, nonce, deadline) {return { domain: { chainId:awaitgetChainId(), name: name, verifyingContract: contractAddress, version:'1', },// Defining the message signing data content. message: { target: daoContractAddress, members: members, nonce: nonce, deadline: deadline, },// Refers to the keys of the *types* object below. primaryType:'AddMemberWithSign', types: { EIP712Domain: [ {name:'name', type:'string'}, {name:'version', type:'string'}, {name:'chainId', type:'uint256'}, {name:'verifyingContract', type:'address'}, ], AddMemberWithSign: [ {name:'target', type:'address'}, {name:'members', type:'address[]'}, {name:'nonce', type:'uint256'}, {name:'deadline', type:'uint256'}, ], }, };}
Open Access(Gas fee can be paid by someone else)
An administrator of a Dao can set it to Open Access, meaning that anyone can join the Dao.
import { Bytes } from'@ethersproject/bytes'constdaoContractAddress='0x000...';constdaoContract=getDaoContractInstance(daoContractAddress)constdaoWithSignContract=getDaoWithSignContractInstance(daoContractAddress)constaccounts=awaitethereum.request({ method:'eth_requestAccounts' })constisFreeJoin=true;let name =awaitdaoWithSignContract.name();let nonce =awaitdaoWithSignContract.nonces(accounts[0]);let deadline =Date.parse(newDate()) /1000+100;let sign =awaitgetSign(awaitbuildSetFreeJoinParam( name,daoWithSignContract.address.toLowerCase(),daoContract.address.toLowerCase(), isFreeJoin,parseInt(nonce), deadline), accounts[0]);let param = {"sig": {"v":sign.v,"r":sign.r,"s":sign.s,"deadline": deadline},"target":daoContract.address,"addr": accounts[0],"isFreeJoin": isFreeJoin}//In reality, this method will be called by the address paying the gas fee.awaitdaoWithSignContract.connect(accounts[1]).setFreeJoinWithSign(param);asyncfunctiongetSign(msgParams, signerAddress) {constparams= [signerAddress, msgParams];consttrace=awaithre.network.provider.send("eth_signTypedData_v4", params);returnBytes.splitSignature(trace);}asyncfunctiongetChainId() {returnawaitethereum.request({ method:'eth_chainId', });}asyncfunctionbuildSetFreeJoinParam(name, contractAddress, daoContractAddress,isFreeJoin, nonce, deadline) {return { domain: { chainId:awaitgetChainId(), name: name, verifyingContract: contractAddress, version:'1', },// Defining the message signing data content. message: { target: daoContractAddress, isFreeJoin: isFreeJoin, nonce: nonce, deadline: deadline, },// Refers to the keys of the *types* object below. primaryType:'SetFreeJoinWithSign', types: { EIP712Domain: [ {name:'name', type:'string'}, {name:'version', type:'string'}, {name:'chainId', type:'uint256'}, {name:'verifyingContract', type:'address'}, ], SetFreeJoinWithSign: [ {name:'target', type:'address'}, {name:'isFreeJoin', type:'bool'}, {name:'nonce', type:'uint256'}, {name:'deadline', type:'uint256'}, ], }, };}
When an user joins a Dao(Gas fee can be paid by someone else)
With Open Access enabled by the administrator of a Dao, users can join the Dao freely.
import { Bytes } from'@ethersproject/bytes'constdaoContractAddress='0x000...';constdaoContract=getDaoContractInstance(daoContractAddress)constdaoWithSignContract=getDaoWithSignContractInstance(daoContractAddress)constaccounts=awaitethereum.request({ method:'eth_requestAccounts' })let name =awaitdaoWithSignContract.name();let nonce =awaitdaoWithSignContract.nonces(accounts[0]);let deadline =Date.parse(newDate()) /1000+100;let sign =awaitgetSign(awaitbuildJoinParam( name,daoWithSignContract.address.toLowerCase(),daoContract.address.toLowerCase(),parseInt(nonce), deadline), accounts[0]);let param = {"sig": {"v":sign.v,"r":sign.r,"s":sign.s,"deadline": deadline},"target":daoContract.address,"addr": accounts[0]}//In reality, this method will be called by the address paying the gas fee.awaitexpect(daoWithSignContract.connect(accounts[1]).joinWithSign(param))asyncfunctiongetSign(msgParams, signerAddress) {constparams= [signerAddress, msgParams];consttrace=awaithre.network.provider.send("eth_signTypedData_v4", params);returnBytes.splitSignature(trace);}asyncfunctiongetChainId() {returnawaitethereum.request({ method:'eth_chainId', });}asyncfunctionbuildJoinParam(name, contractAddress, daoContractAddress,nonce, deadline) {return { domain: { chainId:awaitgetChainId(), name: name, verifyingContract: contractAddress, version:'1', },// Defining the message signing data content. message: { target: daoContractAddress, nonce: nonce, deadline: deadline, },// Refers to the keys of the *types* object below. primaryType:'JoinWithSign', types: { EIP712Domain: [ {name:'name', type:'string'}, {name:'version', type:'string'}, {name:'chainId', type:'uint256'}, {name:'verifyingContract', type:'address'}, ], JoinWithSign: [ {name:'target', type:'address'}, {name:'nonce', type:'uint256'}, {name:'deadline', type:'uint256'}, ], }, };}
Remove a Dao member(Gas fee can be paid by someone else)
An administrator can remove a member from a Dao. Also, users can leave a Dao freely.
import { Bytes } from'@ethersproject/bytes'constdaoContractAddress='0x000...';constdaoContract=getDaoContractInstance(daoContractAddress)constdaoWithSignContract=getDaoWithSignContractInstance(daoContractAddress)constaccounts=awaitethereum.request({ method:'eth_requestAccounts' })let name =awaitdaoWithSignContract.name();let nonce =awaitdaoWithSignContract.nonces(accounts[0]);let deadline =Date.parse(newDate()) /1000+100;let sign =awaitgetSign(awaitbuildRemoveParam( name,daoWithSignContract.address.toLowerCase(),daoContract.address.toLowerCase(), accounts[0].toLowerCase(),parseInt(nonce), deadline), accounts[0]);let param = {"sig": {"v":sign.v,"r":sign.r,"s":sign.s,"deadline": deadline},"target":daoContract.address,"addr": accounts[0],"member": accounts[0]}//In reality, this method will be called by the address paying the gas fee.awaitexpect(daoWithSignContract.connect(accounts[1]).removeWithSign(param))asyncfunctiongetSign(msgParams, signerAddress) {constparams= [signerAddress, msgParams];consttrace=awaithre.network.provider.send("eth_signTypedData_v4", params);returnBytes.splitSignature(trace);}asyncfunctiongetChainId() {returnawaitethereum.request({ method:'eth_chainId', });}asyncfunctionbuildRemoveParam(name, contractAddress, daoContractAddress,member, nonce, deadline) {return { domain: { chainId:awaitgetChainId(), name: name, verifyingContract: contractAddress, version:'1', },// Defining the message signing data content. message: { target: daoContractAddress, member: member, nonce: nonce, deadline: deadline, },// Refers to the keys of the *types* object below. primaryType:'RemoveWithSign', types: { EIP712Domain: [ {name:'name', type:'string'}, {name:'version', type:'string'}, {name:'chainId', type:'uint256'}, {name:'verifyingContract', type:'address'}, ], RemoveWithSign: [ {name:'target', type:'address'}, {name:'member', type:'address'}, {name:'nonce', type:'uint256'}, {name:'deadline', type:'uint256'}, ], }, };}