如果社羣決定以治理的形式對其進行升級,則隨著時間的推移,治理系統的這些關鍵元件可能會發生變化。COMP持有者將是該協議各個方面未來方向的最終仲裁者。
注:COMP 部署在0xc00e94cb662c3520282e6f5717214004a7f26888[7] 、 治理合約部署在0xc0dA01a04C3f3E0be433606045bB7017A7323E38[8]
透過Compound治理可以構建什麼?
應用程式開發人員可以構建自己的自定義工作流和介面,以促進其使用者和社羣參與Compound治理。例如,與Compound的利率市場整合的應用程式可能對新增治理功能感興趣,包括:
· 鼓勵使用者將COMP投票權委託給應用團隊的地址,以便該團隊可以代表使用者參與治理。
· 向使用者顯示特定的管理提案,以便擁有COMP的使用者可以直接對其投票。
· 向使用者提供透明的洞察力,以瞭解Compound的即將發生的潛在變化,包括新增新市場或其他升級的提案。
此類介面將需要以下元件的組合:
· 投票介面 - 使用者能對有效的提案進行投票。
· 委託介面 - 使用者將投票權委託給某個地址。
· 投票權排行榜 — 列出按投票權排序的投票地址。
· 我的代理投票介面 - 使用castVoteBySig 功能,使用者可以建立分配給其他使用者的投票。這將允許另一個使用者代理他們提交投票(並支付gas),而無需委託給另一個使用者。
· 提案資源管理器 - 在簡化的使用者介面中瀏覽過去或現在的治理提案。
· 提案建立介面 - 如果使用者有足夠的投票權重(> 1%),請選擇協議修改並初始化提案。
Compound 治理程式碼示例
治理介面必須在區塊鏈之間進行讀寫,我們將逐步介紹一些基本的JavaScript程式碼示例,以實現這兩種功能。讀取資料將使用Compound API和Web3完成。但是,只能使用Web3完成寫入操作,例如委託或投票。
我們將按順序演示如何執行以下每個操作:
· 獲取所有COMP代幣持有人
· 獲取所有委託
· 獲取所有提案
· 獲取所有提案的選票
· 委託投票權
· 對(有效)提案進行投票
GitHub上的Compound 治理快速入門[9]程式碼庫中提供了以下示例完整程式碼。
獲取所有COMP代幣持有人
讓我們根據其COMP餘額按降序獲取所有COMP代幣持有者。我們可以透過CompoundAPI的治理服務[10]來實現。
let requestParameters = {
"page_size": 100, // number of results in a page
"network": "ropsten", // mainnet, ropsten
"order_by": "balance", // "votes", "balance", "proposals_created"
// "page_number": 1, // see subsequent response's `pagination_summary` to specify the next page
// addresses: ['0x123'], // array of addresses to filter on
// with_history: true, // boolean, returns a list of transaction history for the accounts
};
requestParameters = '?' + new URLSearchParams(requestParameters).toString();
fetch(`https://api.compound.finance/api/v2/governance/accounts${requestParameters}`)
.then((response) => response.json())
.then((result) => {
let accounts = result.accounts;
console.log(accounts);
let holders = [];
accounts.forEach((account) => {
holders.push({
"address": account.address,
"balance": parseFloat(account.balance).toFixed(4),
"delegate": account.delegate.address == 0 ? 'None' : account.delegate.address
});
});
holderListContainer.innerHTML = holderListTemplate(holders);
});
檔案:get_comp_holders_api.js [完整程式碼示例](https://github.com/compound-developers/compound-governance-examples/blob/master/api-examples/get_comp_holders.html "完整程式碼示例")
這段程式碼使用內建的瀏覽器獲取方法,該方法返回JavaScript Promise。程式碼庫有一個相同的示例,在示例中使用Web3.js對COMP持有人進行直接區塊鏈查詢[11]。我們可以使用COMP智慧合約找到相同的資訊。
這兩個程式碼示例的結果都是一個JSON物件陣列,其中包含帳戶地址,COMP代幣餘額和帳戶委託地址。
[
{
"address": "0xb61c5971d9c0472befceffbe662555b78284c307",
"balance": "200000.0000",
"delegate": "0xb61c5971d9c0472befceffbe662555b78284c307",
}
]
comp-holder.json
獲取所有委託
我們可以看到委託了COMP的所有地址。下面是一個區塊鏈查詢,它利用COMP合約的DelegateVotesChanged 事件來收集當前的每個委託。
// Ropsten COMP Contract
const compAddress = '0x1fe16de955718cfab7a44605458ab023838c2793';
const compAbi = window.compAbi;
const comp = new web3.eth.Contract(compAbi, compAddress);
(async () => {
const delegations = await comp.getPastEvents('DelegateVotesChanged', {
fromBlock: 0,
toBlock: 'latest'
});
const delegateAccounts = {};
delegations.forEach(e => {
const { delegate, newBalance } = e.returnValues;
delegateAccounts[delegate] = newBalance;
});
const delegates = [];
Object.keys(delegateAccounts).forEach((account) => {
const voteWeight = +delegateAccounts[account];
if (voteWeight === 0) return;
delegates.push({
delegate: account,
vote_weight: voteWeight
});
});
delegates.sort((a, b) => {
return a.vote_weight < b.vote_weight ? 1 : -1;
});
delegates.forEach(d => {
d.vote_weight = (100 * ((d.vote_weight / 1e18) / 10000000)).toFixed(6) + '%';
});
console.log(delegates);
delegateListContainer.innerHTML = delegateListTemplate(delegates);
})();
get_delegates_web3.js [完整程式碼示例](https://github.com/compound-developers/compound-governance-examples/blob/master/web3-examples/get_delegates.html "完整程式碼示例")
或者,可以從Compound API 檢索此資訊。這是Compound API 示例[12]。這些示例建立一個JSON物件陣列,這些物件具有委託地址和COMP供給總量的投票權重(百分比)。
[
{
"delegate": "0xb61c5971d9c0472befceffbe662555b78284c307",
"vote_weight": "2.000000%"
}
]
delegate.json
獲取所有提案
如果你要建立治理瀏覽器,則獲取所有提案非常有用。Compound API 在這裡很方便。此示例將獲取所有提案,無論其狀態如何。該API能夠根據請求引數按狀態過濾提案。
let requestParameters = {
"network": "ropsten", // mainnet, ropsten
"page_size": 100, // integer, defaults to 10
// "proposal_ids": 1, // an integer ID or array of IDs
// "state": "active", // "pending", "active", "canceled", "defeated", "succeeded", "queued", "expired", "executed"
// "with_detail": true, // boolean
// "page_number": 1, // see subsequent response's `pagination_summary` to specify the next page
};
requestParameters = '?' + new URLSearchParams(requestParameters).toString();
fetch(`https://api.compound.finance/api/v2/governance/proposals${requestParameters}`)
.then((response) => response.json())
.then((result) => {
console.log(result);
const proposals = result.proposals || [];
proposals.forEach((p) => {
p.state = p.states[p.states.length-1].state
p.for_votes = parseFloat(p.for_votes).toFixed(2);
p.against_votes = parseFloat(p.against_votes).toFixed(2);
});
proposalListContainer.innerHTML = proposalItemTemplate(proposals);
});
get_all_proposals_api.js [完整程式碼示例](https://github.com/compound-developers/compound-governance-examples/blob/master/api-examples/get_proposals.html "完整程式碼示例")
我們也可以使用治理合約的ProposalCreated事件直接透過Web3獲取相同的提案資料。程式碼示例使用以下提案資料建立一個JSON物件陣列。
[
{
"against_votes": "601000.00",
"description": "10 BTC is actually a decent amount. Boop!",
"for_votes": "835000.00",
"id": 18,
"title": "Reduce WBTC reserves by 10!",
"state": "succeeded"
}
]
proposal.json [完整程式碼示例](https://github.com/compound-developers/compound-governance-examples/blob/master/api-examples/get_proposals.html "完整程式碼示例")
獲取提案的選票
一旦提案達到“有效”狀態,選民就可以開始投票。選票公開儲存在區塊鏈上,因此我們可以隨時對其進行檢索。以下是在Ropsten上獲取提案1的提交投票的示例。
// Ropsten Governor Alpha Contract
const governanceAddress = '0xc5bfed3bb38a3c4078d4f130f57ca4c560551d45';
const governanceAbi = window.governanceAbi;
const gov = new web3.eth.Contract(governanceAbi, governanceAddress);
(async () => {
const voteCastEvents = await gov.getPastEvents('VoteCast', {
fromBlock: 0,
toBlock: 'latest'
});
let submittedBallots = voteCastEvents;
let formattedBallots = [];
submittedBallots.forEach((ballot) => {
const { voter, support, votes, proposalId } = ballot.returnValues;
if (proposalId == id) {
formattedBallots.push({
blockNumber: ballot.blockNumber,
address: voter,
support: support ? 'In Favor' : 'Against',
votes: (parseFloat(votes) / 1e18).toFixed(2),
});
}
});
formattedBallots.reverse();
console.log(formattedBallots);
ballotListContainer.innerHTML = ballotListTemplate(formattedBallots);
})();
get_all_ballots_web3.js
完整程式碼示例[13]
提案ID從1開始按升序排列。要檢視已提出的提案數量,可以從治理合約中獲取 proposalCount變數。選票可以從Compound API中獲取,例如在此治理服務示例[14]中。這是一個選票資料的JSON物件的結果陣列。
[
{
"address": "0x9687eb285292cba14a60a0c77dfd36dd95b93889",
"support": "In Favor",
"votes": "8500000.00"
}
]
ballot.json
委託投票權
為了參與治理,COMP代幣持有者必須delegate委託其投票權。可以委託到任何地址,包括代幣持有者自己的地址。一次只能委託一個地址。
以下是設定委託地址的Web3示例。如果你沒有COMP代幣,則仍然可以委託,將來收到的COMP代幣將自動委託給你選擇的委託地址。
// Ropsten COMP Contract
compAddress = '0x1fe16de955718cfab7a44605458ab023838c2793';
compAbi = window.compAbi;
comp = new web3.eth.Contract(compAbi, compAddress);
let currentDelegate;
try {
currentDelegate = await comp.methods.delegates(myAccount).call();
} catch (e) {
currentDelegate = 0;
}
delegate.innerText = currentDelegate == 0 ? 'None' : currentDelegate;
submit.onclick = async () => {
const delegateTo = newDelegate.value;
if (!delegateTo) {
alert('Invalid address to delegate your votes.');
return;
}
loader.classList.remove('hidden');
try {
const tx = await comp.methods.delegate(delegateTo).send({ from: myAccount });
console.log(tx);
alert(`Successfully Delagated to ${delegateTo}`);
window.location.reload();
} catch(e) {
console.error(e);
alert(e.message);
}
loader.classList.add('hidden');
};
delegate.js
完整程式碼示例[15]
該程式碼依賴於啟用了Web3的瀏覽器。確保在瀏覽器中安裝MetaMask[16]。可以從水龍頭索取Ropsten ETH。實際效果如下:
對提案進行投票
Compound治理最激動人心的部分是在更改協議的提案中投下你的一票。委託者可以為每個有效的提案投反對票或贊成票。
以下程式碼示例展示了投票使用者介面的功能。如果Ropsten測試網上沒有活動的提案,那麼選擇器中將沒有任何提案!
// Ropsten Governor Contract
governanceAddress = '0xc5bfed3bb38a3c4078d4f130f57ca4c560551d45';
governanceAbi = window.governanceAbi;
gov = new web3.eth.Contract(governanceAbi, governanceAddress);
// Add a list of active proposals to the UI
getProposals();
// Get my account's vote weight
getMyVoteWeight(myAccount);
submit.onclick = async () => {
// An active proposal needs to be selected in the UI
if (proposalSelector.value < 1) {
alert('Select a proposal to vote in.');
return;
}
// A vote choice needs to be selected in the UI
if (!_for.checked && !against.checked) {
alert('Select a vote option.');
return;
}
const proposal = proposalSelector.value;
const vote = _for.checked ? true : false;
loader.classList.remove('hidden');
try {
const tx = await gov.methods.castVote(proposal, vote).send({ from: myAccount });
console.log(tx);
alert(`Successfully voted ${vote ? 'for' : 'against'} Proposal ${proposal}`);
window.location.reload();
} catch(e) {
console.error(e);
alert(e.message);
}
loader.classList.add('hidden');
};
cast_vote.js
完整程式碼示例[17]
建立自己的治理介面
社羣治理的目標是使Compound協議成為對所有人開放和具有彈性的金融基礎設施。要達到這一里程碑,社羣、開發人員、使用者和機構都必須建立自己的介面和功能,以參與Compound治理。
由於以太坊具有可組合和開放訪問的特性,因此任何人和所有人都可以建立自己的COMP和治理專案。這裡有更多資源可以幫助你入門。
Compound治理資源
治理簡介(2020年2月)[18]
治理髮布公告(2020年4月)[19]
Compound協議治理文件[20]
Compound API 治理服務文件[21]
社羣主導的治理論壇[22]
參考資料
[1]COMP 治理合約: https://github.com/compound-finance/compound-protocol/blob/master/contracts/Governance/GovernorAlpha.sol
[2]Compound治理面板: https://compound.finance/governance
[3]文件: https://compound.finance/docs/governance
[4]文件: https://compound.finance/docs/governance
[5]Governor智慧合約: https://etherscan.io/address/0xc0da01a04c3f3e0be433606045bbbb7017a7323e38
[6]對映: https://learnblockchain.cn/docs/solidity/types.html#mapping-types
[7]0xc00e94cb662c3520282e6f5717214004a7f26888: https://etherscan.io/token/0xc00e94cb662c3520282e6f5717214004a7f26888
[8]0xc0dA01a04C3f3E0be433606045bB7017A7323E38:https://etherscan.io/address/0xc0dA01a04C3f3E0be433606045bB7017A7323E38
[9]Compound 治理快速入門: https://github.com/compound-developers/compound-governance-examples
[10]CompoundAPI的治理服務: https://compound.finance/docs/api#GovernanceService
[11]使用Web3.js對COMP持有人進行直接區塊鏈查詢: https://github.com/compound-developers/compound-governance-examples/blob/master/web3-examples/get_comp_holders.html
[12]Compound API 示例: https://github.com/compound-developers/compound-governance-examples/blob/master/api-examples/get_delegates.html
[13]完整程式碼示例: https://github.com/compound-developers/compound-governance-examples/blob/master/web3-examples/get_ballots.html
[14]治理服務示例: https://github.com/compound-developers/compound-governance-examples/blob/master/api-examples/get_ballots.html
[15]完整程式碼示例: https://github.com/compound-developers/compound-governance-examples/blob/master/web3-examples/set_delegate.html
[16]MetaMask: https://metamask.io/
[17]完整程式碼示例: https://github.com/compound-developers/compound-governance-examples/blob/master/web3-examples/cast_vote.html
[18]治理簡介(2020年2月): https://medium.com/compound-finance/compound-governance-5531f524cf68
[19]治理髮布公告(2020年4月): https://medium.com/compound-finance/compound-governance-decentralized-b18659f811e0
[20]Compound協議治理文件: https://compound.finance/docs/governance?ref=medium
[21]Compound API 治理服務文件: https://compound.finance/docs/api#GovernanceService?ref=medium
[22]社羣主導的治理論壇: https://compound.comradery.io/
[23]Cell Network: https://www.cellnetwork.io/?utm_souce=learnblockchain
[24]原文連結: https://medium.com/compound-finance/building-a-governance-interface-474fc271588c
[25]Adam Bavosa: https://medium.com/@adam.bavosa