Source Code

;; drift-seed - Token Launchpad Protocol
;; Decentralized token launch and fair distribution

(define-constant CONTRACT-OWNER tx-sender)
(define-constant MIN-RAISE u1000000000)
(define-constant MAX-RAISE u100000000000)
(define-constant MIN-CONTRIBUTION u10000000)
(define-constant MAX-CONTRIBUTION u1000000000)
(define-constant ERR-OWNER-ONLY (err u100))
(define-constant ERR-NOT-ACTIVE (err u101))
(define-constant ERR-ALREADY-CLAIMED (err u102))
(define-constant ERR-BELOW-MIN (err u103))
(define-constant ERR-ABOVE-MAX (err u104))
(define-constant ERR-NOT-ENDED (err u105))
(define-constant ERR-GOAL-NOT-MET (err u106))

(define-map launches uint
  { creator: principal, token-address: (optional principal),
    soft-cap: uint, hard-cap: uint,
    start-block: uint, end-block: uint,
    total-raised: uint, finalized: bool, refunded: bool,
    title: (string-ascii 64), description: (string-utf8 512) })

(define-map contributions { launch-id: uint, contributor: principal } uint)
(define-map claimed { launch-id: uint, contributor: principal } bool)

(define-data-var launch-count uint u0)
(define-data-var platform-fee uint u200)

(define-public (create-launch
    (soft-cap uint) (hard-cap uint)
    (start-block uint) (end-block uint)
    (title (string-ascii 64)) (description (string-utf8 512)))
  (let ((lid (+ (var-get launch-count) u1)))
    (asserts! (is-eq tx-sender CONTRACT-OWNER) ERR-OWNER-ONLY)
    (asserts! (>= soft-cap MIN-RAISE) ERR-BELOW-MIN)
    (asserts! (<= hard-cap MAX-RAISE) ERR-ABOVE-MAX)
    (map-set launches lid
      { creator: tx-sender, token-address: none,
        soft-cap: soft-cap, hard-cap: hard-cap,
        start-block: start-block, end-block: end-block,
        total-raised: u0, finalized: false, refunded: false,
        title: title, description: description })
    (var-set launch-count lid)
    (ok lid)))

(define-public (contribute (launch-id uint) (amount uint))
  (let ((launch (unwrap! (map-get? launches launch-id) ERR-NOT-ACTIVE)))
    (asserts! (>= block-height (get start-block launch)) ERR-NOT-ACTIVE)
    (asserts! (<= block-height (get end-block launch)) ERR-NOT-ACTIVE)
    (asserts! (>= amount MIN-CONTRIBUTION) ERR-BELOW-MIN)
    (asserts! (<= (+ amount (default-to u0 (map-get? contributions { launch-id: launch-id, contributor: tx-sender })))
                  MAX-CONTRIBUTION) ERR-ABOVE-MAX)
    (asserts! (< (get total-raised launch) (get hard-cap launch)) ERR-ABOVE-MAX)
    (try! (stx-transfer? amount tx-sender (as-contract tx-sender)))
    (map-set contributions { launch-id: launch-id, contributor: tx-sender }
      (+ amount (default-to u0 (map-get? contributions { launch-id: launch-id, contributor: tx-sender }))))
    (map-set launches launch-id (merge launch { total-raised: (+ (get total-raised launch) amount) }))
    (ok true)))

(define-public (finalize (launch-id uint))
  (let ((launch (unwrap! (map-get? launches launch-id) ERR-NOT-ACTIVE)))
    (asserts! (is-eq tx-sender (get creator launch)) ERR-OWNER-ONLY)
    (asserts! (> block-height (get end-block launch)) ERR-NOT-ENDED)
    (asserts! (>= (get total-raised launch) (get soft-cap launch)) ERR-GOAL-NOT-MET)
    (let ((fee (/ (* (get total-raised launch) (var-get platform-fee)) u10000))
          (net (- (get total-raised launch) fee)))
      (try! (as-contract (stx-transfer? net tx-sender (get creator launch))))
      (try! (as-contract (stx-transfer? fee tx-sender CONTRACT-OWNER)))
      (ok (map-set launches launch-id (merge launch { finalized: true }))))))

(define-public (refund (launch-id uint))
  (let ((launch (unwrap! (map-get? launches launch-id) ERR-NOT-ACTIVE))
        (contribution (default-to u0 (map-get? contributions { launch-id: launch-id, contributor: tx-sender }))))
    (asserts! (> block-height (get end-block launch)) ERR-NOT-ENDED)
    (asserts! (or (< (get total-raised launch) (get soft-cap launch)) (get refunded launch)) ERR-ALREADY-CLAIMED)
    (asserts! (> contribution u0) ERR-BELOW-MIN)
    (asserts! (is-none (map-get? claimed { launch-id: launch-id, contributor: tx-sender })) ERR-ALREADY-CLAIMED)
    (map-set claimed { launch-id: launch-id, contributor: tx-sender } true)
    (as-contract (stx-transfer? contribution tx-sender contract-caller))))

(define-read-only (get-launch (launch-id uint)) (ok (map-get? launches launch-id)))
(define-read-only (get-contribution (launch-id uint) (contributor principal))
  (ok (map-get? contributions { launch-id: launch-id, contributor: contributor })))
(define-read-only (get-launch-count) (ok (var-get launch-count)))

Functions (7)

FunctionAccessArgs
create-launchpublicsoft-cap: uint, hard-cap: uint, start-block: uint, end-block: uint, title: (string-ascii 64
contributepubliclaunch-id: uint, amount: uint
finalizepubliclaunch-id: uint
refundpubliclaunch-id: uint
get-launchread-onlylaunch-id: uint
get-contributionread-onlylaunch-id: uint, contributor: principal
get-launch-countread-only