Is there a repo for attestr?
Open and permissionless protocols are already winning. We're starting businesses, jumping over middlemen, leveraging trust networks to publicly attest to contracts, writing books, building shit.
This is a entire alternate parallel economy, market and society and its unstoppable.
For anyone looking for the details on the "contract" stuff... nostr:npub1qfc7rwddjl3lzhkhgge8ch82xjfm6e3gqcgk8zm6pahz3tvvl7gq88xnrh and I used https://attestr.app to sign a simple agreement and publicly attest to our commitment. You can view it in the attestr UI here: https://attestr.app/contract/attestr-17ffc45a-161c-443b-8ca2-de42387cb694 (the UI is a little wonky, you might have to have the Primal relay selected).
Here are the raw events:
- The "Draft" / contract: https://njump.me/naddr1qvzqqqz2r5pzp3at8g4pxshh3nct5sdhpalqns69zspqnl6tqas6shuas7qa502yqy2hwumn8ghj7un9d3shjtnyv9kh2uewd9hj7qpvv968getnw3ez6vfhvenxxdp4vyknzd33vvkngdpnvgknscmpxgkkgef5xgensdmrvgmrjdqppam0l
- nostr:npub1c74n52sngtmceu96gxms7lsfcdz3gqsfla9swcdgt7wc0qw684zqfe2cj2 's signature on the hash of the contract: https://njump.me/nevent1qqs07m40t67ulashgk9ujjz5ws95u6fkvf803gh6zlhp5skefr749zqzyqp8rcde4kt78u276aprylzuag6f80tx9qrpzcut0g8ku29d3nleqmywpzn
- nostr:npub1qfc7rwddjl3lzhkhgge8ch82xjfm6e3gqcgk8zm6pahz3tvvl7gq88xnrh 's signature on the same hash: https://njump.me/nevent1qqsg3krpq99dkh5ath7068w8vvt6dw2dzj74atfz0q4hk7tj7thrkrgzyrr6kw32zdp00r8shfqmwrm7p8p529qzp8l5kpmp4p0empupmg75g9l47j2
Just this week we've had someone [complete a catallax bounty](https://njump.me/nevent1qqsfs2culevc47wv45q6frlppd5pd689cumnhtt6g9zsnwu2uv77rlspp4mhxue69uhkummn9ekx7mqzyqh04fc4hw6xm4d7dd7634msqfndz9n5hyfms9u2mk6u9e3anpenzucehh8) involving a nostr publishing tool, and now Whitepaper Books is signing business deals with nostr authors using a nostr agreements tool.
Any more dog-fooding and I'll start chasing cats!
Discussion
there's just a silly shakespeare export of the ui. i need to make more of a "nip" repo now that i'm seeing the shape of it better. i'll post it when its ready.
briefly for now: https://github.com/vcavallo/attestr/blob/main/NIP.md
## Overview
Attestr is a protocol built on Nostr that allows **two parties to mutually sign a statement or promise**, timestamp it, and later attest whether it was honored. It uses existing Nostr primitives (events, tags, signatures) and optionally integrates OpenTimestamps for third-party timestamping.
## Event Kinds
| Kind | Name | Description |
| ------- | -------------------- | ---------------------------------------------- |
| `18973` | Draft Version | Replaceable drafts during negotiation |
| `30677` | Agreement Commitment | Each party signs the agreed hash |
| `35319` | Outcome Attestation | Each party marks "honored" or "disputed" |
## Event Structure
### Draft Version (`kind: 18973`)
Used during negotiation phase. Replaceable events that contain draft contract text. Each party can update their draft by publishing a new event with the same UUID, with only the latest version from each party being stored.
**Required tags:**
- `["d", "
- `["p", "
**Optional tags:**
- `["attestr-conclusion-date", "
- `["alt", "Attestr contract draft"]` - Human-readable description
**Content:** Draft contract text
**Behavior:** Since these are replaceable events (kind 18973), only the latest draft from each party is stored by relays. When a party updates their draft, it replaces their previous version. This keeps the negotiation focused on current positions without cluttering storage with outdated proposals.
**Note:** We use `attestr-conclusion-date` instead of the standard `expiration` tag to avoid conflicts with NIP-40, which would cause relays to automatically reject events past their expiration time.
### Agreement Commitment (`kind: 30677`)
Signed commitment to the final agreed contract hash.
**Required tags:**
- `["d", "
- `["sha256", "
- `["p", "
**Optional tags:**
- `["attestr-conclusion-date", "
- `["ots", "
- `["alt", "Attestr agreement commitment"]` - Human-readable description
**Content:** `agreement_hash=
### Outcome Attestation (`kind: 35319`)
Attestation of whether the contract was honored or disputed.
**Required tags:**
- `["d", "
- `["sha256", "
- `["p", "
**Optional tags:**
- `["alt", "Attestr outcome attestation"]` - Human-readable description
**Content:** `"honored"` or `"disputed"`
## Contract Lifecycle
1. **Negotiation:** Each party posts replaceable drafts (`18973`) until final text is agreed
- Parties can update their drafts by publishing new events with the same UUID
- Only the latest draft from each party is stored (replaceable behavior)
- Negotiation continues until both parties are satisfied with the current terms
2. **Commitment:** Both parties post `30677` signing the same `agreement_hash`
- Once committed, drafts can no longer be edited
- Both parties must sign the exact same contract text hash
3. **Outcome:** After maturity, parties post `35319` with `"honored"` or `"disputed"`
## Agreement Hash Computation
The agreement hash is computed as SHA-256 of the normalized contract text:
```javascript
function computeAgreementHash(contractText) {
const normalized = contractText.trim().replace(/\r\n/g, '\n');
return sha256(normalized);
}
```
## Verification
A contract is considered mutually agreed when:
1. Two distinct pubkeys have published `30677` events
2. Both events have the same UUID (`d` tag)
3. Both events have the same agreement hash (`sha256` tag)
## Contract UUID
Contract UUIDs should be globally unique identifiers, typically in the format `attestr-
Awesome thanks! Would love to implement this directly into Bloom so might have some ideas to throw your way.
Ooh very interesting... What purpose would agreements serve in bloom? Or are you thinking of the general idea of mutually signing
Yeah cosigning PDFs, things like thqt
cool yea that's great! i didn't exhaustively search the nips first to see if there is an existing "two people sign the same hash" thing anywhere - for all i know there is something even better out there. let me know how it goes!
(...and now that i'm thinking of it, any note id is already a hash of its content, so one of my steps is sort of unnecessary..)