micropayment-with-revenue-sharing

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-insufficient-balance (err u105))

(define-data-var payment-nonce uint u0)

(define-map service-providers
  principal
  {
    service-type: (string-ascii 40),
    revenue-share-rate: uint,
    total-earned: uint,
    total-revenue-shared: uint,
    active: bool
  }
)

(define-map micropayments
  uint
  {
    payer: principal,
    provider: principal,
    amount: uint,
    service-hash: (buff 32),
    payment-block: uint,
    revenue-distributed: bool
  }
)

(define-map revenue-shares
  {payment-id: uint, beneficiary: principal}
  {
    share-amount: uint,
    distributed: bool
  }
)

(define-map user-balances
  principal
  uint
)

(define-map provider-payments principal (list 200 uint))

(define-public (register-provider (service-type (string-ascii 40)) (revenue-share-rate uint))
  (begin
    (asserts! (is-none (map-get? service-providers tx-sender)) err-already-exists)
    (asserts! (<= revenue-share-rate u10000) err-invalid-amount)
    (map-set service-providers tx-sender
      {
        service-type: service-type,
        revenue-share-rate: revenue-share-rate,
        total-earned: u0,
        total-revenue-shared: u0,
        active: true
      }
    )
    (ok true)
  )
)

(define-public (deposit-balance (amount uint))
  (begin
    (asserts! (> amount u0) err-invalid-amount)
    (try! (stx-transfer? amount tx-sender (as-contract tx-sender)))
    (map-set user-balances tx-sender
      (+ (default-to u0 (map-get? user-balances tx-sender)) amount))
    (ok true)
  )
)

(define-public (make-micropayment (provider principal) (amount uint) (service-hash (buff 32)))
  (let
    (
      (provider-info (unwrap! (map-get? service-providers provider) err-not-found))
      (user-balance (default-to u0 (map-get? user-balances tx-sender)))
      (payment-id (+ (var-get payment-nonce) u1))
    )
    (asserts! (> amount u0) err-invalid-amount)
    (asserts! (>= user-balance amount) err-insufficient-balance)
    (asserts! (get active provider-info) err-not-found)
    (map-set user-balances tx-sender (- user-balance amount))
    (map-set micropayments payment-id
      {
        payer: tx-sender,
        provider: provider,
        amount: amount,
        service-hash: service-hash,
        payment-block: stacks-block-height,
        revenue-distributed: false
      }
    )
    (map-set provider-payments provider
      (unwrap-panic (as-max-len? (append (default-to (list) (map-get? provider-payments provider)) payment-id) u200)))
    (var-set payment-nonce payment-id)
    (ok payment-id)
  )
)

(define-public (distribute-revenue (payment-id uint) (beneficiaries (list 10 {addr: principal, share: uint})))
  (let
    (
      (payment (unwrap! (map-get? micropayments payment-id) err-not-found))
      (provider-info (unwrap! (map-get? service-providers (get provider payment)) err-not-found))
    )
    (asserts! (is-eq tx-sender (get provider payment)) err-unauthorized)
    (asserts! (not (get revenue-distributed payment)) err-already-exists)
    (let
      (
        (revenue-to-share (/ (* (get amount payment) (get revenue-share-rate provider-info)) u10000))
        (provider-amount (- (get amount payment) revenue-to-share))
      )
      (try! (as-contract (stx-transfer? provider-amount tx-sender (get provider payment))))
      (map distribute-to-beneficiary beneficiaries)
      (map-set micropayments payment-id (merge payment {revenue-distributed: true}))
      (map-set service-providers (get provider payment) (merge provider-info {
        total-earned: (+ (get total-earned provider-info) provider-amount),
        total-revenue-shared: (+ (get total-revenue-shared provider-info) revenue-to-share)
      }))
      (ok true)
    )
  )
)

(define-private (distribute-to-beneficiary (beneficiary {addr: principal, share: uint}))
  (begin
    (unwrap-panic (as-contract (stx-transfer? (get share beneficiary) tx-sender (get addr beneficiary))))
    true
  )
)

(define-public (withdraw-balance (amount uint))
  (let
    (
      (balance (default-to u0 (map-get? user-balances tx-sender)))
    )
    (asserts! (>= balance amount) err-insufficient-balance)
    (try! (as-contract (stx-transfer? amount tx-sender tx-sender)))
    (map-set user-balances tx-sender (- balance amount))
    (ok true)
  )
)

(define-public (update-revenue-share-rate (new-rate uint))
  (let
    (
      (provider-info (unwrap! (map-get? service-providers tx-sender) err-not-found))
    )
    (asserts! (<= new-rate u10000) err-invalid-amount)
    (map-set service-providers tx-sender (merge provider-info {revenue-share-rate: new-rate}))
    (ok true)
  )
)

(define-read-only (get-provider (provider principal))
  (ok (map-get? service-providers provider))
)

(define-read-only (get-micropayment (payment-id uint))
  (ok (map-get? micropayments payment-id))
)

(define-read-only (get-user-balance (user principal))
  (ok (map-get? user-balances user))
)

(define-read-only (get-provider-payments (provider principal))
  (ok (map-get? provider-payments provider))
)

Functions (11)

FunctionAccessArgs
register-providerpublicservice-type: (string-ascii 40
deposit-balancepublicamount: uint
make-micropaymentpublicprovider: principal, amount: uint, service-hash: (buff 32
distribute-revenuepublicpayment-id: uint, beneficiaries: (list 10 {addr: principal, share: uint}
distribute-to-beneficiaryprivatebeneficiary: {addr: principal, share: uint}
withdraw-balancepublicamount: uint
update-revenue-share-ratepublicnew-rate: uint
get-providerread-onlyprovider: principal
get-micropaymentread-onlypayment-id: uint
get-user-balanceread-onlyuser: principal
get-provider-paymentsread-onlyprovider: principal