Source Code

(define-constant contract-owner tx-sender)
(define-constant err-owner-only (err u100))
(define-constant err-not-found (err u101))
(define-constant err-unauthorized (err u102))
(define-constant err-invalid-params (err u103))
(define-constant err-not-member (err u104))

(define-map members
  {member-id: principal}
  {
    name: (string-ascii 128),
    join-date: uint,
    shares: uint,
    active: bool,
    contribution: uint
  }
)

(define-map proposals
  {proposal-id: uint}
  {
    title: (string-ascii 256),
    proposer: principal,
    votes-for: uint,
    votes-against: uint,
    status: (string-ascii 16),
    created-at: uint,
    ends-at: uint
  }
)

(define-map votes
  {proposal-id: uint, voter: principal}
  {vote: bool, shares: uint}
)

(define-data-var total-shares uint u0)
(define-data-var proposal-nonce uint u0)
(define-data-var treasury-balance uint u0)

(define-read-only (get-member (member-id principal))
  (map-get? members {member-id: member-id})
)

(define-read-only (get-proposal (proposal-id uint))
  (map-get? proposals {proposal-id: proposal-id})
)

(define-read-only (get-vote (proposal-id uint) (voter principal))
  (map-get? votes {proposal-id: proposal-id, voter: voter})
)

(define-public (join-cooperative (name (string-ascii 128)) (initial-contribution uint))
  (begin
    (asserts! (> initial-contribution u0) err-invalid-params)
    (map-set members {member-id: tx-sender}
      {
        name: name,
        join-date: stacks-block-height,
        shares: initial-contribution,
        active: true,
        contribution: initial-contribution
      }
    )
    (var-set total-shares (+ (var-get total-shares) initial-contribution))
    (ok true)
  )
)

(define-public (add-contribution (amount uint))
  (let ((member (unwrap! (map-get? members {member-id: tx-sender}) err-not-member)))
    (asserts! (get active member) err-unauthorized)
    (asserts! (> amount u0) err-invalid-params)
    (map-set members {member-id: tx-sender}
      (merge member {
        shares: (+ (get shares member) amount),
        contribution: (+ (get contribution member) amount)
      })
    )
    (var-set total-shares (+ (var-get total-shares) amount))
    (ok true)
  )
)

(define-public (create-proposal
  (title (string-ascii 256))
  (duration uint)
)
  (let (
    (member (unwrap! (map-get? members {member-id: tx-sender}) err-not-member))
    (proposal-id (var-get proposal-nonce))
  )
    (asserts! (get active member) err-unauthorized)
    (map-set proposals {proposal-id: proposal-id}
      {
        title: title,
        proposer: tx-sender,
        votes-for: u0,
        votes-against: u0,
        status: "active",
        created-at: stacks-block-height,
        ends-at: (+ stacks-block-height duration)
      }
    )
    (var-set proposal-nonce (+ proposal-id u1))
    (ok proposal-id)
  )
)

(define-public (vote-on-proposal (proposal-id uint) (vote-for bool))
  (let (
    (proposal (unwrap! (map-get? proposals {proposal-id: proposal-id}) err-not-found))
    (member (unwrap! (map-get? members {member-id: tx-sender}) err-not-member))
  )
    (asserts! (get active member) err-unauthorized)
    (asserts! (is-eq (get status proposal) "active") err-invalid-params)
    (asserts! (< stacks-block-height (get ends-at proposal)) err-invalid-params)
    (asserts! (is-none (map-get? votes {proposal-id: proposal-id, voter: tx-sender})) err-invalid-params)
    (map-set votes {proposal-id: proposal-id, voter: tx-sender}
      {vote: vote-for, shares: (get shares member)}
    )
    (ok (map-set proposals {proposal-id: proposal-id}
      (merge proposal {
        votes-for: (if vote-for (+ (get votes-for proposal) (get shares member)) (get votes-for proposal)),
        votes-against: (if vote-for (get votes-against proposal) (+ (get votes-against proposal) (get shares member)))
      })
    ))
  )
)

(define-public (finalize-proposal (proposal-id uint))
  (let ((proposal (unwrap! (map-get? proposals {proposal-id: proposal-id}) err-not-found)))
    (asserts! (>= stacks-block-height (get ends-at proposal)) err-invalid-params)
    (ok (map-set proposals {proposal-id: proposal-id}
      (merge proposal {
        status: (if (> (get votes-for proposal) (get votes-against proposal)) "passed" "rejected")
      })
    ))
  )
)

Functions (8)

FunctionAccessArgs
get-memberread-onlymember-id: principal
get-proposalread-onlyproposal-id: uint
get-voteread-onlyproposal-id: uint, voter: principal
join-cooperativepublicname: (string-ascii 128
add-contributionpublicamount: uint
create-proposalpublictitle: (string-ascii 256
vote-on-proposalpublicproposal-id: uint, vote-for: bool
finalize-proposalpublicproposal-id: uint