decentralized-advertisement-network

SP1V95DB4JK47QVPJBXCEN6MT35JK84CQ4CWS15DQ

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-already-exists (err u103))
(define-constant err-invalid-amount (err u104))
(define-constant err-campaign-inactive (err u105))

(define-data-var campaign-nonce uint u0)
(define-data-var impression-nonce uint u0)

(define-map ad-campaigns
  uint
  {
    advertiser: principal,
    campaign-name: (string-ascii 50),
    ad-content-hash: (buff 32),
    budget: uint,
    spent: uint,
    cost-per-impression: uint,
    target-impressions: uint,
    actual-impressions: uint,
    active: bool
  }
)

(define-map ad-impressions
  uint
  {
    campaign-id: uint,
    publisher: principal,
    viewer-hash: (buff 32),
    impression-block: uint,
    payment-amount: uint,
    verified: bool
  }
)

(define-map publisher-earnings
  principal
  uint
)

(define-map campaign-impressions uint (list 1000 uint))
(define-map advertiser-campaigns principal (list 50 uint))

(define-public (create-ad-campaign (campaign-name (string-ascii 50)) (ad-content-hash (buff 32)) (budget uint) (cost-per-impression uint) (target-impressions uint))
  (let
    (
      (campaign-id (+ (var-get campaign-nonce) u1))
    )
    (asserts! (> budget u0) err-invalid-amount)
    (asserts! (> cost-per-impression u0) err-invalid-amount)
    (asserts! (> target-impressions u0) err-invalid-amount)
    (try! (stx-transfer? budget tx-sender (as-contract tx-sender)))
    (map-set ad-campaigns campaign-id
      {
        advertiser: tx-sender,
        campaign-name: campaign-name,
        ad-content-hash: ad-content-hash,
        budget: budget,
        spent: u0,
        cost-per-impression: cost-per-impression,
        target-impressions: target-impressions,
        actual-impressions: u0,
        active: true
      }
    )
    (map-set advertiser-campaigns tx-sender
      (unwrap-panic (as-max-len? (append (default-to (list) (map-get? advertiser-campaigns tx-sender)) campaign-id) u50)))
    (var-set campaign-nonce campaign-id)
    (ok campaign-id)
  )
)

(define-public (record-impression (campaign-id uint) (viewer-hash (buff 32)))
  (let
    (
      (campaign (unwrap! (map-get? ad-campaigns campaign-id) err-not-found))
      (impression-id (+ (var-get impression-nonce) u1))
      (payment (get cost-per-impression campaign))
    )
    (asserts! (get active campaign) err-campaign-inactive)
    (asserts! (< (get actual-impressions campaign) (get target-impressions campaign)) err-campaign-inactive)
    (asserts! (<= (+ (get spent campaign) payment) (get budget campaign)) err-invalid-amount)
    (map-set ad-impressions impression-id
      {
        campaign-id: campaign-id,
        publisher: tx-sender,
        viewer-hash: viewer-hash,
        impression-block: stacks-block-height,
        payment-amount: payment,
        verified: false
      }
    )
    (map-set campaign-impressions campaign-id
      (unwrap-panic (as-max-len? (append (default-to (list) (map-get? campaign-impressions campaign-id)) impression-id) u1000)))
    (var-set impression-nonce impression-id)
    (ok impression-id)
  )
)

(define-public (verify-and-pay-impression (impression-id uint))
  (let
    (
      (impression (unwrap! (map-get? ad-impressions impression-id) err-not-found))
      (campaign (unwrap! (map-get? ad-campaigns (get campaign-id impression)) err-not-found))
    )
    (asserts! (is-eq tx-sender (get advertiser campaign)) err-unauthorized)
    (asserts! (not (get verified impression)) err-already-exists)
    (try! (as-contract (stx-transfer? (get payment-amount impression) tx-sender (get publisher impression))))
    (map-set ad-impressions impression-id (merge impression {verified: true}))
    (map-set ad-campaigns (get campaign-id impression) (merge campaign {
      spent: (+ (get spent campaign) (get payment-amount impression)),
      actual-impressions: (+ (get actual-impressions campaign) u1)
    }))
    (map-set publisher-earnings (get publisher impression)
      (+ (default-to u0 (map-get? publisher-earnings (get publisher impression))) (get payment-amount impression)))
    (ok true)
  )
)

(define-public (pause-campaign (campaign-id uint))
  (let
    (
      (campaign (unwrap! (map-get? ad-campaigns campaign-id) err-not-found))
    )
    (asserts! (is-eq tx-sender (get advertiser campaign)) err-unauthorized)
    (map-set ad-campaigns campaign-id (merge campaign {active: false}))
    (ok true)
  )
)

(define-public (resume-campaign (campaign-id uint))
  (let
    (
      (campaign (unwrap! (map-get? ad-campaigns campaign-id) err-not-found))
    )
    (asserts! (is-eq tx-sender (get advertiser campaign)) err-unauthorized)
    (asserts! (< (get actual-impressions campaign) (get target-impressions campaign)) err-campaign-inactive)
    (map-set ad-campaigns campaign-id (merge campaign {active: true}))
    (ok true)
  )
)

(define-public (withdraw-remaining-budget (campaign-id uint))
  (let
    (
      (campaign (unwrap! (map-get? ad-campaigns campaign-id) err-not-found))
      (remaining (- (get budget campaign) (get spent campaign)))
    )
    (asserts! (is-eq tx-sender (get advertiser campaign)) err-unauthorized)
    (asserts! (not (get active campaign)) err-campaign-inactive)
    (asserts! (> remaining u0) err-invalid-amount)
    (try! (as-contract (stx-transfer? remaining tx-sender (get advertiser campaign))))
    (map-set ad-campaigns campaign-id (merge campaign {budget: (get spent campaign)}))
    (ok true)
  )
)

(define-read-only (get-ad-campaign (campaign-id uint))
  (ok (map-get? ad-campaigns campaign-id))
)

(define-read-only (get-impression (impression-id uint))
  (ok (map-get? ad-impressions impression-id))
)

(define-read-only (get-publisher-earnings (publisher principal))
  (ok (map-get? publisher-earnings publisher))
)

(define-read-only (get-campaign-impressions (campaign-id uint))
  (ok (map-get? campaign-impressions campaign-id))
)

(define-read-only (get-advertiser-campaigns (advertiser principal))
  (ok (map-get? advertiser-campaigns advertiser))
)

Functions (11)

FunctionAccessArgs
create-ad-campaignpubliccampaign-name: (string-ascii 50
record-impressionpubliccampaign-id: uint, viewer-hash: (buff 32
verify-and-pay-impressionpublicimpression-id: uint
pause-campaignpubliccampaign-id: uint
resume-campaignpubliccampaign-id: uint
withdraw-remaining-budgetpubliccampaign-id: uint
get-ad-campaignread-onlycampaign-id: uint
get-impressionread-onlyimpression-id: uint
get-publisher-earningsread-onlypublisher: principal
get-campaign-impressionsread-onlycampaign-id: uint
get-advertiser-campaignsread-onlyadvertiser: principal