Step 1 - Create your community
{
"name": "Gotham DAO",
"description": "Otterspace Raft",
"properties": {
"parentRaftTokenId": 12345,
"generation": 2
},
"image": "https://ipfs.io/ipfs/bafybeihgubwimcvwlmxz3s3iwyzuj5ltouww4wjayj2of3ojfibojridfe"
}
A raft token is an NFT (ERC-721) that represents your community within Otterspace. Above is the underlying metadata of your community.
Step 2 - Design a badge spec & upload to IPFS
{
"schema":"https://api.otterspace.xyz/schemas/badge/1.0.1.json",
"name":"First Badge",
"description":"Otterspace Badge",
"properties":{
"raftTokenId":"90",
"createdByAddress":"0xeD40624Deb1202e63D0729b6411FfA0Efb333aD9",
"expiresAt": "2023-07-21T13:57:28.882Z"
},
"image":"ipfs://bafybeifqjf35xulfl46uauwbsqbrjgxa4d3iybjvdq7bo6xzdlaq6mpr6u/image"
}
Badge are maximally backward compatible with ERC-721 and hence we use NFT metadata to represent the badge spec. The above badge spec on IPFS is uploaded at https://ipfs.io/ipfs/bafyreigrhoupt3dcjuadq7i34cetwla2axfwayyszffoixfrrmr2ttthoe/metadata.json
Step 3 - Airdrop this badge
Install the contracts
npm -i @otterspace-xyz/otterspace-contracts
Call the airdrop funciton on the contracts to mint an non-consented badge
import { Contract, Signer } from 'ethers'
import Badges from '@otterspace-xyz/contracts/out/Badges.sol/Badges.json' assert { type: 'json' }
const BADGES_CONTRACT_ADDRESS = '0x7F9279B24D1c36Fa3E517041fdb4E8788dc63D25'
const mintBadge = async (
toAddress: string,
fromAddress: Signer,
badgeSpecURI: string
): Promise<ContractCallResult> => {
const contract = new Contract(BADGES_CONTRACT_ADDRESS, Badges.abi, fromAddress)
const doAirdrop = contract['airdrop']
return await doAirdrop([toAddress], badgeSpecURI)
}
Minting consented badges
Follow same Step 1 & 2 from the above
Step 3 - Approve someone to mint this badge using EIP-712
In order to approve someone to mint a badge, a signature using EIP-712 is necessary
import { utils } from "ethers"
const typedData = {
domain: {
name: 'BADGES',
version: '1.0.0',
chainId: 10, // optimism chainId
verifyingContract: '0x7F9279B24D1c36Fa3E517041fdb4E8788dc63D25',
},
types: {
Agreement: [
{ name: 'active', type: 'address' },
{ name: 'passive', type: 'address' },
{ name: 'tokenURI', type: 'string' },
],
},
value: {
active: claimant.address, // issuer of badge
passive: issuer.address, // receiver of badge
tokenURI: specUri, // uri of badge
},
}
// See: https://docs.ethers.io/v5/api/signer/#Signer-signTypedData for more detailed instructions.
const signature = await signer._signTypedData(typedData.domain, typedData.types, typedData.value)
const { compactSignature } = utils.splitSignature(signature)
Step 4 - Claim and mint the badge using the signature
Install the contracts
npm -i @otterspace-xyz/otterspace-contracts
Call take(address _from, string calldata _uri, bytes calldata _signature)
on the Badges contract
import { Contract, Signer } from 'ethers'
import Badges from '@otterspace-xyz/contracts/out/Badges.sol/Badges.json' assert { type: 'json' }
const BADGES_CONTRACT_ADDRESS = '0x7F9279B24D1c36Fa3E517041fdb4E8788dc63D25'
const mintBadge = async (
badgeReceiver: Signer,
fromAddress: string,
badgeSpecURI: string,
compactSignature: string
): Promise<ContractCallResult> => {
const contract = new Contract(BADGES_CONTRACT_ADDRESS, Badges.abi, badgeReceiver)
const doTake = contract['take']
return await doTake(fromAddress, badgeSpecURI, compactSignature)
}