Source Code

(define-constant ERR_NOT_AUTH (err u900))
(define-constant ERR_PARTICIPANT_NOT_FOUND (err u901))
(define-constant ERR_ALREADY_CLAIMED (err u902))
(define-constant ERR_INVALID_SHARE (err u903))
(define-constant ERR_NO_CURRENT_EPOCH (err u904))
(define-constant ERR_INVALID_EPOCH (err u905))
(define-constant ERR_NO_AVAILABLE_REBATES (err u906))
(define-constant ERR_PARTICIPANT_ALREADY_SET (err u907))
(define-constant ERR_INVALID_PARAMETERS (err u908))
(define-constant ERR_INVALID_BALANCE (err u909))
(define-constant ERR_INSUFFICIENT_BALANCE (err u910))
(define-constant ERR_INVALID_AGGREGATE_SHARE (err u911))
(define-constant ERR_LIST_OVERFLOW (err u912))

(define-constant ONE_HUNDRED_PERCENT u100000000)

;; Admin for managing the rebate contract
(define-data-var admin principal 'SP1W0BTVH2TASXZMG219X3Y6C2BE01KMQ6TT880YF)

;; Create a map to store the epoch info
(define-map epoch-info uint {epoch: uint, rebate-balance: uint, participants: (list 1000 principal)})

;; Complex map to store participant information for each epoch
(define-map epoch-participants-info 
    {epoch: uint, participant: principal}  
    { 
        share: uint, 
        balance: uint,
        claimed: bool,
    }
)

;; ************* Admin Methods *************
;; set admin
(define-public (set-admin (new-admin principal))
    (begin
        (asserts! (is-eq tx-sender (var-get admin)) ERR_NOT_AUTH)
        (ok (var-set admin new-admin))
    )
)

;; get admin
(define-read-only (get-admin)
    (ok (var-get admin))
)

;; privileged withdraw
(define-public (withdraw-admin (amount uint))
    (begin
        (asserts! (is-eq tx-sender (var-get admin)) ERR_NOT_AUTH)
        (as-contract (contract-call? .bsd-mock-vpv-17 transfer amount tx-sender (var-get admin) none))
    )
)

;; ************* Epoch Methods *************

;; get participant info for an epoch and participant
(define-read-only (get-participant-info (epoch uint) (participant principal))
    (ok (unwrap! (map-get? epoch-participants-info {epoch: epoch, participant: participant}) ERR_PARTICIPANT_NOT_FOUND))
)

;; get all participants for an epoch
(define-read-only (get-epoch-info (epoch uint))
    (ok (unwrap! (map-get? epoch-info epoch) ERR_INVALID_EPOCH))
)

;; batch set participant info for an epoch and participants
(define-public (batch-set-participant-info (epoch uint) (rebate-balance uint) (participants (list 100 principal)) (shares (list 100 uint)) (balances (list 100 uint)))
    (let 
        (
            (is-auth (asserts! (is-eq tx-sender (var-get admin)) ERR_NOT_AUTH))
            (is-valid-epoch (asserts! (is-eq (contract-call? .registry-vpv-17 get-current-epoch) epoch) ERR_INVALID_EPOCH))
            (is-valid-balance (asserts! (> rebate-balance u0) ERR_NO_AVAILABLE_REBATES))
            (is-sufficient-balance (asserts! (>= (unwrap! (contract-call? .bsd-mock-vpv-17 get-balance (as-contract tx-sender)) ERR_NO_AVAILABLE_REBATES) rebate-balance) ERR_INSUFFICIENT_BALANCE))
            (info (default-to {epoch: epoch, rebate-balance: u0, participants: (list)} (map-get? epoch-info epoch)))
            (current-participants (get participants info))
            (update-response (try! (fold set-participant-info participants (ok {index: u0, current-share: u0, epoch: epoch, shares: shares, balances: balances, participants: current-participants}))))
            (new-participants (get participants update-response))
        )
        (map-set epoch-info epoch {epoch: epoch, rebate-balance: rebate-balance, participants: new-participants})
        (print {batch-set-participant-info-event: {epoch: epoch, rebate-balance: rebate-balance, participants: participants, shares: shares, balances: balances}})
        (ok true)
    )
)

;; set participant info for an epoch and participant
(define-private (set-participant-info (participant principal) (update-response (response { index: uint, current-share: uint, epoch: uint, shares: (list 100 uint), balances: (list 100 uint), participants: (list 1000 principal)} uint)))
    (match update-response
        helper-tuple
            (let 
                (
                    (index (get index helper-tuple))
                    (epoch (get epoch helper-tuple))
                    (current-share (get current-share helper-tuple))
                    (shares (get shares helper-tuple))
                    (share (unwrap-panic (element-at? shares index)))
                    (aggregate-share (+ current-share share))
                    (balances (get balances helper-tuple))
                    (balance (unwrap-panic (element-at? balances index)))
                    (participants (get participants helper-tuple))
                    (new-participants (unwrap! (as-max-len? (append participants participant) u1000) ERR_LIST_OVERFLOW))
                )

                (asserts! (<= aggregate-share ONE_HUNDRED_PERCENT) ERR_INVALID_AGGREGATE_SHARE)
                (asserts! (and (> share u0) (<= share ONE_HUNDRED_PERCENT)) ERR_INVALID_SHARE)
                (asserts! (> balance u0) ERR_INVALID_BALANCE)
                (asserts! (is-none (map-get? epoch-participants-info {epoch: epoch, participant: participant})) ERR_PARTICIPANT_ALREADY_SET)
                (map-set epoch-participants-info {epoch: epoch, participant: participant} {share: share, balance: balance, claimed: false})

                (ok {index: (+ index u1), current-share: aggregate-share, epoch: epoch, shares: shares, balances: balances, participants: new-participants})    
            )
        err-resp
        (err err-resp)
    )
)

;; ************* Participant Methods *************

;; claim rebate
(define-public (claim-rebate (epoch uint))
    (let 
        (
            (participant-info (unwrap! (map-get? epoch-participants-info {epoch: epoch, participant: tx-sender}) ERR_PARTICIPANT_NOT_FOUND))
            (share (get share participant-info))
            (balance (get balance participant-info))
            (claimed (get claimed participant-info))
            (current-epoch (contract-call? .registry-vpv-17 get-current-epoch))
            (total-rebate (get rebate-balance (unwrap! (map-get? epoch-info epoch) ERR_NO_AVAILABLE_REBATES)))
            (rebate-amount (/ (* share total-rebate) ONE_HUNDRED_PERCENT))
			(contract-balance (unwrap! (contract-call? .bsd-mock-vpv-17 get-balance (as-contract tx-sender)) ERR_NO_AVAILABLE_REBATES))
        )

        (asserts! (is-eq epoch current-epoch) ERR_INVALID_EPOCH)
        (asserts! (not claimed) ERR_ALREADY_CLAIMED)
        (asserts! (and (> share u0) (<= share ONE_HUNDRED_PERCENT)) ERR_INVALID_SHARE)
        (asserts! (> rebate-amount u0) ERR_NO_AVAILABLE_REBATES)
		(asserts! (>= contract-balance rebate-amount) ERR_INSUFFICIENT_BALANCE)
        (print 
            {
                claim-rebate-event: {
                    epoch: epoch,
                    participant: tx-sender,
                    share: share,
                    balance: balance,
                    claimed: claimed,
                    current-epoch: current-epoch,
                    total-rebate: total-rebate,
                    rebate-amount: rebate-amount,
                }
            }
        )
        (map-set epoch-participants-info {epoch: epoch, participant: tx-sender} {share: share, balance: balance, claimed: true})
        (try! (contract-call? .bsd-mock-vpv-17 transfer rebate-amount (as-contract tx-sender) tx-sender none))
        (ok true)
    )
)

Functions (7)

FunctionAccessArgs
set-adminpublicnew-admin: principal
get-adminread-only
withdraw-adminpublicamount: uint
get-participant-inforead-onlyepoch: uint, participant: principal
get-epoch-inforead-onlyepoch: uint
batch-set-participant-infopublicepoch: uint, rebate-balance: uint, participants: (list 100 principal
claim-rebatepublicepoch: uint