or
or
By clicking below, you agree to our terms of service.
New to HackMD? Sign up
Syntax | Example | Reference | |
---|---|---|---|
# Header | Header | 基本排版 | |
- Unordered List |
|
||
1. Ordered List |
|
||
- [ ] Todo List |
|
||
> Blockquote | Blockquote |
||
**Bold font** | Bold font | ||
*Italics font* | Italics font | ||
~~Strikethrough~~ | |||
19^th^ | 19th | ||
H~2~O | H2O | ||
++Inserted text++ | Inserted text | ||
==Marked text== | Marked text | ||
[link text](https:// "title") | Link | ||
 | Image | ||
`Code` | Code |
在筆記中貼入程式碼 | |
```javascript var i = 0; ``` |
|
||
:smile: | ![]() |
Emoji list | |
{%youtube youtube_id %} | Externals | ||
$L^aT_eX$ | LaTeX | ||
:::info This is a alert area. ::: |
This is a alert area. |
On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?
Please give us some advice and help us improve HackMD.
Do you want to remove this version name and description?
Syncing
Nouns NFT contract analysis
Nouns NFT contract analysis
The objective of this document is to describe how we use the current Nouns NFT Smart Contract to allow prove of delegation and token ownership for voting
Ownership Proof of a single NFT
The checkpoint system (described below) will most likely not be needed. To prove that an
account
had the right to vote for a giventoken_id
at a certain block:(1) if no delegation, prove that at the correct block:
(2) if the a
delegator
has delegated his/her token to anaccount
, prove that at the correct block:Contract Review
Nouns' Token Contract implemented the ERC721 standard (aka NFT) with slight modification to allow voting.
In particular, they use the modified version of ERC721Checkpointable from Compound Lab's to generate checkpoints of token balance. This allows their token contract to have balance history, much like MiniMi did for ERC20 standard.
The contract maintains the current map between delegators and delegates via the
_delegates
mapping. It is not possible to delegate individual tokens, an entry in that mapping means that all NFTs held are delegated.The contract also maintains the full history of voting power of each address via the following data structures, of which the
checkpoints
mapping is the most important one:For a given account
acct
, and a given checkpoint indexid
, the voting power is given bycheckpoints[acct][id].votes
and the corresponding block bycheckpoints[acct][id].fromBlock
.The latest checkpoint index (assuming there are any checkpoints), is
numCheckpoints - 1
. It allows us to see the current amount of voting power the delegate has. Note that the token owner is listed as their own delegate by default.The
checkpoints
map is updated at each token transfer and each change of delegation. This means that by accessing the last checkpoint before the voting has started we can see how many tokens the delegate had delegated to them.Given a past block number, the voting power of an address at that block can be obtained via the following function:
This function has a loop that repeats \(O(log_2(nCheckpoints))\) times on average, as every iteration cuts down the range being searched by 2. This means that as the number of checkpoints associated with an address incrases, this function will also slowly consume more gas if called from within the smart contract.
Storage Proof of Voting Power
Given an election, the voting power of the account is the amount of voting tokens the address had delegated to it just before the election.
We can generate a storage proof based on the Ethereum state at the block when the election has started. Assume we wish to prove that address
acct
hadZ
voting power at that block. We find the valueY
ofnumCheckpoints[acct]
at that block, which is the number of checkpoints for that account. We then require the following storage proofs:numCheckpoints[acct] == Y
checkpoints[acct][Y-1].votes == Z
Only these two storage proofs are required, independently of the amount of voting power.
Storage Trie Depth
On Ethereum, every contract has a Merkle Pratricia Trie that stores the contract’s data. The trie depth corresponds to the number of Keccak hashes that has to be computed in order to generate an Ethereum storage proof in Noir.
By 2 Mar 2023, the depth of
storageProof
(EIP-1186 Merkle proof) fetched for owners and delegates from the Nouns contract are as follows:Most of the proofs are 4-5 levels deep and are at most 7 levels deep, with the root element being shared between all. The elements can be pretty large themselves (~533bytes) for the larger ones.
With minimal tooling for computing the keys for kv store, it's currently possible to get all the proofs via requests to Infura in <15 seconds on a slow to basic connection.