Skip to content

Keep an allowlist, a ban list, a DAO roster, or a five-minute 2FA token on-chain. Membership is a balance; the manager adds by minting and removes by burning.

A membership collection is one token ID and two manager-only approvals: mint to add an address, burn to remove it. Any other collection, any BB-402 server, and any ante handler can then reference the roster with mustOwnTokens. For a plain list with no balances, a stored address list from MsgCreateAddressLists does the same job and plugs into any toListId or initiatedByListId, including inverted with ! for a ban list.

Two variants stretch the same shape. A DAO roster becomes a multi-sig when its approvals carry votingChallenges. A 2FA collection mints tokens that expire in five minutes, so "holds one right now" is proof of a fresh second factor.

What Makes It Work

RequirementToken-standard primitive
Manager adds a membermanager-add approval: fromListId: "Mint", initiatedByListId = manager
Manager removes a membermanager-remove approval: fromListId: "!Mint", toListId = burn address, initiatedByListId = manager, overridesFromOutgoingApprovals: true. See Overrides
Members cannot transfer membershipNo other approval on the collection
Other collections check membershipmustOwnTokens with this collection's ID. See Token Ownership
Allowlist or ban list in any approvalA stored list ID in toListId, or !listId to exclude. See Address Lists
Votes from the rostervotingChallenges with members as voters and a quorumThreshold. See Voting Challenges
Token that expires in minutesownershipTimes of [now, now + 300000] on the mint, with autoDeletionOptions.allowPurgeIfExpired: true. See Auto-Deletion

The Fields That Matter

json
{
  "standards": ["Address List"],
  "validTokenIds": [{ "start": "1", "end": "1" }],
  "collectionApprovals": [
    {
      "approvalId": "manager-add",
      "fromListId": "Mint",
      "toListId": "All",
      "initiatedByListId": "bb1p0rrel3365scadq5k9pv0x0zp9j22js6dnw70d",
      "approvalCriteria": { "overridesFromOutgoingApprovals": true, "overridesToIncomingApprovals": false }
    },
    {
      "approvalId": "manager-remove",
      "fromListId": "!Mint",
      "toListId": "bb1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqs7gvmv",
      "initiatedByListId": "bb1p0rrel3365scadq5k9pv0x0zp9j22js6dnw70d",
      "approvalCriteria": { "overridesFromOutgoingApprovals": true, "overridesToIncomingApprovals": false }
    }
  ]
}
manager-addcollectionID: manager-add
SenderMint
RecipientAll
Initiatorbb1p0rrel3...w70d
Transfer TimesAll time
Token IDsAll
Ownership TimesAll time
Skips sender outgoing approvals

The manager-add approval as the transferability tab lists it: only alice can mint a membership.

A 2FA mint is a MsgTransferTokens whose balance carries the short window:

json
{
  "from": "Mint",
  "toAddresses": ["bb1py4mfpg6uf59qkyzg0nmau322c5873eeysp5ue"],
  "balances": [{ "amount": "1", "tokenIds": [{ "start": "1", "end": "1" }], "ownershipTimes": [{ "start": "1788739200000", "end": "1788739500000" }] }]
}
bash
bb build address-list --name "Allowlist" --description "Approved addresses" \
  --image ipfs://bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi/list.png
bb build custom-2fa --creator bb1p0rrel3365scadq5k9pv0x0zp9j22js6dnw70d --name "Demo 2FA" \
  --image ipfs://bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi/2fa.png --description "Short-lived 2FA token"

The first emits an Address List collection with the two manager approvals above. The second emits a Custom-2FA collection whose mint approval only the manager can use; bb custom-2fa mint then issues tokens with the five-minute window.

Variations

  • Self-service join: replace initiatedByListId on manager-add with All and add coinTransfers for a paid membership, or merkleChallenges for an invite code.
  • Expiring membership: mint with ownershipTimes and renew like a subscription.
  • DAO treasury: a payout approval with votingChallenges over the roster, resetAfterExecution: true for recurring votes, and delayAfterQuorum as a timelock. See Multi-Sig Voting.
  • Public ban list: an Address List collection anyone can reference as ! in their own approvals, or in a BB-402 condition with mustOwnAmounts: { "start": "0", "end": "0" }.
  • Withdraw gate: point a vault's mustOwnTokens at the 2FA collection. See Agent Vaults and Spending Limits.

Build It

text
Load the address-list skill. Build a members collection called Council where only bb1p0rrel3365scadq5k9pv0x0zp9j22js6dnw70d can add and remove members and members cannot transfer. Validate, review, simulate, then give me the review link.

Edit this page on GitHub