diff --git a/Clarinet.toml b/Clarinet.toml index b281098..3a962ea 100644 --- a/Clarinet.toml +++ b/Clarinet.toml @@ -36,12 +36,16 @@ epoch = 2.4 path = "contracts/traits/proposal-trait.clar" epoch = 2.4 -[contracts.transfer-provider-trait] -path = "contracts/traits/transfer-provider-trait.clar" +[contracts.proxy-trait] +path = "contracts/traits/proxy-trait.clar" epoch = 2.4 -[contracts.stx-transfer-provider] -path = "contracts/transfer-providers/stx-transfer-provider.clar" +[contracts.stx-transfer-proxy] +path = "contracts/proxies/stx-transfer-proxy.clar" +epoch = 2.4 + +[contracts.stx-transfer-many-proxy] +path = "contracts/proxies/stx-transfer-many-proxy.clar" epoch = 2.4 [contracts.fastpool-strategy] @@ -137,11 +141,11 @@ path = "contracts/extensions/fastpool-strategy-manager.clar" epoch = 2.4 [contracts.lqstx-mint-endpoint] -path = "contracts/lqstx-mint-endpoint.clar" +path = "contracts/extensions/lqstx-mint-endpoint.clar" epoch = 2.4 [contracts.lqstx-mint-registry] -path = "contracts/lqstx-mint-registry.clar" +path = "contracts/extensions/lqstx-mint-registry.clar" epoch = 2.4 [contracts.token-lqstx] @@ -152,6 +156,14 @@ epoch = 2.4 path = "contracts/token-wlqstx.clar" epoch = 2.4 +[contracts.lisa-rebase] +path = "contracts/extensions/lisa-rebase.clar" +epoch = 2.4 + +[contracts.rebase-1] +path = "contracts/rules/rebase-1.clar" +epoch = 2.4 + # [repl.analysis] # passes = ["check_checker"] # check_checker = { trusted_sender = false, trusted_caller = false, callee_filter = false } diff --git a/contracts/boot.clar b/contracts/boot.clar index b51ea4d..f770add 100644 --- a/contracts/boot.clar +++ b/contracts/boot.clar @@ -6,6 +6,8 @@ {extension: .deposit-stx, enabled: true} {extension: .vault, enabled: true} {extension: .fastpool-strategy-manager, enabled: true} + {extension: .lisa-rebase, enabled: true} + {extension: .rebase-1, enabled: true} ))) (ok true) ) diff --git a/contracts/extensions/fastpool-strategy-manager.clar b/contracts/extensions/fastpool-strategy-manager.clar index 5d22333..2ba92c8 100644 --- a/contracts/extensions/fastpool-strategy-manager.clar +++ b/contracts/extensions/fastpool-strategy-manager.clar @@ -1,5 +1,3 @@ -(impl-trait .extension-trait.extension-trait) - (define-constant err-unauthorised (err u10000)) (define-map authorised-managers principal bool) @@ -33,7 +31,3 @@ (ok (map-set authorised-managers who enabled)) ) ) - -(define-public (callback (sender principal) (memo (buff 34))) - (ok true) -) \ No newline at end of file diff --git a/contracts/extensions/lisa-rebase.clar b/contracts/extensions/lisa-rebase.clar new file mode 100644 index 0000000..617162e --- /dev/null +++ b/contracts/extensions/lisa-rebase.clar @@ -0,0 +1,19 @@ +(use-trait strategy-trait .strategy-trait.strategy-trait) + +(define-constant err-unauthorised (err u3000)) + +(define-read-only (is-dao-or-extension) + (ok (asserts! (or (is-eq tx-sender .lisa-dao) (contract-call? .lisa-dao is-extension contract-caller)) err-unauthorised)) +) + +(define-private (sum-strategy-amounts (strategy ) (accumulator (response uint uint))) + (ok (+ (try! (contract-call? strategy get-amount-in-strategy)) (try! accumulator))) +) + +(define-public (rebase (strategies (list 20 ))) + (let ((total-stx (+ (stx-get-balance .vault) (try! (fold sum-strategy-amounts strategies (ok u0)))))) + (try! (is-dao-or-extension)) + (try! (contract-call? .token-lqstx set-reward-multiplier-from-balance total-stx)) + (ok total-stx) + ) +) diff --git a/contracts/lqstx-mint-endpoint.clar b/contracts/extensions/lqstx-mint-endpoint.clar similarity index 75% rename from contracts/lqstx-mint-endpoint.clar rename to contracts/extensions/lqstx-mint-endpoint.clar index 8eb349e..c0c8896 100644 --- a/contracts/lqstx-mint-endpoint.clar +++ b/contracts/extensions/lqstx-mint-endpoint.clar @@ -1,9 +1,6 @@ ;; ;; lqstx-mint-endpoint ;; - -(impl-trait .extension-trait.extension-trait) - (use-trait sip-010-trait 'SP3FBR2AGK5H9QBDH3EEN6DF8EK8JY7RX8QJ5SVTE.sip-010-trait-ft-standard.sip-010-trait) (define-constant err-unauthorised (err u1000)) @@ -11,6 +8,10 @@ (define-constant err-request-pending (err u1006)) (define-constant err-request-finalized-or-revoked (err u1007)) +(define-constant PENDING 0x00) +(define-constant FINALIZED 0x01) +(define-constant REVOKED 0x02) + (define-data-var paused bool true) ;; read-only calls @@ -24,15 +25,6 @@ (define-read-only (is-paused-or-fail) (ok (asserts! (not (is-paused)) err-paused))) -(define-read-only (get-pending) - (contract-call? .lqstx-mint-registry get-pending)) - -(define-read-only (get-finalized) - (contract-call? .lqstx-mint-registry get-finalized)) - -(define-read-only (get-revoked) - (contract-call? .lqstx-mint-registry get-revoked)) - (define-read-only (get-mint-request-or-fail (request-id uint)) (contract-call? .lqstx-mint-registry get-mint-request-or-fail request-id)) @@ -46,7 +38,7 @@ (let ( (request-details (try! (contract-call? .lqstx-mint-registry get-mint-request-or-fail request-id)))) (asserts! (>= (get-rewards-paid-upto) (get requested-at request-details)) err-request-pending) - (asserts! (is-eq (get-pending) (get status request-details)) err-request-finalized-or-revoked) + (asserts! (is-eq PENDING (get status request-details)) err-request-finalized-or-revoked) (ok true))) ;; @dev it favours smaller amounts as we do not allow partial burn @@ -56,7 +48,7 @@ (vaulted-amount (unwrap-panic (contract-call? .token-wlqstx get-shares-to-tokens (get amount request-details)))) (balance (stx-account .vault))) (asserts! (>= (* (get unlocked balance) u100) vaulted-amount) err-request-pending) - (asserts! (is-eq (get-pending) (get status request-details)) err-request-finalized-or-revoked) + (asserts! (is-eq PENDING (get status request-details)) err-request-finalized-or-revoked) (ok { vaulted-amount: vaulted-amount, balance: balance }))) (define-public (set-paused (new-paused bool)) @@ -70,7 +62,7 @@ (define-public (request-mint (amount-in-fixed uint)) (let ( (cycle (contract-call? 'SP000000000000000000002Q6VF78.pox-3 current-pox-reward-cycle)) - (request-details { requested-by: tx-sender, amount: amount-in-fixed, requested-at: cycle, status: (get-pending) }) + (request-details { requested-by: tx-sender, amount: amount-in-fixed, requested-at: cycle, status: PENDING }) (request-id (as-contract (try! (contract-call? .lqstx-mint-registry set-mint-request u0 request-details))))) (try! (is-paused-or-fail)) (try! (stx-transfer? (/ amount-in-fixed u100) tx-sender .lqstx-mint-registry)) @@ -84,22 +76,22 @@ (try! (validate-mint-request request-id)) (as-contract (try! (contract-call? .lqstx-mint-registry stx-transfer (/ (get amount request-details) u100) .vault))) (as-contract (try! (contract-call? .token-lqstx dao-mint-fixed (get amount request-details) (get requested-by request-details)))) - (as-contract (contract-call? .lqstx-mint-registry set-mint-request request-id (merge request-details { status: (get-finalized) }))))) + (as-contract (contract-call? .lqstx-mint-registry set-mint-request request-id (merge request-details { status: FINALIZED }))))) (define-public (revoke-mint (request-id uint)) (let ( (request-details (try! (get-mint-request-or-fail request-id)))) (try! (is-paused-or-fail)) (asserts! (is-eq tx-sender (get requested-by request-details)) err-unauthorised) - (asserts! (is-eq (get-pending) (get status request-details)) err-request-finalized-or-revoked) + (asserts! (is-eq PENDING (get status request-details)) err-request-finalized-or-revoked) (as-contract (try! (contract-call? .lqstx-mint-registry stx-transfer (/ (get amount request-details) u100) (get requested-by request-details)))) - (as-contract (contract-call? .lqstx-mint-registry set-mint-request request-id (merge request-details { status: (get-revoked) }))))) + (as-contract (contract-call? .lqstx-mint-registry set-mint-request request-id (merge request-details { status: REVOKED }))))) (define-public (request-burn (amount-in-fixed uint)) (let ( ;; @dev requested-at not used for burn (cycle (contract-call? 'SP000000000000000000002Q6VF78.pox-3 current-pox-reward-cycle)) - (request-details { requested-by: tx-sender, amount: amount-in-fixed, requested-at: cycle, status: (get-pending) }) + (request-details { requested-by: tx-sender, amount: amount-in-fixed, requested-at: cycle, status: PENDING }) (request-id (as-contract (try! (contract-call? .lqstx-mint-registry set-burn-request u0 request-details))))) (try! (is-paused-or-fail)) (try! (contract-call? .token-wlqstx mint-fixed amount-in-fixed tx-sender)) @@ -113,19 +105,16 @@ (transfer-wlqstx (as-contract (try! (contract-call? .lqstx-mint-registry transfer-fixed (get amount request-details) tx-sender .token-wlqstx)))) (validation-data (try! (validate-burn-request request-id)))) (try! (is-paused-or-fail)) - (as-contract (try! (contract-call? .token-wlqstx burn-fixed (get amount request-details) tx-sender))) - (as-contract (try! (contract-call? .token-lqstx dao-burn-fixed (get vaulted-amount validation-data) tx-sender))) - (as-contract (try! (contract-call? .vault dynamic-transfer .stx-transfer-provider (unwrap-panic (to-consensus-buff? { ustx: (/ (get vaulted-amount validation-data) u100), recipient: (get requested-by request-details) }))))) - (as-contract (contract-call? .lqstx-mint-registry set-burn-request request-id (merge request-details { status: (get-finalized) }))))) + (try! (contract-call? .token-wlqstx burn-fixed (get amount request-details) tx-sender)) + (try! (contract-call? .token-lqstx dao-burn-fixed (get vaulted-amount validation-data) tx-sender)) + (as-contract (try! (contract-call? .vault proxy-call .stx-transfer-proxy (unwrap-panic (to-consensus-buff? { ustx: (/ (get vaulted-amount validation-data) u100), recipient: (get requested-by request-details) }))))) + (as-contract (contract-call? .lqstx-mint-registry set-burn-request request-id (merge request-details { status: FINALIZED }))))) (define-public (revoke-burn (request-id uint)) (let ( (request-details (try! (get-burn-request-or-fail request-id)))) (try! (is-paused-or-fail)) - (asserts! (is-eq (get-pending) (get status request-details)) err-request-finalized-or-revoked) + (asserts! (is-eq PENDING (get status request-details)) err-request-finalized-or-revoked) (asserts! (is-eq tx-sender (get requested-by request-details)) err-unauthorised) - (as-contract (try! (contract-call? .token-wlqstx burn-fixed (get amount request-details) tx-sender))) + (try! (contract-call? .token-wlqstx burn-fixed (get amount request-details) tx-sender)) (as-contract (contract-call? .token-lqstx transfer-fixed (unwrap-panic (contract-call? .token-wlqstx get-shares-to-tokens (get amount request-details))) tx-sender (get requested-by request-details) none)))) - -(define-public (callback (extension principal) (payload (buff 34))) - (ok true)) diff --git a/contracts/lqstx-mint-registry.clar b/contracts/extensions/lqstx-mint-registry.clar similarity index 91% rename from contracts/lqstx-mint-registry.clar rename to contracts/extensions/lqstx-mint-registry.clar index 3505346..246db7a 100644 --- a/contracts/lqstx-mint-registry.clar +++ b/contracts/extensions/lqstx-mint-registry.clar @@ -8,17 +8,17 @@ (define-constant err-unauthorised (err u1000)) (define-constant err-unknown-request-id (err u1008)) -(define-constant PENDING u0) -(define-constant FINALIZED u1) -(define-constant REVOKED u2) +(define-constant PENDING 0x00) +(define-constant FINALIZED 0x01) +(define-constant REVOKED 0x02) (define-data-var rewards-paid-upto uint u0) (define-data-var mint-request-nonce uint u0) (define-data-var burn-request-nonce uint u0) -(define-map mint-requests uint { requested-by: principal, amount: uint, requested-at: uint, status: uint }) -(define-map burn-requests uint { requested-by: principal, amount: uint, requested-at: uint, status: uint }) +(define-map mint-requests uint { requested-by: principal, amount: uint, requested-at: uint, status: (buff 1) }) +(define-map burn-requests uint { requested-by: principal, amount: uint, requested-at: uint, status: (buff 1) }) ;; read-only calls @@ -53,7 +53,7 @@ (try! (contract-call? .token-lqstx set-reward-multiplier vault-balance)) (ok (var-set rewards-paid-upto cycle)))) -(define-public (set-mint-request (request-id uint) (details { requested-by: principal, amount: uint, requested-at: uint, status: uint })) +(define-public (set-mint-request (request-id uint) (details { requested-by: principal, amount: uint, requested-at: uint, status: (buff 1) })) (let ( (current-nonce (var-get mint-request-nonce)) @@ -63,7 +63,7 @@ (map-set mint-requests id details) (ok id))) -(define-public (set-burn-request (request-id uint) (details { requested-by: principal, amount: uint, requested-at: uint, status: uint })) +(define-public (set-burn-request (request-id uint) (details { requested-by: principal, amount: uint, requested-at: uint, status: (buff 1) })) (let ( (current-nonce (var-get burn-request-nonce)) diff --git a/contracts/lisa-dao.clar b/contracts/lisa-dao.clar index 2ea43f0..1b3ffcf 100644 --- a/contracts/lisa-dao.clar +++ b/contracts/lisa-dao.clar @@ -72,10 +72,10 @@ ;; --- Extension requests -(define-public (request-extension-callback (extension ) (memo (buff 34))) +(define-public (request-extension-callback (extension ) (payload (buff 2048))) (let ((sender tx-sender)) (asserts! (is-extension contract-caller) err-invalid-extension) (asserts! (is-eq contract-caller (contract-of extension)) err-invalid-extension) - (as-contract (contract-call? extension callback sender memo)) + (as-contract (contract-call? extension callback sender payload)) ) ) diff --git a/contracts/proxies/stx-transfer-many-proxy.clar b/contracts/proxies/stx-transfer-many-proxy.clar new file mode 100644 index 0000000..9a26a40 --- /dev/null +++ b/contracts/proxies/stx-transfer-many-proxy.clar @@ -0,0 +1,16 @@ +(impl-trait .proxy-trait.proxy-trait) + +(define-constant err-invalid-payload (err u4000)) + +(define-private (transfer (entry { ustx: uint, recipient: principal}) (previous (response bool uint))) + (if (is-ok previous) + (stx-transfer? (get ustx entry) tx-sender (get recipient entry)) + previous + ) +) + +(define-public (proxy-call (payload (buff 2048))) + (let ((decoded (unwrap! (from-consensus-buff? (list 30 { ustx: uint, recipient: principal }) payload) err-invalid-payload))) + (fold transfer decoded (ok true)) + ) +) diff --git a/contracts/transfer-providers/stx-transfer-provider.clar b/contracts/proxies/stx-transfer-proxy.clar similarity index 67% rename from contracts/transfer-providers/stx-transfer-provider.clar rename to contracts/proxies/stx-transfer-proxy.clar index 2cfbed8..19160d2 100644 --- a/contracts/transfer-providers/stx-transfer-provider.clar +++ b/contracts/proxies/stx-transfer-proxy.clar @@ -1,8 +1,8 @@ -(impl-trait .transfer-provider-trait.transfer-provider-trait) +(impl-trait .proxy-trait.proxy-trait) (define-constant err-invalid-payload (err u4000)) -(define-public (dynamic-transfer (payload (buff 512))) +(define-public (proxy-call (payload (buff 2048))) (let ((decoded (unwrap! (from-consensus-buff? { ustx: uint, recipient: principal } payload) err-invalid-payload))) (stx-transfer? (get ustx decoded) tx-sender (get recipient decoded)) ) diff --git a/contracts/rules/rebase-1.clar b/contracts/rules/rebase-1.clar new file mode 100644 index 0000000..04484d1 --- /dev/null +++ b/contracts/rules/rebase-1.clar @@ -0,0 +1,3 @@ +(define-public (rebase) + (contract-call? .lisa-rebase rebase (list .fastpool-strategy)) +) diff --git a/contracts/strategies/fastpool/fastpool-strategy.clar b/contracts/strategies/fastpool/fastpool-strategy.clar index c53e138..09a5fdf 100644 --- a/contracts/strategies/fastpool/fastpool-strategy.clar +++ b/contracts/strategies/fastpool/fastpool-strategy.clar @@ -2,9 +2,6 @@ (define-constant err-not-vault-caller (err u2000)) (define-constant err-invalid-payload (err u2001)) -(define-constant err-balance-insufficient (err u2002)) - -(define-data-var amount-in-strategy uint u0) (define-constant member-list (list (to-trait .fastpool-member1) (to-trait .fastpool-member2) (to-trait .fastpool-member3) (to-trait .fastpool-member4) (to-trait .fastpool-member5) @@ -29,9 +26,7 @@ (let ( (member-principal (contract-of member)) (account (stx-account member-principal)) - (total-balance (stx-get-balance member-principal)) (locked-amount (get locked account)) - (unlocked-amount (get unlocked account)) ) (if (< amount locked-amount) (begin @@ -40,6 +35,7 @@ ) ;; else (let ( + (unlocked-amount (get unlocked account)) (difference (- amount locked-amount)) (amount-transferred (if (> difference unlocked-amount) (- difference unlocked-amount) u0)) ) @@ -57,11 +53,10 @@ (define-public (execute (payload (buff 2048))) (let ( (amounts (unwrap! (from-consensus-buff? (list 20 uint) payload) err-invalid-payload)) - (total-amount (fold sum (print (map process-strategy amounts member-list)) u0)) + (amount-taken (fold sum (print (map process-strategy amounts member-list)) u0)) ) (try! (is-vault-caller)) - (var-set amount-in-strategy (+ (var-get amount-in-strategy) total-amount)) - (ok total-amount) + (ok amount-taken) ) ) @@ -76,11 +71,10 @@ (define-public (refund (payload (buff 2048))) (let ( (refunds (unwrap! (from-consensus-buff? (list 20 bool) payload) err-invalid-payload)) - (total-amount (fold sum (print (map process-refund refunds member-list)) u0)) + (amount-refunded (fold sum (print (map process-refund refunds member-list)) u0)) ) (try! (is-vault-caller)) - (var-set amount-in-strategy (default-to u0 (safe-sub (var-get amount-in-strategy) total-amount))) - (ok total-amount) + (ok amount-refunded) ) ) @@ -92,7 +86,7 @@ ) (define-read-only (get-amount-in-strategy) - (ok (var-get amount-in-strategy)) + (get-total-member-balances) ) (define-private (get-member-balance-iter (member ) (accumulator uint)) @@ -100,7 +94,7 @@ ) (define-read-only (get-total-member-balances) - (fold get-member-balance-iter member-list u0) + (ok (fold get-member-balance-iter member-list u0)) ) (define-private (get-total-member-locked-amount-iter (member ) (accumulator uint)) @@ -111,8 +105,4 @@ (fold get-total-member-locked-amount-iter member-list u0) ) -(define-private (safe-sub (a uint) (b uint)) - (if (>= a b) (some (- a b)) none) -) - (define-read-only (to-trait (trait )) trait) diff --git a/contracts/token-lqstx.clar b/contracts/token-lqstx.clar index 2ee2a35..52444ef 100644 --- a/contracts/token-lqstx.clar +++ b/contracts/token-lqstx.clar @@ -39,6 +39,13 @@ (try! (is-dao-or-extension)) (ok (var-set token-uri new-uri)))) +(define-public (set-reward-multiplier-from-balance (balance uint)) + (begin + (try! (is-dao-or-extension)) + (ok (var-set reward-multiplier (/ balance (ft-get-supply lqstx)))) + ) +) + (define-public (set-reward-multiplier (new-multiplier uint)) (begin (try! (is-dao-or-extension)) diff --git a/contracts/traits/extension-trait.clar b/contracts/traits/extension-trait.clar index ba6fa34..758886f 100644 --- a/contracts/traits/extension-trait.clar +++ b/contracts/traits/extension-trait.clar @@ -1,5 +1,5 @@ (define-trait extension-trait ( - (callback (principal (buff 34)) (response bool uint)) + (callback (principal (buff 2048)) (response bool uint)) ) ) diff --git a/contracts/traits/proxy-trait.clar b/contracts/traits/proxy-trait.clar new file mode 100644 index 0000000..7618835 --- /dev/null +++ b/contracts/traits/proxy-trait.clar @@ -0,0 +1,3 @@ +(define-trait proxy-trait + ((proxy-call ((buff 2048)) (response bool uint))) +) diff --git a/contracts/traits/transfer-provider-trait.clar b/contracts/traits/transfer-provider-trait.clar deleted file mode 100644 index 04fdda0..0000000 --- a/contracts/traits/transfer-provider-trait.clar +++ /dev/null @@ -1,6 +0,0 @@ -(define-trait transfer-provider-trait - ( - (dynamic-transfer ((buff 512)) (response bool uint)) - ) -) - diff --git a/contracts/vault.clar b/contracts/vault.clar index 7c8e78d..a030252 100644 --- a/contracts/vault.clar +++ b/contracts/vault.clar @@ -1,53 +1,31 @@ ;; This contract holds the STX of the members (use-trait strategy-trait .strategy-trait.strategy-trait) -(use-trait transfer-provider-trait .transfer-provider-trait.transfer-provider-trait) +(use-trait proxy-trait .proxy-trait.proxy-trait) (define-constant err-unauthorised (err u1000)) -(define-map strategy-allocations principal uint) - (define-read-only (is-dao-or-extension) (ok (asserts! (or (is-eq tx-sender .lisa-dao) (contract-call? .lisa-dao is-extension contract-caller)) err-unauthorised)) ) (define-public (fund-strategy (strategy ) (payload (buff 2048))) - (let ( - (strategy-contract (contract-of strategy)) - (amount-taken (try! (as-contract (contract-call? strategy execute payload)))) - ) + (let ((amount-taken (try! (as-contract (contract-call? strategy execute payload))))) (try! (is-dao-or-extension)) - (map-set strategy-allocations strategy-contract (+ (strategy-allocation strategy-contract) amount-taken)) (ok amount-taken) ) ) (define-public (refund-strategy (strategy ) (payload (buff 2048))) - (let ( - (strategy-contract (contract-of strategy)) - (amount-refunded (try! (as-contract (contract-call? strategy refund payload)))) - ) + (let ((amount-refunded (try! (as-contract (contract-call? strategy refund payload))))) (try! (is-dao-or-extension)) - (map-set strategy-allocations strategy-contract (default-to u0 (safe-sub (strategy-allocation strategy-contract) amount-refunded))) (ok amount-refunded) ) ) -(define-public (dynamic-transfer (transfer-provider ) (payload (buff 512))) +(define-public (proxy-call (proxy ) (payload (buff 2048))) (begin (try! (is-dao-or-extension)) - (as-contract (contract-call? transfer-provider dynamic-transfer payload)) + (as-contract (contract-call? proxy proxy-call payload)) ) ) - -(define-private (strategy-allocation (strategy principal)) - (default-to u0 (map-get? strategy-allocations strategy)) -) - -(define-read-only (get-strategy-allocation (strategy principal)) - (ok (strategy-allocation strategy)) -) - -(define-private (safe-sub (a uint) (b uint)) - (if (>= a b) (some (- a b)) none) -)