@msgboard/cosign
v0.0.32
Published
Generic signature-share SDK over MsgBoard, bucketed under rotating day-granular category keys
Maintainers
Readme
@msgboard/cosign
Generic signature-share SDK over MsgBoard: post, read, and
aggregate co-signature artifacts — (digest, signer, signature, scheme, meta) records — bucketed under
rotating, day-granular UTC category keys so the working set stays small and self-pruning.
App-agnostic. A pluggable adapter encodes a specific multisig's verify/order/owner-read rules. cosign is a
coordination/aggregation layer for existing off-chain-signature-aggregation multisig tools — it does not
build its own multisig. The generic core plus the CosignAdapter interface land first; concrete adapters ship
in this same package's src/adapters/ (the Gnosis Safe adapter first; full roadmap + non-fits in the cosign SDK
spec). Pure board + crypto: no chain writes.
Canonical encodings (law — downstream tooling mirrors these)
- Category key:
keccak256(toBytes(${namespace}:${scope}:${isoDate})), whereisoDateis UTCYYYY-MM-DD. Field separator is:; order isnamespace:scope:isoDate. - SignatureRecord ABI tuple (order is law):
(bytes32 digest, address signer, bytes signature, uint8 scheme, bytes meta). - Schemes:
SCHEME = { ECDSA: 0, EIP1271: 1, EIP712: 2 }.
Quick start
import { MsgBoardClient } from '@msgboard/sdk'
import {
type BoardClient,
type CosignAdapter,
SCHEME,
postSignature,
readSignatures,
groupByDigest,
aggregate,
} from '@msgboard/cosign'
// Wrap the real, lower-level MsgBoardClient into cosign's BoardClient seam.
// Posting is a two-step on the real client: doPoW (find a nonce) then addMessage.
function boardFrom(client: MsgBoardClient): BoardClient {
return {
async addMessage({ category, data }) {
const { message } = await client.doPoW(category, data)
return client.addMessage(message)
},
content({ category }) {
return client.content({ category })
},
}
}
const board = boardFrom(new MsgBoardClient(provider))
// Post a signature under today's rotating category.
await postSignature(board, {
namespace: 'cosign',
scope: 'acme-team',
record: { digest, signer, signature, scheme: SCHEME.ECDSA, meta: '0x' },
})
// Read the rolling 7-day window, group by digest, and aggregate via your adapter.
const records = await readSignatures(board, { namespace: 'cosign', scope: 'acme-team', days: 7 })
const forDigest = groupByDigest(records).get(digest) ?? []
const ordered = await aggregate(forDigest, myAdapter) // myAdapter satisfies CosignAdapter
// `ordered` is `{ signer, signature }[]` — hand to your existing execute path (out of scope here).The core +
CosignAdapterinterface land first — supply a concrete adapter to aggregate. Concrete adapters ship in this same package'ssrc/adapters/(the Gnosis Safe adapter first — its own spec/plan; full roadmap + non-fits in the cosign SDK spec §9).
API
keys:isoDay,categoryKey,currentKey,keysForWindow(all accept an explicitnow?: Date).record:SignatureRecord,SCHEME,RECORD_ABI,encodeRecord,decodeRecord(decode throws on junk).client:BoardClient,postSignature,readSignatures(skips undecodable junk, dedupes by data),groupByDigest,aggregate(filters byadapter.verify, appliesadapter.order; verify errors propagate).adapters:CosignAdapter(the seam — interface lands first; concrete adapters ship insrc/adapters/via follow-up plans, Safe first).
