It may be time we built a new way to verify token ownership within Discord.
We’ve tried collab.land on the Nouns Discord and it works well for accounts that can sign messages but breaks down for multisig contracts or other accounts that can’t sign messages. Collab.land is attractive for large audiences when you don’t want each participant to have to pay gas for an on-chain transaction verifying ownership.
However, Noun ownership will remain a relatively small audience for the next few years (<365 Nouns created per year) and we’re already asking each Noun owner to periodically perform on chain actions when voting for proposals. I think this means that we can take an on-chain approach to verification. Since this is novel and I believe it could be useful to other organizations I’d like to collect some feedback before making a proof of concept implementation.
I’ll write generally in Projects
rather than Nouns
as I think this scheme can be made such that other projects could use the same on-chain data for their own attestation.
Overview
The model I’m thinking of has a few main components:
- On-Chain Attestation Events - EVM Events emitted by a smart contract that allows for token holders to log a piece of data along with a verification that they hold a token
- Token Transfers - EVM Events that are already emitted by ERC20 and ERC721 token contracts
- (Optionally) The Graph - Providing more efficient event indexing
- Role Management Bot - A bot that merges attestation events and Discord server membership to assign roles to token holders
Attestation
I’m thinking of a couple sets of generic Attest
events that are emitted by a smart contract. These events would include the token address, the address doing the attesting, and a 256 bit word for a hash of arbitrary data. Events are eventually pruned by Ethereum full nodes making their cost much cheaper but can be kept on archive nodes or otherwise indexed.
event AttestErc20 (
address indexed token,
uint256 indexed attestationType,
address from,
uint256 hashedData
);
Projects could then prompt their token holders to hash their data using Keccak hashing with an optional salt. A salt would allow token participants to put their data on chain without being as easily brute forced using a lookup table. This could be provided via an API endpoint provided by the Project in order to keep the salt a secret. In our use case this would be a Discord username which could later be recovered by hashing every server member’s username concatenated with a secret salt.
This salted and hashed data would then be sent to a smart contract that verifies that the transaction sender holds a non-zero amount of the specified ERC20 token or owns a specific ID of a specified ERC721 token. If the balance check passes, the smart contract would emit an EVM Event that can be indexed by consumers.
The contract would look sort of like the following:
/**
* This is psudo code only, it hasn't been tested,
* reviewed, or fully developed.
*/
contract TokenAttestation {
event AttestErc20 (
address indexed token,
uint256 indexed attestationType,
address from,
uint256 hashedData
);
event AttestErc721 (
address indexed token,
uint256 indexed attestationType,
address from,
uint256 id,
uint256 hashedData
);
function erc20Verify (address token, uint256 attestationType, uint256 hashedData) public {
IERC20 erc20 = IERC20(token);
if (erc20.balanceOf(msg.sender) > 0) {
emit AttestErc20(token, attestationType, msg.sender, hashedData);
}
}
function erc721Verify (address token, uint256 attestationType, uint256 id, uint256 hashedData) public {
IERC721 erc721 = IERC721(token);
if (erc721.ownerOf(id) == msg.sender) {
emit AttestErc721(token, attestationType, msg.sender, id, hashedData);
}
}
}
Verification
One of the possible consumers - and our use case - would be a Discord bot that periodically fetches all of the on-chain attestations, token transfers, and Discord server members. It would then remove any outdated attestations and transfers (events that predate transfers of NFTs or balances). The set of attestations would then be used to filter the list of server members to find token holders. Any mismatch between the two lists would be where the Discord bot would add/remove Roles.
This is an early draft but I want to share it early to see if anyone has any useful input on how the system could work.