├── .editorconfig ├── .github └── workflows │ └── ci.yaml ├── .gitignore ├── .vscode └── settings.json ├── Clarinet.toml ├── LICENSE ├── README.md ├── bin └── install_clarinet.sh ├── contracts ├── executor-dao.clar ├── extensions │ ├── executive-team │ │ ├── sde-emergency-execute.clar │ │ └── sde-emergency-proposals.clar │ ├── lockup │ │ └── sde-token-lockup.clar │ ├── membership │ │ ├── sde-membership.clar │ │ └── tokens │ │ │ ├── sde-citycoin-token.clar │ │ │ ├── sde-governance-token-with-delegation.clar │ │ │ ├── sde-governance-token-with-lockup.clar │ │ │ ├── sde-governance-token.clar │ │ │ ├── sde-miamicoin-token.clar │ │ │ ├── sde-newyorkcoin-token.clar │ │ │ ├── sde-sip10-token.clar │ │ │ └── sde-stackerdao-token.clar │ ├── misc │ │ ├── sde-dev-fund.clar │ │ ├── sde-mia-stacking.clar │ │ └── sde-token-vesting.clar │ ├── multisignature │ │ └── sde-multisig.clar │ ├── proposal-submissions │ │ ├── sde-proposal-submission-with-delegation.clar │ │ ├── sde-proposal-submission-with-lockup.clar │ │ ├── sde-proposal-submission-with-members.clar │ │ ├── sde-proposal-submission-with-nft.clar │ │ └── sde-proposal-submission.clar │ ├── vaults │ │ └── sde-vault.clar │ └── voting │ │ ├── sde-proposal-voting-snapshot.clar │ │ ├── sde-proposal-voting-with-delegation.clar │ │ ├── sde-proposal-voting-with-external-lockup.clar │ │ ├── sde-proposal-voting-with-lockup.clar │ │ ├── sde-proposal-voting-with-members.clar │ │ ├── sde-proposal-voting-with-nft.clar │ │ └── sde-proposal-voting.clar ├── external │ ├── citycoins │ │ ├── citycoin-auth.clar │ │ ├── citycoin-core-trait.clar │ │ ├── citycoin-core-v1.clar │ │ ├── citycoin-token-trait.clar │ │ ├── citycoin-token.clar │ │ └── citycoin-vrf.clar │ ├── ft-membership.clar │ ├── nft-escrow.clar │ └── nft-membership.clar ├── proposals │ ├── bootstraps │ │ ├── sdp-citycoins-dao.clar │ │ ├── sdp-delegate-voting-dao.clar │ │ ├── sdp-multisignature-dao.clar │ │ ├── sdp-nft-dao.clar │ │ ├── sdp-stackerdao.clar │ │ └── sdp-vault.clar │ ├── management │ │ └── sdp-whitelist-asset.clar │ ├── multisignature │ │ └── sdp-add-signer.clar │ ├── sdp-dev-fund.clar │ ├── sdp-disable-emergency-powers.clar │ ├── sdp-token-vesting.clar │ └── transfers │ │ ├── sdp-transfer-ft.clar │ │ ├── sdp-transfer-nft.clar │ │ ├── sdp-transfer-stx.clar │ │ └── sdp-unauthorized-transfer-stx.clar └── traits │ ├── delegate-token-trait.clar │ ├── extension-trait.clar │ ├── governance-token-trait.clar │ ├── member-trait.clar │ ├── ownable-trait.clar │ ├── proposal-trait.clar │ ├── sdt-governance-token-trait.clar │ ├── sip009-nft-trait.clar │ └── sip010-ft-trait.clar ├── docs ├── extensions.md └── proposals.md ├── settings └── Devnet.toml └── tests ├── executor-dao_test.ts ├── ft-membership └── governance-token-delegation_test.ts ├── multisignature_test.ts ├── nft-membership └── governance-nft_test.ts ├── utils ├── api │ ├── executor-dao.ts │ ├── ft-membership.ts │ ├── governance-token-with-delegation.ts │ ├── multisignature.ts │ ├── nft-membership.ts │ ├── proposal-submission-with-delegation.ts │ ├── proposal-submission-with-nft.ts │ ├── proposal-voting-with-delegation.ts │ ├── proposal-voting-with-nft.ts │ └── vault.ts ├── common.ts └── deps.ts └── vault_test.ts /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | insert_final_newline = true 6 | indent_style = spaces 7 | indent_size = 2 8 | 9 | [*.md] 10 | trim_trailing_whitespace = false -------------------------------------------------------------------------------- /.github/workflows/ci.yaml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: [push] 3 | 4 | jobs: 5 | check: 6 | name: Clarinet check 7 | runs-on: ubuntu-latest 8 | steps: 9 | - name: Checkout repository 10 | uses: actions/checkout@v2 11 | with: 12 | submodules: recursive 13 | 14 | - name: Install Rust toolchain 15 | uses: actions-rs/toolchain@v1 16 | with: 17 | toolchain: stable 18 | profile: minimal 19 | components: rustfmt 20 | override: true 21 | 22 | - name: Install clarinet 23 | run: chmod +x ./bin/install_clarinet.sh && ./bin/install_clarinet.sh 24 | 25 | - name: Run clarinet check 26 | run: clarinet check 27 | 28 | - name: Run clarinet test 29 | run: clarinet test 30 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | settings/Mainnet.toml 2 | settings/Testnet.toml 3 | history.txt 4 | scraps.txt 5 | cvm/vmstate.db 6 | .DS_Store 7 | coverage.lcov 8 | deployments/ -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | 2 | { 3 | "deno.enable": true, 4 | } 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2022 Marvin Janssen 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 14 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 15 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 16 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 17 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 18 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE 19 | OR OTHER DEALINGS IN THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # StackerDAO 2 | 3 | * [The Protocol](#the-protocol) 4 | * [Extensions](#extensions) 5 | * [Proposals](#proposals) 6 | * [Usage](#usage) 7 | * [Testing](#testing) 8 | * [Examples](#examples) 9 | 10 | ## The Protocol 11 | 12 | StackerDAOs began as a fork of [ExecutorDAO](https://github.com/MarvinJanssen/executor-dao), and models its design in the same modular and flexible way. The core tenets remain the same: 13 | 14 | 1. Proposals are smart contracts. 15 | 2. The core executes, the extensions give form. 16 | 3. Ownership control happens via sending context. 17 | 18 | ### Proposals are smart contracts 19 | --- 20 | Proposals are expressed as smart contracts. These smart contracts implement a specific `proposal-trait` and may be executed by the DAO when certain conditions are met. It makes StackerDAO extremely flexible and powerful. 21 | 22 | ### The core executes, the extensions give form 23 | --- 24 | StackerDAO initially consists of just one core contract. Its sole purpose is to execute proposals and to keep a list of authorized extensions. There are no other features: no token, no voting, no functions. The DAO is given form through extension contracts. 25 | 26 | Extensions are contracts that can be enabled or disabled by proposals and add specific features to the DAO. They are allowed to assume the "sending context" of the DAO and can thus enact change. Since different groups and organisations have different needs, extensions are rather varied. Some example functionality that can be added to StackerDAO via an extension include: 27 | 28 | - The issuance and management of a governance token. 29 | - The ability to submit proposals. 30 | - The ability to vote on proposals. 31 | - The creation and management of a treasury. 32 | - And more... 33 | 34 | Since extensions become part of the DAO, they have privileged access to everything else included in the DAO. The trick that allows for extension interoperability is a common authorization check. 35 | 36 | *Privileged access is granted when the sending context is equal to that of the DAO or if the contract caller is an enabled DAO extension*. 37 | 38 | It allows for extensions that depend on other extensions to be designed. They can be disabled and replaced at any time making StackerDAO fully polymorphic. 39 | 40 | ### Ownership control happens via sending context 41 | --- 42 | StackerDAO follows a single-address ownership model. The core contract is the de facto owner of external ownable contracts. External contracts thus do not need to implement a complicated access model, as any proposal or extension may act upon it. 43 | 44 | *An ownable contract is to be understood as a contract that stores one privileged principal that may change internal state.* 45 | 46 | *Any ownable contract, even the ones that were deployed before StackerDAO came into use, can be owned and managed by the DAO*. 47 | 48 | ## Extensions 49 | 50 | ## Proposals 51 | 52 | ## Testing 53 | 54 | ```clarinet test``` 55 | 56 | ## Examples 57 | 58 | ### Multisignature Setup 59 | --- 60 | 61 | To showcase how it works, let's say we want to set up a basic "Multisignature" DAO. The first thing you need to do is give your DAO form, via `Extensions`. 62 | 63 | You can do this through what we call a "Bootstrap" proposal that enables the `Multisignature` extensions you need: 64 | 65 | ```clojure 66 | ;; Example Bootstrap Proposal 67 | ;; sdp-multisignature-dao.clar 68 | 69 | (impl-trait .proposal-trait.proposal-trait) 70 | 71 | (define-public (execute (sender principal)) 72 | (begin 73 | ;; Enable extensions to give your DAO form. 74 | (try! (contract-call? .executor-dao set-extensions 75 | (list 76 | {extension: .sde-vault, enabled: true} 77 | {extension: .sde-multisig, enabled: true} 78 | ) 79 | )) 80 | 81 | ;; Add signers to your DAO. 82 | (try! (contract-call? .sde-multisig add-signer 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM)) 83 | (try! (contract-call? .sde-multisig add-signer 'ST1SJ3DTE5DN7X54YDH5D64R3BCB6A2AG2ZQ8YPD5)) 84 | (try! (contract-call? .sde-multisig add-signer 'ST2CY5V39NHDPWSXMW9QDT3HC3GD6Q6XX4CFRK9AG)) 85 | (ok true) 86 | ) 87 | ) 88 | ``` 89 | 90 | You can think of the "Bootstrap" proposal as an initializer for your DAO. Inside `clarinet console`, you can execute it by typing: 91 | 92 | ```clojure 93 | (contract-call? .executor-dao init .sdp-multisignature-bootstrap) 94 | ``` 95 | 96 | # License 97 | 98 | MIT license 99 | -------------------------------------------------------------------------------- /bin/install_clarinet.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | apt-get update 4 | apt-get install -y unzip wget 5 | 6 | wget -nv https://github.com/hirosystems/clarinet/releases/download/v0.27.0/clarinet-linux-x64-glibc.tar.gz -O clarinet-linux-x64.tar.gz 7 | tar -xf clarinet-linux-x64.tar.gz 8 | chmod +x ./clarinet 9 | mv ./clarinet /usr/local/bin 10 | 11 | -------------------------------------------------------------------------------- /contracts/executor-dao.clar: -------------------------------------------------------------------------------- 1 | ;; _____________ _______ _________ ___ ___ ____ ____ 2 | ;; / __/_ __/ _ |/ ___/ //_/ __/ _ \/ _ \/ _ |/ __ \/ __/ 3 | ;; _\ \ / / / __ / /__/ ,< / _// , _/ // / __ / /_/ /\ \ 4 | ;; /___/ /_/ /_/ |_\___/_/|_/___/_/|_/____/_/ |_\____/___/ 5 | 6 | ;; _________ ___ ____ 7 | ;; / ___/ __ \/ _ \/ __/ 8 | ;; / /__/ /_/ / , _/ _/ 9 | ;; \___/\____/_/|_/___/ 10 | ;; 11 | 12 | (use-trait proposal-trait .proposal-trait.proposal-trait) 13 | (use-trait extension-trait .extension-trait.extension-trait) 14 | 15 | (define-constant ERR_UNAUTHORIZED (err u1000)) 16 | (define-constant ERR_ALREADY_EXECUTED (err u1001)) 17 | (define-constant ERR_INVALID_EXTENSION (err u1002)) 18 | 19 | (define-data-var executive principal tx-sender) 20 | (define-map ExecutedProposals principal uint) 21 | (define-map Extensions principal bool) 22 | 23 | ;; --- Authorization check 24 | 25 | (define-private (is-self-or-extension) 26 | (ok (asserts! (or (is-eq tx-sender (as-contract tx-sender)) (is-extension contract-caller)) ERR_UNAUTHORIZED)) 27 | ) 28 | 29 | ;; --- Extensions 30 | 31 | (define-read-only (is-extension (extension principal)) 32 | (default-to false (map-get? Extensions extension)) 33 | ) 34 | 35 | (define-public (set-extension (extension principal) (enabled bool)) 36 | (begin 37 | (try! (is-self-or-extension)) 38 | (print {event: "extension", extension: extension, enabled: enabled}) 39 | (ok (map-set Extensions extension enabled)) 40 | ) 41 | ) 42 | 43 | (define-private (set-extensions-iter (item {extension: principal, enabled: bool})) 44 | (begin 45 | (print {event: "extension", extension: (get extension item), enabled: (get enabled item)}) 46 | (map-set Extensions (get extension item) (get enabled item)) 47 | ) 48 | ) 49 | 50 | (define-public (set-extensions (extensionList (list 200 {extension: principal, enabled: bool}))) 51 | (begin 52 | (try! (is-self-or-extension)) 53 | (ok (map set-extensions-iter extensionList)) 54 | ) 55 | ) 56 | 57 | ;; --- Proposals 58 | 59 | (define-read-only (executed-at (proposal )) 60 | (map-get? ExecutedProposals (contract-of proposal)) 61 | ) 62 | 63 | (define-public (execute (proposal ) (sender principal)) 64 | (begin 65 | (try! (is-self-or-extension)) 66 | (asserts! (map-insert ExecutedProposals (contract-of proposal) block-height) ERR_ALREADY_EXECUTED) 67 | (print {event: "execute", proposal: proposal}) 68 | (as-contract (contract-call? proposal execute sender)) 69 | ) 70 | ) 71 | 72 | ;; --- Initialize DAO 73 | 74 | (define-public (init (proposal )) 75 | (let ((sender tx-sender)) 76 | (asserts! (is-eq sender (var-get executive)) ERR_UNAUTHORIZED) 77 | (var-set executive (as-contract tx-sender)) 78 | (print {event: "init", proposal: proposal}) 79 | (as-contract (execute proposal sender)) 80 | ) 81 | ) 82 | 83 | ;; --- Extension requests 84 | 85 | (define-public (request-extension-callback (extension ) (memo (buff 34))) 86 | (let ((sender tx-sender)) 87 | (asserts! (and (is-extension contract-caller) (is-eq contract-caller (contract-of extension))) ERR_INVALID_EXTENSION) 88 | (as-contract (contract-call? extension callback sender memo)) 89 | ) 90 | ) 91 | -------------------------------------------------------------------------------- /contracts/extensions/executive-team/sde-emergency-execute.clar: -------------------------------------------------------------------------------- 1 | ;; _____________ _______ _________ ___ ___ ____ ____ 2 | ;; / __/_ __/ _ |/ ___/ //_/ __/ _ \/ _ \/ _ |/ __ \/ __/ 3 | ;; _\ \ / / / __ / /__/ ,< / _// , _/ // / __ / /_/ /\ \ 4 | ;; /___/ /_/ /_/ |_\___/_/|_/___/_/|_/____/_/ |_\____/___/ 5 | ;; 6 | ;; _____ _____________ ______________ _ __ 7 | ;; / __/ |/_/_ __/ __/ |/ / __/ _/ __ \/ |/ / 8 | ;; / _/_> < / / / _// /\ \_/ // /_/ / / 9 | ;; /___/_/|_| /_/ /___/_/|_/___/___/\____/_/|_/ 10 | 11 | (use-trait proposal-trait .proposal-trait.proposal-trait) 12 | 13 | (impl-trait .extension-trait.extension-trait) 14 | 15 | (define-constant ERR_UNAUTHORIZED (err u2800)) 16 | (define-constant ERR_NOT_EXECUTIVE_TEAM_MEMBER (err u2801)) 17 | (define-constant ERR_ALREADY_EXECUTED (err u2802)) 18 | (define-constant ERR_SUNSET_HEIGHT_REACHED (err u2803)) 19 | (define-constant ERR_SUNSET_HEIGHT_IN_PAST (err u2804)) 20 | 21 | (define-map ExecutiveTeam principal bool) 22 | (define-map ExecutiveActionSignals {proposal: principal, teamMember: principal} bool) 23 | (define-map ExecutiveActionSignalCount principal uint) 24 | 25 | (define-data-var executiveSignalsRequired uint u1) ;; signals required for an executive action. 26 | (define-data-var executiveTeamSunsetHeight uint (+ block-height u4380)) ;; ~1 month from deploy time 27 | 28 | ;; --- Authorization check 29 | 30 | (define-public (is-dao-or-extension) 31 | (ok (asserts! (or (is-eq tx-sender .executor-dao) (contract-call? .executor-dao is-extension contract-caller)) ERR_UNAUTHORIZED)) 32 | ) 33 | 34 | ;; --- Internal DAO functions 35 | 36 | (define-public (set-executive-team-sunset-height (height uint)) 37 | (begin 38 | (try! (is-dao-or-extension)) 39 | (asserts! (> height block-height) ERR_SUNSET_HEIGHT_IN_PAST) 40 | (ok (var-set executiveTeamSunsetHeight height)) 41 | ) 42 | ) 43 | 44 | (define-public (set-executive-team-member (who principal) (member bool)) 45 | (begin 46 | (try! (is-dao-or-extension)) 47 | (ok (map-set ExecutiveTeam who member)) 48 | ) 49 | ) 50 | 51 | (define-public (set-signals-required (newRequirement uint)) 52 | (begin 53 | (try! (is-dao-or-extension)) 54 | (ok (var-set executiveSignalsRequired newRequirement)) 55 | ) 56 | ) 57 | 58 | ;; --- Public functions 59 | 60 | (define-read-only (is-executive-team-member (who principal)) 61 | (default-to false (map-get? ExecutiveTeam who)) 62 | ) 63 | 64 | (define-read-only (has-signaled (proposal principal) (who principal)) 65 | (default-to false (map-get? ExecutiveActionSignals {proposal: proposal, teamMember: who})) 66 | ) 67 | 68 | (define-read-only (get-signals-required) 69 | (var-get executiveSignalsRequired) 70 | ) 71 | 72 | (define-read-only (get-signals (proposal principal)) 73 | (default-to u0 (map-get? ExecutiveActionSignalCount proposal)) 74 | ) 75 | 76 | (define-public (executive-action (proposal )) 77 | (let 78 | ( 79 | (proposalPrincipal (contract-of proposal)) 80 | (signals (+ (get-signals proposalPrincipal) (if (has-signaled proposalPrincipal tx-sender) u0 u1))) 81 | ) 82 | (asserts! (is-executive-team-member tx-sender) ERR_NOT_EXECUTIVE_TEAM_MEMBER) 83 | (asserts! (is-none (contract-call? .executor-dao executed-at proposal)) ERR_ALREADY_EXECUTED) 84 | (asserts! (< block-height (var-get executiveTeamSunsetHeight)) ERR_SUNSET_HEIGHT_REACHED) 85 | (and (>= signals (var-get executiveSignalsRequired)) 86 | (try! (contract-call? .executor-dao execute proposal tx-sender)) 87 | ) 88 | (map-set ExecutiveActionSignals {proposal: proposalPrincipal, teamMember: tx-sender} true) 89 | (map-set ExecutiveActionSignalCount proposalPrincipal signals) 90 | (ok signals) 91 | ) 92 | ) 93 | 94 | ;; --- Extension callback 95 | 96 | (define-public (callback (sender principal) (memo (buff 34))) 97 | (ok true) 98 | ) 99 | -------------------------------------------------------------------------------- /contracts/extensions/executive-team/sde-emergency-proposals.clar: -------------------------------------------------------------------------------- 1 | ;; _____________ _______ _________ ___ ___ ____ ____ 2 | ;; / __/_ __/ _ |/ ___/ //_/ __/ _ \/ _ \/ _ |/ __ \/ __/ 3 | ;; _\ \ / / / __ / /__/ ,< / _// , _/ // / __ / /_/ /\ \ 4 | ;; /___/ /_/ /_/ |_\___/_/|_/___/_/|_/____/_/ |_\____/___/ 5 | ;; 6 | ;; _____ _____________ ______________ _ __ 7 | ;; / __/ |/_/_ __/ __/ |/ / __/ _/ __ \/ |/ / 8 | ;; / _/_> < / / / _// /\ \_/ // /_/ / / 9 | ;; /___/_/|_| /_/ /___/_/|_/___/___/\____/_/|_/ 10 | 11 | (use-trait proposal-trait .proposal-trait.proposal-trait) 12 | 13 | (impl-trait .extension-trait.extension-trait) 14 | 15 | (define-constant ERR_UNAUTHORIZED (err u2700)) 16 | (define-constant ERR_NOT_EMERGENCY_TEAM_MEMBER (err u2701)) 17 | (define-constant ERR_SUNSET_HEIGHT_REACHED (err u2702)) 18 | (define-constant ERR_SUNSET_HEIGHT_IN_PAST (err u2703)) 19 | 20 | (define-data-var emergencyProposalDuration uint u144) ;; ~1 day 21 | (define-data-var emergencyTeamSunsetHeight uint (+ block-height u13140)) ;; ~3 months from deploy time 22 | 23 | (define-map EmergencyTeam principal bool) 24 | 25 | ;; --- Authorization check 26 | 27 | (define-public (is-dao-or-extension) 28 | (ok (asserts! (or (is-eq tx-sender .executor-dao) (contract-call? .executor-dao is-extension contract-caller)) ERR_UNAUTHORIZED)) 29 | ) 30 | 31 | ;; --- Internal DAO functions 32 | 33 | (define-public (set-emergency-proposal-duration (duration uint)) 34 | (begin 35 | (try! (is-dao-or-extension)) 36 | (ok (var-set emergencyProposalDuration duration)) 37 | ) 38 | ) 39 | 40 | (define-public (set-emergency-team-sunset-height (height uint)) 41 | (begin 42 | (try! (is-dao-or-extension)) 43 | (asserts! (> height block-height) ERR_SUNSET_HEIGHT_IN_PAST) 44 | (ok (var-set emergencyTeamSunsetHeight height)) 45 | ) 46 | ) 47 | 48 | (define-public (set-emergency-team-member (who principal) (member bool)) 49 | (begin 50 | (try! (is-dao-or-extension)) 51 | (ok (map-set EmergencyTeam who member)) 52 | ) 53 | ) 54 | 55 | ;; --- Public functions 56 | 57 | (define-read-only (is-emergency-team-member (who principal)) 58 | (default-to false (map-get? EmergencyTeam who)) 59 | ) 60 | 61 | (define-public (emergency-propose (proposal )) 62 | (begin 63 | (asserts! (is-emergency-team-member tx-sender) ERR_NOT_EMERGENCY_TEAM_MEMBER) 64 | (asserts! (< block-height (var-get emergencyTeamSunsetHeight)) ERR_SUNSET_HEIGHT_REACHED) 65 | (contract-call? .sde-proposal-voting-with-lockup add-proposal proposal 66 | { 67 | startBlockHeight: block-height, 68 | endBlockHeight: (+ block-height (var-get emergencyProposalDuration)), 69 | proposer: tx-sender 70 | } 71 | ) 72 | ) 73 | ) 74 | 75 | ;; --- Extension callback 76 | 77 | (define-public (callback (sender principal) (memo (buff 34))) 78 | (ok true) 79 | ) 80 | -------------------------------------------------------------------------------- /contracts/extensions/lockup/sde-token-lockup.clar: -------------------------------------------------------------------------------- 1 | ;; _____________ _______ _________ ___ ___ ____ ____ 2 | ;; / __/_ __/ _ |/ ___/ //_/ __/ _ \/ _ \/ _ |/ __ \/ __/ 3 | ;; _\ \ / / / __ / /__/ ,< / _// , _/ // / __ / /_/ /\ \ 4 | ;; /___/ /_/ /_/ |_\___/_/|_/___/_/|_/____/_/ |_\____/___/ 5 | ;; 6 | ;; _____ _____________ ______________ _ __ 7 | ;; / __/ |/_/_ __/ __/ |/ / __/ _/ __ \/ |/ / 8 | ;; / _/_> < / / / _// /\ \_/ // /_/ / / 9 | ;; /___/_/|_| /_/ /___/_/|_/___/___/\____/_/|_/ 10 | ;; 11 | 12 | (impl-trait .extension-trait.extension-trait) 13 | (impl-trait .sip010-ft-trait.sip010-ft-trait) 14 | 15 | (define-constant ERR_UNAUTHORIZED (err u2300)) 16 | (define-constant ERR_FAILED_TO_LOCK (err u2301)) 17 | (define-constant ERR_FAILED_TO_UNLOCK (err u2302)) 18 | (define-constant ERR_AMOUNT_MISMATCH (err u2304)) 19 | 20 | (define-constant CONTRACT_ADDRESS (as-contract tx-sender)) 21 | 22 | (define-fungible-token Locked-Mega) 23 | 24 | (define-data-var tokenName (string-ascii 32) "Locked Mega") 25 | (define-data-var tokenSymbol (string-ascii 10) "LMEGA") 26 | (define-data-var tokenUri (optional (string-utf8 256)) none) 27 | (define-data-var tokenDecimals uint u2) 28 | 29 | (define-map LockedTokens { voter: principal, proposal: principal } uint) 30 | 31 | (define-public (is-dao-or-extension) 32 | (ok (asserts! (or (is-eq tx-sender .executor-dao) (contract-call? .executor-dao is-extension contract-caller)) ERR_UNAUTHORIZED)) 33 | ) 34 | 35 | (define-public (lock (amount uint) (proposal principal) (owner principal)) 36 | (begin 37 | (try! (is-dao-or-extension)) 38 | (unwrap! (contract-call? .sde-stackerdao-token transfer amount owner CONTRACT_ADDRESS none) ERR_FAILED_TO_LOCK) 39 | (map-set LockedTokens { voter: owner, proposal: proposal } 40 | (+ (get-current-total-locked proposal owner) amount) 41 | ) 42 | (print {event: "lock", amount: amount, voter: owner, proposal: proposal}) 43 | (ft-mint? Locked-Mega amount owner) 44 | ) 45 | ) 46 | 47 | (define-public (unlock (amount uint) (proposal principal) (owner principal)) 48 | (let 49 | ( 50 | (unlockAmount (get-current-total-locked proposal owner)) 51 | ) 52 | 53 | (try! (is-dao-or-extension)) 54 | (asserts! (is-eq unlockAmount amount) ERR_AMOUNT_MISMATCH) 55 | (unwrap! (as-contract (contract-call? .sde-stackerdao-token transfer (get-current-total-locked proposal owner) CONTRACT_ADDRESS owner (some 0x11))) ERR_FAILED_TO_UNLOCK) 56 | (print {event: "unlock", amount: unlockAmount, voter: owner, proposal: proposal}) 57 | (ft-burn? Locked-Mega unlockAmount owner) 58 | ) 59 | ) 60 | 61 | (define-read-only (get-locked-token-data (voter principal ) (proposal principal)) 62 | (map-get? LockedTokens { voter: voter, proposal: proposal }) 63 | ) 64 | 65 | (define-read-only (get-current-total-locked (proposal principal) (voter principal)) 66 | (default-to u0 (map-get? LockedTokens { voter: voter, proposal: proposal })) 67 | ) 68 | 69 | ;; --- SIP010 traits 70 | 71 | (define-public (transfer (amount uint) (sender principal) (recipient principal) (memo (optional (buff 34)))) 72 | (ok true) 73 | ) 74 | 75 | (define-read-only (get-name) 76 | (ok (var-get tokenName)) 77 | ) 78 | 79 | (define-read-only (get-symbol) 80 | (ok (var-get tokenSymbol)) 81 | ) 82 | 83 | (define-read-only (get-decimals) 84 | (ok (var-get tokenDecimals)) 85 | ) 86 | 87 | (define-read-only (get-balance (who principal)) 88 | (ok (ft-get-balance Locked-Mega who)) 89 | ) 90 | 91 | (define-read-only (get-total-supply) 92 | (ok (ft-get-supply Locked-Mega)) 93 | ) 94 | 95 | (define-read-only (get-token-uri) 96 | (ok (var-get tokenUri)) 97 | ) 98 | 99 | ;; --- Extension callback 100 | 101 | (define-public (callback (sender principal) (memo (buff 34))) 102 | (ok true) 103 | ) 104 | -------------------------------------------------------------------------------- /contracts/extensions/membership/sde-membership.clar: -------------------------------------------------------------------------------- 1 | ;; _____________ _______ _________ ___ ___ ____ ____ 2 | ;; / __/_ __/ _ |/ ___/ //_/ __/ _ \/ _ \/ _ |/ __ \/ __/ 3 | ;; _\ \ / / / __ / /__/ ,< / _// , _/ // / __ / /_/ /\ \ 4 | ;; /___/ /_/ /_/ |_\___/_/|_/___/_/|_/____/_/ |_\____/___/ 5 | ;; 6 | ;; _____ _____________ ______________ _ __ 7 | ;; / __/ |/_/_ __/ __/ |/ / __/ _/ __ \/ |/ / 8 | ;; / _/_> < / / / _// /\ \_/ // /_/ / / 9 | ;; /___/_/|_| /_/ /___/_/|_/___/___/\____/_/|_/ 10 | ;; 11 | 12 | ;; Title: SDE006 DAO Membership 13 | ;; Author: StackerDAO Dev Team 14 | ;; Depends-On: 15 | ;; Synopsis: 16 | ;; This extension allows members to be added manually when creating the DAO. 17 | ;; Description: 18 | ;; An extension meant for creating safes or small groups of members to perform actions. 19 | 20 | (use-trait proposal-trait .proposal-trait.proposal-trait) 21 | 22 | (impl-trait .member-trait.member-trait) 23 | (impl-trait .extension-trait.extension-trait) 24 | 25 | (define-constant ERR_UNAUTHORIZED (err u2900)) 26 | (define-constant ERR_NOT_A_MEMBER (err u2901)) 27 | (define-constant ERR_MEMBER_BLACKLISTED (err u2902)) 28 | 29 | (define-map Members principal bool) 30 | (define-map BlacklistMembers principal bool) 31 | 32 | ;; --- Authorization check 33 | 34 | (define-public (is-dao-or-extension) 35 | (ok (asserts! (or (is-eq tx-sender .executor-dao) (contract-call? .executor-dao is-extension contract-caller)) ERR_UNAUTHORIZED)) 36 | ) 37 | 38 | ;; --- Internal DAO functions 39 | 40 | (define-public (set-member (who principal) (member bool)) 41 | (begin 42 | (try! (is-dao-or-extension)) 43 | (asserts! (is-none (map-get? BlacklistMembers who)) ERR_MEMBER_BLACKLISTED) 44 | (ok (map-set Members who member)) 45 | ) 46 | ) 47 | 48 | (define-public (set-blacklist (who principal) (member bool)) 49 | (begin 50 | (try! (is-dao-or-extension)) 51 | (ok (map-set BlacklistMembers who member)) 52 | ) 53 | ) 54 | 55 | ;; --- Public functions 56 | 57 | ;; --- Read only functions 58 | 59 | (define-read-only (is-member (who principal)) 60 | (if (is-blacklisted who) 61 | (ok false) 62 | (ok (default-to false (map-get? Members who))) 63 | ) 64 | ) 65 | 66 | (define-read-only (is-blacklisted (who principal)) 67 | (default-to false (map-get? BlacklistMembers who)) 68 | ) 69 | 70 | ;; --- Extension callback 71 | 72 | (define-public (callback (sender principal) (memo (buff 34))) 73 | (ok true) 74 | ) 75 | -------------------------------------------------------------------------------- /contracts/extensions/membership/tokens/sde-citycoin-token.clar: -------------------------------------------------------------------------------- 1 | ;; Title: SIP10 Governance Token 2 | ;; Author: StackerDAO Dev Team 3 | ;; Description: 4 | 5 | (impl-trait .sip010-ft-trait.sip010-ft-trait) 6 | 7 | (define-constant ERR_UNAUTHORIZED (err u2400)) 8 | (define-constant ERR_NOT_TOKEN_OWNER (err u2401)) 9 | 10 | (define-constant TOTAL_SUPPLY (* (pow u10 u2) u1000000)) 11 | 12 | (define-fungible-token CityCoins TOTAL_SUPPLY) ;; 1m tokens 13 | 14 | (define-data-var tokenName (string-ascii 32) "CityCoins") 15 | (define-data-var tokenSymbol (string-ascii 10) "CITY") 16 | (define-data-var tokenUri (optional (string-utf8 256)) none) 17 | (define-data-var tokenDecimals uint u2) 18 | 19 | ;; --- Authorization check 20 | 21 | (define-public (is-dao-or-extension) 22 | (ok (asserts! (or (is-eq tx-sender .executor-dao) (contract-call? .executor-dao is-extension contract-caller)) ERR_UNAUTHORIZED)) 23 | ) 24 | 25 | (define-public (mint (amount uint) (recipient principal)) 26 | (begin 27 | (try! (is-dao-or-extension)) 28 | (ft-mint? CityCoins amount recipient) 29 | ) 30 | ) 31 | 32 | ;; --- Public functions 33 | 34 | (define-public (burn (amount uint) (owner principal)) 35 | (begin 36 | (asserts! (or (is-eq tx-sender owner) (is-eq contract-caller owner)) ERR_NOT_TOKEN_OWNER) 37 | (ft-burn? CityCoins amount owner) 38 | ) 39 | ) 40 | 41 | (define-public (set-name (newName (string-ascii 32))) 42 | (begin 43 | (try! (is-dao-or-extension)) 44 | (ok (var-set tokenName newName)) 45 | ) 46 | ) 47 | 48 | (define-public (set-symbol (newSymbol (string-ascii 10))) 49 | (begin 50 | (try! (is-dao-or-extension)) 51 | (ok (var-set tokenSymbol newSymbol)) 52 | ) 53 | ) 54 | 55 | (define-public (set-decimals (newDecimals uint)) 56 | (begin 57 | (try! (is-dao-or-extension)) 58 | (ok (var-set tokenDecimals newDecimals)) 59 | ) 60 | ) 61 | 62 | (define-public (set-token-uri (newUri (optional (string-utf8 256)))) 63 | (begin 64 | (try! (is-dao-or-extension)) 65 | (ok (var-set tokenUri newUri)) 66 | ) 67 | ) 68 | 69 | (define-private (mint-many-iter (item {amount: uint, recipient: principal})) 70 | (ft-mint? CityCoins (get amount item) (get recipient item)) 71 | ) 72 | 73 | (define-public (mint-many (recipients (list 200 {amount: uint, recipient: principal}))) 74 | (begin 75 | (try! (is-dao-or-extension)) 76 | (ok (map mint-many-iter recipients)) 77 | ) 78 | ) 79 | 80 | ;; --- SIP010 traits 81 | 82 | (define-public (transfer (amount uint) (sender principal) (recipient principal) (memo (optional (buff 34)))) 83 | (begin 84 | (asserts! (or (is-eq tx-sender sender) (is-eq contract-caller sender)) ERR_NOT_TOKEN_OWNER) 85 | (ft-transfer? CityCoins amount sender recipient) 86 | ) 87 | ) 88 | 89 | (define-read-only (get-name) 90 | (ok (var-get tokenName)) 91 | ) 92 | 93 | (define-read-only (get-symbol) 94 | (ok (var-get tokenSymbol)) 95 | ) 96 | 97 | (define-read-only (get-decimals) 98 | (ok (var-get tokenDecimals)) 99 | ) 100 | 101 | (define-read-only (get-balance (who principal)) 102 | (ok (ft-get-balance CityCoins who)) 103 | ) 104 | 105 | (define-read-only (get-total-supply) 106 | (ok (ft-get-supply CityCoins)) 107 | ) 108 | 109 | (define-read-only (get-token-uri) 110 | (ok (var-get tokenUri)) 111 | ) -------------------------------------------------------------------------------- /contracts/extensions/membership/tokens/sde-governance-token-with-delegation.clar: -------------------------------------------------------------------------------- 1 | ;; _____________ _______ _________ ___ ___ ____ ____ 2 | ;; / __/_ __/ _ |/ ___/ //_/ __/ _ \/ _ \/ _ |/ __ \/ __/ 3 | ;; _\ \ / / / __ / /__/ ,< / _// , _/ // / __ / /_/ /\ \ 4 | ;; /___/ /_/ /_/ |_\___/_/|_/___/_/|_/____/_/ |_\____/___/ 5 | ;; 6 | ;; _____ _____________ ______________ _ __ 7 | ;; / __/ |/_/_ __/ __/ |/ / __/ _/ __ \/ |/ / 8 | ;; / _/_> < / / / _// /\ \_/ // /_/ / / 9 | ;; /___/_/|_| /_/ /___/_/|_/___/___/\____/_/|_/ 10 | ;; 11 | 12 | ;; Title: Governance Token with Delegation 13 | ;; Author: StackerDAO Dev Team 14 | ;; Description: 15 | 16 | (impl-trait .delegate-token-trait.delegate-token-trait) 17 | (impl-trait .sip010-ft-trait.sip010-ft-trait) 18 | (impl-trait .extension-trait.extension-trait) 19 | 20 | (define-constant ERR_UNAUTHORIZED (err u2400)) 21 | (define-constant ERR_NOT_TOKEN_OWNER (err u2401)) 22 | 23 | (define-fungible-token Governance-Token) 24 | 25 | (define-data-var tokenName (string-ascii 32) "Governance Token") 26 | (define-data-var tokenSymbol (string-ascii 10) "GT") 27 | (define-data-var tokenUri (optional (string-utf8 256)) none) 28 | (define-data-var tokenDecimals uint u6) 29 | 30 | ;; --- Authorization check 31 | 32 | (define-public (is-dao-or-extension) 33 | (ok (asserts! (or (is-eq tx-sender .executor-dao) (contract-call? .executor-dao is-extension contract-caller)) ERR_UNAUTHORIZED)) 34 | ) 35 | 36 | ;; --- Internal DAO functions 37 | 38 | (define-public (mint (amount uint) (recipient principal)) 39 | (begin 40 | (try! (is-dao-or-extension)) 41 | (ft-mint? Governance-Token amount recipient) 42 | ) 43 | ) 44 | 45 | (define-public (burn (amount uint) (owner principal)) 46 | (begin 47 | (try! (is-dao-or-extension)) 48 | (ft-burn? Governance-Token amount owner) 49 | ) 50 | ) 51 | 52 | ;; --- Public functions 53 | 54 | (define-public (set-name (newName (string-ascii 32))) 55 | (begin 56 | (try! (is-dao-or-extension)) 57 | (ok (var-set tokenName newName)) 58 | ) 59 | ) 60 | 61 | (define-public (set-symbol (newSymbol (string-ascii 10))) 62 | (begin 63 | (try! (is-dao-or-extension)) 64 | (ok (var-set tokenSymbol newSymbol)) 65 | ) 66 | ) 67 | 68 | (define-public (set-decimals (newDecimals uint)) 69 | (begin 70 | (try! (is-dao-or-extension)) 71 | (ok (var-set tokenDecimals newDecimals)) 72 | ) 73 | ) 74 | 75 | (define-public (set-token-uri (newUri (optional (string-utf8 256)))) 76 | (begin 77 | (try! (is-dao-or-extension)) 78 | (ok (var-set tokenUri newUri)) 79 | ) 80 | ) 81 | 82 | (define-private (mint-many-iter (item {amount: uint, recipient: principal})) 83 | (ft-mint? Governance-Token (get amount item) (get recipient item)) 84 | ) 85 | 86 | (define-public (mint-many (recipients (list 200 {amount: uint, recipient: principal}))) 87 | (begin 88 | (try! (is-dao-or-extension)) 89 | (ok (map mint-many-iter recipients)) 90 | ) 91 | ) 92 | 93 | ;; --- SIP010 traits 94 | 95 | (define-public (transfer (amount uint) (sender principal) (recipient principal) (memo (optional (buff 34)))) 96 | (begin 97 | (asserts! (or (is-eq tx-sender sender) (is-eq contract-caller sender)) ERR_NOT_TOKEN_OWNER) 98 | (ft-transfer? Governance-Token amount sender recipient) 99 | ) 100 | ) 101 | 102 | (define-read-only (get-name) 103 | (ok (var-get tokenName)) 104 | ) 105 | 106 | (define-read-only (get-symbol) 107 | (ok (var-get tokenSymbol)) 108 | ) 109 | 110 | (define-read-only (get-decimals) 111 | (ok (var-get tokenDecimals)) 112 | ) 113 | 114 | (define-read-only (get-balance (who principal)) 115 | (ok (ft-get-balance Governance-Token who)) 116 | ) 117 | 118 | (define-read-only (get-total-supply) 119 | (ok (ft-get-supply Governance-Token)) 120 | ) 121 | 122 | (define-read-only (get-token-uri) 123 | (ok (var-get tokenUri)) 124 | ) 125 | 126 | (define-read-only (has-percentage-weight (who principal) (factor uint)) 127 | (ok (>= (* (unwrap-panic (get-balance who)) factor) (* (unwrap-panic (get-total-supply)) u1000))) 128 | ) 129 | 130 | ;; --- Extension callback 131 | 132 | (define-public (callback (sender principal) (memo (buff 34))) 133 | (ok true) 134 | ) 135 | -------------------------------------------------------------------------------- /contracts/extensions/membership/tokens/sde-governance-token-with-lockup.clar: -------------------------------------------------------------------------------- 1 | ;; _____________ _______ _________ ___ ___ ____ ____ 2 | ;; / __/_ __/ _ |/ ___/ //_/ __/ _ \/ _ \/ _ |/ __ \/ __/ 3 | ;; _\ \ / / / __ / /__/ ,< / _// , _/ // / __ / /_/ /\ \ 4 | ;; /___/ /_/ /_/ |_\___/_/|_/___/_/|_/____/_/ |_\____/___/ 5 | ;; 6 | ;; _____ _____________ ______________ _ __ 7 | ;; / __/ |/_/_ __/ __/ |/ / __/ _/ __ \/ |/ / 8 | ;; / _/_> < / / / _// /\ \_/ // /_/ / / 9 | ;; /___/_/|_| /_/ /___/_/|_/___/___/\____/_/|_/ 10 | ;; 11 | 12 | ;; Title: Governance Token with Lockup 13 | ;; Author: StackerDAO Dev Team 14 | ;; Description: 15 | ;; The governance token is a simple SIP010-compliant fungible token 16 | ;; with some added functions to make it easier to manage by 17 | ;; StackerDAO proposals and extensions. 18 | 19 | (impl-trait .governance-token-trait.governance-token-trait) 20 | (impl-trait .sip010-ft-trait.sip010-ft-trait) 21 | (impl-trait .extension-trait.extension-trait) 22 | 23 | (define-constant ERR_UNAUTHORIZED (err u2400)) 24 | (define-constant ERR_NOT_TOKEN_OWNER (err u4)) 25 | 26 | (define-fungible-token Stacker-DAO-Token) 27 | (define-fungible-token Stacker-DAO-Token-Locked) 28 | 29 | (define-data-var tokenName (string-ascii 32) "StackerDAO Governance Token") 30 | (define-data-var tokenSymbol (string-ascii 10) "SDG") 31 | (define-data-var tokenUri (optional (string-utf8 256)) none) 32 | (define-data-var tokenDecimals uint u6) 33 | 34 | ;; --- Authorization check 35 | 36 | (define-public (is-dao-or-extension) 37 | (ok (asserts! (or (is-eq tx-sender .executor-dao) (contract-call? .executor-dao is-extension contract-caller)) ERR_UNAUTHORIZED)) 38 | ) 39 | 40 | ;; --- Internal DAO functions 41 | 42 | (define-public (lock (amount uint) (owner principal)) 43 | (begin 44 | (try! (is-dao-or-extension)) 45 | (try! (ft-burn? Stacker-DAO-Token amount owner)) 46 | (ft-mint? Stacker-DAO-Token-Locked amount owner) 47 | ) 48 | ) 49 | 50 | (define-public (unlock (amount uint) (owner principal)) 51 | (begin 52 | (try! (is-dao-or-extension)) 53 | (try! (ft-burn? Stacker-DAO-Token-Locked amount owner)) 54 | (ft-mint? Stacker-DAO-Token amount owner) 55 | ) 56 | ) 57 | 58 | (define-public (mint (amount uint) (recipient principal)) 59 | (begin 60 | (try! (is-dao-or-extension)) 61 | (ft-mint? Stacker-DAO-Token amount recipient) 62 | ) 63 | ) 64 | 65 | (define-public (burn (amount uint) (owner principal)) 66 | (begin 67 | (try! (is-dao-or-extension)) 68 | (ft-burn? Stacker-DAO-Token amount owner) 69 | ) 70 | ) 71 | 72 | ;; --- Public functions 73 | 74 | (define-public (set-name (newName (string-ascii 32))) 75 | (begin 76 | (try! (is-dao-or-extension)) 77 | (ok (var-set tokenName newName)) 78 | ) 79 | ) 80 | 81 | (define-public (set-symbol (newSymbol (string-ascii 10))) 82 | (begin 83 | (try! (is-dao-or-extension)) 84 | (ok (var-set tokenSymbol newSymbol)) 85 | ) 86 | ) 87 | 88 | (define-public (set-decimals (newDecimals uint)) 89 | (begin 90 | (try! (is-dao-or-extension)) 91 | (ok (var-set tokenDecimals newDecimals)) 92 | ) 93 | ) 94 | 95 | (define-public (set-token-uri (newUri (optional (string-utf8 256)))) 96 | (begin 97 | (try! (is-dao-or-extension)) 98 | (ok (var-set tokenUri newUri)) 99 | ) 100 | ) 101 | 102 | (define-private (mint-many-iter (item {amount: uint, recipient: principal})) 103 | (ft-mint? Stacker-DAO-Token (get amount item) (get recipient item)) 104 | ) 105 | 106 | (define-public (mint-many (recipients (list 200 {amount: uint, recipient: principal}))) 107 | (begin 108 | (try! (is-dao-or-extension)) 109 | (ok (map mint-many-iter recipients)) 110 | ) 111 | ) 112 | 113 | ;; --- SIP010 traits 114 | 115 | (define-public (transfer (amount uint) (sender principal) (recipient principal) (memo (optional (buff 34)))) 116 | (begin 117 | (asserts! (or (is-eq tx-sender sender) (is-eq contract-caller sender)) ERR_NOT_TOKEN_OWNER) 118 | (ft-transfer? Stacker-DAO-Token amount sender recipient) 119 | ) 120 | ) 121 | 122 | (define-read-only (get-name) 123 | (ok (var-get tokenName)) 124 | ) 125 | 126 | (define-read-only (get-symbol) 127 | (ok (var-get tokenSymbol)) 128 | ) 129 | 130 | (define-read-only (get-decimals) 131 | (ok (var-get tokenDecimals)) 132 | ) 133 | 134 | (define-read-only (get-balance (who principal)) 135 | (ok (+ (ft-get-balance Stacker-DAO-Token who) (ft-get-balance Stacker-DAO-Token-Locked who))) 136 | ) 137 | 138 | (define-read-only (get-total-supply) 139 | (ok (+ (ft-get-supply Stacker-DAO-Token) (ft-get-supply Stacker-DAO-Token-Locked))) 140 | ) 141 | 142 | (define-read-only (get-token-uri) 143 | (ok (var-get tokenUri)) 144 | ) 145 | 146 | ;; --- Governance token traits 147 | 148 | (define-read-only (has-percentage-balance (who principal) (factor uint)) 149 | (ok (>= (* (unwrap-panic (get-balance who)) factor) (* (unwrap-panic (get-total-supply)) u1000))) 150 | ) 151 | 152 | (define-read-only (get-locked (owner principal)) 153 | (ok (ft-get-balance Stacker-DAO-Token-Locked owner)) 154 | ) 155 | 156 | ;; --- Extension callback 157 | 158 | (define-public (callback (sender principal) (memo (buff 34))) 159 | (ok true) 160 | ) 161 | -------------------------------------------------------------------------------- /contracts/extensions/membership/tokens/sde-governance-token.clar: -------------------------------------------------------------------------------- 1 | ;; _____________ _______ _________ ___ ___ ____ ____ 2 | ;; / __/_ __/ _ |/ ___/ //_/ __/ _ \/ _ \/ _ |/ __ \/ __/ 3 | ;; _\ \ / / / __ / /__/ ,< / _// , _/ // / __ / /_/ /\ \ 4 | ;; /___/ /_/ /_/ |_\___/_/|_/___/_/|_/____/_/ |_\____/___/ 5 | ;; 6 | ;; _____ _____________ ______________ _ __ 7 | ;; / __/ |/_/_ __/ __/ |/ / __/ _/ __ \/ |/ / 8 | ;; / _/_> < / / / _// /\ \_/ // /_/ / / 9 | ;; /___/_/|_| /_/ /___/_/|_/___/___/\____/_/|_/ 10 | ;; 11 | 12 | ;; Title: Governance Token 13 | ;; Author: StackerDAO Dev Team 14 | ;; Description: 15 | 16 | (impl-trait .sdt-governance-token-trait.sdt-governance-token-trait) 17 | (impl-trait .sip010-ft-trait.sip010-ft-trait) 18 | (impl-trait .extension-trait.extension-trait) 19 | 20 | (define-constant ERR_UNAUTHORIZED (err u2400)) 21 | (define-constant ERR_NOT_TOKEN_OWNER (err u2401)) 22 | 23 | (define-constant TOTAL_SUPPLY (* (pow u10 u6) u100000000)) 24 | 25 | (define-fungible-token Force TOTAL_SUPPLY) ;; Token supply cap at 100m 26 | 27 | (define-data-var tokenName (string-ascii 32) "Tiger Force") 28 | (define-data-var tokenSymbol (string-ascii 10) "FORCE") 29 | (define-data-var tokenUri (optional (string-utf8 256)) none) 30 | (define-data-var tokenDecimals uint u6) 31 | 32 | ;; --- Authorization check 33 | 34 | (define-public (is-dao-or-extension) 35 | (ok (asserts! (or (is-eq tx-sender .executor-dao) (contract-call? .executor-dao is-extension contract-caller)) ERR_UNAUTHORIZED)) 36 | ) 37 | 38 | (define-public (mint (amount uint) (recipient principal)) 39 | (begin 40 | (try! (is-dao-or-extension)) 41 | (ft-mint? Force amount recipient) 42 | ) 43 | ) 44 | 45 | ;; --- Public functions 46 | 47 | (define-public (burn (amount uint) (owner principal)) 48 | (begin 49 | (asserts! (or (is-eq tx-sender owner) (is-eq contract-caller owner)) ERR_NOT_TOKEN_OWNER) 50 | (ft-burn? Force amount owner) 51 | ) 52 | ) 53 | 54 | (define-public (set-name (newName (string-ascii 32))) 55 | (begin 56 | (try! (is-dao-or-extension)) 57 | (ok (var-set tokenName newName)) 58 | ) 59 | ) 60 | 61 | (define-public (set-symbol (newSymbol (string-ascii 10))) 62 | (begin 63 | (try! (is-dao-or-extension)) 64 | (ok (var-set tokenSymbol newSymbol)) 65 | ) 66 | ) 67 | 68 | (define-public (set-decimals (newDecimals uint)) 69 | (begin 70 | (try! (is-dao-or-extension)) 71 | (ok (var-set tokenDecimals newDecimals)) 72 | ) 73 | ) 74 | 75 | (define-public (set-token-uri (newUri (optional (string-utf8 256)))) 76 | (begin 77 | (try! (is-dao-or-extension)) 78 | (ok (var-set tokenUri newUri)) 79 | ) 80 | ) 81 | 82 | (define-private (mint-many-iter (item {amount: uint, recipient: principal})) 83 | (ft-mint? Force (get amount item) (get recipient item)) 84 | ) 85 | 86 | (define-public (mint-many (recipients (list 200 {amount: uint, recipient: principal}))) 87 | (begin 88 | (try! (is-dao-or-extension)) 89 | (ok (map mint-many-iter recipients)) 90 | ) 91 | ) 92 | 93 | ;; --- SIP010 traits 94 | 95 | (define-public (transfer (amount uint) (sender principal) (recipient principal) (memo (optional (buff 34)))) 96 | (begin 97 | (asserts! (or (is-eq tx-sender sender) (is-eq contract-caller sender)) ERR_NOT_TOKEN_OWNER) 98 | (ft-transfer? Force amount sender recipient) 99 | ) 100 | ) 101 | 102 | (define-read-only (get-name) 103 | (ok (var-get tokenName)) 104 | ) 105 | 106 | (define-read-only (get-symbol) 107 | (ok (var-get tokenSymbol)) 108 | ) 109 | 110 | (define-read-only (get-decimals) 111 | (ok (var-get tokenDecimals)) 112 | ) 113 | 114 | (define-read-only (get-balance (who principal)) 115 | (ok (ft-get-balance Force who)) 116 | ) 117 | 118 | (define-read-only (get-total-supply) 119 | (ok (ft-get-supply Force)) 120 | ) 121 | 122 | (define-read-only (get-token-uri) 123 | (ok (var-get tokenUri)) 124 | ) 125 | 126 | (define-read-only (has-percentage-weight (who principal) (factor uint)) 127 | (ok (>= (* (unwrap-panic (get-balance who)) factor) (* (unwrap-panic (get-total-supply)) u1000))) 128 | ) 129 | 130 | ;; --- Extension callback 131 | 132 | (define-public (callback (sender principal) (memo (buff 34))) 133 | (ok true) 134 | ) 135 | -------------------------------------------------------------------------------- /contracts/extensions/membership/tokens/sde-miamicoin-token.clar: -------------------------------------------------------------------------------- 1 | ;; Title: SIP10 Governance Token 2 | ;; Author: StackerDAO Dev Team 3 | ;; Description: 4 | 5 | (impl-trait .sip010-ft-trait.sip010-ft-trait) 6 | 7 | (define-constant ERR_UNAUTHORIZED (err u2400)) 8 | (define-constant ERR_NOT_TOKEN_OWNER (err u2401)) 9 | 10 | (define-constant TOTAL_SUPPLY (* (pow u10 u2) u1000000)) 11 | 12 | (define-fungible-token MiamiCoin TOTAL_SUPPLY) ;; 1m tokens 13 | 14 | (define-data-var tokenName (string-ascii 32) "MiamiCoin") 15 | (define-data-var tokenSymbol (string-ascii 10) "MIA") 16 | (define-data-var tokenUri (optional (string-utf8 256)) none) 17 | (define-data-var tokenDecimals uint u2) 18 | 19 | ;; --- Authorization check 20 | 21 | (define-public (is-dao-or-extension) 22 | (ok (asserts! (or (is-eq tx-sender .executor-dao) (contract-call? .executor-dao is-extension contract-caller)) ERR_UNAUTHORIZED)) 23 | ) 24 | 25 | (define-public (mint (amount uint) (recipient principal)) 26 | (begin 27 | (try! (is-dao-or-extension)) 28 | (ft-mint? MiamiCoin amount recipient) 29 | ) 30 | ) 31 | 32 | ;; --- Public functions 33 | 34 | (define-public (burn (amount uint) (owner principal)) 35 | (begin 36 | (asserts! (or (is-eq tx-sender owner) (is-eq contract-caller owner)) ERR_NOT_TOKEN_OWNER) 37 | (ft-burn? MiamiCoin amount owner) 38 | ) 39 | ) 40 | 41 | (define-public (set-name (newName (string-ascii 32))) 42 | (begin 43 | (try! (is-dao-or-extension)) 44 | (ok (var-set tokenName newName)) 45 | ) 46 | ) 47 | 48 | (define-public (set-symbol (newSymbol (string-ascii 10))) 49 | (begin 50 | (try! (is-dao-or-extension)) 51 | (ok (var-set tokenSymbol newSymbol)) 52 | ) 53 | ) 54 | 55 | (define-public (set-decimals (newDecimals uint)) 56 | (begin 57 | (try! (is-dao-or-extension)) 58 | (ok (var-set tokenDecimals newDecimals)) 59 | ) 60 | ) 61 | 62 | (define-public (set-token-uri (newUri (optional (string-utf8 256)))) 63 | (begin 64 | (try! (is-dao-or-extension)) 65 | (ok (var-set tokenUri newUri)) 66 | ) 67 | ) 68 | 69 | (define-private (mint-many-iter (item {amount: uint, recipient: principal})) 70 | (ft-mint? MiamiCoin (get amount item) (get recipient item)) 71 | ) 72 | 73 | (define-public (mint-many (recipients (list 200 {amount: uint, recipient: principal}))) 74 | (begin 75 | (try! (is-dao-or-extension)) 76 | (ok (map mint-many-iter recipients)) 77 | ) 78 | ) 79 | 80 | ;; --- SIP010 traits 81 | 82 | (define-public (transfer (amount uint) (sender principal) (recipient principal) (memo (optional (buff 34)))) 83 | (begin 84 | (asserts! (or (is-eq tx-sender sender) (is-eq contract-caller sender)) ERR_NOT_TOKEN_OWNER) 85 | (ft-transfer? MiamiCoin amount sender recipient) 86 | ) 87 | ) 88 | 89 | (define-read-only (get-name) 90 | (ok (var-get tokenName)) 91 | ) 92 | 93 | (define-read-only (get-symbol) 94 | (ok (var-get tokenSymbol)) 95 | ) 96 | 97 | (define-read-only (get-decimals) 98 | (ok (var-get tokenDecimals)) 99 | ) 100 | 101 | (define-read-only (get-balance (who principal)) 102 | (ok (ft-get-balance MiamiCoin who)) 103 | ) 104 | 105 | (define-read-only (get-total-supply) 106 | (ok (ft-get-supply MiamiCoin)) 107 | ) 108 | 109 | (define-read-only (get-token-uri) 110 | (ok (var-get tokenUri)) 111 | ) -------------------------------------------------------------------------------- /contracts/extensions/membership/tokens/sde-newyorkcoin-token.clar: -------------------------------------------------------------------------------- 1 | ;; Title: SIP10 Governance Token 2 | ;; Author: StackerDAO Dev Team 3 | ;; Description: 4 | 5 | (impl-trait .sip010-ft-trait.sip010-ft-trait) 6 | 7 | (define-constant ERR_UNAUTHORIZED (err u2400)) 8 | (define-constant ERR_NOT_TOKEN_OWNER (err u2401)) 9 | 10 | (define-constant TOTAL_SUPPLY (* (pow u10 u2) u1000000)) 11 | 12 | (define-fungible-token NewYorkCoin TOTAL_SUPPLY) ;; 1m tokens 13 | 14 | (define-data-var tokenName (string-ascii 32) "NewYorkCoin") 15 | (define-data-var tokenSymbol (string-ascii 10) "NYC") 16 | (define-data-var tokenUri (optional (string-utf8 256)) none) 17 | (define-data-var tokenDecimals uint u2) 18 | 19 | ;; --- Authorization check 20 | 21 | (define-public (is-dao-or-extension) 22 | (ok (asserts! (or (is-eq tx-sender .executor-dao) (contract-call? .executor-dao is-extension contract-caller)) ERR_UNAUTHORIZED)) 23 | ) 24 | 25 | (define-public (mint (amount uint) (recipient principal)) 26 | (begin 27 | (try! (is-dao-or-extension)) 28 | (ft-mint? NewYorkCoin amount recipient) 29 | ) 30 | ) 31 | 32 | ;; --- Public functions 33 | 34 | (define-public (burn (amount uint) (owner principal)) 35 | (begin 36 | (asserts! (or (is-eq tx-sender owner) (is-eq contract-caller owner)) ERR_NOT_TOKEN_OWNER) 37 | (ft-burn? NewYorkCoin amount owner) 38 | ) 39 | ) 40 | 41 | (define-public (set-name (newName (string-ascii 32))) 42 | (begin 43 | (try! (is-dao-or-extension)) 44 | (ok (var-set tokenName newName)) 45 | ) 46 | ) 47 | 48 | (define-public (set-symbol (newSymbol (string-ascii 10))) 49 | (begin 50 | (try! (is-dao-or-extension)) 51 | (ok (var-set tokenSymbol newSymbol)) 52 | ) 53 | ) 54 | 55 | (define-public (set-decimals (newDecimals uint)) 56 | (begin 57 | (try! (is-dao-or-extension)) 58 | (ok (var-set tokenDecimals newDecimals)) 59 | ) 60 | ) 61 | 62 | (define-public (set-token-uri (newUri (optional (string-utf8 256)))) 63 | (begin 64 | (try! (is-dao-or-extension)) 65 | (ok (var-set tokenUri newUri)) 66 | ) 67 | ) 68 | 69 | (define-private (mint-many-iter (item {amount: uint, recipient: principal})) 70 | (ft-mint? NewYorkCoin (get amount item) (get recipient item)) 71 | ) 72 | 73 | (define-public (mint-many (recipients (list 200 {amount: uint, recipient: principal}))) 74 | (begin 75 | (try! (is-dao-or-extension)) 76 | (ok (map mint-many-iter recipients)) 77 | ) 78 | ) 79 | 80 | ;; --- SIP010 traits 81 | 82 | (define-public (transfer (amount uint) (sender principal) (recipient principal) (memo (optional (buff 34)))) 83 | (begin 84 | (asserts! (or (is-eq tx-sender sender) (is-eq contract-caller sender)) ERR_NOT_TOKEN_OWNER) 85 | (ft-transfer? NewYorkCoin amount sender recipient) 86 | ) 87 | ) 88 | 89 | (define-read-only (get-name) 90 | (ok (var-get tokenName)) 91 | ) 92 | 93 | (define-read-only (get-symbol) 94 | (ok (var-get tokenSymbol)) 95 | ) 96 | 97 | (define-read-only (get-decimals) 98 | (ok (var-get tokenDecimals)) 99 | ) 100 | 101 | (define-read-only (get-balance (who principal)) 102 | (ok (ft-get-balance NewYorkCoin who)) 103 | ) 104 | 105 | (define-read-only (get-total-supply) 106 | (ok (ft-get-supply NewYorkCoin)) 107 | ) 108 | 109 | (define-read-only (get-token-uri) 110 | (ok (var-get tokenUri)) 111 | ) -------------------------------------------------------------------------------- /contracts/extensions/membership/tokens/sde-sip10-token.clar: -------------------------------------------------------------------------------- 1 | ;; Title: SIP10 Governance Token 2 | ;; Author: StackerDAO Dev Team 3 | ;; Description: 4 | 5 | (impl-trait .sip010-ft-trait.sip010-ft-trait) 6 | 7 | (define-constant ERR_UNAUTHORIZED (err u2400)) 8 | (define-constant ERR_NOT_TOKEN_OWNER (err u2401)) 9 | 10 | (define-constant TOTAL_SUPPLY (* (pow u10 u2) u1000000)) 11 | 12 | (define-fungible-token Mega TOTAL_SUPPLY) ;; 1m tokens 13 | 14 | (define-data-var tokenName (string-ascii 32) "Mega") 15 | (define-data-var tokenSymbol (string-ascii 10) "MEGA") 16 | (define-data-var tokenUri (optional (string-utf8 256)) (some u"ipfs://QmegBfV56VVh5XjgwMi3CoshLoLHRuR5kGDJNNge368oWW")) 17 | (define-data-var tokenDecimals uint u2) 18 | 19 | ;; --- Authorization check 20 | 21 | (define-public (is-dao-or-extension) 22 | (ok (asserts! (or (is-eq tx-sender .executor-dao) (contract-call? .executor-dao is-extension contract-caller)) ERR_UNAUTHORIZED)) 23 | ) 24 | 25 | (define-public (mint (amount uint) (recipient principal)) 26 | (begin 27 | (try! (is-dao-or-extension)) 28 | (ft-mint? Mega amount recipient) 29 | ) 30 | ) 31 | 32 | ;; --- Public functions 33 | 34 | (define-public (burn (amount uint) (owner principal)) 35 | (begin 36 | (asserts! (or (is-eq tx-sender owner) (is-eq contract-caller owner)) ERR_NOT_TOKEN_OWNER) 37 | (ft-burn? Mega amount owner) 38 | ) 39 | ) 40 | 41 | (define-public (set-name (newName (string-ascii 32))) 42 | (begin 43 | (try! (is-dao-or-extension)) 44 | (ok (var-set tokenName newName)) 45 | ) 46 | ) 47 | 48 | (define-public (set-symbol (newSymbol (string-ascii 10))) 49 | (begin 50 | (try! (is-dao-or-extension)) 51 | (ok (var-set tokenSymbol newSymbol)) 52 | ) 53 | ) 54 | 55 | (define-public (set-decimals (newDecimals uint)) 56 | (begin 57 | (try! (is-dao-or-extension)) 58 | (ok (var-set tokenDecimals newDecimals)) 59 | ) 60 | ) 61 | 62 | (define-public (set-token-uri (newUri (optional (string-utf8 256)))) 63 | (begin 64 | (try! (is-dao-or-extension)) 65 | (ok (var-set tokenUri newUri)) 66 | ) 67 | ) 68 | 69 | (define-private (mint-many-iter (item {amount: uint, recipient: principal})) 70 | (ft-mint? Mega (get amount item) (get recipient item)) 71 | ) 72 | 73 | (define-public (mint-many (recipients (list 200 {amount: uint, recipient: principal}))) 74 | (begin 75 | (try! (is-dao-or-extension)) 76 | (ok (map mint-many-iter recipients)) 77 | ) 78 | ) 79 | 80 | ;; --- SIP010 traits 81 | 82 | (define-public (transfer (amount uint) (sender principal) (recipient principal) (memo (optional (buff 34)))) 83 | (begin 84 | (asserts! (or (is-eq tx-sender sender) (is-eq contract-caller sender)) ERR_NOT_TOKEN_OWNER) 85 | (ft-transfer? Mega amount sender recipient) 86 | ) 87 | ) 88 | 89 | (define-read-only (get-name) 90 | (ok (var-get tokenName)) 91 | ) 92 | 93 | (define-read-only (get-symbol) 94 | (ok (var-get tokenSymbol)) 95 | ) 96 | 97 | (define-read-only (get-decimals) 98 | (ok (var-get tokenDecimals)) 99 | ) 100 | 101 | (define-read-only (get-balance (who principal)) 102 | (ok (ft-get-balance Mega who)) 103 | ) 104 | 105 | (define-read-only (get-total-supply) 106 | (ok (ft-get-supply Mega)) 107 | ) 108 | 109 | (define-read-only (get-token-uri) 110 | (ok (var-get tokenUri)) 111 | ) -------------------------------------------------------------------------------- /contracts/extensions/membership/tokens/sde-stackerdao-token.clar: -------------------------------------------------------------------------------- 1 | ;; Title: SIP10 Governance Token 2 | ;; Author: StackerDAO Dev Team 3 | ;; Description: 4 | 5 | (impl-trait .sip010-ft-trait.sip010-ft-trait) 6 | 7 | (define-constant ERR_UNAUTHORIZED (err u2400)) 8 | (define-constant ERR_NOT_TOKEN_OWNER (err u2401)) 9 | 10 | (define-constant TOTAL_SUPPLY (* (pow u10 u2) u1000000)) 11 | 12 | (define-fungible-token StackerDAO TOTAL_SUPPLY) ;; 1m tokens 13 | 14 | (define-data-var tokenName (string-ascii 32) "StackerDAO") 15 | (define-data-var tokenSymbol (string-ascii 10) "SDAO") 16 | (define-data-var tokenUri (optional (string-utf8 256)) none) 17 | (define-data-var tokenDecimals uint u2) 18 | 19 | ;; --- Authorization check 20 | 21 | (define-public (is-dao-or-extension) 22 | (ok (asserts! (or (is-eq tx-sender .executor-dao) (contract-call? .executor-dao is-extension contract-caller)) ERR_UNAUTHORIZED)) 23 | ) 24 | 25 | (define-public (mint (amount uint) (recipient principal)) 26 | (begin 27 | (try! (is-dao-or-extension)) 28 | (ft-mint? StackerDAO amount recipient) 29 | ) 30 | ) 31 | 32 | ;; --- Public functions 33 | 34 | (define-public (burn (amount uint) (owner principal)) 35 | (begin 36 | (asserts! (or (is-eq tx-sender owner) (is-eq contract-caller owner)) ERR_NOT_TOKEN_OWNER) 37 | (ft-burn? StackerDAO amount owner) 38 | ) 39 | ) 40 | 41 | (define-public (set-name (newName (string-ascii 32))) 42 | (begin 43 | (try! (is-dao-or-extension)) 44 | (ok (var-set tokenName newName)) 45 | ) 46 | ) 47 | 48 | (define-public (set-symbol (newSymbol (string-ascii 10))) 49 | (begin 50 | (try! (is-dao-or-extension)) 51 | (ok (var-set tokenSymbol newSymbol)) 52 | ) 53 | ) 54 | 55 | (define-public (set-decimals (newDecimals uint)) 56 | (begin 57 | (try! (is-dao-or-extension)) 58 | (ok (var-set tokenDecimals newDecimals)) 59 | ) 60 | ) 61 | 62 | (define-public (set-token-uri (newUri (optional (string-utf8 256)))) 63 | (begin 64 | (try! (is-dao-or-extension)) 65 | (ok (var-set tokenUri newUri)) 66 | ) 67 | ) 68 | 69 | (define-private (mint-many-iter (item {amount: uint, recipient: principal})) 70 | (ft-mint? StackerDAO (get amount item) (get recipient item)) 71 | ) 72 | 73 | (define-public (mint-many (recipients (list 200 {amount: uint, recipient: principal}))) 74 | (begin 75 | (try! (is-dao-or-extension)) 76 | (ok (map mint-many-iter recipients)) 77 | ) 78 | ) 79 | 80 | ;; --- SIP010 traits 81 | 82 | (define-public (transfer (amount uint) (sender principal) (recipient principal) (memo (optional (buff 34)))) 83 | (begin 84 | (asserts! (or (is-eq tx-sender sender) (is-eq contract-caller sender)) ERR_NOT_TOKEN_OWNER) 85 | (ft-transfer? StackerDAO amount sender recipient) 86 | ) 87 | ) 88 | 89 | (define-read-only (get-name) 90 | (ok (var-get tokenName)) 91 | ) 92 | 93 | (define-read-only (get-symbol) 94 | (ok (var-get tokenSymbol)) 95 | ) 96 | 97 | (define-read-only (get-decimals) 98 | (ok (var-get tokenDecimals)) 99 | ) 100 | 101 | (define-read-only (get-balance (who principal)) 102 | (ok (ft-get-balance StackerDAO who)) 103 | ) 104 | 105 | (define-read-only (get-total-supply) 106 | (ok (ft-get-supply StackerDAO)) 107 | ) 108 | 109 | (define-read-only (get-token-uri) 110 | (ok (var-get tokenUri)) 111 | ) -------------------------------------------------------------------------------- /contracts/extensions/misc/sde-dev-fund.clar: -------------------------------------------------------------------------------- 1 | ;; _____________ _______ _________ ___ ___ ____ ____ 2 | ;; / __/_ __/ _ |/ ___/ //_/ __/ _ \/ _ \/ _ |/ __ \/ __/ 3 | ;; _\ \ / / / __ / /__/ ,< / _// , _/ // / __ / /_/ /\ \ 4 | ;; /___/ /_/ /_/ |_\___/_/|_/___/_/|_/____/_/ |_\____/___/ 5 | ;; 6 | ;; _____ _____________ ______________ _ __ 7 | ;; / __/ |/_/_ __/ __/ |/ / __/ _/ __ \/ |/ / 8 | ;; / _/_> < / / / _// /\ \_/ // /_/ / / 9 | ;; /___/_/|_| /_/ /___/_/|_/___/___/\____/_/|_/ 10 | ;; 11 | 12 | ;; Title: SDE005 Dev Fund 13 | ;; Author: Marvin Janssen / StackerDAO Dev Team 14 | 15 | (impl-trait .extension-trait.extension-trait) 16 | 17 | (define-constant ONE_MONTH_TIME u4380) ;; 43,800 minutes / 10 minute average block time. 18 | 19 | (define-constant ERR_UNAUTHORIZED (err u3000)) 20 | (define-constant ERR_NO_ALLOWANCE (err u3001)) 21 | (define-constant ERR_ALREADY_CLAIMED (err u3002)) 22 | 23 | (define-data-var allowanceStartHeight uint u0) 24 | 25 | (define-map MonthlyDeveloperAllowances principal uint) 26 | (define-map ClaimCounts principal uint) 27 | 28 | ;; --- Authorization check 29 | 30 | (define-public (is-dao-or-extension) 31 | (ok (asserts! (or (is-eq tx-sender .executor-dao) (contract-call? .executor-dao is-extension contract-caller)) ERR_UNAUTHORIZED)) 32 | ) 33 | 34 | ;; --- Internal DAO functions 35 | 36 | (define-public (set-allowance-start-height (startHeight uint)) 37 | (begin 38 | (try! (is-dao-or-extension)) 39 | (ok (var-set allowanceStartHeight startHeight)) 40 | ) 41 | ) 42 | 43 | (define-public (set-developer-allowance (allowance uint) (who principal)) 44 | (begin 45 | (try! (is-dao-or-extension)) 46 | (ok (map-set MonthlyDeveloperAllowances who allowance)) 47 | ) 48 | ) 49 | 50 | (define-private (set-developer-allowances-iter (item {allowance: uint, who: principal}) (previous bool)) 51 | (map-set MonthlyDeveloperAllowances (get who item) (get allowance item)) 52 | ) 53 | 54 | (define-public (set-developer-allowances (developers (list 200 {allowance: uint, who: principal}))) 55 | (begin 56 | (try! (is-dao-or-extension)) 57 | (ok (fold set-developer-allowances-iter developers true)) 58 | ) 59 | ) 60 | 61 | (define-public (transfer (amount uint) (recipient principal) (memo (optional (buff 34)))) 62 | (begin 63 | (try! (is-dao-or-extension)) 64 | (as-contract (contract-call? .sde-governance-token-with-lockup transfer amount tx-sender recipient memo)) 65 | ) 66 | ) 67 | 68 | ;; --- Public functions 69 | 70 | (define-read-only (get-developer-allowance (who principal)) 71 | (default-to u0 (map-get? MonthlyDeveloperAllowances who)) 72 | ) 73 | 74 | (define-read-only (get-developer-claim-count (who principal)) 75 | (default-to u0 (map-get? ClaimCounts who)) 76 | ) 77 | 78 | (define-public (claim (memo (optional (buff 34)))) 79 | (let 80 | ( 81 | (allowance (get-developer-allowance tx-sender)) 82 | (claimCount (get-developer-claim-count tx-sender)) 83 | (startHeight (var-get allowanceStartHeight)) 84 | (maxClaims (/ (- block-height startHeight) ONE_MONTH_TIME)) 85 | (developer tx-sender) 86 | ) 87 | (asserts! (> startHeight u0) ERR_UNAUTHORIZED) 88 | (asserts! (> allowance u0) ERR_NO_ALLOWANCE) 89 | (asserts! (< claimCount maxClaims) ERR_ALREADY_CLAIMED) 90 | (map-set ClaimCounts tx-sender maxClaims) 91 | (as-contract (contract-call? .sde-governance-token-with-lockup transfer (* (- maxClaims claimCount) allowance) tx-sender developer memo)) 92 | ) 93 | ) 94 | 95 | ;; --- Extension callback 96 | 97 | (define-public (callback (sender principal) (memo (buff 34))) 98 | (ok true) 99 | ) 100 | -------------------------------------------------------------------------------- /contracts/extensions/misc/sde-mia-stacking.clar: -------------------------------------------------------------------------------- 1 | ;; _____________ _______ _________ ___ ___ ____ ____ 2 | ;; / __/_ __/ _ |/ ___/ //_/ __/ _ \/ _ \/ _ |/ __ \/ __/ 3 | ;; _\ \ / / / __ / /__/ ,< / _// , _/ // / __ / /_/ /\ \ 4 | ;; /___/ /_/ /_/ |_\___/_/|_/___/_/|_/____/_/ |_\____/___/ 5 | ;; 6 | ;; _____ _____________ ______________ _ __ 7 | ;; / __/ |/_/_ __/ __/ |/ / __/ _/ __ \/ |/ / 8 | ;; / _/_> < / / / _// /\ \_/ // /_/ / / 9 | ;; /___/_/|_| /_/ /___/_/|_/___/___/\____/_/|_/ 10 | ;; 11 | 12 | ;; Title: SDE010 MiamiCoin Stacking 13 | ;; Author: StackerDAO Dev Team 14 | ;; Depends-On: 15 | ;; Synopsis: 16 | ;; This extension part of the core of StackerDAO. It allows for basic treasury operations. 17 | ;; Description: 18 | ;; Proposals may be submitted by any members to send funds from the treasury. 19 | 20 | (use-trait ft-trait .sip010-ft-trait.sip010-ft-trait) 21 | 22 | (impl-trait .extension-trait.extension-trait) 23 | 24 | (define-constant ERR_UNAUTHORIZED (err u3300)) 25 | 26 | 27 | ;; --- Authorization check 28 | 29 | (define-public (is-dao-or-extension) 30 | (ok (asserts! (or (is-eq tx-sender .executor-dao) (contract-call? .executor-dao is-extension contract-caller)) ERR_UNAUTHORIZED)) 31 | ) 32 | 33 | ;; --- Public functions 34 | 35 | ;; --- Read only functions 36 | 37 | ;; --- Extension callback 38 | 39 | (define-public (callback (sender principal) (memo (buff 34))) 40 | (ok true) 41 | ) 42 | -------------------------------------------------------------------------------- /contracts/extensions/misc/sde-token-vesting.clar: -------------------------------------------------------------------------------- 1 | ;; _____________ _______ _________ ___ ___ ____ ____ 2 | ;; / __/_ __/ _ |/ ___/ //_/ __/ _ \/ _ \/ _ |/ __ \/ __/ 3 | ;; _\ \ / / / __ / /__/ ,< / _// , _/ // / __ / /_/ /\ \ 4 | ;; /___/ /_/ /_/ |_\___/_/|_/___/_/|_/____/_/ |_\____/___/ 5 | ;; 6 | ;; _____ _____________ ______________ _ __ 7 | ;; / __/ |/_/_ __/ __/ |/ / __/ _/ __ \/ |/ / 8 | ;; / _/_> < / / / _// /\ \_/ // /_/ / / 9 | ;; /___/_/|_| /_/ /___/_/|_/___/___/\____/_/|_/ 10 | ;; 11 | 12 | ;; Title: SDE005 Dev Fund 13 | ;; Author: Marvin Janssen / StackerDAO Dev Team 14 | 15 | (impl-trait .extension-trait.extension-trait) 16 | 17 | (define-constant ONE_MONTH_TIME u4380) ;; 43,800 minutes / 10 minute average block time. 18 | 19 | (define-constant ERR_UNAUTHORIZED (err u3000)) 20 | (define-constant ERR_NO_ALLOWANCE (err u3001)) 21 | (define-constant ERR_ALREADY_CLAIMED (err u3002)) 22 | 23 | (define-data-var allowanceStartHeight uint u0) 24 | 25 | (define-map MonthlyDeveloperAllowances principal uint) 26 | (define-map ClaimCounts principal uint) 27 | 28 | ;; --- Authorization check 29 | 30 | (define-public (is-dao-or-extension) 31 | (ok (asserts! (or (is-eq tx-sender .executor-dao) (contract-call? .executor-dao is-extension contract-caller)) ERR_UNAUTHORIZED)) 32 | ) 33 | 34 | ;; --- Internal DAO functions 35 | 36 | (define-public (set-issuance-start-height (startHeight uint)) 37 | (begin 38 | (try! (is-dao-or-extension)) 39 | (ok (var-set allowanceStartHeight startHeight)) 40 | ) 41 | ) 42 | 43 | (define-public (set-investor-issuance (amount uint) (who principal)) 44 | (begin 45 | (try! (is-dao-or-extension)) 46 | (ok (map-set MonthlyDeveloperAllowances who amount)) 47 | ) 48 | ) 49 | 50 | (define-private (set-investor-issuances-iter (item {amount: uint, who: principal}) (previous bool)) 51 | (map-set MonthlyDeveloperAllowances (get who item) (get amount item)) 52 | ) 53 | 54 | (define-public (set-investor-issuances (investors (list 200 {amount: uint, who: principal}))) 55 | (begin 56 | (try! (is-dao-or-extension)) 57 | (ok (fold set-investor-issuances-iter investors true)) 58 | ) 59 | ) 60 | 61 | (define-public (transfer (amount uint) (recipient principal) (memo (optional (buff 34)))) 62 | (begin 63 | (try! (is-dao-or-extension)) 64 | (as-contract (contract-call? .sde-governance-token-with-lockup transfer amount tx-sender recipient memo)) 65 | ) 66 | ) 67 | 68 | ;; --- Public functions 69 | 70 | (define-read-only (get-developer-allowance (who principal)) 71 | (default-to u0 (map-get? MonthlyDeveloperAllowances who)) 72 | ) 73 | 74 | (define-read-only (get-developer-claim-count (who principal)) 75 | (default-to u0 (map-get? ClaimCounts who)) 76 | ) 77 | 78 | (define-public (claim (memo (optional (buff 34)))) 79 | (let 80 | ( 81 | (allowance (get-developer-allowance tx-sender)) 82 | (claimCount (get-developer-claim-count tx-sender)) 83 | (startHeight (var-get allowanceStartHeight)) 84 | (maxClaims (/ (- block-height startHeight) ONE_MONTH_TIME)) 85 | (developer tx-sender) 86 | ) 87 | (asserts! (> startHeight u0) ERR_UNAUTHORIZED) 88 | (asserts! (> allowance u0) ERR_NO_ALLOWANCE) 89 | (asserts! (< claimCount maxClaims) ERR_ALREADY_CLAIMED) 90 | (map-set ClaimCounts tx-sender maxClaims) 91 | (as-contract (contract-call? .sde-governance-token-with-lockup transfer (* (- maxClaims claimCount) allowance) tx-sender developer memo)) 92 | ) 93 | ) 94 | 95 | ;; --- Extension callback 96 | 97 | (define-public (callback (sender principal) (memo (buff 34))) 98 | (ok true) 99 | ) 100 | -------------------------------------------------------------------------------- /contracts/extensions/multisignature/sde-multisig.clar: -------------------------------------------------------------------------------- 1 | ;; _____________ _______ _________ ___ ___ ____ ____ 2 | ;; / __/_ __/ _ |/ ___/ //_/ __/ _ \/ _ \/ _ |/ __ \/ __/ 3 | ;; _\ \ / / / __ / /__/ ,< / _// , _/ // / __ / /_/ /\ \ 4 | ;; /___/ /_/ /_/ |_\___/_/|_/___/_/|_/____/_/ |_\____/___/ 5 | ;; 6 | ;; _____ _____________ ______________ _ __ 7 | ;; / __/ |/_/_ __/ __/ |/ / __/ _/ __ \/ |/ / 8 | ;; / _/_> < / / / _// /\ \_/ // /_/ / / 9 | ;; /___/_/|_| /_/ /___/_/|_/___/___/\____/_/|_/ 10 | ;; 11 | 12 | ;; Title: SDE013 Multisig 13 | ;; Author: StackerDAO Dev Team 14 | ;; Depends-On: 15 | ;; Synopsis: 16 | ;; Description: 17 | 18 | (use-trait proposal-trait .proposal-trait.proposal-trait) 19 | 20 | (impl-trait .extension-trait.extension-trait) 21 | 22 | (define-constant ERR_UNAUTHORIZED (err u3600)) 23 | (define-constant ERR_NOT_SIGNER (err u3601)) 24 | (define-constant ERR_INVALID (err u3602)) 25 | (define-constant ERR_ALREADY_EXECUTED (err u3603)) 26 | (define-constant ERR_PROPOSAL_NOT_FOUND (err u3604)) 27 | (define-constant ERR_PROPOSAL_ALREADY_EXISTS (err u3605)) 28 | (define-constant ERR_PROPOSAL_ALREADY_EXECUTED (err u3606)) 29 | 30 | (define-data-var signers (list 10 principal) (list)) 31 | (define-data-var signalsRequired uint u2) 32 | (define-data-var lastRemovedSigner (optional principal) none) 33 | (define-data-var proposalList (list 100 principal) (list)) 34 | 35 | (define-map Proposals 36 | principal 37 | { 38 | proposer: principal, 39 | concluded: bool 40 | } 41 | ) 42 | 43 | (define-map Signals {proposal: principal, teamMember: principal} bool) 44 | (define-map SignalCount principal uint) 45 | 46 | ;; --- Authorization check 47 | 48 | (define-public (is-dao-or-extension) 49 | (ok (asserts! (or (is-eq tx-sender .executor-dao) (contract-call? .executor-dao is-extension contract-caller)) ERR_UNAUTHORIZED)) 50 | ) 51 | 52 | ;; --- Internal DAO functions 53 | 54 | (define-public (add-signer (who principal)) 55 | (begin 56 | (try! (is-dao-or-extension)) 57 | (var-set signers (unwrap-panic (as-max-len? (append (var-get signers) who) u10))) 58 | (ok true) 59 | ) 60 | ) 61 | 62 | (define-public (remove-signer (who principal)) 63 | (begin 64 | (try! (is-dao-or-extension)) 65 | (asserts! (>= (- (get-signers-count) u1) (var-get signalsRequired)) ERR_INVALID) 66 | (asserts! (not (is-none (index-of (var-get signers) who))) ERR_INVALID) 67 | (var-set lastRemovedSigner (some who)) 68 | (var-set signers (unwrap-panic (as-max-len? (filter remove-signer-filter (var-get signers)) u10))) 69 | (ok true) 70 | ) 71 | ) 72 | 73 | (define-public (set-signals-required (newRequirement uint)) 74 | (begin 75 | (try! (is-dao-or-extension)) 76 | (asserts! (and (<= (var-get signalsRequired) (get-signers-count)) (<= newRequirement (get-signers-count))) ERR_INVALID) 77 | (ok (var-set signalsRequired newRequirement)) 78 | ) 79 | ) 80 | 81 | ;; --- Read only functions 82 | 83 | (define-read-only (is-signer (who principal)) 84 | (is-some (index-of (var-get signers) tx-sender)) 85 | ) 86 | 87 | (define-read-only (has-signaled (proposal principal) (who principal)) 88 | (default-to false (map-get? Signals {proposal: proposal, teamMember: who})) 89 | ) 90 | 91 | (define-read-only (get-proposal-data (proposal principal)) 92 | (map-get? Proposals proposal) 93 | ) 94 | 95 | (define-read-only (get-signals-required) 96 | (var-get signalsRequired) 97 | ) 98 | 99 | (define-read-only (get-signer (who principal)) 100 | (match (index-of (var-get signers) who) 101 | success (some who) 102 | none 103 | ) 104 | ) 105 | 106 | (define-read-only (get-signers) 107 | (var-get signers) 108 | ) 109 | 110 | (define-read-only (get-signers-count) 111 | (len (var-get signers)) 112 | ) 113 | 114 | (define-read-only (get-proposal-signals (proposal principal)) 115 | (default-to u0 (map-get? SignalCount proposal)) 116 | ) 117 | 118 | (define-read-only (get-proposals (proposals (list 100 principal))) 119 | (map get-proposal-info proposals) 120 | ) 121 | 122 | ;; --- Public functions 123 | 124 | (define-public (add-proposal (proposal )) 125 | (let 126 | ( 127 | (proposalPrincipal (contract-of proposal)) 128 | ) 129 | (asserts! (is-signer tx-sender) ERR_NOT_SIGNER) 130 | (asserts! (map-insert Proposals proposalPrincipal {proposer: tx-sender, concluded: false}) ERR_PROPOSAL_ALREADY_EXISTS) 131 | (asserts! (is-none (contract-call? .executor-dao executed-at proposal)) ERR_PROPOSAL_ALREADY_EXECUTED) 132 | (var-set proposalList (unwrap-panic (as-max-len? (append (var-get proposalList) proposalPrincipal) u100))) 133 | (print {event: "propose", proposal: proposal, proposer: tx-sender}) 134 | (map-set Signals {proposal: proposalPrincipal, teamMember: tx-sender} true) 135 | (map-set SignalCount proposalPrincipal u1) 136 | (ok true) 137 | ) 138 | ) 139 | 140 | (define-public (sign (proposal )) 141 | (let 142 | ( 143 | (proposalPrincipal (contract-of proposal)) 144 | (signals 145 | (+ 146 | (get-proposal-signals proposalPrincipal) 147 | (if (has-signaled proposalPrincipal tx-sender) u0 u1) 148 | ) 149 | ) 150 | (proposalData (unwrap! (get-proposal-data proposalPrincipal) ERR_PROPOSAL_NOT_FOUND)) 151 | ) 152 | (asserts! (is-signer tx-sender) ERR_NOT_SIGNER) 153 | (asserts! (is-none (contract-call? .executor-dao executed-at proposal)) ERR_ALREADY_EXECUTED) 154 | (and (>= signals (var-get signalsRequired)) 155 | (begin 156 | (try! (contract-call? .executor-dao execute proposal tx-sender)) 157 | (map-set Proposals proposalPrincipal 158 | (merge proposalData {concluded: true}) 159 | ) 160 | ) 161 | ) 162 | (map-set Signals {proposal: proposalPrincipal, teamMember: tx-sender} true) 163 | (map-set SignalCount proposalPrincipal signals) 164 | (ok signals) 165 | ) 166 | ) 167 | 168 | ;; Private functions 169 | 170 | (define-private (remove-signer-filter (signer principal)) 171 | (not (is-eq signer (unwrap-panic (var-get lastRemovedSigner)))) 172 | ) 173 | 174 | (define-private (get-proposal-info (proposalPrincipal principal)) 175 | (begin 176 | (let 177 | ( 178 | (proposalData (unwrap-panic (get-proposal-data proposalPrincipal))) 179 | ) 180 | (some 181 | { 182 | proposer: (get proposer proposalData), 183 | concluded: (get concluded proposalData) 184 | } 185 | ) 186 | ) 187 | ) 188 | ) 189 | 190 | ;; --- Extension callback 191 | 192 | (define-public (callback (sender principal) (memo (buff 34))) 193 | (ok true) 194 | ) 195 | -------------------------------------------------------------------------------- /contracts/extensions/proposal-submissions/sde-proposal-submission-with-delegation.clar: -------------------------------------------------------------------------------- 1 | ;; _____________ _______ _________ ___ ___ ____ ____ 2 | ;; / __/_ __/ _ |/ ___/ //_/ __/ _ \/ _ \/ _ |/ __ \/ __/ 3 | ;; _\ \ / / / __ / /__/ ,< / _// , _/ // / __ / /_/ /\ \ 4 | ;; /___/ /_/ /_/ |_\___/_/|_/___/_/|_/____/_/ |_\____/___/ 5 | ;; 6 | ;; _____ _____________ ______________ _ __ 7 | ;; / __/ |/_/_ __/ __/ |/ / __/ _/ __ \/ |/ / 8 | ;; / _/_> < / / / _// /\ \_/ // /_/ / / 9 | ;; /___/_/|_| /_/ /___/_/|_/___/___/\____/_/|_/ 10 | ;; 11 | 12 | ;; Title: Proposal Submission with Delegation 13 | ;; Author: StackerDAO 14 | ;; Description: 15 | 16 | (use-trait proposal-trait .proposal-trait.proposal-trait) 17 | (use-trait delegate-token-trait .delegate-token-trait.delegate-token-trait) 18 | 19 | (impl-trait .extension-trait.extension-trait) 20 | 21 | (define-constant ERR_UNAUTHORIZED (err u2600)) 22 | (define-constant ERR_NOT_GOVERNANCE_TOKEN (err u2601)) 23 | (define-constant ERR_INSUFFICIENT_WEIGHT (err u2602)) 24 | (define-constant ERR_UNKNOWN_PARAMETER (err u2603)) 25 | (define-constant ERR_PROPOSAL_MINIMUM_START_DELAY (err u2604)) 26 | (define-constant ERR_PROPOSAL_MAXIMUM_START_DELAY (err u2605)) 27 | 28 | (define-data-var governanceTokenPrincipal principal .sde-governance-token) 29 | 30 | (define-map parameters (string-ascii 34) uint) 31 | 32 | (map-set parameters "proposeFactor" u100000) 33 | (map-set parameters "proposalDuration" u1440) ;; ~10 days based on a ~10 minute block time. 34 | (map-set parameters "minimumProposalStartDelay" u144) ;; ~1 day minimum delay before voting on a proposal can start. 35 | (map-set parameters "maximumProposalStartDelay" u1008) ;; ~7 days maximum delay before voting on a proposal can start. 36 | 37 | ;; --- Authorization check 38 | 39 | (define-public (is-dao-or-extension) 40 | (ok (asserts! (or (is-eq tx-sender .executor-dao) (contract-call? .executor-dao is-extension contract-caller)) ERR_UNAUTHORIZED)) 41 | ) 42 | 43 | ;; --- Internal DAO functions 44 | 45 | (define-public (set-governance-token (governanceToken )) 46 | (begin 47 | (try! (is-dao-or-extension)) 48 | (ok (var-set governanceTokenPrincipal (contract-of governanceToken))) 49 | ) 50 | ) 51 | 52 | (define-public (set-parameter (parameter (string-ascii 34)) (value uint)) 53 | (begin 54 | (try! (is-dao-or-extension)) 55 | (try! (get-parameter parameter)) 56 | (ok (map-set parameters parameter value)) 57 | ) 58 | ) 59 | 60 | (define-private (set-parameters-iter (item {parameter: (string-ascii 34), value: uint}) (previous (response bool uint))) 61 | (begin 62 | (try! previous) 63 | (try! (get-parameter (get parameter item))) 64 | (ok (map-set parameters (get parameter item) (get value item))) 65 | ) 66 | ) 67 | 68 | (define-public (set-parameters (parameter-list (list 200 {parameter: (string-ascii 34), value: uint}))) 69 | (begin 70 | (try! (is-dao-or-extension)) 71 | (fold set-parameters-iter parameter-list (ok true)) 72 | ) 73 | ) 74 | 75 | ;; --- Public functions 76 | 77 | (define-read-only (get-governance-token) 78 | (var-get governanceTokenPrincipal) 79 | ) 80 | 81 | (define-private (is-governance-token (governanceToken )) 82 | (ok (asserts! (is-eq (contract-of governanceToken) (var-get governanceTokenPrincipal)) ERR_NOT_GOVERNANCE_TOKEN)) 83 | ) 84 | 85 | (define-read-only (get-parameter (parameter (string-ascii 34))) 86 | (ok (unwrap! (map-get? parameters parameter) ERR_UNKNOWN_PARAMETER)) 87 | ) 88 | 89 | (define-public (propose (proposal ) (startBlockHeight uint) (governanceToken )) 90 | (begin 91 | (try! (is-governance-token governanceToken)) 92 | (asserts! (>= startBlockHeight (+ block-height (try! (get-parameter "minimumProposalStartDelay")))) ERR_PROPOSAL_MINIMUM_START_DELAY) 93 | (asserts! (<= startBlockHeight (+ block-height (try! (get-parameter "maximumProposalStartDelay")))) ERR_PROPOSAL_MAXIMUM_START_DELAY) 94 | (asserts! (try! (contract-call? governanceToken has-percentage-weight tx-sender (try! (get-parameter "proposeFactor")))) ERR_INSUFFICIENT_WEIGHT) 95 | (contract-call? .sde-proposal-voting-with-delegation add-proposal 96 | proposal 97 | { 98 | startBlockHeight: startBlockHeight, 99 | endBlockHeight: (+ startBlockHeight (try! (get-parameter "proposalDuration"))), 100 | proposer: tx-sender 101 | } 102 | ) 103 | ) 104 | ) 105 | 106 | ;; TODO: Should this have to go through a DAO vote? 107 | ;; TODO: Possibly only allow proposer to be able to cancel their own proposal if submitted by accident 108 | (define-public (cancel (proposal ) (governanceToken ) (reason (string-ascii 34))) 109 | (begin 110 | (try! (is-governance-token governanceToken)) 111 | (asserts! (try! (contract-call? governanceToken has-percentage-weight tx-sender (try! (get-parameter "proposeFactor")))) ERR_INSUFFICIENT_WEIGHT) 112 | (print { event: "cancel", proposal: proposal, reason: reason }) 113 | (contract-call? .sde-proposal-voting-with-delegation cancel-proposal proposal) 114 | ) 115 | ) 116 | 117 | ;; --- Extension callback 118 | 119 | (define-public (callback (sender principal) (memo (buff 34))) 120 | (ok true) 121 | ) 122 | -------------------------------------------------------------------------------- /contracts/extensions/proposal-submissions/sde-proposal-submission-with-lockup.clar: -------------------------------------------------------------------------------- 1 | ;; _____________ _______ _________ ___ ___ ____ ____ 2 | ;; / __/_ __/ _ |/ ___/ //_/ __/ _ \/ _ \/ _ |/ __ \/ __/ 3 | ;; _\ \ / / / __ / /__/ ,< / _// , _/ // / __ / /_/ /\ \ 4 | ;; /___/ /_/ /_/ |_\___/_/|_/___/_/|_/____/_/ |_\____/___/ 5 | ;; 6 | ;; _____ _____________ ______________ _ __ 7 | ;; / __/ |/_/_ __/ __/ |/ / __/ _/ __ \/ |/ / 8 | ;; / _/_> < / / / _// /\ \_/ // /_/ / / 9 | ;; /___/_/|_| /_/ /___/_/|_/___/___/\____/_/|_/ 10 | ;; 11 | 12 | ;; Title: SDE002 Proposal Submission 13 | ;; Author: Marvin Janssen / StackerDAO Dev Team 14 | ;; Depends-On: SDE001 15 | ;; Synopsis: 16 | ;; This extension part of the core of StackerDAO. It allows governance token 17 | ;; holders to submit proposals when they hold at least n% percentage of the 18 | ;; token supply. 19 | ;; Description: 20 | ;; Proposals may be submitted by anyone that holds at least n% of governance 21 | ;; tokens. Any submission is subject to a pre-defined start delay before voting 22 | ;; can begin, and will then run for a pre-defined duration. The percentage, 23 | ;; start delay, and proposal duration can all by changed by means of a future 24 | ;; proposal. 25 | 26 | (use-trait proposal-trait .proposal-trait.proposal-trait) 27 | (use-trait governance-token-trait .governance-token-trait.governance-token-trait) 28 | 29 | (impl-trait .extension-trait.extension-trait) 30 | 31 | (define-constant ERR_UNAUTHORIZED (err u2600)) 32 | (define-constant ERR_NOT_GOVERNANCE_TOKEN (err u2601)) 33 | (define-constant ERR_INSUFFICIENT_BALANCE (err u2602)) 34 | (define-constant ERR_UNKNOWN_PARAMETER (err u2603)) 35 | (define-constant ERR_PROPOSAL_MINIMUM_START_DELAY (err u2604)) 36 | (define-constant ERR_PROPOSAL_MAXIMUM_START_DELAY (err u2605)) 37 | 38 | (define-data-var governanceTokenPrincipal principal .sde-governance-token-with-lockup) 39 | 40 | (define-map parameters (string-ascii 34) uint) 41 | 42 | (map-set parameters "proposeFactor" u100000) ;; 1% initially required to propose (100/n*1000). 43 | (map-set parameters "proposalDuration" u1440) ;; ~10 days based on a ~10 minute block time. 44 | (map-set parameters "minimumProposalStartDelay" u144) ;; ~1 day minimum delay before voting on a proposal can start. 45 | (map-set parameters "maximumProposalStartDelay" u1008) ;; ~7 days maximum delay before voting on a proposal can start. 46 | 47 | ;; --- Authorization check 48 | 49 | (define-public (is-dao-or-extension) 50 | (ok (asserts! (or (is-eq tx-sender .executor-dao) (contract-call? .executor-dao is-extension contract-caller)) ERR_UNAUTHORIZED)) 51 | ) 52 | 53 | ;; --- Internal DAO functions 54 | 55 | (define-public (set-governance-token (governance-token )) 56 | (begin 57 | (try! (is-dao-or-extension)) 58 | (ok (var-set governanceTokenPrincipal (contract-of governance-token))) 59 | ) 60 | ) 61 | 62 | (define-public (set-parameter (parameter (string-ascii 34)) (value uint)) 63 | (begin 64 | (try! (is-dao-or-extension)) 65 | (try! (get-parameter parameter)) 66 | (ok (map-set parameters parameter value)) 67 | ) 68 | ) 69 | 70 | (define-private (set-parameters-iter (item {parameter: (string-ascii 34), value: uint}) (previous (response bool uint))) 71 | (begin 72 | (try! previous) 73 | (try! (get-parameter (get parameter item))) 74 | (ok (map-set parameters (get parameter item) (get value item))) 75 | ) 76 | ) 77 | 78 | (define-public (set-parameters (parameter-list (list 200 {parameter: (string-ascii 34), value: uint}))) 79 | (begin 80 | (try! (is-dao-or-extension)) 81 | (fold set-parameters-iter parameter-list (ok true)) 82 | ) 83 | ) 84 | 85 | ;; --- Public functions 86 | 87 | (define-read-only (get-governance-token) 88 | (var-get governanceTokenPrincipal) 89 | ) 90 | 91 | (define-private (is-governance-token (governance-token )) 92 | (ok (asserts! (is-eq (contract-of governance-token) (var-get governanceTokenPrincipal)) ERR_NOT_GOVERNANCE_TOKEN)) 93 | ) 94 | 95 | (define-read-only (get-parameter (parameter (string-ascii 34))) 96 | (ok (unwrap! (map-get? parameters parameter) ERR_UNKNOWN_PARAMETER)) 97 | ) 98 | 99 | (define-public (propose (proposal ) (startBlockHeight uint) (governance-token )) 100 | (begin 101 | (try! (is-governance-token governance-token)) 102 | (asserts! (>= startBlockHeight (+ block-height (try! (get-parameter "minimumProposalStartDelay")))) ERR_PROPOSAL_MINIMUM_START_DELAY) 103 | (asserts! (<= startBlockHeight (+ block-height (try! (get-parameter "maximumProposalStartDelay")))) ERR_PROPOSAL_MAXIMUM_START_DELAY) 104 | (asserts! (try! (contract-call? governance-token has-percentage-balance tx-sender (try! (get-parameter "proposeFactor")))) ERR_INSUFFICIENT_BALANCE) 105 | (contract-call? .sde-proposal-voting-with-lockup add-proposal 106 | proposal 107 | { 108 | startBlockHeight: startBlockHeight, 109 | endBlockHeight: (+ startBlockHeight (try! (get-parameter "proposalDuration"))), 110 | proposer: tx-sender 111 | } 112 | ) 113 | ) 114 | ) 115 | 116 | ;; --- Extension callback 117 | 118 | (define-public (callback (sender principal) (memo (buff 34))) 119 | (ok true) 120 | ) 121 | -------------------------------------------------------------------------------- /contracts/extensions/proposal-submissions/sde-proposal-submission-with-members.clar: -------------------------------------------------------------------------------- 1 | ;; _____________ _______ _________ ___ ___ ____ ____ 2 | ;; / __/_ __/ _ |/ ___/ //_/ __/ _ \/ _ \/ _ |/ __ \/ __/ 3 | ;; _\ \ / / / __ / /__/ ,< / _// , _/ // / __ / /_/ /\ \ 4 | ;; /___/ /_/ /_/ |_\___/_/|_/___/_/|_/____/_/ |_\____/___/ 5 | ;; 6 | ;; _____ _____________ ______________ _ __ 7 | ;; / __/ |/_/_ __/ __/ |/ / __/ _/ __ \/ |/ / 8 | ;; / _/_> < / / / _// /\ \_/ // /_/ / / 9 | ;; /___/_/|_| /_/ /___/_/|_/___/___/\____/_/|_/ 10 | ;; 11 | 12 | ;; Title: SDE008 Proposal Submission 13 | ;; Author: StackerDAO Dev Team 14 | ;; Depends-On: SDE007 15 | ;; Synopsis: 16 | ;; This extension part of the core of StackerDAO. It allows governance token 17 | ;; holders to submit proposals when they hold at least n% percentage of the 18 | ;; token supply. 19 | ;; Description: 20 | ;; Proposals may be submitted by anyone that holds at least n% of governance 21 | ;; tokens. Any submission is subject to a pre-defined start delay before voting 22 | ;; can begin, and will then run for a pre-defined duration. The percentage, 23 | ;; start delay, and proposal duration can all by changed by means of a future 24 | ;; proposal. 25 | 26 | (use-trait proposal-trait .proposal-trait.proposal-trait) 27 | (use-trait member-trait .member-trait.member-trait) 28 | 29 | (impl-trait .extension-trait.extension-trait) 30 | 31 | (define-constant ERR_UNAUTHORIZED (err u3100)) 32 | (define-constant ERR_NOT_A_MEMBER (err u3101)) 33 | (define-constant ERR_NOT_MEMBER_CONTRACT (err u3102)) 34 | (define-constant ERR_UNKNOWN_PARAMETER (err u3103)) 35 | (define-constant ERR_PROPOSAL_MINIMUM_START_DELAY (err u3104)) 36 | (define-constant ERR_PROPOSAL_MAXIMUM_START_DELAY (err u3105)) 37 | 38 | (define-data-var memberContractPrincipal principal .sde-membership) 39 | 40 | (define-map Parameters (string-ascii 34) uint) 41 | 42 | (map-set Parameters "proposalDuration" u1440) ;; ~10 days based on a ~10 minute block time. 43 | (map-set Parameters "minimumProposalStartDelay" u144) ;; ~1 day minimum delay before voting on a proposal can start. 44 | (map-set Parameters "maximumProposalStartDelay" u1008) ;; ~7 days maximum delay before voting on a proposal can start. 45 | 46 | ;; --- Authorization check 47 | 48 | (define-public (is-dao-or-extension) 49 | (ok (asserts! (or (is-eq tx-sender .executor-dao) (contract-call? .executor-dao is-extension contract-caller)) ERR_UNAUTHORIZED)) 50 | ) 51 | 52 | ;; --- Internal DAO functions 53 | 54 | (define-public (set-member-contract (memberContract )) 55 | (begin 56 | (try! (is-dao-or-extension)) 57 | (ok (var-set memberContractPrincipal (contract-of memberContract))) 58 | ) 59 | ) 60 | 61 | (define-public (set-parameter (parameter (string-ascii 34)) (value uint)) 62 | (begin 63 | (try! (is-dao-or-extension)) 64 | (try! (get-parameter parameter)) 65 | (ok (map-set Parameters parameter value)) 66 | ) 67 | ) 68 | 69 | (define-private (set-parameters-iter (item {parameter: (string-ascii 34), value: uint}) (previous (response bool uint))) 70 | (begin 71 | (try! previous) 72 | (try! (get-parameter (get parameter item))) 73 | (ok (map-set Parameters (get parameter item) (get value item))) 74 | ) 75 | ) 76 | 77 | (define-public (set-parameters (parameter-list (list 200 {parameter: (string-ascii 34), value: uint}))) 78 | (begin 79 | (try! (is-dao-or-extension)) 80 | (fold set-parameters-iter parameter-list (ok true)) 81 | ) 82 | ) 83 | 84 | ;; --- Public functions 85 | 86 | (define-read-only (get-member-contract) 87 | (var-get memberContractPrincipal) 88 | ) 89 | 90 | (define-private (is-member-contract (memberContract )) 91 | (ok (asserts! (is-eq (contract-of memberContract) (get-member-contract)) ERR_NOT_MEMBER_CONTRACT)) 92 | ) 93 | 94 | (define-read-only (get-parameter (parameter (string-ascii 34))) 95 | (ok (unwrap! (map-get? Parameters parameter) ERR_UNKNOWN_PARAMETER)) 96 | ) 97 | 98 | (define-public (propose (proposal ) (startBlockHeight uint) (memberContract )) 99 | (begin 100 | (try! (is-member-contract memberContract)) 101 | (asserts! (is-eq true (unwrap-panic (contract-call? memberContract is-member contract-caller))) ERR_NOT_A_MEMBER) 102 | (asserts! (>= startBlockHeight (+ block-height (try! (get-parameter "minimumProposalStartDelay")))) ERR_PROPOSAL_MINIMUM_START_DELAY) 103 | (asserts! (<= startBlockHeight (+ block-height (try! (get-parameter "maximumProposalStartDelay")))) ERR_PROPOSAL_MAXIMUM_START_DELAY) 104 | (contract-call? .sde-proposal-voting-with-members add-proposal 105 | proposal 106 | { 107 | startBlockHeight: startBlockHeight, 108 | endBlockHeight: (+ startBlockHeight (try! (get-parameter "proposalDuration"))), 109 | proposer: tx-sender 110 | } 111 | ) 112 | ) 113 | ) 114 | 115 | ;; --- Extension callback 116 | 117 | (define-public (callback (sender principal) (memo (buff 34))) 118 | (ok true) 119 | ) 120 | -------------------------------------------------------------------------------- /contracts/extensions/proposal-submissions/sde-proposal-submission-with-nft.clar: -------------------------------------------------------------------------------- 1 | ;; _____________ _______ _________ ___ ___ ____ ____ 2 | ;; / __/_ __/ _ |/ ___/ //_/ __/ _ \/ _ \/ _ |/ __ \/ __/ 3 | ;; _\ \ / / / __ / /__/ ,< / _// , _/ // / __ / /_/ /\ \ 4 | ;; /___/ /_/ /_/ |_\___/_/|_/___/_/|_/____/_/ |_\____/___/ 5 | ;; 6 | ;; _____ _____________ ______________ _ __ 7 | ;; / __/ |/_/_ __/ __/ |/ / __/ _/ __ \/ |/ / 8 | ;; / _/_> < / / / _// /\ \_/ // /_/ / / 9 | ;; /___/_/|_| /_/ /___/_/|_/___/___/\____/_/|_/ 10 | ;; 11 | 12 | ;; Title: SDE012 Proposal Submission 13 | ;; Author: StackerDAO Dev Team 14 | ;; Depends-On: SDE0011 15 | ;; Synopsis: 16 | ;; This extension part of the core of StackerDAO. It allows NFT 17 | ;; holders to submit proposals when they hold at least 1 NFT. 18 | ;; Description: 19 | ;; Proposals may be submitted by anyone that holds at least 1 20 | ;; token. Any submission is subject to a pre-defined start delay before voting 21 | ;; can begin, and will then run for a pre-defined duration. The percentage, 22 | ;; start delay, and proposal duration can all by changed by means of a future 23 | ;; proposal. 24 | 25 | (use-trait proposal-trait .proposal-trait.proposal-trait) 26 | (use-trait sip009-nft-trait .sip009-nft-trait.sip009-nft-trait) 27 | 28 | (impl-trait .extension-trait.extension-trait) 29 | 30 | (define-constant ERR_UNAUTHORIZED (err u3500)) 31 | (define-constant ERR_NOT_NFT_OWNER (err u3501)) 32 | (define-constant ERR_UNKNOWN_PARAMETER (err u3502)) 33 | (define-constant ERR_PROPOSAL_MINIMUM_START_DELAY (err u3503)) 34 | (define-constant ERR_PROPOSAL_MAXIMUM_START_DELAY (err u3504)) 35 | 36 | (define-data-var nftContract principal .nft-membership) 37 | 38 | (define-map parameters (string-ascii 34) uint) 39 | 40 | (map-set parameters "proposeFactor" u100000) ;; 1% initially required to propose (100/n*1000). 41 | (map-set parameters "proposalDuration" u1440) ;; ~10 days based on a ~10 minute block time. 42 | (map-set parameters "minimumProposalStartDelay" u144) ;; ~1 day minimum delay before voting on a proposal can start. 43 | (map-set parameters "maximumProposalStartDelay" u1008) ;; ~7 days maximum delay before voting on a proposal can start. 44 | 45 | ;; --- Authorization check 46 | 47 | (define-public (is-dao-or-extension) 48 | (ok (asserts! (or (is-eq tx-sender .executor-dao) (contract-call? .executor-dao is-extension contract-caller)) ERR_UNAUTHORIZED)) 49 | ) 50 | 51 | ;; --- Internal DAO functions 52 | 53 | (define-public (set-parameter (parameter (string-ascii 34)) (value uint)) 54 | (begin 55 | (try! (is-dao-or-extension)) 56 | (try! (get-parameter parameter)) 57 | (ok (map-set parameters parameter value)) 58 | ) 59 | ) 60 | 61 | (define-private (set-parameters-iter (item {parameter: (string-ascii 34), value: uint}) (previous (response bool uint))) 62 | (begin 63 | (try! previous) 64 | (try! (get-parameter (get parameter item))) 65 | (ok (map-set parameters (get parameter item) (get value item))) 66 | ) 67 | ) 68 | 69 | (define-public (set-parameters (parameter-list (list 200 {parameter: (string-ascii 34), value: uint}))) 70 | (begin 71 | (try! (is-dao-or-extension)) 72 | (fold set-parameters-iter parameter-list (ok true)) 73 | ) 74 | ) 75 | 76 | ;; --- Public functions 77 | 78 | ;; Parameters 79 | 80 | (define-read-only (get-parameter (parameter (string-ascii 34))) 81 | (ok (unwrap! (map-get? parameters parameter) ERR_UNKNOWN_PARAMETER)) 82 | ) 83 | 84 | (define-read-only (get-nft-contract) 85 | (var-get nftContract) 86 | ) 87 | 88 | ;; Proposals 89 | 90 | (define-public (propose (proposal ) (tokenId uint) (startBlockHeight uint)) 91 | (begin 92 | (asserts! (is-eq contract-caller (unwrap! (unwrap-panic (contract-call? .nft-membership get-owner tokenId)) ERR_NOT_NFT_OWNER)) ERR_UNAUTHORIZED) 93 | (asserts! (>= startBlockHeight (+ block-height (try! (get-parameter "minimumProposalStartDelay")))) ERR_PROPOSAL_MINIMUM_START_DELAY) 94 | (asserts! (<= startBlockHeight (+ block-height (try! (get-parameter "maximumProposalStartDelay")))) ERR_PROPOSAL_MAXIMUM_START_DELAY) 95 | (contract-call? .sde-proposal-voting-with-nft add-proposal 96 | proposal 97 | { 98 | startBlockHeight: startBlockHeight, 99 | endBlockHeight: (+ startBlockHeight (try! (get-parameter "proposalDuration"))), 100 | proposer: tx-sender 101 | } 102 | ) 103 | ) 104 | ) 105 | 106 | ;; --- Extension callback 107 | 108 | (define-public (callback (sender principal) (memo (buff 34))) 109 | (ok true) 110 | ) 111 | -------------------------------------------------------------------------------- /contracts/extensions/proposal-submissions/sde-proposal-submission.clar: -------------------------------------------------------------------------------- 1 | ;; _____________ _______ _________ ___ ___ ____ ____ 2 | ;; / __/_ __/ _ |/ ___/ //_/ __/ _ \/ _ \/ _ |/ __ \/ __/ 3 | ;; _\ \ / / / __ / /__/ ,< / _// , _/ // / __ / /_/ /\ \ 4 | ;; /___/ /_/ /_/ |_\___/_/|_/___/_/|_/____/_/ |_\____/___/ 5 | ;; 6 | ;; _____ _____________ ______________ _ __ 7 | ;; / __/ |/_/_ __/ __/ |/ / __/ _/ __ \/ |/ / 8 | ;; / _/_> < / / / _// /\ \_/ // /_/ / / 9 | ;; /___/_/|_| /_/ /___/_/|_/___/___/\____/_/|_/ 10 | 11 | 12 | (use-trait proposal-trait .proposal-trait.proposal-trait) 13 | (use-trait sip010-ft-trait .sip010-ft-trait.sip010-ft-trait) 14 | 15 | (impl-trait .extension-trait.extension-trait) 16 | 17 | (define-constant ERR_UNAUTHORIZED (err u2600)) 18 | (define-constant ERR_NOT_GOVERNANCE_TOKEN (err u2601)) 19 | (define-constant ERR_INSUFFICIENT_WEIGHT (err u2602)) 20 | (define-constant ERR_UNKNOWN_PARAMETER (err u2603)) 21 | (define-constant ERR_PROPOSAL_MINIMUM_START_DELAY (err u2604)) 22 | (define-constant ERR_PROPOSAL_MAXIMUM_START_DELAY (err u2605)) 23 | 24 | (define-constant MICRO (pow u10 u2)) 25 | 26 | (define-data-var governanceTokenPrincipal principal .sde-stackerdao-token) 27 | 28 | (define-map parameters (string-ascii 34) uint) 29 | 30 | (map-set parameters "proposeThreshold" u150) ;; Tokens required to submit a proposal 31 | (map-set parameters "proposalDuration" u720) ;; ~5 days based on a ~10 minute block time. 32 | (map-set parameters "minimumProposalStartDelay" u144) ;; ~1 day minimum delay before voting on a proposal can start. 33 | (map-set parameters "maximumProposalStartDelay" u1008) ;; ~7 days maximum delay before voting on a proposal can start. 34 | 35 | ;; --- Authorization check 36 | 37 | (define-public (is-dao-or-extension) 38 | (ok (asserts! (or (is-eq tx-sender .executor-dao) (contract-call? .executor-dao is-extension contract-caller)) ERR_UNAUTHORIZED)) 39 | ) 40 | 41 | ;; --- Internal DAO functions 42 | 43 | (define-public (set-parameter (parameter (string-ascii 34)) (value uint)) 44 | (begin 45 | (try! (is-dao-or-extension)) 46 | (try! (get-parameter parameter)) 47 | (ok (map-set parameters parameter value)) 48 | ) 49 | ) 50 | 51 | (define-private (set-parameters-iter (item {parameter: (string-ascii 34), value: uint}) (previous (response bool uint))) 52 | (begin 53 | (try! previous) 54 | (try! (get-parameter (get parameter item))) 55 | (ok (map-set parameters (get parameter item) (get value item))) 56 | ) 57 | ) 58 | 59 | (define-public (set-parameters (parameter-list (list 200 {parameter: (string-ascii 34), value: uint}))) 60 | (begin 61 | (try! (is-dao-or-extension)) 62 | (fold set-parameters-iter parameter-list (ok true)) 63 | ) 64 | ) 65 | 66 | (define-read-only (get-governance-token) 67 | (var-get governanceTokenPrincipal) 68 | ) 69 | 70 | (define-private (is-governance-token (governanceToken )) 71 | (ok (asserts! (is-eq (contract-of governanceToken) (var-get governanceTokenPrincipal)) ERR_NOT_GOVERNANCE_TOKEN)) 72 | ) 73 | 74 | (define-read-only (get-parameter (parameter (string-ascii 34))) 75 | (ok (unwrap! (map-get? parameters parameter) ERR_UNKNOWN_PARAMETER)) 76 | ) 77 | 78 | (define-public (can-propose (who principal) (tokenThreshold uint) (governanceToken )) 79 | (let 80 | ( 81 | (balance (unwrap-panic (contract-call? governanceToken get-balance tx-sender))) 82 | ) 83 | (ok (>= balance (* MICRO tokenThreshold))) 84 | ) 85 | ) 86 | 87 | (define-public (propose (proposal ) (startBlockHeight uint) (governanceToken )) 88 | (begin 89 | (try! (is-governance-token governanceToken)) 90 | (asserts! (>= startBlockHeight (+ block-height (try! (get-parameter "minimumProposalStartDelay")))) ERR_PROPOSAL_MINIMUM_START_DELAY) 91 | (asserts! (<= startBlockHeight (+ block-height (try! (get-parameter "maximumProposalStartDelay")))) ERR_PROPOSAL_MAXIMUM_START_DELAY) 92 | (asserts! (unwrap-panic (can-propose tx-sender (try! (get-parameter "proposeThreshold")) governanceToken)) ERR_INSUFFICIENT_WEIGHT) 93 | (contract-call? .sde-proposal-voting-with-external-lockup add-proposal 94 | proposal 95 | { 96 | startBlockHeight: startBlockHeight, 97 | endBlockHeight: (+ startBlockHeight (try! (get-parameter "proposalDuration"))), 98 | proposer: tx-sender 99 | } 100 | ) 101 | ) 102 | ) 103 | 104 | ;; --- Extension callback 105 | 106 | (define-public (callback (sender principal) (memo (buff 34))) 107 | (ok true) 108 | ) 109 | -------------------------------------------------------------------------------- /contracts/extensions/vaults/sde-vault.clar: -------------------------------------------------------------------------------- 1 | ;; _____________ _______ _________ ___ ___ ____ ____ 2 | ;; / __/_ __/ _ |/ ___/ //_/ __/ _ \/ _ \/ _ |/ __ \/ __/ 3 | ;; _\ \ / / / __ / /__/ ,< / _// , _/ // / __ / /_/ /\ \ 4 | ;; /___/ /_/ /_/ |_\___/_/|_/___/_/|_/____/_/ |_\____/___/ 5 | ;; 6 | ;; _____ _____________ ______________ _ __ 7 | ;; / __/ |/_/_ __/ __/ |/ / __/ _/ __ \/ |/ / 8 | ;; / _/_> < / / / _// /\ \_/ // /_/ / / 9 | ;; /___/_/|_| /_/ /___/_/|_/___/___/\____/_/|_/ 10 | 11 | (use-trait nft-trait .sip009-nft-trait.sip009-nft-trait) 12 | (use-trait ft-trait .sip010-ft-trait.sip010-ft-trait) 13 | 14 | (impl-trait .extension-trait.extension-trait) 15 | 16 | (define-constant ERR_UNAUTHORIZED (err u3200)) 17 | (define-constant ERR_ASSET_NOT_WHITELISTED (err u3201)) 18 | (define-constant ERR_FAILED_TO_TRANSFER_STX (err u3202)) 19 | (define-constant ERR_FAILED_TO_TRANSFER_FT (err u3203)) 20 | (define-constant ERR_FAILED_TO_TRANSFER_NFT (err u3204)) 21 | 22 | (define-constant CONTRACT_ADDRESS (as-contract tx-sender)) 23 | 24 | (define-map WhitelistedAssets principal bool) 25 | 26 | ;; --- Authorization check 27 | 28 | (define-public (is-dao-or-extension) 29 | (ok (asserts! (or (is-eq tx-sender .executor-dao) (contract-call? .executor-dao is-extension contract-caller)) ERR_UNAUTHORIZED)) 30 | ) 31 | 32 | ;; --- Internal DAO functions 33 | 34 | (define-public (set-whitelist (token principal) (enabled bool)) 35 | (begin 36 | (try! (is-dao-or-extension)) 37 | (ok (map-set WhitelistedAssets token enabled)) 38 | ) 39 | ) 40 | 41 | (define-private (set-whitelist-iter (item {token: principal, enabled: bool})) 42 | (begin 43 | (print {event: "whitelist", token: (get token item), enabled: (get enabled item)}) 44 | (map-set WhitelistedAssets (get token item) (get enabled item)) 45 | ) 46 | ) 47 | 48 | (define-public (set-whitelists (whitelist (list 100 {token: principal, enabled: bool}))) 49 | (begin 50 | (try! (is-dao-or-extension)) 51 | (ok (map set-whitelist-iter whitelist)) 52 | ) 53 | ) 54 | 55 | ;; --- Public functions 56 | 57 | (define-public (deposit (amount uint)) 58 | (begin 59 | (unwrap! (stx-transfer? amount tx-sender CONTRACT_ADDRESS) ERR_FAILED_TO_TRANSFER_STX) 60 | (print {event: "deposit", amount: amount, caller: tx-sender}) 61 | (ok true) 62 | ) 63 | ) 64 | 65 | (define-public (deposit-ft (ft ) (amount uint)) 66 | (begin 67 | (asserts! (is-whitelisted (contract-of ft)) ERR_ASSET_NOT_WHITELISTED) 68 | (unwrap! (contract-call? ft transfer amount tx-sender CONTRACT_ADDRESS (some 0x11)) ERR_FAILED_TO_TRANSFER_FT) 69 | (print {event: "deposit-ft", amount: amount, assetContract: (contract-of ft), caller: tx-sender}) 70 | (ok true) 71 | ) 72 | ) 73 | 74 | (define-public (deposit-nft (nft ) (id uint)) 75 | (begin 76 | (asserts! (is-whitelisted (contract-of nft)) ERR_ASSET_NOT_WHITELISTED) 77 | (unwrap! (contract-call? nft transfer id tx-sender CONTRACT_ADDRESS) ERR_FAILED_TO_TRANSFER_NFT) 78 | (print {event: "deposit-nft", assetContract: (contract-of nft), tokenId: id, caller: tx-sender}) 79 | (ok true) 80 | ) 81 | ) 82 | 83 | (define-public (transfer (amount uint) (recipient principal)) 84 | (begin 85 | (try! (is-dao-or-extension)) 86 | (unwrap! (as-contract (stx-transfer? amount CONTRACT_ADDRESS recipient)) ERR_FAILED_TO_TRANSFER_STX) 87 | (print {event: "transfer", amount: amount, caller: tx-sender, recipient: recipient}) 88 | (ok true) 89 | ) 90 | ) 91 | 92 | (define-public (transfer-ft (ft ) (amount uint) (recipient principal)) 93 | (begin 94 | (try! (is-dao-or-extension)) 95 | (asserts! (is-whitelisted (contract-of ft)) ERR_ASSET_NOT_WHITELISTED) 96 | (unwrap! (as-contract (contract-call? ft transfer amount CONTRACT_ADDRESS recipient (some 0x11))) ERR_FAILED_TO_TRANSFER_FT) 97 | (print {event: "transfer-ft", assetContract: (contract-of ft), caller: tx-sender, recipient: recipient}) 98 | (ok true) 99 | ) 100 | ) 101 | 102 | (define-public (transfer-nft (nft ) (id uint) (recipient principal)) 103 | (begin 104 | (try! (is-dao-or-extension)) 105 | (asserts! (is-whitelisted (contract-of nft)) ERR_ASSET_NOT_WHITELISTED) 106 | (unwrap! (as-contract (contract-call? nft transfer id CONTRACT_ADDRESS recipient)) ERR_FAILED_TO_TRANSFER_NFT) 107 | (print {event: "transfer-nft", assetContract: (contract-of nft), tokenId: id, caller: tx-sender, recipient: recipient}) 108 | (ok true) 109 | ) 110 | ) 111 | 112 | ;; --- Read only functions 113 | 114 | (define-read-only (is-whitelisted (assetContract principal)) 115 | (default-to false (get-whitelisted-asset assetContract)) 116 | ) 117 | 118 | (define-read-only (get-whitelisted-asset (assetContract principal)) 119 | (map-get? WhitelistedAssets assetContract) 120 | ) 121 | 122 | (define-read-only (get-balance) 123 | (stx-get-balance CONTRACT_ADDRESS) 124 | ) 125 | 126 | (define-public (get-balance-of (assetContract )) 127 | (contract-call? assetContract get-balance CONTRACT_ADDRESS) 128 | ) 129 | 130 | ;; --- Extension callback 131 | 132 | (define-public (callback (sender principal) (memo (buff 34))) 133 | (ok true) 134 | ) 135 | -------------------------------------------------------------------------------- /contracts/extensions/voting/sde-proposal-voting-with-external-lockup.clar: -------------------------------------------------------------------------------- 1 | ;; _____________ _______ _________ ___ ___ ____ ____ 2 | ;; / __/_ __/ _ |/ ___/ //_/ __/ _ \/ _ \/ _ |/ __ \/ __/ 3 | ;; _\ \ / / / __ / /__/ ,< / _// , _/ // / __ / /_/ /\ \ 4 | ;; /___/ /_/ /_/ |_\___/_/|_/___/_/|_/____/_/ |_\____/___/ 5 | ;; 6 | ;; _____ _____________ ______________ _ __ 7 | ;; / __/ |/_/_ __/ __/ |/ / __/ _/ __ \/ |/ / 8 | ;; / _/_> < / / / _// /\ \_/ // /_/ / / 9 | ;; /___/_/|_| /_/ /___/_/|_/___/___/\____/_/|_/ 10 | ;; 11 | 12 | (use-trait proposal-trait .proposal-trait.proposal-trait) 13 | (use-trait sip010-ft-trait .sip010-ft-trait.sip010-ft-trait) 14 | 15 | (impl-trait .extension-trait.extension-trait) 16 | 17 | (define-constant ERR_UNAUTHORIZED (err u2500)) 18 | (define-constant ERR_NOT_GOVERNANCE_TOKEN (err u2501)) 19 | (define-constant ERR_PROPOSAL_ALREADY_EXECUTED (err u2502)) 20 | (define-constant ERR_PROPOSAL_ALREADY_EXISTS (err u2503)) 21 | (define-constant ERR_UNKNOWN_PROPOSAL (err u2504)) 22 | (define-constant ERR_PROPOSAL_ALREADY_STARTED (err u2505)) 23 | (define-constant ERR_PROPOSAL_ALREADY_CONCLUDED (err u2506)) 24 | (define-constant ERR_PROPOSAL_INACTIVE (err u2507)) 25 | (define-constant ERR_PROPOSAL_NOT_CONCLUDED (err u2508)) 26 | (define-constant ERR_INSUFFICIENT_AMOUNT (err u2509)) 27 | (define-constant ERR_NO_VOTES_TO_RETURN (err u2510)) 28 | (define-constant ERR_END_BLOCK_HEIGHT_NOT_REACHED (err u2511)) 29 | (define-constant ERR_UNKNOWN_PARAMETER (err u2512)) 30 | 31 | (define-constant MICRO (pow u10 u2)) 32 | 33 | (define-data-var governanceTokenPrincipal principal .sde-stackerdao-token) 34 | 35 | (define-map Proposals 36 | principal 37 | { 38 | votesFor: uint, 39 | votesAgainst: uint, 40 | startBlockHeight: uint, 41 | endBlockHeight: uint, 42 | concluded: bool, 43 | passed: bool, 44 | proposer: principal 45 | } 46 | ) 47 | 48 | (define-map MemberTotalVotes {proposal: principal, voter: principal, governanceToken: principal} uint) 49 | 50 | (define-map parameters (string-ascii 34) uint) 51 | (map-set parameters "voteThreshold" u1) ;; Tokens required to vote 52 | (map-set parameters "quorumThreshold" u12500) ;; 5% of 250k initially distributed to Megapoont holders required for quorum 53 | (map-set parameters "executionDelay" u144) ;; Delay execution of proposal by ~ 1 day 54 | 55 | (define-public (is-dao-or-extension) 56 | (ok (asserts! (or (is-eq tx-sender .executor-dao) (contract-call? .executor-dao is-extension contract-caller)) ERR_UNAUTHORIZED)) 57 | ) 58 | 59 | (define-public (add-proposal (proposal ) (data {startBlockHeight: uint, endBlockHeight: uint, proposer: principal})) 60 | (begin 61 | (try! (is-dao-or-extension)) 62 | (asserts! (is-none (contract-call? .executor-dao executed-at proposal)) ERR_PROPOSAL_ALREADY_EXECUTED) 63 | (print {event: "propose", proposal: proposal, proposer: tx-sender}) 64 | (ok (asserts! (map-insert Proposals (contract-of proposal) (merge {votesFor: u0, votesAgainst: u0, concluded: false, passed: false} data)) ERR_PROPOSAL_ALREADY_EXISTS)) 65 | ) 66 | ) 67 | 68 | (define-public (set-parameter (parameter (string-ascii 34)) (value uint)) 69 | (begin 70 | (try! (is-dao-or-extension)) 71 | (try! (get-parameter parameter)) 72 | (ok (map-set parameters parameter value)) 73 | ) 74 | ) 75 | 76 | (define-public (cancel-proposal (proposal )) 77 | (begin 78 | (asserts! (is-none (contract-call? .executor-dao executed-at proposal)) ERR_PROPOSAL_ALREADY_EXECUTED) 79 | (asserts! (is-eq tx-sender (get proposer (unwrap-panic (get-proposal-data (contract-of proposal))))) ERR_UNAUTHORIZED) 80 | (asserts! (< block-height (get startBlockHeight (unwrap-panic (get-proposal-data (contract-of proposal))))) ERR_PROPOSAL_ALREADY_STARTED) 81 | (print {event: "cancel", proposal: proposal, proposer: tx-sender}) 82 | (ok (asserts! (map-delete Proposals (contract-of proposal)) ERR_UNKNOWN_PROPOSAL)) 83 | ) 84 | ) 85 | 86 | ;; --- Public functions 87 | 88 | (define-read-only (get-governance-token) 89 | (var-get governanceTokenPrincipal) 90 | ) 91 | 92 | (define-read-only (get-parameter (parameter (string-ascii 34))) 93 | (ok (unwrap! (map-get? parameters parameter) ERR_UNKNOWN_PARAMETER)) 94 | ) 95 | 96 | (define-read-only (get-proposal-data (proposal principal)) 97 | (map-get? Proposals proposal) 98 | ) 99 | 100 | (define-read-only (get-current-total-votes (proposal principal) (voter principal) (governanceToken principal)) 101 | (default-to u0 (map-get? MemberTotalVotes {proposal: proposal, voter: voter, governanceToken: governanceToken})) 102 | ) 103 | 104 | (define-public (vote (amount uint) (for bool) (proposal principal)) 105 | (let 106 | ( 107 | (proposalData (unwrap! (map-get? Proposals proposal) ERR_UNKNOWN_PROPOSAL)) 108 | ) 109 | (asserts! (>= amount (try! (get-parameter "voteThreshold"))) ERR_INSUFFICIENT_AMOUNT) 110 | (asserts! (>= block-height (get startBlockHeight proposalData)) ERR_PROPOSAL_INACTIVE) 111 | (asserts! (< block-height (get endBlockHeight proposalData)) ERR_PROPOSAL_INACTIVE) 112 | (map-set MemberTotalVotes {proposal: proposal, voter: tx-sender, governanceToken: (get-governance-token)} 113 | (+ (get-current-total-votes proposal tx-sender (get-governance-token)) amount) 114 | ) 115 | (map-set Proposals proposal 116 | (if for 117 | (merge proposalData {votesFor: (+ (get votesFor proposalData) amount)}) 118 | (merge proposalData {votesAgainst: (+ (get votesAgainst proposalData) amount)}) 119 | ) 120 | ) 121 | (print {event: "vote", proposal: proposal, voter: tx-sender, for: for, amount: amount}) 122 | (contract-call? .sde-token-lockup lock amount proposal tx-sender) 123 | ) 124 | ) 125 | 126 | (define-public (conclude (proposal )) 127 | (let 128 | ( 129 | (proposalData (unwrap! (map-get? Proposals (contract-of proposal)) ERR_UNKNOWN_PROPOSAL)) 130 | (passed (> (get votesFor proposalData) (get votesAgainst proposalData))) 131 | ) 132 | (asserts! (not (get concluded proposalData)) ERR_PROPOSAL_ALREADY_CONCLUDED) 133 | (asserts! (>= block-height (get endBlockHeight proposalData)) ERR_END_BLOCK_HEIGHT_NOT_REACHED) 134 | (map-set Proposals (contract-of proposal) (merge proposalData {concluded: true, passed: passed})) 135 | (print {event: "conclude", proposal: proposal, passed: passed}) 136 | (and passed (try! (contract-call? .executor-dao execute proposal tx-sender))) 137 | (ok passed) 138 | ) 139 | ) 140 | 141 | (define-public (reclaim-votes (proposal )) 142 | (let 143 | ( 144 | (proposalPrincipal (contract-of proposal)) 145 | (proposalData (unwrap! (map-get? Proposals proposalPrincipal) ERR_UNKNOWN_PROPOSAL)) 146 | (votes (unwrap! (map-get? MemberTotalVotes {proposal: proposalPrincipal, voter: tx-sender, governanceToken: (get-governance-token)}) ERR_NO_VOTES_TO_RETURN)) 147 | ) 148 | (asserts! (get concluded proposalData) ERR_PROPOSAL_NOT_CONCLUDED) 149 | (map-delete MemberTotalVotes {proposal: proposalPrincipal, voter: tx-sender, governanceToken: (get-governance-token)}) 150 | (contract-call? .sde-token-lockup unlock votes proposalPrincipal tx-sender) 151 | ) 152 | ) 153 | 154 | (define-public (reclaim-and-vote (amount uint) (for bool) (proposal principal) (reclaim-from )) 155 | (begin 156 | (try! (reclaim-votes reclaim-from)) 157 | (vote amount for proposal) 158 | ) 159 | ) 160 | 161 | ;; --- Extension callback 162 | 163 | (define-public (callback (sender principal) (memo (buff 34))) 164 | (ok true) 165 | ) 166 | -------------------------------------------------------------------------------- /contracts/extensions/voting/sde-proposal-voting-with-lockup.clar: -------------------------------------------------------------------------------- 1 | ;; _____________ _______ _________ ___ ___ ____ ____ 2 | ;; / __/_ __/ _ |/ ___/ //_/ __/ _ \/ _ \/ _ |/ __ \/ __/ 3 | ;; _\ \ / / / __ / /__/ ,< / _// , _/ // / __ / /_/ /\ \ 4 | ;; /___/ /_/ /_/ |_\___/_/|_/___/_/|_/____/_/ |_\____/___/ 5 | ;; 6 | ;; _____ _____________ ______________ _ __ 7 | ;; / __/ |/_/_ __/ __/ |/ / __/ _/ __ \/ |/ / 8 | ;; / _/_> < / / / _// /\ \_/ // /_/ / / 9 | ;; /___/_/|_| /_/ /___/_/|_/___/___/\____/_/|_/ 10 | ;; 11 | 12 | ;; Title: SDE001 Proposal Voting 13 | ;; Author: Marvin Janssen / StackerDAO Dev Team 14 | ;; Depends-On: SDE000 15 | ;; Synopsis: 16 | ;; This extension is part of the core of StackerDAO. It allows governance token 17 | ;; holders to vote on and conclude proposals. 18 | ;; Description: 19 | ;; Once proposals are submitted, they are open for voting after a lead up time 20 | ;; passes. Any token holder may vote on an open proposal, where one token equals 21 | ;; one vote. Members can vote until the voting period is over. After this period 22 | ;; anyone may trigger a conclusion. The proposal will then be executed if the 23 | ;; votes in favour exceed the ones against. 24 | 25 | (use-trait proposal-trait .proposal-trait.proposal-trait) 26 | (use-trait governance-token-trait .governance-token-trait.governance-token-trait) 27 | 28 | (impl-trait .extension-trait.extension-trait) 29 | 30 | (define-constant ERR_UNAUTHORIZED (err u2500)) 31 | (define-constant ERR_NOT_GOVERNANCE_TOKEN (err u2501)) 32 | (define-constant ERR_PROPOSAL_ALREADY_EXECUTED (err u2502)) 33 | (define-constant ERR_PROPOSAL_ALREADY_EXISTS (err u2503)) 34 | (define-constant ERR_UNKNOWN_PROPOSAL (err u2504)) 35 | (define-constant ERR_PROPOSAL_ALREADY_STARTED (err u2505)) 36 | (define-constant ERR_PROPOSAL_ALREADY_CONCLUDED (err u2506)) 37 | (define-constant ERR_PROPOSAL_INACTIVE (err u2507)) 38 | (define-constant ERR_PROPOSAL_NOT_CONCLUDED (err u2508)) 39 | (define-constant ERR_NO_VOTES_TO_RETURN (err u2509)) 40 | (define-constant ERR_END_BLOCK_HEIGHT_NOT_REACHED (err u2510)) 41 | (define-constant ERR_DISABLED (err u2511)) 42 | 43 | (define-data-var governanceTokenPrincipal principal .sde-governance-token-with-lockup) 44 | 45 | (define-map Proposals 46 | principal 47 | { 48 | votesFor: uint, 49 | votesAgainst: uint, 50 | startBlockHeight: uint, 51 | endBlockHeight: uint, 52 | concluded: bool, 53 | passed: bool, 54 | proposer: principal 55 | } 56 | ) 57 | 58 | (define-map MemberTotalVotes {proposal: principal, voter: principal, governanceToken: principal} uint) 59 | 60 | ;; --- Authorization check 61 | 62 | (define-public (is-dao-or-extension) 63 | (ok (asserts! (or (is-eq tx-sender .executor-dao) (contract-call? .executor-dao is-extension contract-caller)) ERR_UNAUTHORIZED)) 64 | ) 65 | 66 | ;; --- Internal DAO functions 67 | 68 | (define-public (set-governance-token (governanceToken )) 69 | (begin 70 | (try! (is-dao-or-extension)) 71 | (ok (var-set governanceTokenPrincipal (contract-of governanceToken))) 72 | ) 73 | ) 74 | 75 | (define-public (add-proposal (proposal ) (data {startBlockHeight: uint, endBlockHeight: uint, proposer: principal})) 76 | (begin 77 | (try! (is-dao-or-extension)) 78 | (asserts! (is-none (contract-call? .executor-dao executed-at proposal)) ERR_PROPOSAL_ALREADY_EXECUTED) 79 | (print {event: "propose", proposal: proposal, proposer: tx-sender}) 80 | (ok (asserts! (map-insert Proposals (contract-of proposal) (merge {votesFor: u0, votesAgainst: u0, concluded: false, passed: false} data)) ERR_PROPOSAL_ALREADY_EXISTS)) 81 | ) 82 | ) 83 | 84 | (define-public (cancel-proposal (proposal )) 85 | (begin 86 | (try! (is-dao-or-extension)) 87 | (asserts! (is-none (contract-call? .executor-dao executed-at proposal)) ERR_PROPOSAL_ALREADY_EXECUTED) 88 | (asserts! (< block-height (get startBlockHeight (unwrap-panic (get-proposal-data (contract-of proposal))))) ERR_PROPOSAL_ALREADY_STARTED) 89 | (print {event: "cancel", proposal: proposal, proposer: tx-sender}) 90 | (ok (asserts! (map-delete Proposals (contract-of proposal)) ERR_UNKNOWN_PROPOSAL)) 91 | ) 92 | ) 93 | 94 | ;; --- Public functions 95 | 96 | (define-read-only (get-governance-token) 97 | (var-get governanceTokenPrincipal) 98 | ) 99 | 100 | (define-private (is-governance-token (governanceToken )) 101 | (ok (asserts! (is-eq (contract-of governanceToken) (var-get governanceTokenPrincipal)) ERR_NOT_GOVERNANCE_TOKEN)) 102 | ) 103 | 104 | (define-read-only (get-proposal-data (proposal principal)) 105 | (map-get? Proposals proposal) 106 | ) 107 | 108 | (define-read-only (get-current-total-votes (proposal principal) (voter principal) (governanceToken principal)) 109 | (default-to u0 (map-get? MemberTotalVotes {proposal: proposal, voter: voter, governanceToken: governanceToken})) 110 | ) 111 | 112 | (define-public (vote (amount uint) (for bool) (proposal principal) (governanceToken )) 113 | (let 114 | ( 115 | (proposalData (unwrap! (map-get? Proposals proposal) ERR_UNKNOWN_PROPOSAL)) 116 | (tokenPrincipal (contract-of governanceToken)) 117 | ) 118 | (try! (is-governance-token governanceToken)) 119 | (asserts! (>= block-height (get startBlockHeight proposalData)) ERR_PROPOSAL_INACTIVE) 120 | (asserts! (< block-height (get endBlockHeight proposalData)) ERR_PROPOSAL_INACTIVE) 121 | (map-set MemberTotalVotes {proposal: proposal, voter: tx-sender, governanceToken: tokenPrincipal} 122 | (+ (get-current-total-votes proposal tx-sender tokenPrincipal) amount) 123 | ) 124 | (map-set Proposals proposal 125 | (if for 126 | (merge proposalData {votesFor: (+ (get votesFor proposalData) amount)}) 127 | (merge proposalData {votesAgainst: (+ (get votesAgainst proposalData) amount)}) 128 | ) 129 | ) 130 | (print {event: "vote", proposal: proposal, voter: tx-sender, for: for, amount: amount}) 131 | (contract-call? governanceToken lock amount tx-sender) 132 | ) 133 | ) 134 | 135 | (define-public (conclude (proposal )) 136 | (let 137 | ( 138 | (proposalData (unwrap! (map-get? Proposals (contract-of proposal)) ERR_UNKNOWN_PROPOSAL)) 139 | (passed (> (get votesFor proposalData) (get votesAgainst proposalData))) 140 | ) 141 | (asserts! (not (get concluded proposalData)) ERR_PROPOSAL_ALREADY_CONCLUDED) 142 | (asserts! (>= block-height (get endBlockHeight proposalData)) ERR_END_BLOCK_HEIGHT_NOT_REACHED) 143 | (map-set Proposals (contract-of proposal) (merge proposalData {concluded: true, passed: passed})) 144 | (print {event: "conclude", proposal: proposal, passed: passed}) 145 | (and passed (try! (contract-call? .executor-dao execute proposal tx-sender))) 146 | (ok passed) 147 | ) 148 | ) 149 | 150 | (define-public (reclaim-votes (proposal ) (governanceToken )) 151 | (let 152 | ( 153 | (proposalPrincipal (contract-of proposal)) 154 | (tokenPrincipal (contract-of governanceToken)) 155 | (proposalData (unwrap! (map-get? Proposals proposalPrincipal) ERR_UNKNOWN_PROPOSAL)) 156 | (votes (unwrap! (map-get? MemberTotalVotes {proposal: proposalPrincipal, voter: tx-sender, governanceToken: tokenPrincipal}) ERR_NO_VOTES_TO_RETURN)) 157 | ) 158 | (asserts! (get concluded proposalData) ERR_PROPOSAL_NOT_CONCLUDED) 159 | (map-delete MemberTotalVotes {proposal: proposalPrincipal, voter: tx-sender, governanceToken: tokenPrincipal}) 160 | (contract-call? governanceToken unlock votes tx-sender) 161 | ) 162 | ) 163 | 164 | (define-public (reclaim-and-vote (amount uint) (for bool) (proposal principal) (reclaim-from ) (governanceToken )) 165 | (begin 166 | (try! (reclaim-votes reclaim-from governanceToken)) 167 | (vote amount for proposal governanceToken) 168 | ) 169 | ) 170 | 171 | ;; --- Extension callback 172 | 173 | (define-public (callback (sender principal) (memo (buff 34))) 174 | (ok true) 175 | ) 176 | -------------------------------------------------------------------------------- /contracts/extensions/voting/sde-proposal-voting-with-members.clar: -------------------------------------------------------------------------------- 1 | ;; _____________ _______ _________ ___ ___ ____ ____ 2 | ;; / __/_ __/ _ |/ ___/ //_/ __/ _ \/ _ \/ _ |/ __ \/ __/ 3 | ;; _\ \ / / / __ / /__/ ,< / _// , _/ // / __ / /_/ /\ \ 4 | ;; /___/ /_/ /_/ |_\___/_/|_/___/_/|_/____/_/ |_\____/___/ 5 | ;; 6 | ;; _____ _____________ ______________ _ __ 7 | ;; / __/ |/_/_ __/ __/ |/ / __/ _/ __ \/ |/ / 8 | ;; / _/_> < / / / _// /\ \_/ // /_/ / / 9 | ;; /___/_/|_| /_/ /___/_/|_/___/___/\____/_/|_/ 10 | ;; 11 | 12 | ;; Title: SDE007 Membership Proposal Voting 13 | ;; Author: StackerDAO Dev Team 14 | ;; Depends-On: SDE000 15 | ;; Synopsis: 16 | ;; This extension is part of the core of ExecutorDAO. It allows governance token 17 | ;; holders to vote on and conclude proposals. 18 | ;; Description: 19 | ;; Once proposals are submitted, they are open for voting after a lead up time 20 | ;; passes. Any token holder may vote on an open proposal, where one token equals 21 | ;; one vote. Members can vote until the voting period is over. After this period 22 | ;; anyone may trigger a conclusion. The proposal will then be executed if the 23 | ;; votes in favour exceed the ones against. 24 | 25 | (use-trait proposal-trait .proposal-trait.proposal-trait) 26 | (use-trait member-trait .member-trait.member-trait) 27 | 28 | (impl-trait .extension-trait.extension-trait) 29 | 30 | (define-constant ERR_UNAUTHORIZED (err u3000)) 31 | (define-constant ERR_NOT_MEMBER_CONTRACT (err u3001)) 32 | (define-constant ERR_PROPOSAL_ALREADY_EXECUTED (err u3002)) 33 | (define-constant ERR_PROPOSAL_ALREADY_EXISTS (err u3003)) 34 | (define-constant ERR_UNKNOWN_PROPOSAL (err u3004)) 35 | (define-constant ERR_PROPOSAL_ALREADY_CONCLUDED (err u3005)) 36 | (define-constant ERR_PROPOSAL_ALREADY_STARTED (err u3006)) 37 | (define-constant ERR_PROPOSAL_INACTIVE (err u3007)) 38 | (define-constant ERR_PROPOSAL_NOT_CONCLUDED (err u3008)) 39 | (define-constant ERR_NO_VOTES_TO_RETURN (err u3009)) 40 | (define-constant ERR_END_BLOCK_HEIGHT_NOT_REACHED (err u3010)) 41 | (define-constant ERR_DISABLED (err u3011)) 42 | (define-constant ERR_QUORUM_THRESHOLD_NOT_REACHED (err u3012)) 43 | 44 | (define-data-var memberContractPrincipal principal .sde-membership) 45 | (define-data-var quorumThresholdPercentage uint u10) 46 | 47 | (define-map Proposals 48 | principal 49 | { 50 | votesFor: uint, 51 | votesAgainst: uint, 52 | startBlockHeight: uint, 53 | endBlockHeight: uint, 54 | concluded: bool, 55 | passed: bool, 56 | proposer: principal 57 | } 58 | ) 59 | 60 | (define-map MemberTotalVotes {proposal: principal, voter: principal} uint) 61 | 62 | ;; --- Authorization check 63 | 64 | (define-public (is-dao-or-extension) 65 | (ok (asserts! (or (is-eq tx-sender .executor-dao) (contract-call? .executor-dao is-extension contract-caller)) ERR_UNAUTHORIZED)) 66 | ) 67 | 68 | ;; --- Internal DAO functions 69 | 70 | (define-public (set-member-contract (memberContract )) 71 | (begin 72 | (try! (is-dao-or-extension)) 73 | (ok (var-set memberContractPrincipal (contract-of memberContract))) 74 | ) 75 | ) 76 | 77 | (define-public (add-proposal (proposal ) (data {startBlockHeight: uint, endBlockHeight: uint, proposer: principal})) 78 | (begin 79 | (try! (is-dao-or-extension)) 80 | (asserts! (is-none (contract-call? .executor-dao executed-at proposal)) ERR_PROPOSAL_ALREADY_EXECUTED) 81 | (print {event: "propose", proposal: proposal, proposer: tx-sender}) 82 | (ok (asserts! (map-insert Proposals (contract-of proposal) (merge {votesFor: u0, votesAgainst: u0, concluded: false, passed: false} data)) ERR_PROPOSAL_ALREADY_EXISTS)) 83 | ) 84 | ) 85 | 86 | (define-public (cancel-proposal (proposal )) 87 | (begin 88 | (try! (is-dao-or-extension)) 89 | (asserts! (is-none (contract-call? .executor-dao executed-at proposal)) ERR_PROPOSAL_ALREADY_EXECUTED) 90 | (asserts! (< block-height (get startBlockHeight (unwrap-panic (get-proposal-data (contract-of proposal))))) ERR_PROPOSAL_ALREADY_STARTED) 91 | (print {event: "cancel", proposal: proposal, proposer: tx-sender}) 92 | (ok (asserts! (map-delete Proposals (contract-of proposal)) ERR_UNKNOWN_PROPOSAL)) 93 | ) 94 | ) 95 | 96 | ;; --- Public functions 97 | 98 | (define-read-only (get-member-contract) 99 | (var-get memberContractPrincipal) 100 | ) 101 | 102 | (define-private (is-member-contract (memberContract )) 103 | (ok (asserts! (is-eq (contract-of memberContract) (get-member-contract)) ERR_NOT_MEMBER_CONTRACT)) 104 | ) 105 | 106 | (define-read-only (get-proposal-data (proposal principal)) 107 | (map-get? Proposals proposal) 108 | ) 109 | 110 | (define-read-only (get-current-total-votes (proposal principal) (voter principal)) 111 | (default-to u0 (map-get? MemberTotalVotes {proposal: proposal, voter: voter})) 112 | ) 113 | 114 | (define-public (vote (for bool) (proposal principal) (member-contract )) 115 | (let 116 | ( 117 | (proposalData (unwrap! (map-get? Proposals proposal) ERR_UNKNOWN_PROPOSAL)) 118 | ) 119 | (try! (is-member-contract member-contract)) 120 | (asserts! (>= block-height (get startBlockHeight proposalData)) ERR_PROPOSAL_INACTIVE) 121 | (asserts! (< block-height (get endBlockHeight proposalData)) ERR_PROPOSAL_INACTIVE) 122 | (map-set MemberTotalVotes {proposal: proposal, voter: tx-sender} 123 | (+ (get-current-total-votes proposal tx-sender) u1) 124 | ) 125 | (map-set Proposals proposal 126 | (if for 127 | (merge proposalData {votesFor: (+ (get votesFor proposalData) u1)}) 128 | (merge proposalData {votesAgainst: (+ (get votesAgainst proposalData) u1)}) 129 | ) 130 | ) 131 | (print {event: "vote", proposal: proposal, voter: tx-sender, for: for}) 132 | (ok true) 133 | ) 134 | ) 135 | 136 | ;; Conclusion 137 | 138 | (define-public (conclude (proposal )) 139 | (let 140 | ( 141 | (proposalData (unwrap! (map-get? Proposals (contract-of proposal)) ERR_UNKNOWN_PROPOSAL)) 142 | (totalVotes (+ (get votesFor proposalData) (get votesAgainst proposalData))) 143 | (quorum (/ (* totalVotes (var-get quorumThresholdPercentage)) u100)) 144 | (passed (> (get votesFor proposalData) (get votesAgainst proposalData))) 145 | ) 146 | (asserts! (not (get concluded proposalData)) ERR_PROPOSAL_ALREADY_CONCLUDED) 147 | (asserts! (>= block-height (get endBlockHeight proposalData)) ERR_END_BLOCK_HEIGHT_NOT_REACHED) 148 | (asserts! (>= totalVotes quorum) ERR_QUORUM_THRESHOLD_NOT_REACHED) 149 | (map-set Proposals (contract-of proposal) (merge proposalData {concluded: true, passed: passed})) 150 | (print {event: "conclude", proposal: proposal, totalVotes: totalVotes, quorum: quorum, passed: passed}) 151 | (and passed (try! (contract-call? .executor-dao execute proposal tx-sender))) 152 | (ok passed) 153 | ) 154 | ) 155 | 156 | ;; --- Extension callback 157 | 158 | (define-public (callback (sender principal) (memo (buff 34))) 159 | (ok true) 160 | ) 161 | -------------------------------------------------------------------------------- /contracts/extensions/voting/sde-proposal-voting-with-nft.clar: -------------------------------------------------------------------------------- 1 | ;; _____________ _______ _________ ___ ___ ____ ____ 2 | ;; / __/_ __/ _ |/ ___/ //_/ __/ _ \/ _ \/ _ |/ __ \/ __/ 3 | ;; _\ \ / / / __ / /__/ ,< / _// , _/ // / __ / /_/ /\ \ 4 | ;; /___/ /_/ /_/ |_\___/_/|_/___/_/|_/____/_/ |_\____/___/ 5 | ;; 6 | ;; _____ _____________ ______________ _ __ 7 | ;; / __/ |/_/_ __/ __/ |/ / __/ _/ __ \/ |/ / 8 | ;; / _/_> < / / / _// /\ \_/ // /_/ / / 9 | ;; /___/_/|_| /_/ /___/_/|_/___/___/\____/_/|_/ 10 | ;; 11 | 12 | ;; Title: SDE0011 Proposal Voting 13 | ;; Author: StackerDAO Dev Team 14 | ;; Depends-On: 15 | ;; Synopsis: 16 | ;; This extension is part of the core of StackerDAO. It allows NFT 17 | ;; holders to vote on and conclude proposals. 18 | ;; Description: 19 | ;; Once proposals are submitted, they are open for voting after a lead up time 20 | ;; passes. Any token holder may vote on an open proposal, where one token equals 21 | ;; one vote. Members can vote until the voting period is over. After this period 22 | ;; anyone may trigger a conclusion. The proposal will then be executed if the 23 | ;; votes in favour exceed the ones against. 24 | 25 | (use-trait proposal-trait .proposal-trait.proposal-trait) 26 | (use-trait sip009-nft-trait .sip009-nft-trait.sip009-nft-trait) 27 | 28 | (impl-trait .extension-trait.extension-trait) 29 | 30 | (define-constant ERR_UNAUTHORIZED (err u3400)) 31 | (define-constant ERR_NOT_NFT_OWNER (err u3401)) 32 | (define-constant ERR_PROPOSAL_ALREADY_EXECUTED (err u3402)) 33 | (define-constant ERR_PROPOSAL_ALREADY_EXISTS (err u3403)) 34 | (define-constant ERR_UNKNOWN_PROPOSAL (err u3404)) 35 | (define-constant ERR_PROPOSAL_ALREADY_STARTED (err u3405)) 36 | (define-constant ERR_PROPOSAL_ALREADY_CONCLUDED (err u3406)) 37 | (define-constant ERR_PROPOSAL_INACTIVE (err u3407)) 38 | (define-constant ERR_PROPOSAL_NOT_CONCLUDED (err u3408)) 39 | (define-constant ERR_NO_VOTES_TO_RETURN (err u3409)) 40 | (define-constant ERR_ALREADY_VOTED (err u3410)) 41 | (define-constant ERR_END_BLOCK_HEIGHT_NOT_REACHED (err u3411)) 42 | (define-constant ERR_DISABLED (err u3412)) 43 | 44 | (define-data-var nftContract principal .nft-membership) 45 | 46 | (define-map Proposals 47 | principal 48 | { 49 | votesFor: uint, 50 | votesAgainst: uint, 51 | startBlockHeight: uint, 52 | endBlockHeight: uint, 53 | concluded: bool, 54 | passed: bool, 55 | proposer: principal 56 | } 57 | ) 58 | 59 | (define-map MemberVotes {proposal: principal, voter: principal, tokenId: uint} uint) 60 | 61 | ;; --- Authorization check 62 | 63 | (define-public (is-dao-or-extension) 64 | (ok (asserts! (or (is-eq tx-sender .executor-dao) (contract-call? .executor-dao is-extension contract-caller)) ERR_UNAUTHORIZED)) 65 | ) 66 | 67 | ;; --- Internal DAO functions 68 | 69 | (define-public (add-proposal (proposal ) (data {startBlockHeight: uint, endBlockHeight: uint, proposer: principal})) 70 | (begin 71 | (try! (is-dao-or-extension)) 72 | (asserts! (is-none (contract-call? .executor-dao executed-at proposal)) ERR_PROPOSAL_ALREADY_EXECUTED) 73 | (print {event: "propose", proposal: proposal, proposer: tx-sender}) 74 | (ok (asserts! (map-insert Proposals (contract-of proposal) (merge {votesFor: u0, votesAgainst: u0, concluded: false, passed: false} data)) ERR_PROPOSAL_ALREADY_EXISTS)) 75 | ) 76 | ) 77 | 78 | (define-public (cancel-proposal (proposal )) 79 | (begin 80 | (try! (is-dao-or-extension)) 81 | (asserts! (is-none (contract-call? .executor-dao executed-at proposal)) ERR_PROPOSAL_ALREADY_EXECUTED) 82 | (asserts! (< block-height (get startBlockHeight (unwrap-panic (get-proposal-data (contract-of proposal))))) ERR_PROPOSAL_ALREADY_STARTED) 83 | (print {event: "cancel", proposal: proposal, proposer: tx-sender}) 84 | (ok (asserts! (map-delete Proposals (contract-of proposal)) ERR_UNKNOWN_PROPOSAL)) 85 | ) 86 | ) 87 | 88 | ;; Proposals 89 | 90 | (define-read-only (get-proposal-data (proposal principal)) 91 | (map-get? Proposals proposal) 92 | ) 93 | 94 | ;; Votes 95 | 96 | (define-read-only (get-current-total-votes (proposal principal) (voter principal) (tokenId uint)) 97 | (default-to u0 (map-get? MemberVotes {proposal: proposal, voter: voter, tokenId: tokenId})) 98 | ) 99 | 100 | ;; --- Read only functions 101 | 102 | (define-read-only (get-nft-contract) 103 | (var-get nftContract) 104 | ) 105 | 106 | (define-public (vote (tokenId uint) (for bool) (proposal principal)) 107 | (let 108 | ( 109 | (proposalData (unwrap! (map-get? Proposals proposal) ERR_UNKNOWN_PROPOSAL)) 110 | ) 111 | (asserts! (is-eq contract-caller (unwrap! (unwrap-panic (contract-call? .nft-membership get-owner tokenId)) ERR_NOT_NFT_OWNER)) ERR_UNAUTHORIZED) 112 | (asserts! (>= block-height (get startBlockHeight proposalData)) ERR_PROPOSAL_INACTIVE) 113 | (asserts! (< block-height (get endBlockHeight proposalData)) ERR_PROPOSAL_INACTIVE) 114 | (asserts! (is-none (map-get? MemberVotes {proposal: proposal, voter: tx-sender, tokenId: tokenId})) ERR_ALREADY_VOTED) 115 | (map-set MemberVotes {proposal: proposal, voter: tx-sender, tokenId: tokenId} u1) 116 | (map-set Proposals proposal 117 | (if for 118 | (merge proposalData {votesFor: (+ (get votesFor proposalData) u1)}) 119 | (merge proposalData {votesAgainst: (+ (get votesAgainst proposalData) u1)}) 120 | ) 121 | ) 122 | (print {event: "vote", proposal: proposal, voter: tx-sender, for: for, amount: u1, tokenId: tokenId}) 123 | (ok true) 124 | ) 125 | ) 126 | 127 | (define-private (vote-many-iter (item {tokenId: uint, for: bool, proposal: principal})) 128 | (let 129 | ( 130 | (tokenId (get tokenId item)) 131 | (for (get for item)) 132 | (proposal (get proposal item)) 133 | (proposalData (unwrap! (map-get? Proposals proposal) ERR_UNKNOWN_PROPOSAL)) 134 | ) 135 | (asserts! (is-eq contract-caller (unwrap! (unwrap-panic (contract-call? .nft-membership get-owner tokenId)) ERR_NOT_NFT_OWNER)) ERR_UNAUTHORIZED) 136 | (asserts! (>= block-height (get startBlockHeight proposalData)) ERR_PROPOSAL_INACTIVE) 137 | (asserts! (< block-height (get endBlockHeight proposalData)) ERR_PROPOSAL_INACTIVE) 138 | (asserts! (is-none (map-get? MemberVotes {proposal: proposal, voter: tx-sender, tokenId: tokenId})) ERR_ALREADY_VOTED) 139 | (map-set MemberVotes {proposal: proposal, voter: tx-sender, tokenId: tokenId} u1) 140 | (map-set Proposals proposal 141 | (if for 142 | (merge proposalData {votesFor: (+ (get votesFor proposalData) u1)}) 143 | (merge proposalData {votesAgainst: (+ (get votesAgainst proposalData) u1)}) 144 | ) 145 | ) 146 | (print {event: "vote", proposal: proposal, voter: tx-sender, for: for, amount: u1, tokenId: tokenId}) 147 | (ok true) 148 | ) 149 | ) 150 | 151 | (define-public (vote-many (votes (list 50 {tokenId: uint, for: bool, proposal: principal}))) 152 | (ok (map vote-many-iter votes)) 153 | ) 154 | 155 | ;; Conclusion 156 | 157 | (define-public (conclude (proposal )) 158 | (let 159 | ( 160 | (proposalData (unwrap! (map-get? Proposals (contract-of proposal)) ERR_UNKNOWN_PROPOSAL)) 161 | (passed (> (get votesFor proposalData) (get votesAgainst proposalData))) 162 | ) 163 | (asserts! (not (get concluded proposalData)) ERR_PROPOSAL_ALREADY_CONCLUDED) 164 | (asserts! (>= block-height (get endBlockHeight proposalData)) ERR_END_BLOCK_HEIGHT_NOT_REACHED) 165 | (map-set Proposals (contract-of proposal) (merge proposalData {concluded: true, passed: passed})) 166 | (print {event: "conclude", proposal: proposal, passed: passed}) 167 | (and passed (try! (contract-call? .executor-dao execute proposal tx-sender))) 168 | (ok passed) 169 | ) 170 | ) 171 | 172 | ;; --- Extension callback 173 | 174 | (define-public (callback (sender principal) (memo (buff 34))) 175 | (ok true) 176 | ) 177 | -------------------------------------------------------------------------------- /contracts/extensions/voting/sde-proposal-voting.clar: -------------------------------------------------------------------------------- 1 | ;; _____________ _______ _________ ___ ___ ____ ____ 2 | ;; / __/_ __/ _ |/ ___/ //_/ __/ _ \/ _ \/ _ |/ __ \/ __/ 3 | ;; _\ \ / / / __ / /__/ ,< / _// , _/ // / __ / /_/ /\ \ 4 | ;; /___/ /_/ /_/ |_\___/_/|_/___/_/|_/____/_/ |_\____/___/ 5 | ;; 6 | ;; _____ _____________ ______________ _ __ 7 | ;; / __/ |/_/_ __/ __/ |/ / __/ _/ __ \/ |/ / 8 | ;; / _/_> < / / / _// /\ \_/ // /_/ / / 9 | ;; /___/_/|_| /_/ /___/_/|_/___/___/\____/_/|_/ 10 | 11 | (use-trait sip010-ft-trait .sip010-ft-trait.sip010-ft-trait) 12 | (use-trait proposal-trait .proposal-trait.proposal-trait) 13 | 14 | (impl-trait .extension-trait.extension-trait) 15 | 16 | (define-constant ERR_UNAUTHORIZED (err u2500)) 17 | (define-constant ERR_NOT_GOVERNANCE_TOKEN (err u2501)) 18 | (define-constant ERR_PROPOSAL_ALREADY_EXECUTED (err u2502)) 19 | (define-constant ERR_PROPOSAL_ALREADY_EXISTS (err u2503)) 20 | (define-constant ERR_UNKNOWN_PROPOSAL (err u2504)) 21 | (define-constant ERR_PROPOSAL_ALREADY_ACTIVE (err u2505)) 22 | (define-constant ERR_PROPOSAL_ALREADY_CONCLUDED (err u2506)) 23 | (define-constant ERR_PROPOSAL_INACTIVE (err u2507)) 24 | (define-constant ERR_PROPOSAL_NOT_CONCLUDED (err u2508)) 25 | (define-constant ERR_NO_VOTES_TO_RETURN (err u2509)) 26 | (define-constant ERR_QUORUM_NOT_MET (err u2510)) 27 | (define-constant ERR_END_BLOCK_HEIGHT_NOT_REACHED (err u2511)) 28 | (define-constant ERR_DISABLED (err u2512)) 29 | (define-constant ERR_INSUFFICIENT_WEIGHT (err u2513)) 30 | (define-constant ERR_ALREADY_VOTED (err u2514)) 31 | (define-constant ERR_UNKNOWN_PARAMETER (err u2515)) 32 | (define-constant ERR_NOT_TOKEN_OWNER (err u2516)) 33 | (define-constant ERR_CANT_DELEGATE_TO_SELF (err u2517)) 34 | (define-constant ERR_NOT_ENOUGH_TOKENS (err u2518)) 35 | (define-constant ERR_INVALID_WEIGHT (err u2519)) 36 | (define-constant ERR_MUST_REVOKE_CURRENT_DELEGATION (err u2520)) 37 | (define-constant ERR_NO_DELEGATION_TO_REVOKE (err u2521)) 38 | (define-constant ERR_NOT_DELEGATE (err u2522)) 39 | 40 | (define-constant MICRO (pow u10 u2)) 41 | 42 | (define-data-var governanceTokenPrincipal principal .sde-stackerdao-token) 43 | (define-data-var proposalSize uint u0) 44 | 45 | (define-map Proposals 46 | principal 47 | { 48 | votesFor: uint, 49 | votesAgainst: uint, 50 | startBlockHeight: uint, 51 | endBlockHeight: uint, 52 | concluded: bool, 53 | passed: bool, 54 | proposer: principal 55 | } 56 | ) 57 | (define-map proposalList uint principal) 58 | (define-map MemberTotalVotes {proposal: principal, voter: principal, governanceToken: principal} uint) 59 | (define-map parameters (string-ascii 34) uint) 60 | 61 | (map-set parameters "voteThreshold" u1) ;; Tokens required to vote 62 | (map-set parameters "quorumThreshold" u12500) ;; 5% of 250k initially distributed to Megapoont holders required for quorum 63 | (map-set parameters "executionDelay" u144) ;; Delay execution of proposal by ~ 1 day 64 | 65 | (define-map Delegates principal principal) 66 | (define-map Delegators principal bool) 67 | 68 | ;; --- Authorization check 69 | 70 | (define-public (is-dao-or-extension) 71 | (ok (asserts! (or (is-eq tx-sender .executor-dao) (contract-call? .executor-dao is-extension contract-caller)) ERR_UNAUTHORIZED)) 72 | ) 73 | 74 | ;; --- Internal DAO functions 75 | 76 | (define-public (set-parameter (parameter (string-ascii 34)) (value uint)) 77 | (begin 78 | (try! (is-dao-or-extension)) 79 | (try! (get-parameter parameter)) 80 | (ok (map-set parameters parameter value)) 81 | ) 82 | ) 83 | 84 | (define-public (add-proposal (proposal ) (data {startBlockHeight: uint, endBlockHeight: uint, proposer: principal})) 85 | (begin 86 | (try! (is-dao-or-extension)) 87 | (asserts! (is-none (contract-call? .executor-dao executed-at proposal)) ERR_PROPOSAL_ALREADY_EXECUTED) 88 | (var-set proposalSize (+ u1 (var-get proposalSize))) 89 | (map-insert proposalList (var-get proposalSize) (contract-of proposal)) 90 | (print {event: "propose", proposal: proposal, proposer: tx-sender}) 91 | (ok (asserts! (map-insert Proposals (contract-of proposal) (merge {votesFor: u0, votesAgainst: u0, concluded: false, passed: false} data)) ERR_PROPOSAL_ALREADY_EXISTS)) 92 | ) 93 | ) 94 | 95 | ;; --- Public functions 96 | 97 | (define-read-only (get-governance-token) 98 | (var-get governanceTokenPrincipal) 99 | ) 100 | 101 | (define-read-only (get-parameter (parameter (string-ascii 34))) 102 | (ok (unwrap! (map-get? parameters parameter) ERR_UNKNOWN_PARAMETER)) 103 | ) 104 | 105 | (define-read-only (get-proposal-data (proposal principal)) 106 | (map-get? Proposals proposal) 107 | ) 108 | 109 | (define-read-only (get-proposals (atIndex uint)) 110 | (map-get? proposalList atIndex) 111 | ) 112 | 113 | (define-read-only (get-proposals-count) 114 | (var-get proposalSize) 115 | ) 116 | 117 | (define-read-only (get-current-total-votes (proposal principal) (voter principal) (governanceToken principal)) 118 | (default-to u0 (map-get? MemberTotalVotes {proposal: proposal, voter: voter, governanceToken: governanceToken})) 119 | ) 120 | 121 | (define-public (can-vote (who principal) (tokenThreshold uint) (governanceToken )) 122 | (let 123 | ( 124 | (balance (unwrap-panic (contract-call? governanceToken get-balance tx-sender))) 125 | ) 126 | (ok (>= balance (* MICRO tokenThreshold))) 127 | ) 128 | ) 129 | 130 | (define-public (vote (for bool) (proposal principal) (delegator (optional principal))) 131 | (let 132 | ( 133 | (proposalData (unwrap! (map-get? Proposals proposal) ERR_UNKNOWN_PROPOSAL)) 134 | (voter (default-to tx-sender delegator)) 135 | (amount (unwrap-panic (contract-call? .sde-stackerdao-token get-balance voter))) 136 | ) 137 | (asserts! (>= block-height (get startBlockHeight proposalData)) ERR_PROPOSAL_INACTIVE) 138 | (asserts! (< block-height (get endBlockHeight proposalData)) ERR_PROPOSAL_INACTIVE) 139 | (asserts! (can-vote-on-behalf tx-sender delegator) ERR_NOT_DELEGATE) 140 | (asserts! (unwrap-panic (can-vote voter (try! (get-parameter "voteThreshold")) .sde-stackerdao-token)) ERR_INSUFFICIENT_WEIGHT) 141 | (asserts! (is-eq u0 (get-current-total-votes proposal voter .sde-stackerdao-token)) ERR_ALREADY_VOTED) 142 | (map-set MemberTotalVotes {proposal: proposal, voter: voter, governanceToken: .sde-stackerdao-token} 143 | (+ (get-current-total-votes proposal voter .sde-stackerdao-token) amount) 144 | ) 145 | (map-set Proposals proposal 146 | (if for 147 | (merge proposalData {votesFor: (+ (get votesFor proposalData) amount)}) 148 | (merge proposalData {votesAgainst: (+ (get votesAgainst proposalData) amount)}) 149 | ) 150 | ) 151 | (print {event: "vote", proposal: proposal, voter: voter, delegate: (if (is-none delegator) none (some tx-sender)), for: for, amount: amount}) 152 | (ok true) 153 | ) 154 | ) 155 | 156 | (define-public (vote-many (votes (list 200 {for: bool, proposal: principal, delegator: (optional principal)}))) 157 | (ok (map vote-map votes)) 158 | ) 159 | 160 | (define-private (vote-map (delegator {for: bool, proposal: principal, delegator: (optional principal)})) 161 | (let 162 | ( 163 | (for (get for delegator)) 164 | (proposal (get proposal delegator)) 165 | (voter (get delegator delegator)) 166 | ) 167 | (match voter 168 | foundDelegator (try! (vote for proposal (some foundDelegator))) 169 | (try! (vote for proposal none)) 170 | ) 171 | (ok true) 172 | ) 173 | ) 174 | 175 | (define-public (conclude (proposal )) 176 | (let 177 | ( 178 | (proposalData (unwrap! (map-get? Proposals (contract-of proposal)) ERR_UNKNOWN_PROPOSAL)) 179 | (totalVotes (+ (get votesFor proposalData) (get votesAgainst proposalData))) 180 | (quorumThreshold (* MICRO (try! (get-parameter "quorumThreshold")))) 181 | (passed (and (>= totalVotes quorumThreshold) (> (get votesFor proposalData) (get votesAgainst proposalData)))) 182 | ) 183 | (asserts! (not (get concluded proposalData)) ERR_PROPOSAL_ALREADY_CONCLUDED) 184 | (asserts! (>= block-height (+ (try! (get-parameter "executionDelay")) (get endBlockHeight proposalData))) ERR_END_BLOCK_HEIGHT_NOT_REACHED) 185 | (map-set Proposals (contract-of proposal) (merge proposalData {concluded: true, passed: passed})) 186 | (print {event: "conclude", proposal: proposal, totalVotes: totalVotes, quorum: quorumThreshold, passed: passed}) 187 | (and passed (try! (contract-call? .executor-dao execute proposal tx-sender))) 188 | (ok passed) 189 | ) 190 | ) 191 | 192 | ;; --- Delegation 193 | 194 | (define-public (delegate (who principal)) 195 | (begin 196 | (asserts! (or (not (is-eq tx-sender who)) (not (is-eq contract-caller who))) ERR_CANT_DELEGATE_TO_SELF) 197 | (print {event: "delegate", who: who, delegator: tx-sender}) 198 | (map-set Delegators tx-sender true) 199 | (ok (map-set Delegates tx-sender who)) 200 | ) 201 | ) 202 | 203 | (define-public (revoke-delegation (who principal)) 204 | (begin 205 | (asserts! (or (is-eq tx-sender who) (is-eq contract-caller who)) ERR_NOT_TOKEN_OWNER) 206 | (asserts! (is-some (map-get? Delegates who)) ERR_NO_DELEGATION_TO_REVOKE) 207 | (print {event: "revoke-delegation", who: who, delegator: tx-sender}) 208 | (map-delete Delegators tx-sender) 209 | (ok (map-delete Delegates who)) 210 | ) 211 | ) 212 | 213 | (define-read-only (can-vote-on-behalf (sender principal) (delegator (optional principal))) 214 | (match delegator 215 | voter (is-eq (map-get? Delegates voter) (some sender)) 216 | true 217 | ) 218 | ) 219 | 220 | (define-read-only (get-delegate (who principal)) 221 | (ok (map-get? Delegates who)) 222 | ) 223 | 224 | (define-read-only (is-delegating (who principal)) 225 | (default-to false (map-get? Delegators who)) 226 | ) 227 | 228 | ;; --- Extension callback 229 | 230 | (define-public (callback (sender principal) (memo (buff 34))) 231 | (ok true) 232 | ) 233 | -------------------------------------------------------------------------------- /contracts/external/citycoins/citycoin-core-trait.clar: -------------------------------------------------------------------------------- 1 | ;; CITYCOIN CORE TRAIT 2 | 3 | (define-trait citycoin-core 4 | ( 5 | 6 | (register-user ((optional (string-utf8 50))) 7 | (response bool uint) 8 | ) 9 | 10 | (mine-tokens (uint (optional (buff 34))) 11 | (response bool uint) 12 | ) 13 | 14 | (claim-mining-reward (uint) 15 | (response bool uint) 16 | ) 17 | 18 | (stack-tokens (uint uint) 19 | (response bool uint) 20 | ) 21 | 22 | (claim-stacking-reward (uint) 23 | (response bool uint) 24 | ) 25 | 26 | (set-city-wallet (principal) 27 | (response bool uint) 28 | ) 29 | 30 | (shutdown-contract (uint) 31 | (response bool uint) 32 | ) 33 | 34 | ) 35 | ) -------------------------------------------------------------------------------- /contracts/external/citycoins/citycoin-token-trait.clar: -------------------------------------------------------------------------------- 1 | 2 | 3 | ;; CITYCOIN TOKEN TRAIT 4 | 5 | (define-trait citycoin-token 6 | ( 7 | 8 | (activate-token (principal uint) 9 | (response bool uint) 10 | ) 11 | 12 | (set-token-uri ((optional (string-utf8 256))) 13 | (response bool uint) 14 | ) 15 | 16 | (mint (uint principal) 17 | (response bool uint) 18 | ) 19 | 20 | (burn (uint principal) 21 | (response bool uint) 22 | ) 23 | 24 | (send-many ((list 200 { to: principal, amount: uint, memo: (optional (buff 34)) })) 25 | (response bool uint) 26 | ) 27 | 28 | ) 29 | ) -------------------------------------------------------------------------------- /contracts/external/citycoins/citycoin-token.clar: -------------------------------------------------------------------------------- 1 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 2 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 3 | ;; TOKEN CONTRACT 4 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 5 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 6 | 7 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 8 | ;; CONTRACT OWNER 9 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 10 | 11 | (define-constant CONTRACT_OWNER tx-sender) 12 | 13 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 14 | ;; TRAIT DEFINITIONS 15 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 16 | 17 | (impl-trait .citycoin-token-trait.citycoin-token) 18 | (use-trait coreTrait .citycoin-core-trait.citycoin-core) 19 | 20 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 21 | ;; ERROR CODES 22 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 23 | 24 | (define-constant ERR_UNAUTHORIZED u2000) 25 | (define-constant ERR_TOKEN_NOT_ACTIVATED u2001) 26 | (define-constant ERR_TOKEN_ALREADY_ACTIVATED u2002) 27 | 28 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 29 | ;; SIP-010 DEFINITION 30 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 31 | 32 | (impl-trait 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.citycoin-token-trait.citycoin-token) 33 | 34 | (define-fungible-token citycoins) 35 | 36 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 37 | ;; SIP-010 FUNCTIONS 38 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 39 | 40 | (define-public (transfer (amount uint) (from principal) (to principal) (memo (optional (buff 34)))) 41 | (begin 42 | (asserts! (is-eq from tx-sender) (err ERR_UNAUTHORIZED)) 43 | (if (is-some memo) 44 | (print memo) 45 | none 46 | ) 47 | (ft-transfer? citycoins amount from to) 48 | ) 49 | ) 50 | 51 | (define-read-only (get-name) 52 | (ok "citycoins") 53 | ) 54 | 55 | (define-read-only (get-symbol) 56 | (ok "CYCN") 57 | ) 58 | 59 | (define-read-only (get-decimals) 60 | (ok u0) 61 | ) 62 | 63 | (define-read-only (get-balance (user principal)) 64 | (ok (ft-get-balance citycoins user)) 65 | ) 66 | 67 | (define-read-only (get-total-supply) 68 | (ok (ft-get-supply citycoins)) 69 | ) 70 | 71 | (define-read-only (get-token-uri) 72 | (ok (var-get tokenUri)) 73 | ) 74 | 75 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 76 | ;; TOKEN CONFIGURATION 77 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 78 | 79 | ;; how many blocks until the next halving occurs 80 | (define-constant TOKEN_HALVING_BLOCKS u210000) 81 | 82 | ;; store block height at each halving, set by register-user in core contract 83 | (define-data-var coinbaseThreshold1 uint u0) 84 | (define-data-var coinbaseThreshold2 uint u0) 85 | (define-data-var coinbaseThreshold3 uint u0) 86 | (define-data-var coinbaseThreshold4 uint u0) 87 | (define-data-var coinbaseThreshold5 uint u0) 88 | 89 | ;; once activated, thresholds cannot be updated again 90 | (define-data-var tokenActivated bool false) 91 | 92 | ;; one-time function to activate the token 93 | (define-public (activate-token (coreContract principal) (stacksHeight uint)) 94 | (let 95 | ( 96 | (coreContractMap (try! (contract-call? .citycoin-auth get-core-contract-info coreContract))) 97 | (statusActive u1) 98 | ) 99 | (asserts! (is-eq (get state coreContractMap) statusActive) (err ERR_UNAUTHORIZED)) 100 | (asserts! (not (var-get tokenActivated)) (err ERR_TOKEN_ALREADY_ACTIVATED)) 101 | (var-set tokenActivated true) 102 | (var-set coinbaseThreshold1 (+ stacksHeight TOKEN_HALVING_BLOCKS)) 103 | (var-set coinbaseThreshold2 (+ stacksHeight (* u2 TOKEN_HALVING_BLOCKS))) 104 | (var-set coinbaseThreshold3 (+ stacksHeight (* u3 TOKEN_HALVING_BLOCKS))) 105 | (var-set coinbaseThreshold4 (+ stacksHeight (* u4 TOKEN_HALVING_BLOCKS))) 106 | (var-set coinbaseThreshold5 (+ stacksHeight (* u5 TOKEN_HALVING_BLOCKS))) 107 | (ok true) 108 | ) 109 | ) 110 | 111 | ;; return coinbase thresholds if token activated 112 | (define-read-only (get-coinbase-thresholds) 113 | (let 114 | ( 115 | (activated (var-get tokenActivated)) 116 | ) 117 | (asserts! activated (err ERR_TOKEN_NOT_ACTIVATED)) 118 | (ok { 119 | coinbaseThreshold1: (var-get coinbaseThreshold1), 120 | coinbaseThreshold2: (var-get coinbaseThreshold2), 121 | coinbaseThreshold3: (var-get coinbaseThreshold3), 122 | coinbaseThreshold4: (var-get coinbaseThreshold4), 123 | coinbaseThreshold5: (var-get coinbaseThreshold5) 124 | }) 125 | ) 126 | ) 127 | 128 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 129 | ;; UTILITIES 130 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 131 | 132 | (define-data-var tokenUri (optional (string-utf8 256)) (some u"https://cdn.citycoins.co/metadata/citycoin.json")) 133 | 134 | ;; set token URI to new value, only accessible by Auth 135 | (define-public (set-token-uri (newUri (optional (string-utf8 256)))) 136 | (begin 137 | (asserts! (is-authorized-auth) (err ERR_UNAUTHORIZED)) 138 | (ok (var-set tokenUri newUri)) 139 | ) 140 | ) 141 | 142 | ;; TESTING 143 | ;; mint new tokens, only accessible by a Core contract 144 | (define-public (mint (amount uint) (recipient principal)) 145 | ;; (let 146 | ;; ( 147 | ;; (coreContract (try! (contract-call? .citycoin-auth get-core-contract-info contract-caller))) 148 | ;; ) 149 | ;; (ft-mint? citycoins amount recipient) 150 | ;; ) 151 | (ft-mint? citycoins amount recipient) 152 | ) 153 | 154 | ;; burn tokens, only accessible by a Core contract 155 | (define-public (burn (amount uint) (recipient principal)) 156 | (let 157 | ( 158 | (coreContract (try! (contract-call? .citycoin-auth get-core-contract-info contract-caller))) 159 | ) 160 | (ft-burn? citycoins amount recipient) 161 | ) 162 | ) 163 | 164 | ;; checks if caller is Auth contract 165 | (define-private (is-authorized-auth) 166 | (is-eq contract-caller .citycoin-auth) 167 | ) 168 | 169 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 170 | ;; SEND-MANY 171 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 172 | 173 | (define-public (send-many (recipients (list 200 { to: principal, amount: uint, memo: (optional (buff 34)) }))) 174 | (fold check-err 175 | (map send-token recipients) 176 | (ok true) 177 | ) 178 | ) 179 | 180 | (define-private (check-err (result (response bool uint)) (prior (response bool uint))) 181 | (match prior ok-value result 182 | err-value (err err-value) 183 | ) 184 | ) 185 | 186 | (define-private (send-token (recipient { to: principal, amount: uint, memo: (optional (buff 34)) })) 187 | (send-token-with-memo (get amount recipient) (get to recipient) (get memo recipient)) 188 | ) 189 | 190 | (define-private (send-token-with-memo (amount uint) (to principal) (memo (optional (buff 34)))) 191 | (let 192 | ( 193 | (transferOk (try! (transfer amount tx-sender to memo))) 194 | ) 195 | (ok transferOk) 196 | ) 197 | ) -------------------------------------------------------------------------------- /contracts/external/citycoins/citycoin-vrf.clar: -------------------------------------------------------------------------------- 1 | ;; CITYCOIN VRF CONTRACT 2 | 3 | ;; VRF 4 | 5 | ;; Read the on-chain VRF and turn the lower 16 bytes into a uint, in order to sample the set of miners and determine 6 | ;; which one may claim the token batch for the given block height. 7 | (define-read-only (get-random-uint-at-block (stacksBlock uint)) 8 | (let ( 9 | (vrf-lower-uint-opt 10 | (match (get-block-info? vrf-seed stacksBlock) 11 | vrf-seed (some (buff-to-uint-le (lower-16-le vrf-seed))) 12 | none)) 13 | ) 14 | vrf-lower-uint-opt) 15 | ) 16 | 17 | ;; UTILITIES 18 | 19 | ;; lookup table for converting 1-byte buffers to uints via index-of 20 | (define-constant BUFF_TO_BYTE (list 21 | 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0a 0x0b 0x0c 0x0d 0x0e 0x0f 22 | 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1a 0x1b 0x1c 0x1d 0x1e 0x1f 23 | 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2a 0x2b 0x2c 0x2d 0x2e 0x2f 24 | 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3a 0x3b 0x3c 0x3d 0x3e 0x3f 25 | 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4a 0x4b 0x4c 0x4d 0x4e 0x4f 26 | 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5a 0x5b 0x5c 0x5d 0x5e 0x5f 27 | 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6a 0x6b 0x6c 0x6d 0x6e 0x6f 28 | 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7a 0x7b 0x7c 0x7d 0x7e 0x7f 29 | 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8a 0x8b 0x8c 0x8d 0x8e 0x8f 30 | 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9a 0x9b 0x9c 0x9d 0x9e 0x9f 31 | 0xa0 0xa1 0xa2 0xa3 0xa4 0xa5 0xa6 0xa7 0xa8 0xa9 0xaa 0xab 0xac 0xad 0xae 0xaf 32 | 0xb0 0xb1 0xb2 0xb3 0xb4 0xb5 0xb6 0xb7 0xb8 0xb9 0xba 0xbb 0xbc 0xbd 0xbe 0xbf 33 | 0xc0 0xc1 0xc2 0xc3 0xc4 0xc5 0xc6 0xc7 0xc8 0xc9 0xca 0xcb 0xcc 0xcd 0xce 0xcf 34 | 0xd0 0xd1 0xd2 0xd3 0xd4 0xd5 0xd6 0xd7 0xd8 0xd9 0xda 0xdb 0xdc 0xdd 0xde 0xdf 35 | 0xe0 0xe1 0xe2 0xe3 0xe4 0xe5 0xe6 0xe7 0xe8 0xe9 0xea 0xeb 0xec 0xed 0xee 0xef 36 | 0xf0 0xf1 0xf2 0xf3 0xf4 0xf5 0xf6 0xf7 0xf8 0xf9 0xfa 0xfb 0xfc 0xfd 0xfe 0xff 37 | )) 38 | 39 | ;; Convert a 1-byte buffer into its uint representation. 40 | (define-private (buff-to-u8 (byte (buff 1))) 41 | (unwrap-panic (index-of BUFF_TO_BYTE byte)) 42 | ) 43 | 44 | ;; Convert a little-endian 16-byte buff into a uint. 45 | (define-private (buff-to-uint-le (word (buff 16))) 46 | (get acc 47 | (fold add-and-shift-uint-le (list u0 u1 u2 u3 u4 u5 u6 u7 u8 u9 u10 u11 u12 u13 u14 u15) { acc: u0, data: word }) 48 | ) 49 | ) 50 | 51 | ;; Inner fold function for converting a 16-byte buff into a uint. 52 | (define-private (add-and-shift-uint-le (idx uint) (input { acc: uint, data: (buff 16) })) 53 | (let ( 54 | (acc (get acc input)) 55 | (data (get data input)) 56 | (byte (buff-to-u8 (unwrap-panic (element-at data idx)))) 57 | ) 58 | { 59 | ;; acc = byte * (2**(8 * (15 - idx))) + acc 60 | acc: (+ (* byte (pow u2 (* u8 (- u15 idx)))) acc), 61 | data: data 62 | }) 63 | ) 64 | 65 | ;; Convert the lower 16 bytes of a buff into a little-endian uint. 66 | (define-private (lower-16-le (input (buff 32))) 67 | (get acc 68 | (fold lower-16-le-closure (list u16 u17 u18 u19 u20 u21 u22 u23 u24 u25 u26 u27 u28 u29 u30 u31) { acc: 0x, data: input }) 69 | ) 70 | ) 71 | 72 | ;; Inner closure for obtaining the lower 16 bytes of a 32-byte buff 73 | (define-private (lower-16-le-closure (idx uint) (input { acc: (buff 16), data: (buff 32) })) 74 | (let ( 75 | (acc (get acc input)) 76 | (data (get data input)) 77 | (byte (unwrap-panic (element-at data idx))) 78 | ) 79 | { 80 | acc: (unwrap-panic (as-max-len? (concat acc byte) u16)), 81 | data: data 82 | }) 83 | ) -------------------------------------------------------------------------------- /contracts/external/ft-membership.clar: -------------------------------------------------------------------------------- 1 | (impl-trait .sip010-ft-trait.sip010-ft-trait) 2 | 3 | (define-constant ERR_UNAUTHORIZED (err u2000)) 4 | 5 | (define-fungible-token ryancoin) 6 | 7 | (define-data-var tokenUri (optional (string-utf8 256)) (some u"https://stackerdaos.com/metadata/ryancoin.json")) 8 | 9 | (define-public (transfer (amount uint) (from principal) (to principal) (memo (optional (buff 34)))) 10 | (begin 11 | (asserts! (is-eq from tx-sender) ERR_UNAUTHORIZED) 12 | (if (is-some memo) 13 | (print memo) 14 | none 15 | ) 16 | (ft-transfer? ryancoin amount from to) 17 | ) 18 | ) 19 | 20 | (define-read-only (get-name) 21 | (ok "ryancoin") 22 | ) 23 | 24 | (define-read-only (get-symbol) 25 | (ok "RYAN") 26 | ) 27 | 28 | (define-read-only (get-decimals) 29 | (ok u0) 30 | ) 31 | 32 | (define-read-only (get-balance (user principal)) 33 | (ok (ft-get-balance ryancoin user)) 34 | ) 35 | 36 | (define-read-only (get-total-supply) 37 | (ok (ft-get-supply ryancoin)) 38 | ) 39 | 40 | (define-read-only (get-token-uri) 41 | (ok (var-get tokenUri)) 42 | ) 43 | 44 | (define-public (set-token-uri (newUri (optional (string-utf8 256)))) 45 | (begin 46 | ;; TODO: add authorization check 47 | (ok (var-set tokenUri newUri)) 48 | ) 49 | ) 50 | 51 | (define-public (mint (amount uint) (recipient principal)) 52 | (ft-mint? ryancoin amount recipient) 53 | ) 54 | 55 | (define-public (burn (amount uint) (recipient principal)) 56 | (ft-burn? ryancoin amount recipient) 57 | ) -------------------------------------------------------------------------------- /contracts/external/nft-escrow.clar: -------------------------------------------------------------------------------- 1 | ;; An example external contract to show how the ExecutorDAO is able to 2 | ;; manage external contracts that might not be aware of the DAO. See 3 | ;; sdp003-whitelist-escrow-nft for more details. 4 | 5 | (impl-trait .ownable-trait.ownable-trait) 6 | 7 | (define-constant err-not-contract-owner (err u100)) 8 | (define-constant err-not-whitelisted (err u101)) 9 | (define-constant err-unknown-escrow (err u102)) 10 | (define-constant err-wrong-nft (err u103)) 11 | (define-constant err-not-nft-owner (err u104)) 12 | 13 | (define-data-var contract-owner principal tx-sender) 14 | (define-map nft-whitelist principal bool) 15 | (define-map nfts-in-escrow {token-id: uint, recipient: principal} {owner: principal, price: uint, asset: principal}) 16 | 17 | (define-trait sip009-transferable 18 | ( 19 | (transfer (uint principal principal) (response bool uint)) 20 | ) 21 | ) 22 | 23 | (define-private (is-owner) 24 | (ok (asserts! (is-eq (var-get contract-owner) tx-sender) err-not-contract-owner)) 25 | ) 26 | 27 | (define-read-only (get-contract-owner) 28 | (ok (var-get contract-owner)) 29 | ) 30 | 31 | (define-public (set-contract-owner (new-owner principal)) 32 | (begin 33 | (try! (is-owner)) 34 | (ok (var-set contract-owner new-owner)) 35 | ) 36 | ) 37 | 38 | (define-read-only (is-whitelisted (nft principal)) 39 | (default-to false (map-get? nft-whitelist nft)) 40 | ) 41 | 42 | (define-public (set-whitelisted (nft principal) (enabled bool)) 43 | (begin 44 | (try! (is-owner)) 45 | (ok (map-set nft-whitelist nft enabled)) 46 | ) 47 | ) 48 | 49 | (define-read-only (get-escrow (token-id uint) (recipient principal)) 50 | (map-get? nfts-in-escrow {token-id: token-id, recipient: recipient}) 51 | ) 52 | 53 | (define-private (send-nft (token-id uint) (recipient principal) (nft )) 54 | (as-contract (contract-call? nft transfer token-id tx-sender recipient)) 55 | ) 56 | 57 | (define-public (place-in-escrow (token-id uint) (recipient principal) (amount uint) (nft )) 58 | (begin 59 | (asserts! (is-whitelisted (contract-of nft)) err-not-whitelisted) 60 | (map-set nfts-in-escrow {token-id: token-id, recipient: recipient} {owner: tx-sender, price: amount, asset: (contract-of nft)}) 61 | (contract-call? nft transfer token-id tx-sender (as-contract tx-sender)) 62 | ) 63 | ) 64 | 65 | (define-public (pay-and-redeem (token-id uint) (nft )) 66 | (let ((escrow (unwrap! (get-escrow token-id tx-sender) err-unknown-escrow))) 67 | (asserts! (is-eq (contract-of nft) (get asset escrow)) err-wrong-nft) 68 | (map-delete nfts-in-escrow {token-id: token-id, recipient: tx-sender}) 69 | (try! (stx-transfer? (get price escrow) tx-sender (get owner escrow))) 70 | (send-nft token-id tx-sender nft) 71 | ) 72 | ) 73 | 74 | (define-public (cancel-escrow (token-id uint) (recipient principal) (nft )) 75 | (let ((escrow (unwrap! (get-escrow token-id recipient) err-unknown-escrow))) 76 | (asserts! (is-eq (get owner escrow) tx-sender) err-not-nft-owner) 77 | (asserts! (is-eq (contract-of nft) (get asset escrow)) err-wrong-nft) 78 | (map-delete nfts-in-escrow {token-id: token-id, recipient: recipient}) 79 | (send-nft token-id tx-sender nft) 80 | ) 81 | ) 82 | -------------------------------------------------------------------------------- /contracts/external/nft-membership.clar: -------------------------------------------------------------------------------- 1 | (impl-trait .sip009-nft-trait.sip009-nft-trait) 2 | 3 | (define-constant ERR_ONLY_OWNER (err u100)) 4 | (define-constant ERR_NOT_TOKEN_OWNER (err u101)) 5 | 6 | (define-constant CONTRACT_OWNER tx-sender) 7 | 8 | (define-non-fungible-token Stacker-Dao-Token uint) 9 | 10 | (define-data-var last-token-id uint u0) 11 | 12 | (define-read-only (get-last-token-id) 13 | (ok (var-get last-token-id)) 14 | ) 15 | 16 | (define-read-only (get-token-uri (tokenId uint)) 17 | (ok none) 18 | ) 19 | 20 | (define-read-only (get-owner (tokenId uint)) 21 | (ok (nft-get-owner? Stacker-Dao-Token tokenId)) 22 | ) 23 | 24 | (define-public (transfer (tokenId uint) (sender principal) (recipient principal)) 25 | (begin 26 | (asserts! (is-eq tx-sender sender) ERR_NOT_TOKEN_OWNER) 27 | (nft-transfer? Stacker-Dao-Token tokenId sender recipient) 28 | ) 29 | ) 30 | 31 | (define-public (mint (recipient principal)) 32 | (let 33 | ( 34 | (tokenId (+ (var-get last-token-id) u1)) 35 | ) 36 | (asserts! (is-eq tx-sender CONTRACT_OWNER) ERR_ONLY_OWNER) 37 | (try! (nft-mint? Stacker-Dao-Token tokenId recipient)) 38 | (var-set last-token-id tokenId) 39 | (ok tokenId) 40 | ) 41 | ) -------------------------------------------------------------------------------- /contracts/proposals/bootstraps/sdp-citycoins-dao.clar: -------------------------------------------------------------------------------- 1 | ;; _____________ _______ _________ ___ ___ ____ ____ 2 | ;; / __/_ __/ _ |/ ___/ //_/ __/ _ \/ _ \/ _ |/ __ \/ __/ 3 | ;; _\ \ / / / __ / /__/ ,< / _// , _/ // / __ / /_/ /\ \ 4 | ;; /___/ /_/ /_/ |_\___/_/|_/___/_/|_/____/_/ |_\____/___/ 5 | ;; 6 | ;; ___ ___ ____ ___ ____ _______ __ 7 | ;; / _ \/ _ \/ __ \/ _ \/ __ \/ __/ _ | / / 8 | ;; / ___/ , _/ /_/ / ___/ /_/ /\ \/ __ |/ /__ 9 | ;; /_/ /_/|_|\____/_/ \____/___/_/ |_/____/ 10 | ;; 11 | 12 | ;; Title: SDP Delegate Voting DAO 13 | ;; Author: StackerDAO Dev Team 14 | ;; Type: Bootstrap 15 | 16 | (impl-trait .proposal-trait.proposal-trait) 17 | 18 | (define-public (execute (sender principal)) 19 | (begin 20 | (let 21 | ( 22 | (decimals (unwrap-panic (contract-call? .sde-sip10-token get-decimals))) 23 | (microTokens (pow u10 decimals)) 24 | ) 25 | 26 | ;; Enable extensions. 27 | (try! (contract-call? .executor-dao set-extensions 28 | (list 29 | {extension: .sde-vault, enabled: true} 30 | {extension: .sde-citycoin-token, enabled: true} 31 | {extension: .sde-proposal-submission, enabled: true} 32 | {extension: .sde-proposal-voting, enabled: true} 33 | ) 34 | )) 35 | 36 | ;; Whitelist token 37 | (try! (contract-call? .sde-vault set-whitelist .sde-citycoin-token true)) 38 | (try! (contract-call? .sde-vault set-whitelist .sde-miamicoin-token true)) 39 | (try! (contract-call? .sde-vault set-whitelist .sde-newyorkcoin-token true)) 40 | 41 | ;; Change minimum start delay 42 | (try! (contract-call? .sde-proposal-submission set-parameter "minimumProposalStartDelay" u10)) 43 | 44 | ;; Change duration of voting 45 | (try! (contract-call? .sde-proposal-submission set-parameter "proposalDuration" u50)) 46 | 47 | ;; Change execution delay 48 | (try! (contract-call? .sde-proposal-voting set-parameter "executionDelay" u25)) 49 | 50 | ;; Mint 237,500k tokens to the DAO treasury upon initialization. 51 | (try! (contract-call? .sde-citycoin-token mint (* microTokens u480000) .sde-vault)) 52 | (try! (contract-call? .sde-miamicoin-token mint (* microTokens u215000) .sde-vault)) 53 | (try! (contract-call? .sde-newyorkcoin-token mint (* microTokens u185750) .sde-vault)) 54 | 55 | ;; Mint 12,500 tokens (min for delegation and quorum) to the deployer. 56 | (try! (contract-call? .sde-citycoin-token mint (* microTokens u25000) sender)) 57 | (try! (contract-call? .sde-citycoin-token mint (* microTokens u5000) 'ST2ST2H80NP5C9SPR4ENJ1Z9CDM9PKAJVPYWPQZ50)) 58 | (try! (contract-call? .sde-citycoin-token mint (* microTokens u2500) 'ST2Y2SFNVZBT8SSZ00XXKH930MCN0RFREB2GQG7CJ)) 59 | (try! (contract-call? .sde-citycoin-token mint (* microTokens u3500) 'STPJ2HPED2TMR1HAFBFA5VQF986CRD4ZWHH36F6X)) 60 | (try! (contract-call? .sde-citycoin-token mint (* microTokens u1500) 'ST2GG57WCVCS6AAVSKRHSKP10HJTQZ0M4AVTM0NAQ)) 61 | (try! (contract-call? .sde-citycoin-token mint (* microTokens u5000) 'ST2RMJ7Y80B7MD438K60M2FSTEZNQGKYTYF21P9KC)) 62 | 63 | 64 | (print {message: "...to be a completely separate network and separate block chain, yet share CPU power with Bitcoin.", sender: sender}) 65 | (ok true) 66 | ) 67 | ) 68 | ) 69 | -------------------------------------------------------------------------------- /contracts/proposals/bootstraps/sdp-delegate-voting-dao.clar: -------------------------------------------------------------------------------- 1 | ;; _____________ _______ _________ ___ ___ ____ ____ 2 | ;; / __/_ __/ _ |/ ___/ //_/ __/ _ \/ _ \/ _ |/ __ \/ __/ 3 | ;; _\ \ / / / __ / /__/ ,< / _// , _/ // / __ / /_/ /\ \ 4 | ;; /___/ /_/ /_/ |_\___/_/|_/___/_/|_/____/_/ |_\____/___/ 5 | ;; 6 | ;; ___ ___ ____ ___ ____ _______ __ 7 | ;; / _ \/ _ \/ __ \/ _ \/ __ \/ __/ _ | / / 8 | ;; / ___/ , _/ /_/ / ___/ /_/ /\ \/ __ |/ /__ 9 | ;; /_/ /_/|_|\____/_/ \____/___/_/ |_/____/ 10 | ;; 11 | 12 | ;; Title: SDP Delegate Voting DAO 13 | ;; Author: StackerDAO Dev Team 14 | ;; Type: Bootstrap 15 | 16 | (impl-trait .proposal-trait.proposal-trait) 17 | 18 | (define-public (execute (sender principal)) 19 | (begin 20 | (let 21 | ( 22 | (decimals (unwrap-panic (contract-call? .sde-sip10-token get-decimals))) 23 | (microTokens (pow u10 decimals)) 24 | ) 25 | 26 | ;; Enable extensions. 27 | (try! (contract-call? .executor-dao set-extensions 28 | (list 29 | {extension: .sde-vault, enabled: true} 30 | {extension: .sde-sip10-token, enabled: true} 31 | {extension: .sde-proposal-submission, enabled: true} 32 | {extension: .sde-proposal-voting, enabled: true} 33 | ) 34 | )) 35 | 36 | ;; Whitelist token 37 | (try! (contract-call? .sde-vault set-whitelist .sde-sip10-token true)) 38 | 39 | ;; Change minimum start delay 40 | (try! (contract-call? .sde-proposal-submission set-parameter "minimumProposalStartDelay" u10)) 41 | 42 | ;; Change duration of voting 43 | (try! (contract-call? .sde-proposal-submission set-parameter "proposalDuration" u85)) 44 | 45 | ;; Change execution delay 46 | (try! (contract-call? .sde-proposal-voting set-parameter "executionDelay" u50)) 47 | 48 | ;; Mint 237,500k tokens to the DAO treasury upon initialization. 49 | (try! (contract-call? .sde-sip10-token mint (* microTokens u480000) .sde-vault)) 50 | ;; Mint 12,500 tokens (min for delegation and quorum) to the deployer. 51 | (try! (contract-call? .sde-sip10-token mint (* microTokens u25000) sender)) 52 | (try! (contract-call? .sde-sip10-token mint (* microTokens u5000) 'ST2ST2H80NP5C9SPR4ENJ1Z9CDM9PKAJVPYWPQZ50)) 53 | (try! (contract-call? .sde-sip10-token mint (* microTokens u2500) 'ST2Y2SFNVZBT8SSZ00XXKH930MCN0RFREB2GQG7CJ)) 54 | (try! (contract-call? .sde-sip10-token mint (* microTokens u3500) 'STPJ2HPED2TMR1HAFBFA5VQF986CRD4ZWHH36F6X)) 55 | (try! (contract-call? .sde-sip10-token mint (* microTokens u1500) 'ST2GG57WCVCS6AAVSKRHSKP10HJTQZ0M4AVTM0NAQ)) 56 | (try! (contract-call? .sde-sip10-token mint (* microTokens u5000) 'ST2RMJ7Y80B7MD438K60M2FSTEZNQGKYTYF21P9KC)) 57 | 58 | 59 | (print {message: "...to be a completely separate network and separate block chain, yet share CPU power with Bitcoin.", sender: sender}) 60 | (ok true) 61 | ) 62 | ) 63 | ) 64 | -------------------------------------------------------------------------------- /contracts/proposals/bootstraps/sdp-multisignature-dao.clar: -------------------------------------------------------------------------------- 1 | ;; _____________ _______ _________ ___ ___ ____ ____ 2 | ;; / __/_ __/ _ |/ ___/ //_/ __/ _ \/ _ \/ _ |/ __ \/ __/ 3 | ;; _\ \ / / / __ / /__/ ,< / _// , _/ // / __ / /_/ /\ \ 4 | ;; /___/ /_/ /_/ |_\___/_/|_/___/_/|_/____/_/ |_\____/___/ 5 | ;; 6 | ;; ___ ___ ____ ___ ____ _______ __ 7 | ;; / _ \/ _ \/ __ \/ _ \/ __ \/ __/ _ | / / 8 | ;; / ___/ , _/ /_/ / ___/ /_/ /\ \/ __ |/ /__ 9 | ;; /_/ /_/|_|\____/_/ \____/___/_/ |_/____/ 10 | ;; 11 | 12 | ;; Title: SDP Multisignature DAO 13 | ;; Author: StackerDAO Dev Team 14 | ;; Type: Bootstrap 15 | 16 | (impl-trait .proposal-trait.proposal-trait) 17 | 18 | (define-public (execute (sender principal)) 19 | (begin 20 | ;; Enable extensions. 21 | (try! (contract-call? .executor-dao set-extensions 22 | (list 23 | {extension: .sde-vault, enabled: true} 24 | {extension: .sde-multisig, enabled: true} 25 | ) 26 | )) 27 | 28 | ;; Whitelist fungible tokens for the vault. 29 | (try! (contract-call? .sde-vault set-whitelists 30 | (list 31 | {token: .citycoin-token, enabled: true} 32 | ) 33 | )) 34 | 35 | ;; Add members to the multisig. 36 | (try! (contract-call? .sde-multisig add-signer 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM)) 37 | (try! (contract-call? .sde-multisig add-signer 'ST1SJ3DTE5DN7X54YDH5D64R3BCB6A2AG2ZQ8YPD5)) 38 | (try! (contract-call? .sde-multisig add-signer 'ST2CY5V39NHDPWSXMW9QDT3HC3GD6Q6XX4CFRK9AG)) 39 | 40 | (print {message: "...to be a completely separate network and separate block chain, yet share CPU power with Bitcoin.", sender: sender}) 41 | (ok true) 42 | ) 43 | ) 44 | -------------------------------------------------------------------------------- /contracts/proposals/bootstraps/sdp-nft-dao.clar: -------------------------------------------------------------------------------- 1 | ;; _____________ _______ _________ ___ ___ ____ ____ 2 | ;; / __/_ __/ _ |/ ___/ //_/ __/ _ \/ _ \/ _ |/ __ \/ __/ 3 | ;; _\ \ / / / __ / /__/ ,< / _// , _/ // / __ / /_/ /\ \ 4 | ;; /___/ /_/ /_/ |_\___/_/|_/___/_/|_/____/_/ |_\____/___/ 5 | ;; 6 | ;; ___ ___ ____ ___ ____ _______ __ 7 | ;; / _ \/ _ \/ __ \/ _ \/ __ \/ __/ _ | / / 8 | ;; / ___/ , _/ /_/ / ___/ /_/ /\ \/ __ |/ /__ 9 | ;; /_/ /_/|_|\____/_/ \____/___/_/ |_/____/ 10 | ;; 11 | 12 | ;; Title: SDP NFT DAO 13 | ;; Author: StackerDAO Dev Team 14 | ;; Type: Bootstrap 15 | 16 | (impl-trait .proposal-trait.proposal-trait) 17 | 18 | (define-public (execute (sender principal)) 19 | (begin 20 | ;; Enable extensions. 21 | (try! (contract-call? .executor-dao set-extensions 22 | (list 23 | {extension: .sde-vault, enabled: true} 24 | {extension: .sde-proposal-submission-with-nft, enabled: true} 25 | {extension: .sde-proposal-voting-with-nft, enabled: true} 26 | ) 27 | )) 28 | 29 | (print {message: "...to be a completely separate network and separate block chain, yet share CPU power with Bitcoin.", sender: sender}) 30 | (ok true) 31 | ) 32 | ) 33 | -------------------------------------------------------------------------------- /contracts/proposals/bootstraps/sdp-stackerdao.clar: -------------------------------------------------------------------------------- 1 | ;; _____________ _______ _________ ___ ___ ____ ____ 2 | ;; / __/_ __/ _ |/ ___/ //_/ __/ _ \/ _ \/ _ |/ __ \/ __/ 3 | ;; _\ \ / / / __ / /__/ ,< / _// , _/ // / __ / /_/ /\ \ 4 | ;; /___/ /_/ /_/ |_\___/_/|_/___/_/|_/____/_/ |_\____/___/ 5 | ;; 6 | ;; ___ ___ ____ ___ ____ _______ __ 7 | ;; / _ \/ _ \/ __ \/ _ \/ __ \/ __/ _ | / / 8 | ;; / ___/ , _/ /_/ / ___/ /_/ /\ \/ __ |/ /__ 9 | ;; /_/ /_/|_|\____/_/ \____/___/_/ |_/____/ 10 | ;; 11 | 12 | ;; Title: SDP Delegate Voting DAO 13 | ;; Author: StackerDAO Dev Team 14 | ;; Type: Bootstrap 15 | 16 | (impl-trait .proposal-trait.proposal-trait) 17 | 18 | (define-public (execute (sender principal)) 19 | (begin 20 | (let 21 | ( 22 | (decimals (unwrap-panic (contract-call? .sde-stackerdao-token get-decimals))) 23 | (microTokens (pow u10 decimals)) 24 | ) 25 | 26 | ;; Enable extensions. 27 | (try! (contract-call? .executor-dao set-extensions 28 | (list 29 | {extension: .sde-vault, enabled: true} 30 | {extension: .sde-stackerdao-token, enabled: true} 31 | {extension: .sde-proposal-submission, enabled: true} 32 | {extension: .sde-proposal-voting, enabled: true} 33 | ) 34 | )) 35 | 36 | ;; Whitelist token 37 | (try! (contract-call? .sde-vault set-whitelist .sde-stackerdao-token true)) 38 | (try! (contract-call? .sde-vault set-whitelist .sde-miamicoin-token true)) 39 | (try! (contract-call? .sde-vault set-whitelist .sde-newyorkcoin-token true)) 40 | 41 | ;; Change minimum start delay 42 | (try! (contract-call? .sde-proposal-submission set-parameter "minimumProposalStartDelay" u25)) 43 | 44 | ;; Change duration of voting 45 | (try! (contract-call? .sde-proposal-submission set-parameter "proposalDuration" u75)) 46 | 47 | ;; Change execution delay 48 | (try! (contract-call? .sde-proposal-voting set-parameter "executionDelay" u25)) 49 | 50 | ;; Mint 237,500k tokens to the DAO treasury upon initialization. 51 | (try! (contract-call? .sde-stackerdao-token mint (* microTokens u700000) .sde-vault)) 52 | (try! (contract-call? .sde-miamicoin-token mint (* microTokens u215000) .sde-vault)) 53 | (try! (contract-call? .sde-newyorkcoin-token mint (* microTokens u185750) .sde-vault)) 54 | 55 | ;; Mint 12,500 tokens (min for delegation and quorum) to the deployer. 56 | (try! (contract-call? .sde-stackerdao-token mint (* microTokens u100000) sender)) 57 | (try! (contract-call? .sde-stackerdao-token mint (* microTokens u100000) 'ST2ST2H80NP5C9SPR4ENJ1Z9CDM9PKAJVPYWPQZ50)) 58 | (try! (contract-call? .sde-stackerdao-token mint (* microTokens u100000) 'ST2Y2SFNVZBT8SSZ00XXKH930MCN0RFREB2GQG7CJ)) 59 | 60 | 61 | (print {message: "...to be a completely separate network and separate block chain, yet share CPU power with Bitcoin.", sender: sender}) 62 | (ok true) 63 | ) 64 | ) 65 | ) 66 | -------------------------------------------------------------------------------- /contracts/proposals/bootstraps/sdp-vault.clar: -------------------------------------------------------------------------------- 1 | ;; _____________ _______ _________ ___ ___ ____ ____ 2 | ;; / __/_ __/ _ |/ ___/ //_/ __/ _ \/ _ \/ _ |/ __ \/ __/ 3 | ;; _\ \ / / / __ / /__/ ,< / _// , _/ // / __ / /_/ /\ \ 4 | ;; /___/ /_/ /_/ |_\___/_/|_/___/_/|_/____/_/ |_\____/___/ 5 | ;; 6 | ;; ___ ___ ____ ___ ____ _______ __ 7 | ;; / _ \/ _ \/ __ \/ _ \/ __ \/ __/ _ | / / 8 | ;; / ___/ , _/ /_/ / ___/ /_/ /\ \/ __ |/ /__ 9 | ;; /_/ /_/|_|\____/_/ \____/___/_/ |_/____/ 10 | ;; 11 | 12 | ;; Title: SDP Multisignature DAO 13 | ;; Author: StackerDAO Dev Team 14 | ;; Type: Bootstrap 15 | 16 | (impl-trait .proposal-trait.proposal-trait) 17 | 18 | (define-public (execute (sender principal)) 19 | (begin 20 | ;; Enable extensions. 21 | (try! (contract-call? .executor-dao set-extensions 22 | (list 23 | {extension: .sde-vault, enabled: true} 24 | ) 25 | )) 26 | 27 | ;; Whitelist fungible tokens for the vault. 28 | (try! (contract-call? .sde-vault set-whitelists 29 | (list 30 | {token: .citycoin-token, enabled: false} 31 | {token: .ft-membership, enabled: true} 32 | {token: .nft-membership, enabled: true} 33 | ) 34 | )) 35 | 36 | (print {message: "...to be a completely separate network and separate block chain, yet share CPU power with Bitcoin.", sender: sender}) 37 | (ok true) 38 | ) 39 | ) 40 | -------------------------------------------------------------------------------- /contracts/proposals/management/sdp-whitelist-asset.clar: -------------------------------------------------------------------------------- 1 | ;; _____________ _______ _________ ___ ___ ____ ____ 2 | ;; / __/_ __/ _ |/ ___/ //_/ __/ _ \/ _ \/ _ |/ __ \/ __/ 3 | ;; _\ \ / / / __ / /__/ ,< / _// , _/ // / __ / /_/ /\ \ 4 | ;; /___/ /_/ /_/ |_\___/_/|_/___/_/|_/____/_/ |_\____/___/ 5 | ;; 6 | ;; ___ ___ ____ ___ ____ _______ __ 7 | ;; / _ \/ _ \/ __ \/ _ \/ __ \/ __/ _ | / / 8 | ;; / ___/ , _/ /_/ / ___/ /_/ /\ \/ __ |/ /__ 9 | ;; /_/ /_/|_|\____/_/ \____/___/_/ |_/____/ 10 | ;; 11 | 12 | ;; Title: SDP Whitelist Asset 13 | ;; Author: StackerDAO Dev Team 14 | ;; Type: Management 15 | 16 | (impl-trait .proposal-trait.proposal-trait) 17 | 18 | (define-public (execute (sender principal)) 19 | (begin 20 | (try! (contract-call? .sde-vault set-whitelist .sde-sip10-token true)) 21 | 22 | (print {event: "execute", sender: sender}) 23 | (ok true) 24 | ) 25 | ) 26 | -------------------------------------------------------------------------------- /contracts/proposals/multisignature/sdp-add-signer.clar: -------------------------------------------------------------------------------- 1 | ;; _____________ _______ _________ ___ ___ ____ ____ 2 | ;; / __/_ __/ _ |/ ___/ //_/ __/ _ \/ _ \/ _ |/ __ \/ __/ 3 | ;; _\ \ / / / __ / /__/ ,< / _// , _/ // / __ / /_/ /\ \ 4 | ;; /___/ /_/ /_/ |_\___/_/|_/___/_/|_/____/_/ |_\____/___/ 5 | ;; 6 | ;; ___ ___ ____ ___ ____ _______ __ 7 | ;; / _ \/ _ \/ __ \/ _ \/ __ \/ __/ _ | / / 8 | ;; / ___/ , _/ /_/ / ___/ /_/ /\ \/ __ |/ /__ 9 | ;; /_/ /_/|_|\____/_/ \____/___/_/ |_/____/ 10 | ;; 11 | 12 | ;; Title: SDP Add Signer 13 | ;; Author: StackerDAO Dev Team 14 | ;; Type: Operational 15 | ;; Description: Adds a new member to the Multisig. This signer will have all the same rights as the existing signers. In order to remove a member, another proposal will need to be created and signed to remove them from the Multisig. 16 | 17 | (impl-trait .proposal-trait.proposal-trait) 18 | 19 | (define-public (execute (sender principal)) 20 | (begin 21 | (try! (contract-call? .sde-multisig add-signer 'ST2JHG361ZXG51QTKY2NQCVBPPRRE2KZB1HR05NNC)) 22 | (try! (contract-call? .sde-multisig set-signals-required u3)) 23 | 24 | (print {event: "execute", sender: sender}) 25 | (ok true) 26 | ) 27 | ) 28 | -------------------------------------------------------------------------------- /contracts/proposals/sdp-dev-fund.clar: -------------------------------------------------------------------------------- 1 | ;; _____________ _______ _________ ___ ___ ____ ____ 2 | ;; / __/_ __/ _ |/ ___/ //_/ __/ _ \/ _ \/ _ |/ __ \/ __/ 3 | ;; _\ \ / / / __ / /__/ ,< / _// , _/ // / __ / /_/ /\ \ 4 | ;; /___/ /_/ /_/ |_\___/_/|_/___/_/|_/____/_/ |_\____/___/ 5 | ;; 6 | ;; ___ ___ ____ ___ ____ _______ __ 7 | ;; / _ \/ _ \/ __ \/ _ \/ __ \/ __/ _ | / / 8 | ;; / ___/ , _/ /_/ / ___/ /_/ /\ \/ __ |/ /__ 9 | ;; /_/ /_/|_|\____/_/ \____/___/_/ |_/____/ 10 | ;; 11 | 12 | ;; Title: SDP Dev fund 13 | ;; Author: StackerDAO Dev Team 14 | ;; Type: External 15 | ;; Description: 16 | ;; If this proposal passes, it mints new governance tokens equal to 30% of the total 17 | ;; supply and awards them to the SDE005 Dev Fund extension. It contains a number of 18 | ;; principals and set allowances. Any principal with an allowance is able to claim 19 | ;; an amount of tokens equal to the allowance on a (roughly) monthly basis. 20 | ;; Principals can be added and removed, and allowances can be changed via future 21 | ;; proposals. 22 | 23 | (impl-trait .proposal-trait.proposal-trait) 24 | 25 | (define-constant DEV_FUND_PERCENTAGE u30) 26 | 27 | (define-public (execute (sender principal)) 28 | (let 29 | ( 30 | (totalSupply (unwrap-panic (contract-call? .sde-governance-token-with-lockup get-total-supply))) 31 | (devFundAmount (/ (* totalSupply DEV_FUND_PERCENTAGE) u100)) 32 | ) 33 | (try! (contract-call? .executor-dao set-extension .sde-dev-fund true)) 34 | (try! (contract-call? .sde-dev-fund set-allowance-start-height block-height)) 35 | (try! (contract-call? .sde-dev-fund set-developer-allowances (list 36 | {who: 'ST2CY5V39NHDPWSXMW9QDT3HC3GD6Q6XX4CFRK9AG, allowance: u100} 37 | {who: 'ST2JHG361ZXG51QTKY2NQCVBPPRRE2KZB1HR05NNC, allowance: u20} 38 | ))) 39 | 40 | (print {event: "execute", sender: sender}) 41 | (contract-call? .sde-governance-token-with-lockup mint devFundAmount .sde-dev-fund) 42 | ) 43 | ) 44 | -------------------------------------------------------------------------------- /contracts/proposals/sdp-disable-emergency-powers.clar: -------------------------------------------------------------------------------- 1 | ;; _____________ _______ _________ ___ ___ ____ ____ 2 | ;; / __/_ __/ _ |/ ___/ //_/ __/ _ \/ _ \/ _ |/ __ \/ __/ 3 | ;; _\ \ / / / __ / /__/ ,< / _// , _/ // / __ / /_/ /\ \ 4 | ;; /___/ /_/ /_/ |_\___/_/|_/___/_/|_/____/_/ |_\____/___/ 5 | ;; 6 | ;; ___ ___ ____ ___ ____ _______ __ 7 | ;; / _ \/ _ \/ __ \/ _ \/ __ \/ __/ _ | / / 8 | ;; / ___/ , _/ /_/ / ___/ /_/ /\ \/ __ |/ /__ 9 | ;; /_/ /_/|_|\____/_/ \____/___/_/ |_/____/ 10 | ;; 11 | 12 | ;; Title: SDP Disable Emergency Powers 13 | ;; Author: StackerDAO Dev Team 14 | ;; Type: Operational 15 | ;; Description: 16 | ;; Disabled both emergency extensions and removes the ability to 17 | ;; propose and execute any emergency proposals on behalf of the DAO. 18 | 19 | (impl-trait .proposal-trait.proposal-trait) 20 | 21 | (define-public (execute (sender principal)) 22 | (begin 23 | (try! (contract-call? .executor-dao set-extension .sde-emergency-execute false)) 24 | (try! (contract-call? .executor-dao set-extension .sde-emergency-proposals false)) 25 | 26 | (print {event: "execute", sender: sender}) 27 | (ok true) 28 | ) 29 | ) 30 | -------------------------------------------------------------------------------- /contracts/proposals/sdp-token-vesting.clar: -------------------------------------------------------------------------------- 1 | ;; _____________ _______ _________ ___ ___ ____ ____ 2 | ;; / __/_ __/ _ |/ ___/ //_/ __/ _ \/ _ \/ _ |/ __ \/ __/ 3 | ;; _\ \ / / / __ / /__/ ,< / _// , _/ // / __ / /_/ /\ \ 4 | ;; /___/ /_/ /_/ |_\___/_/|_/___/_/|_/____/_/ |_\____/___/ 5 | ;; 6 | ;; ___ ___ ____ ___ ____ _______ __ 7 | ;; / _ \/ _ \/ __ \/ _ \/ __ \/ __/ _ | / / 8 | ;; / ___/ , _/ /_/ / ___/ /_/ /\ \/ __ |/ /__ 9 | ;; /_/ /_/|_|\____/_/ \____/___/_/ |_/____/ 10 | ;; 11 | 12 | ;; Title: SDP Dev fund 13 | ;; Author: StackerDAO Dev Team 14 | ;; Type: External 15 | ;; Description: 16 | ;; If this proposal passes, it mints new governance tokens equal to 30% of the total 17 | ;; supply and awards them to the SDE005 Dev Fund extension. It contains a number of 18 | ;; principals and set allowances. Any principal with an allowance is able to claim 19 | ;; an amount of tokens equal to the allowance on a (roughly) monthly basis. 20 | ;; Principals can be added and removed, and allowances can be changed via future 21 | ;; proposals. 22 | 23 | (impl-trait .proposal-trait.proposal-trait) 24 | 25 | (define-public (execute (sender principal)) 26 | (let 27 | ( 28 | (decimals (unwrap-panic (contract-call? .sde-governance-token get-decimals))) 29 | (totalSupply (* (pow u10 decimals) u100000000)) ;; 100m tokens 30 | (issuedAmount (/ (* totalSupply u30) u100)) ;; 30% of total supply 31 | (microTokens (pow u10 decimals)) 32 | ) 33 | (try! (contract-call? .executor-dao set-extension .sde-token-vesting true)) 34 | (try! (contract-call? .sde-token-vesting set-issuance-start-height block-height)) 35 | (try! (contract-call? .sde-token-vesting set-investor-issuances (list 36 | {who: 'ST2CY5V39NHDPWSXMW9QDT3HC3GD6Q6XX4CFRK9AG, amount: (* microTokens u100)} 37 | {who: 'ST2JHG361ZXG51QTKY2NQCVBPPRRE2KZB1HR05NNC, amount: (* microTokens u20)} 38 | ))) 39 | 40 | (print {event: "execute", sender: sender}) 41 | (contract-call? .sde-governance-token mint issuedAmount .sde-token-vesting) 42 | ) 43 | ) 44 | -------------------------------------------------------------------------------- /contracts/proposals/transfers/sdp-transfer-ft.clar: -------------------------------------------------------------------------------- 1 | ;; _____________ _______ _________ ___ ___ ____ ____ 2 | ;; / __/_ __/ _ |/ ___/ //_/ __/ _ \/ _ \/ _ |/ __ \/ __/ 3 | ;; _\ \ / / / __ / /__/ ,< / _// , _/ // / __ / /_/ /\ \ 4 | ;; /___/ /_/ /_/ |_\___/_/|_/___/_/|_/____/_/ |_\____/___/ 5 | ;; 6 | ;; ___ ___ ____ ___ ____ _______ __ 7 | ;; / _ \/ _ \/ __ \/ _ \/ __ \/ __/ _ | / / 8 | ;; / ___/ , _/ /_/ / ___/ /_/ /\ \/ __ |/ /__ 9 | ;; /_/ /_/|_|\____/_/ \____/___/_/ |_/____/ 10 | ;; 11 | 12 | ;; Title: SDP Transfer Fungible Tokens 13 | ;; Author: StackerDAO Dev Team 14 | ;; Type: Transfer 15 | 16 | (impl-trait .proposal-trait.proposal-trait) 17 | 18 | (define-constant MICRO (pow u10 u2)) 19 | 20 | (define-public (execute (sender principal)) 21 | (begin 22 | (try! (contract-call? .sde-vault transfer-ft .sde-governance-token-with-delegation (* MICRO u100) 'STNHKEPYEPJ8ET55ZZ0M5A34J0R3N5FM2CMMMAZ6)) 23 | 24 | (print {event: "execute", sender: sender}) 25 | (ok true) 26 | ) 27 | ) 28 | -------------------------------------------------------------------------------- /contracts/proposals/transfers/sdp-transfer-nft.clar: -------------------------------------------------------------------------------- 1 | ;; _____________ _______ _________ ___ ___ ____ ____ 2 | ;; / __/_ __/ _ |/ ___/ //_/ __/ _ \/ _ \/ _ |/ __ \/ __/ 3 | ;; _\ \ / / / __ / /__/ ,< / _// , _/ // / __ / /_/ /\ \ 4 | ;; /___/ /_/ /_/ |_\___/_/|_/___/_/|_/____/_/ |_\____/___/ 5 | ;; 6 | ;; ___ ___ ____ ___ ____ _______ __ 7 | ;; / _ \/ _ \/ __ \/ _ \/ __ \/ __/ _ | / / 8 | ;; / ___/ , _/ /_/ / ___/ /_/ /\ \/ __ |/ /__ 9 | ;; /_/ /_/|_|\____/_/ \____/___/_/ |_/____/ 10 | ;; 11 | 12 | ;; Title: SDP Transfer NFT 13 | ;; Author: StackerDAO Dev Team 14 | ;; Description: Transfer an NFT Membership to STNHKEPYEPJ8ET55ZZ0M5A34J0R3N5FM2CMMMAZ6 for helping support the project. 15 | ;; Type: Transfer 16 | 17 | (impl-trait .proposal-trait.proposal-trait) 18 | 19 | (define-public (execute (sender principal)) 20 | (begin 21 | (try! (contract-call? .sde-vault transfer-nft .nft-membership u1 'STNHKEPYEPJ8ET55ZZ0M5A34J0R3N5FM2CMMMAZ6)) 22 | 23 | (print {event: "execute", sender: sender}) 24 | (ok true) 25 | ) 26 | ) 27 | -------------------------------------------------------------------------------- /contracts/proposals/transfers/sdp-transfer-stx.clar: -------------------------------------------------------------------------------- 1 | ;; _____________ _______ _________ ___ ___ ____ ____ 2 | ;; / __/_ __/ _ |/ ___/ //_/ __/ _ \/ _ \/ _ |/ __ \/ __/ 3 | ;; _\ \ / / / __ / /__/ ,< / _// , _/ // / __ / /_/ /\ \ 4 | ;; /___/ /_/ /_/ |_\___/_/|_/___/_/|_/____/_/ |_\____/___/ 5 | ;; 6 | ;; ___ ___ ____ ___ ____ _______ __ 7 | ;; / _ \/ _ \/ __ \/ _ \/ __ \/ __/ _ | / / 8 | ;; / ___/ , _/ /_/ / ___/ /_/ /\ \/ __ |/ /__ 9 | ;; /_/ /_/|_|\____/_/ \____/___/_/ |_/____/ 10 | ;; 11 | 12 | ;; Title: SDP Transfer Stacks 13 | ;; Author: StackerDAO Dev Team 14 | ;; Description: Transfer 100 STX to STNHKEPYEPJ8ET55ZZ0M5A34J0R3N5FM2CMMMAZ6 for developing features for the upcoming release. 15 | ;; Type: Transfer 16 | 17 | (impl-trait .proposal-trait.proposal-trait) 18 | 19 | (define-constant MICRO (pow u10 u6)) 20 | 21 | (define-public (execute (sender principal)) 22 | (begin 23 | (try! (contract-call? .sde-vault transfer (* MICRO u100) 'STNHKEPYEPJ8ET55ZZ0M5A34J0R3N5FM2CMMMAZ6)) 24 | 25 | (print {event: "execute", sender: sender}) 26 | (ok true) 27 | ) 28 | ) -------------------------------------------------------------------------------- /contracts/proposals/transfers/sdp-unauthorized-transfer-stx.clar: -------------------------------------------------------------------------------- 1 | ;; _____________ _______ _________ ___ ___ ____ ____ 2 | ;; / __/_ __/ _ |/ ___/ //_/ __/ _ \/ _ \/ _ |/ __ \/ __/ 3 | ;; _\ \ / / / __ / /__/ ,< / _// , _/ // / __ / /_/ /\ \ 4 | ;; /___/ /_/ /_/ |_\___/_/|_/___/_/|_/____/_/ |_\____/___/ 5 | ;; 6 | ;; ___ ___ ____ ___ ____ _______ __ 7 | ;; / _ \/ _ \/ __ \/ _ \/ __ \/ __/ _ | / / 8 | ;; / ___/ , _/ /_/ / ___/ /_/ /\ \/ __ |/ /__ 9 | ;; /_/ /_/|_|\____/_/ \____/___/_/ |_/____/ 10 | ;; 11 | 12 | ;; Title: SDP Transfer Stacks 13 | ;; Author: StackerDAO Dev Team 14 | ;; Type: Transfer 15 | 16 | (impl-trait .proposal-trait.proposal-trait) 17 | 18 | (define-public (execute (sender principal)) 19 | (begin 20 | (try! (stx-transfer? u100 .sde-vault 'STNHKEPYEPJ8ET55ZZ0M5A34J0R3N5FM2CMMMAZ6)) 21 | 22 | (print {event: "execute", sender: sender}) 23 | (ok true) 24 | ) 25 | ) 26 | -------------------------------------------------------------------------------- /contracts/traits/delegate-token-trait.clar: -------------------------------------------------------------------------------- 1 | (define-trait delegate-token-trait 2 | ( 3 | (has-percentage-weight (principal uint) (response bool uint)) 4 | (get-balance (principal) (response uint uint)) 5 | (mint (uint principal) (response bool uint)) 6 | (burn (uint principal) (response bool uint)) 7 | ) 8 | ) 9 | -------------------------------------------------------------------------------- /contracts/traits/extension-trait.clar: -------------------------------------------------------------------------------- 1 | (define-trait extension-trait 2 | ( 3 | (callback (principal (buff 34)) (response bool uint)) 4 | ) 5 | ) 6 | -------------------------------------------------------------------------------- /contracts/traits/governance-token-trait.clar: -------------------------------------------------------------------------------- 1 | (define-trait governance-token-trait 2 | ( 3 | (has-percentage-balance (principal uint) (response bool uint)) 4 | (lock (uint principal) (response bool uint)) 5 | (unlock (uint principal) (response bool uint)) 6 | (get-locked (principal) (response uint uint)) 7 | (mint (uint principal) (response bool uint)) 8 | (burn (uint principal) (response bool uint)) 9 | ) 10 | ) 11 | -------------------------------------------------------------------------------- /contracts/traits/member-trait.clar: -------------------------------------------------------------------------------- 1 | (define-trait member-trait 2 | ( 3 | (is-member (principal) (response bool bool)) 4 | (callback (principal (buff 34)) (response bool uint)) 5 | ) 6 | ) 7 | -------------------------------------------------------------------------------- /contracts/traits/ownable-trait.clar: -------------------------------------------------------------------------------- 1 | (define-trait ownable-trait 2 | ( 3 | (get-contract-owner () (response principal uint)) 4 | (set-contract-owner (principal) (response bool uint)) 5 | ) 6 | ) 7 | -------------------------------------------------------------------------------- /contracts/traits/proposal-trait.clar: -------------------------------------------------------------------------------- 1 | (define-trait proposal-trait 2 | ( 3 | (execute (principal) (response bool uint)) 4 | ) 5 | ) 6 | -------------------------------------------------------------------------------- /contracts/traits/sdt-governance-token-trait.clar: -------------------------------------------------------------------------------- 1 | (define-trait sdt-governance-token-trait 2 | ( 3 | (has-percentage-weight (principal uint) (response bool uint)) 4 | (get-balance (principal) (response uint uint)) 5 | (mint (uint principal) (response bool uint)) 6 | (burn (uint principal) (response bool uint)) 7 | ) 8 | ) 9 | -------------------------------------------------------------------------------- /contracts/traits/sip009-nft-trait.clar: -------------------------------------------------------------------------------- 1 | (define-trait sip009-nft-trait 2 | ( 3 | (get-last-token-id () (response uint uint)) 4 | 5 | (get-token-uri (uint) (response (optional (string-ascii 256)) uint)) 6 | 7 | (get-owner (uint) (response (optional principal) uint)) 8 | 9 | (transfer (uint principal principal) (response bool uint)) 10 | ) 11 | ) -------------------------------------------------------------------------------- /contracts/traits/sip010-ft-trait.clar: -------------------------------------------------------------------------------- 1 | (define-trait sip010-ft-trait 2 | ( 3 | (transfer (uint principal principal (optional (buff 34))) (response bool uint)) 4 | 5 | (get-name () (response (string-ascii 32) uint)) 6 | 7 | (get-symbol () (response (string-ascii 32) uint)) 8 | 9 | (get-decimals () (response uint uint)) 10 | 11 | (get-balance (principal) (response uint uint)) 12 | 13 | (get-total-supply () (response uint uint)) 14 | 15 | (get-token-uri () (response (optional (string-utf8 256)) uint)) 16 | ) 17 | ) 18 | -------------------------------------------------------------------------------- /docs/extensions.md: -------------------------------------------------------------------------------- 1 | # StackerDAO Extensions -------------------------------------------------------------------------------- /docs/proposals.md: -------------------------------------------------------------------------------- 1 | # StackerDAO Proposals -------------------------------------------------------------------------------- /settings/Devnet.toml: -------------------------------------------------------------------------------- 1 | [network] 2 | name = "devnet" 3 | deployment_fee_rate = 10 4 | 5 | [accounts.deployer] 6 | mnemonic = "twice kind fence tip hidden tilt action fragile skin nothing glory cousin green tomorrow spring wrist shed math olympic multiply hip blue scout claw" 7 | balance = 100_000_000_000_000 8 | secret_key = "753b7cc01a1a2e86221266a154af739463fce51219d97e4f856cd7200c3bd2a601" 9 | stx_address = "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM" 10 | # btc_address: mqVnk6NPRdhntvfm4hh9vvjiRkFDUuSYsH 11 | 12 | [accounts.wallet_1] 13 | mnemonic = "sell invite acquire kitten bamboo drastic jelly vivid peace spawn twice guilt pave pen trash pretty park cube fragile unaware remain midnight betray rebuild" 14 | balance = 100_000_000_000_000 15 | # secret_key: 7287ba251d44a4d3fd9276c88ce34c5c52a038955511cccaf77e61068649c17801 16 | # stx_address: ST1SJ3DTE5DN7X54YDH5D64R3BCB6A2AG2ZQ8YPD5 17 | # btc_address: mr1iPkD9N3RJZZxXRk7xF9d36gffa6exNC 18 | 19 | [accounts.wallet_2] 20 | mnemonic = "hold excess usual excess ring elephant install account glad dry fragile donkey gaze humble truck breeze nation gasp vacuum limb head keep delay hospital" 21 | balance = 100_000_000_000_000 22 | # secret_key: 530d9f61984c888536871c6573073bdfc0058896dc1adfe9a6a10dfacadc209101 23 | # stx_address: ST2CY5V39NHDPWSXMW9QDT3HC3GD6Q6XX4CFRK9AG 24 | # btc_address: muYdXKmX9bByAueDe6KFfHd5Ff1gdN9ErG 25 | 26 | [accounts.wallet_3] 27 | mnemonic = "cycle puppy glare enroll cost improve round trend wrist mushroom scorpion tower claim oppose clever elephant dinosaur eight problem before frozen dune wagon high" 28 | balance = 100_000_000_000_000 29 | # secret_key: d655b2523bcd65e34889725c73064feb17ceb796831c0e111ba1a552b0f31b3901 30 | # stx_address: ST2JHG361ZXG51QTKY2NQCVBPPRRE2KZB1HR05NNC 31 | # btc_address: mvZtbibDAAA3WLpY7zXXFqRa3T4XSknBX7 32 | 33 | [accounts.wallet_4] 34 | mnemonic = "board list obtain sugar hour worth raven scout denial thunder horse logic fury scorpion fold genuine phrase wealth news aim below celery when cabin" 35 | balance = 100_000_000_000_000 36 | # secret_key: f9d7206a47f14d2870c163ebab4bf3e70d18f5d14ce1031f3902fbbc894fe4c701 37 | # stx_address: ST2NEB84ASENDXKYGJPQW86YXQCEFEX2ZQPG87ND 38 | # btc_address: mg1C76bNTutiCDV3t9nWhZs3Dc8LzUufj8 39 | 40 | [accounts.wallet_5] 41 | mnemonic = "hurry aunt blame peanut heavy update captain human rice crime juice adult scale device promote vast project quiz unit note reform update climb purchase" 42 | balance = 100_000_000_000_000 43 | # secret_key: 3eccc5dac8056590432db6a35d52b9896876a3d5cbdea53b72400bc9c2099fe801 44 | # stx_address: ST2REHHS5J3CERCRBEPMGH7921Q6PYKAADT7JP2VB 45 | # btc_address: mweN5WVqadScHdA81aATSdcVr4B6dNokqx 46 | 47 | [accounts.wallet_6] 48 | mnemonic = "area desk dutch sign gold cricket dawn toward giggle vibrant indoor bench warfare wagon number tiny universe sand talk dilemma pottery bone trap buddy" 49 | balance = 100_000_000_000_000 50 | # secret_key: 7036b29cb5e235e5fd9b09ae3e8eec4404e44906814d5d01cbca968a60ed4bfb01 51 | # stx_address: ST3AM1A56AK2C1XAFJ4115ZSV26EB49BVQ10MGCS0 52 | # btc_address: mzxXgV6e4BZSsz8zVHm3TmqbECt7mbuErt 53 | 54 | [accounts.wallet_7] 55 | mnemonic = "prevent gallery kind limb income control noise together echo rival record wedding sense uncover school version force bleak nuclear include danger skirt enact arrow" 56 | balance = 100_000_000_000_000 57 | # secret_key: b463f0df6c05d2f156393eee73f8016c5372caa0e9e29a901bb7171d90dc4f1401 58 | # stx_address: ST3PF13W7Z0RRM42A8VZRVFQ75SV1K26RXEP8YGKJ 59 | # btc_address: n37mwmru2oaVosgfuvzBwgV2ysCQRrLko7 60 | 61 | [accounts.wallet_8] 62 | mnemonic = "female adjust gallery certain visit token during great side clown fitness like hurt clip knife warm bench start reunion globe detail dream depend fortune" 63 | balance = 100_000_000_000_000 64 | # secret_key: 6a1a754ba863d7bab14adbbc3f8ebb090af9e871ace621d3e5ab634e1422885e01 65 | # stx_address: ST3NBRSFKX28FQ2ZJ1MAKX58HKHSDGNV5N7R21XCP 66 | # btc_address: n2v875jbJ4RjBnTjgbfikDfnwsDV5iUByw 67 | 68 | [accounts.wallet_9] 69 | mnemonic = "shadow private easily thought say logic fault paddle word top book during ignore notable orange flight clock image wealth health outside kitten belt reform" 70 | balance = 100_000_000_000_000 71 | # secret_key: de433bdfa14ec43aa1098d5be594c8ffb20a31485ff9de2923b2689471c401b801 72 | # stx_address: STNHKEPYEPJ8ET55ZZ0M5A34J0R3N5FM2CMMMAZ6 73 | # btc_address: mjSrB3wS4xab3kYqFktwBzfTdPg367ZJ2d 74 | 75 | [devnet] 76 | disable_bitcoin_explorer = true 77 | # disable_stacks_explorer = true 78 | # disable_stacks_api = true 79 | # working_dir = "tmp/devnet" 80 | # stacks_node_events_observers = ["host.docker.internal:8002"] 81 | # miner_mnemonic = "twice kind fence tip hidden tilt action fragile skin nothing glory cousin green tomorrow spring wrist shed math olympic multiply hip blue scout claw" 82 | # miner_derivation_path = "m/44'/5757'/0'/0/0" 83 | # orchestrator_port = 20445 84 | # bitcoin_node_p2p_port = 18444 85 | # bitcoin_node_rpc_port = 18443 86 | # bitcoin_node_username = "devnet" 87 | # bitcoin_node_password = "devnet" 88 | # bitcoin_controller_port = 18442 89 | # bitcoin_controller_block_time = 30_000 90 | # stacks_node_rpc_port = 20443 91 | # stacks_node_p2p_port = 20444 92 | stacks_api_port = 3999 93 | stacks_api_events_port = 3700 94 | # bitcoin_explorer_port = 8001 95 | stacks_explorer_port = 8000 96 | # postgres_port = 5432 97 | # postgres_username = "postgres" 98 | # postgres_password = "postgres" 99 | # postgres_database = "postgres" 100 | # bitcoin_node_image_url = "quay.io/hirosystems/bitcoind:devnet" 101 | # stacks_node_image_url = "localhost:5000/stacks-node:devnet" 102 | stacks_api_image_url = "blockstack/stacks-blockchain-api:latest" 103 | # stacks_explorer_image_url = "blockstack/explorer:latest" 104 | # bitcoin_explorer_image_url = "quay.io/hirosystems/bitcoin-explorer:devnet" 105 | # postgres_image_url = "postgres:alpine" 106 | 107 | # Send some stacking orders 108 | [[devnet.pox_stacking_orders]] 109 | start_at_cycle = 3 110 | duration = 12 111 | wallet = "wallet_1" 112 | slots = 2 113 | btc_address = "mr1iPkD9N3RJZZxXRk7xF9d36gffa6exNC" 114 | 115 | [[devnet.pox_stacking_orders]] 116 | start_at_cycle = 3 117 | duration = 12 118 | wallet = "wallet_2" 119 | slots = 1 120 | btc_address = "muYdXKmX9bByAueDe6KFfHd5Ff1gdN9ErG" 121 | 122 | [[devnet.pox_stacking_orders]] 123 | start_at_cycle = 3 124 | duration = 12 125 | wallet = "wallet_3" 126 | slots = 1 127 | btc_address = "mvZtbibDAAA3WLpY7zXXFqRa3T4XSknBX7" 128 | -------------------------------------------------------------------------------- /tests/executor-dao_test.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Account, 3 | assertEquals, 4 | Clarinet, 5 | Chain, 6 | Tx, 7 | types, 8 | } from './utils/deps.ts'; 9 | import { BOOTSTRAPS, EXTENSIONS, EXECUTOR_DAO_CODES } from './utils/common.ts'; 10 | import { fetchApi } from './utils/api/executor-dao.ts'; 11 | 12 | Clarinet.test({ 13 | name: '`executor-dao` - initialize the dao', 14 | async fn(chain: Chain, accounts: Map) { 15 | const { init, isExtension } = fetchApi(accounts.get('deployer')!); 16 | const { receipts } = chain.mineBlock([ 17 | init(BOOTSTRAPS.MULTISIG_DAO), 18 | isExtension(EXTENSIONS.VAULT), 19 | ]) 20 | receipts[0].result.expectOk().expectBool(true); 21 | receipts[1].result.expectBool(true); 22 | }, 23 | }); 24 | 25 | Clarinet.test({ 26 | name: '`executor-dao` - should return unauthorized when trying to call init twice', 27 | async fn(chain: Chain, accounts: Map) { 28 | const { init } = fetchApi(accounts.get('deployer')!); 29 | const { receipts } = chain.mineBlock([ 30 | init(BOOTSTRAPS.MULTISIG_DAO), 31 | init(BOOTSTRAPS.MULTISIG_DAO), 32 | ]) 33 | receipts[0].result.expectOk().expectBool(true); 34 | receipts[1].result.expectErr().expectUint(EXECUTOR_DAO_CODES.ERR_UNAUTHORIZED); 35 | }, 36 | }); 37 | -------------------------------------------------------------------------------- /tests/multisignature_test.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Account, 3 | assertEquals, 4 | Clarinet, 5 | Chain, 6 | Tx, 7 | types, 8 | } from './utils/deps.ts'; 9 | import { BOOTSTRAPS, EXTENSIONS, PROPOSALS, MULTISIG_CODES } from './utils/common.ts'; 10 | import { fetchApi as executorApi } from './utils/api/executor-dao.ts'; 11 | import { fetchApi as multisigApi } from './utils/api/multisignature.ts'; 12 | 13 | Clarinet.test({ 14 | name: '`multisig` - add a signer', 15 | async fn(chain: Chain, accounts: Map) { 16 | const { init, isExtension } = await executorApi(accounts.get('deployer')!); 17 | const { 18 | addSigner, 19 | getSigner, 20 | propose, 21 | getProposalData, 22 | getSignalsRequired, 23 | getSignersCount, 24 | } = multisigApi(accounts.get('deployer')!); 25 | const newSigner = accounts.get('wallet_3')!; 26 | const { receipts } = chain.mineBlock([ 27 | addSigner(newSigner.address), 28 | getSigner(newSigner.address), 29 | ]); 30 | receipts[0].result.expectErr().expectUint(MULTISIG_CODES.ERR_UNAUTHORIZED); 31 | receipts[1].result.expectNone(); 32 | 33 | // Begin proposal process for adding a signer 34 | const { receipts: proposalReceipts } = chain.mineBlock([ 35 | init(BOOTSTRAPS.MULTISIG_DAO), 36 | isExtension(EXTENSIONS.MULTISIG), 37 | propose(PROPOSALS.SDP_ADD_SIGNER), 38 | getProposalData(PROPOSALS.SDP_ADD_SIGNER), 39 | ]); 40 | proposalReceipts[0].result.expectOk().expectBool(true); 41 | proposalReceipts[1].result.expectBool(true); 42 | proposalReceipts[2].result.expectOk().expectBool(true); 43 | assertEquals(proposalReceipts[3].result.expectSome().expectTuple(), { 44 | concluded: types.bool(false), 45 | proposer: accounts.get('deployer')!.address, 46 | }) 47 | 48 | // Another signer signs off on the proposal and executes automatically 49 | const signer = accounts.get('wallet_1')! 50 | const { sign } = multisigApi(signer); 51 | const { receipts: signerReceipts } = chain.mineBlock([ 52 | sign(PROPOSALS.SDP_ADD_SIGNER), 53 | getProposalData(PROPOSALS.SDP_ADD_SIGNER), 54 | getSigner(newSigner.address), 55 | getSignalsRequired(), 56 | getSignersCount(), 57 | ]); 58 | signerReceipts[0].result.expectOk().expectUint(2); 59 | assertEquals(signerReceipts[1].result.expectSome().expectTuple(), { 60 | concluded: types.bool(true), 61 | proposer: accounts.get('deployer')!.address, 62 | }) 63 | signerReceipts[2].result.expectSome().expectPrincipal(newSigner.address); 64 | signerReceipts[3].result.expectUint(3); 65 | signerReceipts[4].result.expectUint(4); 66 | }, 67 | }); 68 | 69 | Clarinet.test({ 70 | name: '`multisig` - unauthorized proposal failure', 71 | async fn(chain: Chain, accounts: Map, contracts: Map) { 72 | const { init, isExtension } = executorApi(accounts.get('deployer')!); 73 | const { propose, getProposalData } = multisigApi(accounts.get('deployer')!); 74 | const recipient = accounts.get('deployer')!.address; 75 | const { receipts } = chain.mineBlock([ 76 | init(BOOTSTRAPS.MULTISIG_DAO), 77 | propose(PROPOSALS.SDP_UNAUTHORIZED_TRANSFER_STX), 78 | getProposalData(PROPOSALS.SDP_UNAUTHORIZED_TRANSFER_STX), 79 | ]); 80 | receipts[0].result.expectOk().expectBool(true); 81 | receipts[1].result.expectOk().expectBool(true); 82 | assertEquals(receipts[2].result.expectSome().expectTuple(), { 83 | concluded: types.bool(false), 84 | proposer: accounts.get('deployer')!.address, 85 | }) 86 | 87 | // Another signer signs off on the proposal and executes automatically 88 | const signer = accounts.get('wallet_1')! 89 | const { sign } = multisigApi(signer); 90 | const { receipts: signerReceipts } = chain.mineBlock([ 91 | sign(PROPOSALS.SDP_ADD_SIGNER), 92 | sign(PROPOSALS.SDP_UNAUTHORIZED_TRANSFER_STX), 93 | ]); 94 | signerReceipts[0].result.expectErr().expectUint(MULTISIG_CODES.ERR_PROPOSAL_NOT_FOUND); 95 | signerReceipts[1].result.expectErr().expectUint(4); // returns (err u4) because the sender principal in proposal is not authorized 96 | }, 97 | }); -------------------------------------------------------------------------------- /tests/nft-membership/governance-nft_test.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Account, 3 | assertEquals, 4 | Clarinet, 5 | Chain, 6 | Tx, 7 | types, 8 | } from '../utils/deps.ts'; 9 | import { 10 | BOOTSTRAPS, 11 | EXTENSIONS, 12 | GOVERNANCE, 13 | PROPOSALS, 14 | NFT_VOTING_CODES, 15 | NFT_SUBMISSION_CODES, 16 | } from '../utils/common.ts'; 17 | import { fetchApi as executorApi } from '../utils/api/executor-dao.ts'; 18 | import { fetchApi as proposalApi } from '../utils/api/proposal-submission-with-nft.ts'; 19 | import { fetchApi as voteApi } from '../utils/api/proposal-voting-with-nft.ts'; 20 | import { fetchApi as nftApi } from '../utils/api/nft-membership.ts'; 21 | 22 | Clarinet.test({ 23 | name: '`nft governance` - initialize the dao', 24 | async fn(chain: Chain, accounts: Map) { 25 | const { init } = executorApi(accounts.get('deployer')!); 26 | let { receipts } = chain.mineBlock([ 27 | init(BOOTSTRAPS.NFT_DAO), 28 | ]); 29 | receipts[0].result.expectOk().expectBool(true); 30 | assertEquals(receipts[0].events.length, 6); 31 | }, 32 | }); 33 | 34 | Clarinet.test({ 35 | name: '`nft governance` - submit a proposal with invalid start block height', 36 | async fn(chain: Chain, accounts: Map) { 37 | const { init } = executorApi(accounts.get('deployer')!); 38 | const { mint } = nftApi(accounts.get('deployer')!); 39 | const { propose } = proposalApi(accounts.get('deployer')!); 40 | const invalidStartHeight = 144; 41 | let { receipts: mintReceipts } = chain.mineBlock([ 42 | mint(accounts.get('deployer')!.address), 43 | ]); 44 | mintReceipts[0].result.expectOk().expectUint(1); 45 | const tokenId = 1; 46 | let { receipts } = chain.mineBlock([ 47 | init(BOOTSTRAPS.NFT_DAO), 48 | propose(PROPOSALS.SDP_TRANSFER_FUNGIBLE_TOKENS, tokenId, invalidStartHeight), 49 | ]); 50 | receipts[1].result.expectErr().expectUint(NFT_SUBMISSION_CODES.ERR_PROPOSAL_MINIMUM_START_DELAY); 51 | }, 52 | }); 53 | -------------------------------------------------------------------------------- /tests/utils/api/executor-dao.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Account, 3 | Tx, 4 | types, 5 | } from '../deps.ts'; 6 | 7 | const call = (method: string, args: any[], address: string) => { 8 | return Tx.contractCall('executor-dao', method, args, address) 9 | }; 10 | 11 | export const fetchApi = ({ address }: Account) => ({ 12 | init: (proposal: any) => 13 | call('init', [types.principal(proposal)], address), 14 | isExtension: (extension: any) => 15 | call('is-extension', [types.principal(extension)], address), 16 | setExtension: (extension: any, enabled: any) => 17 | call('set-extension', [types.principal(extension), types.bool(enabled)], address), 18 | execute: (proposal: any) => 19 | call('execute', [types.principal(proposal)], address), 20 | executedAt: (proposal: any) => 21 | call('executed-at', [types.principal(proposal)], address), 22 | }); -------------------------------------------------------------------------------- /tests/utils/api/ft-membership.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Account, 3 | Tx, 4 | types, 5 | } from '../deps.ts'; 6 | 7 | const call = (method: string, args: any[], address: string) => { 8 | return Tx.contractCall('ft-membership', method, args, address) 9 | }; 10 | 11 | export const fetchApi = ({ address }: Account) => ({ 12 | mint: (amount: any, recipient: any) => 13 | call('mint', [types.uint(amount), types.principal(recipient)], address), 14 | }); -------------------------------------------------------------------------------- /tests/utils/api/governance-token-with-delegation.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Account, 3 | Tx, 4 | types, 5 | } from '../deps.ts'; 6 | 7 | const call = (method: string, args: any[], address: string) => { 8 | return Tx.contractCall('sde-governance-token-with-delegation', method, args, address) 9 | }; 10 | 11 | export const fetchApi = ({ address }: Account) => ({ 12 | delegate: (delegatee: any, delegator: any) => 13 | call('delegate', [types.principal(delegatee), types.principal(delegator)], address), 14 | getVotingWeight: (delegatee: any) => 15 | call('get-voting-weight', [types.principal(delegatee)], address), 16 | getBalance: (who: any) => 17 | call('get-balance', [types.principal(who)], address), 18 | }); -------------------------------------------------------------------------------- /tests/utils/api/multisignature.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Account, 3 | Tx, 4 | types, 5 | } from '../deps.ts'; 6 | 7 | const call = (method: string, args: any[], address: string) => { 8 | return Tx.contractCall('sde-multisig', method, args, address) 9 | }; 10 | 11 | export const fetchApi = ({ address }: Account) => ({ 12 | addSigner: (principal: any) => 13 | call('add-signer', [types.principal(principal)], address), 14 | propose: (proposal: any) => 15 | call('add-proposal', [types.principal(proposal)], address), 16 | getProposalData: (proposal: any) => 17 | call('get-proposal-data', [types.principal(proposal)], address), 18 | sign: (proposal: any) => 19 | call('sign', [types.principal(proposal)], address), 20 | getSigner: (who: any) => 21 | call('get-signer', [types.principal(who)], address), 22 | getSignalsRequired: () => 23 | call('get-signals-required', [], address), 24 | getSignersCount: () => 25 | call('get-signers-count', [], address), 26 | }); -------------------------------------------------------------------------------- /tests/utils/api/nft-membership.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Account, 3 | Tx, 4 | types, 5 | } from '../deps.ts'; 6 | 7 | const call = (method: string, args: any[], address: string) => { 8 | return Tx.contractCall('nft-membership', method, args, address) 9 | }; 10 | 11 | export const fetchApi = ({ address }: Account) => ({ 12 | mint: (recipient: any) => 13 | call('mint', [types.principal(recipient)], address), 14 | getOwner: (tokenId: any) => 15 | call('get-owner', [types.uint(tokenId)], address), 16 | }); -------------------------------------------------------------------------------- /tests/utils/api/proposal-submission-with-delegation.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Account, 3 | Tx, 4 | types, 5 | } from '../deps.ts'; 6 | 7 | const call = (method: string, args: any[], address: string) => { 8 | return Tx.contractCall('sde-proposal-submission-with-delegation', method, args, address) 9 | }; 10 | 11 | export const fetchApi = ({ address }: Account) => ({ 12 | propose: (proposal: any, startBlock: any, governanceContract: any) => 13 | call( 14 | 'propose', 15 | [ 16 | types.principal(proposal), 17 | types.uint(startBlock), 18 | types.principal(governanceContract), 19 | ], 20 | address 21 | ), 22 | }); -------------------------------------------------------------------------------- /tests/utils/api/proposal-submission-with-nft.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Account, 3 | Tx, 4 | types, 5 | } from '../deps.ts'; 6 | 7 | const call = (method: string, args: any[], address: string) => { 8 | return Tx.contractCall('sde-proposal-submission-with-nft', method, args, address) 9 | }; 10 | 11 | export const fetchApi = ({ address }: Account) => ({ 12 | propose: (proposal: any, tokenId: any, startBlock: any) => 13 | call( 14 | 'propose', 15 | [ 16 | types.principal(proposal), 17 | types.uint(tokenId), 18 | types.uint(startBlock), 19 | ], 20 | address 21 | ), 22 | }); -------------------------------------------------------------------------------- /tests/utils/api/proposal-voting-with-delegation.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Account, 3 | Tx, 4 | types, 5 | } from '../deps.ts'; 6 | 7 | const call = (method: string, args: any[], address: string) => { 8 | return Tx.contractCall('sde-proposal-voting-with-delegation', method, args, address) 9 | }; 10 | 11 | export const fetchApi = ({ address }: Account) => ({ 12 | vote: (vote: any, proposal: any, governanceContract: any) => 13 | call( 14 | 'vote', 15 | [ 16 | types.bool(vote), 17 | types.principal(proposal), 18 | types.principal(governanceContract), 19 | ], 20 | address, 21 | ), 22 | getCurrentVotes: (proposal: any, voter: any, governanceContract: any) => 23 | call( 24 | 'get-current-total-votes', 25 | [ 26 | types.principal(proposal), 27 | types.principal(voter), 28 | types.principal(governanceContract) 29 | ], 30 | address 31 | ), 32 | getProposalData: (proposal: any) => 33 | call( 34 | 'get-proposal-data', 35 | [ 36 | types.principal(proposal), 37 | ], 38 | address 39 | ), 40 | conclude: (proposal: any) => 41 | call('conclude', [types.principal(proposal)], address), 42 | }); -------------------------------------------------------------------------------- /tests/utils/api/proposal-voting-with-nft.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Account, 3 | Tx, 4 | types, 5 | } from '../deps.ts'; 6 | 7 | const call = (method: string, args: any[], address: string) => { 8 | return Tx.contractCall('sde-proposal-voting-with-nft', method, args, address) 9 | }; 10 | 11 | export const fetchApi = ({ address }: Account) => ({ 12 | vote: (vote: any, proposal: any, nftContract: any) => 13 | call( 14 | 'vote', 15 | [ 16 | types.bool(vote), 17 | types.principal(proposal), 18 | types.principal(nftContract), 19 | ], 20 | address, 21 | ), 22 | getCurrentVotes: (proposal: any, voter: any, nftContract: any) => 23 | call( 24 | 'get-current-total-votes', 25 | [ 26 | types.principal(proposal), 27 | types.principal(voter), 28 | types.principal(nftContract) 29 | ], 30 | address 31 | ), 32 | getProposalData: (proposal: any) => 33 | call( 34 | 'get-proposal-data', 35 | [ 36 | types.principal(proposal), 37 | ], 38 | address 39 | ), 40 | }); -------------------------------------------------------------------------------- /tests/utils/api/vault.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Account, 3 | Tx, 4 | types, 5 | } from '../deps.ts'; 6 | 7 | const call = (method: string, args: any[], address: string) => { 8 | return Tx.contractCall('sde-vault', method, args, address) 9 | }; 10 | 11 | export const fetchApi = ({ address }: Account) => ({ 12 | deposit: (amount: any) => 13 | call('deposit', [types.uint(amount)], address), 14 | depositFt: (fungibleToken: any, amount: any) => 15 | call('deposit-ft', [types.principal(fungibleToken), types.uint(amount)], address), 16 | depositNft: (nonFungibleToken: any, amount: any) => 17 | call('deposit-nft', [types.principal(nonFungibleToken), types.uint(amount)], address), 18 | transfer: (amount: any, recipient: any) => 19 | call('transfer', [types.uint(amount), types.principal(recipient)], address), 20 | transferFt: (fungibleToken: any, amount: any, recipient: any) => 21 | call('transfer-ft', [types.principal(fungibleToken), types.uint(amount), types.principal(recipient)], address), 22 | transferNft: (nonFungibleToken: any, amount: any, recipient: any) => 23 | call('transfer-nft', [types.principal(nonFungibleToken), types.uint(amount), types.principal(recipient)], address), 24 | getBalance: () => 25 | call('get-balance', [], address), 26 | getBalanceOf: (token: any) => 27 | call('get-balance-of', [types.principal(token)], address), 28 | isWhitelisted: (token: any) => 29 | call('is-whitelisted', [types.principal(token)], address), 30 | }); -------------------------------------------------------------------------------- /tests/utils/common.ts: -------------------------------------------------------------------------------- 1 | export const CONTRACTS = { 2 | executorDao: "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.executor-dao", 3 | }; 4 | 5 | export const EXTENSIONS = { 6 | VAULT: "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.sde-vault", 7 | MULTISIG: "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.sde-multisig", 8 | DELEGATE_PROPOSAL_SUBMISSION: "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.sde-proposal-submission-with-delegation", 9 | }; 10 | 11 | export const GOVERNANCE = { 12 | DELEGATE_TOKEN: "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.sde-governance-token-with-delegation", 13 | NFT_TOKEN: "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.nft-membership", 14 | } 15 | 16 | export const BOOTSTRAPS = { 17 | MULTISIG_DAO: "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.sdp-multisignature-dao", 18 | DELEGATE_VOTING_DAO: "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.sdp-delegate-voting-dao", 19 | NFT_DAO: "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.sdp-nft-dao", 20 | VAULT: "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.sdp-vault", 21 | }; 22 | 23 | export const PROPOSALS = { 24 | SDP_TRANSFER_FUNGIBLE_TOKENS: "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.sdp-transfer-ft", 25 | SDP_UNAUTHORIZED_TRANSFER_STX: "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.sdp-unauthorized-transfer-stx", 26 | SDP_ADD_SIGNER: "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.sdp-add-signer", 27 | }; 28 | 29 | export const FUNGIBLE_TOKENS = { 30 | CITY_COIN: "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.citycoin-token", 31 | DELEGATE_TOKEN: "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.sde-governance-token-with-delegation", 32 | FT_MEMBERSHIP: "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.ft-membership", 33 | }; 34 | 35 | export const NON_FUNGIBLE_TOKENS = { 36 | NFT_MEMBERSHIP: "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.nft-membership", 37 | }; 38 | 39 | // ERROR CODES 40 | 41 | export enum EXECUTOR_DAO_CODES { 42 | ERR_UNAUTHORIZED = 1000, 43 | ERR_ALREADY_EXECUTED = 1001, 44 | ERR_INVALID_EXTENSION = 1002, 45 | }; 46 | 47 | export enum VAULT_CODES { 48 | ERR_UNAUTHORIZED = 3200, 49 | ERR_ASSET_NOT_WHITELISTED = 3201, 50 | ERR_FAILED_TO_TRANSFER_STX = 3202, 51 | ERR_FAILED_TO_TRANSFER_FT = 3203, 52 | ERR_FAILED_TO_TRANSFER_NFT = 3204, 53 | }; 54 | 55 | export enum MULTISIG_CODES { 56 | ERR_UNAUTHORIZED = 3600, 57 | ERR_NOT_SIGNER = 3601, 58 | ERR_INVALID = 3602, 59 | ERR_ALREADY_EXECUTED = 3603, 60 | ERR_PROPOSAL_NOT_FOUND = 3604, 61 | ERR_PROPOSAL_ALREADY_EXISTS = 3605, 62 | ERR_PROPOSAL_ALREADY_EXECUTED = 3606, 63 | }; 64 | 65 | export enum NFT_VOTING_CODES { 66 | ERR_UNAUTHORIZED = 3400, 67 | ERR_NOT_NFT_OWNER = 3401, 68 | ERR_PROPOSAL_ALREADY_EXECUTED = 3402, 69 | ERR_PROPOSAL_ALREADY_EXISTS = 3403, 70 | ERR_UNKNOWN_PROPOSAL = 3404, 71 | ERR_PROPOSAL_ALREADY_STARTED = 3405, 72 | ERR_PROPOSAL_ALREADY_CONCLUDED = 3406, 73 | ERR_PROPOSAL_INACTIVE = 3407, 74 | ERR_PROPOSAL_NOT_CONCLUDED = 3408, 75 | ERR_NO_VOTES_TO_RETURN = 3409, 76 | ERR_ALREADY_VOTED = 3410, 77 | ERR_END_BLOCK_HEIGHT_NOT_REACHED = 3411, 78 | ERR_DISABLED = 3412, 79 | }; 80 | 81 | export enum NFT_SUBMISSION_CODES { 82 | ERR_UNAUTHORIZED = 3500, 83 | ERR_NOT_NFT_OWNER = 3501, 84 | ERR_UNKNOWN_PARAMETER = 3502, 85 | ERR_PROPOSAL_MINIMUM_START_DELAY = 3503, 86 | ERR_PROPOSAL_MAXIMUM_START_DELAY = 3504, 87 | }; 88 | 89 | export enum DELEGATE_GOVERNANCE_CODES { 90 | ERR_UNAUTHORIZED = 2400, 91 | ERR_NOT_TOKEN_OWNER = 2401, 92 | ERR_CANT_DELEGATE_TO_SELF = 2402, 93 | ERR_NOT_ENOUGH_TOKENS = 2403, 94 | ERR_INVALID_WEIGHT = 2404, 95 | ERR_MUST_REVOKE_CURRENT_DELEGATION = 2405, 96 | ERR_NO_DELEGATION_TO_REVOKE = 2406, 97 | }; 98 | 99 | export enum DELEGATE_VOTING_CODES { 100 | ERR_UNAUTHORIZED = 2500, 101 | ERR_NOT_GOVERNANCE_TOKEN = 2501, 102 | ERR_PROPOSAL_ALREADY_EXECUTED = 2502, 103 | ERR_PROPOSAL_ALREADY_EXISTS = 2503, 104 | ERR_UNKNOWN_PROPOSAL = 2504, 105 | ERR_PROPOSAL_ALREADY_ACTIVE = 2505, 106 | ERR_PROPOSAL_ALREADY_CONCLUDED = 2506, 107 | ERR_PROPOSAL_INACTIVE = 2507, 108 | ERR_PROPOSAL_NOT_CONCLUDED = 2508, 109 | ERR_NO_VOTES_TO_RETURN = 2509, 110 | ERR_QUORUM_NOT_MET = 2510, 111 | ERR_END_BLOCK_HEIGHT_NOT_REACHED = 2511, 112 | ERR_DISABLED = 2512, 113 | ERR_INSUFFICIENT_WEIGHT = 2513, 114 | ERR_ALREADY_VOTED = 2514, 115 | ERR_UNKNOWN_PARAMETER = 2515, 116 | }; 117 | 118 | export enum DELEGATE_SUBMISSION_CODES { 119 | ERR_UNAUTHORIZED = 2600, 120 | ERR_NOT_GOVERNANCE_TOKEN = 2601, 121 | ERR_INSUFFICIENT_WEIGHT = 2602, 122 | ERR_UNKNOWN_PARAMETER = 2603, 123 | ERR_PROPOSAL_MINIMUM_START_DELAY = 2604, 124 | ERR_PROPOSAL_MAXIMUM_START_DELAY = 2605, 125 | }; -------------------------------------------------------------------------------- /tests/utils/deps.ts: -------------------------------------------------------------------------------- 1 | export type { 2 | Account, 3 | Block, 4 | ReadOnlyFn, 5 | TxReceipt, 6 | } from "https://deno.land/x/clarinet@v0.31.1/index.ts"; 7 | 8 | export { 9 | Clarinet, 10 | Chain, 11 | Tx, 12 | types, 13 | } from "https://deno.land/x/clarinet@v0.31.1/index.ts"; 14 | 15 | export { assertEquals } from "https://deno.land/std@0.113.0/testing/asserts.ts"; 16 | 17 | export { 18 | describe, 19 | it, 20 | beforeAll, 21 | beforeEach, 22 | afterAll, 23 | afterEach, 24 | test, 25 | run, 26 | } from "https://deno.land/x/dspec@v0.2.0/mod.ts"; -------------------------------------------------------------------------------- /tests/vault_test.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Account, 3 | assertEquals, 4 | Clarinet, 5 | Chain, 6 | Tx, 7 | types, 8 | } from './utils/deps.ts'; 9 | import { 10 | BOOTSTRAPS, 11 | EXTENSIONS, 12 | FUNGIBLE_TOKENS, 13 | NON_FUNGIBLE_TOKENS, 14 | VAULT_CODES, 15 | } from './utils/common.ts'; 16 | import { fetchApi as executorApi } from './utils/api/executor-dao.ts'; 17 | import { fetchApi as vaultApi } from './utils/api/vault.ts'; 18 | import { fetchApi as ftApi } from './utils/api/ft-membership.ts'; 19 | import { fetchApi as nftApi } from './utils/api/nft-membership.ts'; 20 | 21 | Clarinet.test({ 22 | name: '`vault` - deposit STX', 23 | async fn(chain: Chain, accounts: Map, contracts: Map) { 24 | const { deposit, getBalance } = vaultApi(accounts.get('deployer')!); 25 | const { receipts } = chain.mineBlock([ 26 | getBalance(), 27 | deposit(150), 28 | getBalance(), 29 | ]); 30 | receipts[0].result.expectUint(0); 31 | receipts[1].result.expectOk().expectBool(true); 32 | receipts[2].result.expectUint(150); 33 | }, 34 | }); 35 | 36 | Clarinet.test({ 37 | name: '`vault` - deposit fungible tokens', 38 | async fn(chain: Chain, accounts: Map, contracts: Map) { 39 | const { init } = executorApi(accounts.get('deployer')!); 40 | const { mint } = ftApi(accounts.get('deployer')!); 41 | const { 42 | depositFt, 43 | getBalanceOf, 44 | isWhitelisted, 45 | } = vaultApi(accounts.get('deployer')!); 46 | const recipient = accounts.get('deployer')!; 47 | const { receipts } = chain.mineBlock([ 48 | init(BOOTSTRAPS.VAULT), 49 | isWhitelisted(FUNGIBLE_TOKENS.FT_MEMBERSHIP), 50 | mint(150, recipient.address), 51 | getBalanceOf(FUNGIBLE_TOKENS.FT_MEMBERSHIP), 52 | depositFt(FUNGIBLE_TOKENS.FT_MEMBERSHIP, 150), 53 | getBalanceOf(FUNGIBLE_TOKENS.FT_MEMBERSHIP), 54 | ]); 55 | receipts[0].result.expectOk().expectBool(true); 56 | receipts[1].result.expectBool(true); 57 | receipts[2].result.expectOk().expectBool(true); 58 | receipts[3].result.expectOk().expectUint(0); 59 | receipts[4].result.expectOk().expectBool(true); 60 | receipts[5].result.expectOk().expectUint(150); 61 | }, 62 | }); 63 | 64 | Clarinet.test({ 65 | name: '`vault` - deposit unwhitelisted fungible tokens', 66 | async fn(chain: Chain, accounts: Map, contracts: Map) { 67 | const { init } = executorApi(accounts.get('deployer')!); 68 | const { mint } = ftApi(accounts.get('deployer')!); 69 | const { 70 | depositFt, 71 | getBalanceOf, 72 | isWhitelisted, 73 | } = vaultApi(accounts.get('deployer')!); 74 | const { receipts } = chain.mineBlock([ 75 | getBalanceOf(FUNGIBLE_TOKENS.FT_MEMBERSHIP), 76 | depositFt(FUNGIBLE_TOKENS.FT_MEMBERSHIP, 150), 77 | ]); 78 | receipts[0].result.expectOk().expectUint(0); 79 | receipts[1].result.expectErr().expectUint(VAULT_CODES.ERR_ASSET_NOT_WHITELISTED); 80 | }, 81 | }); 82 | 83 | Clarinet.test({ 84 | name: '`vault` - deposit nfts', 85 | async fn(chain: Chain, accounts: Map, contracts: Map) { 86 | const { init } = executorApi(accounts.get('deployer')!); 87 | const { mint, getOwner } = nftApi(accounts.get('deployer')!); 88 | const { 89 | depositNft, 90 | isWhitelisted, 91 | } = vaultApi(accounts.get('deployer')!); 92 | const recipient = accounts.get('deployer')!; 93 | const { receipts } = chain.mineBlock([ 94 | init(BOOTSTRAPS.VAULT), 95 | isWhitelisted(NON_FUNGIBLE_TOKENS.NFT_MEMBERSHIP), 96 | mint(recipient.address), 97 | getOwner(1), 98 | depositNft(NON_FUNGIBLE_TOKENS.NFT_MEMBERSHIP, 1), 99 | getOwner(1), 100 | ]); 101 | receipts[0].result.expectOk().expectBool(true); 102 | receipts[1].result.expectBool(true); 103 | receipts[2].result.expectOk().expectUint(1); 104 | receipts[3].result.expectOk().expectSome().expectPrincipal(recipient.address); 105 | receipts[4].result.expectOk().expectBool(true); 106 | receipts[5].result.expectOk().expectSome().expectPrincipal(EXTENSIONS.VAULT); 107 | }, 108 | }); 109 | 110 | Clarinet.test({ 111 | name: '`vault` - deposit unwhitelisted nfts', 112 | async fn(chain: Chain, accounts: Map, contracts: Map) { 113 | const { mint, getOwner } = nftApi(accounts.get('deployer')!); 114 | const { 115 | depositNft, 116 | } = vaultApi(accounts.get('deployer')!); 117 | const recipient = accounts.get('deployer')!; 118 | const { receipts } = chain.mineBlock([ 119 | mint(recipient.address), 120 | getOwner(1), 121 | depositNft(NON_FUNGIBLE_TOKENS.NFT_MEMBERSHIP, 1), 122 | getOwner(1), 123 | ]); 124 | receipts[0].result.expectOk().expectUint(1); 125 | receipts[1].result.expectOk().expectSome().expectPrincipal(recipient.address); 126 | receipts[2].result.expectErr().expectUint(VAULT_CODES.ERR_ASSET_NOT_WHITELISTED); 127 | receipts[3].result.expectOk().expectSome().expectPrincipal(recipient.address); 128 | }, 129 | }); 130 | 131 | Clarinet.test({ 132 | name: '`vault` - transfer of STX', 133 | async fn(chain: Chain, accounts: Map, contracts: Map) { 134 | const { 135 | deposit, 136 | transfer, 137 | } = vaultApi(accounts.get('deployer')!); 138 | const recipient = accounts.get('deployer')!; 139 | const { receipts } = chain.mineBlock([ 140 | deposit(150), 141 | transfer(150, recipient.address), 142 | ]); 143 | receipts[0].result.expectOk().expectBool(true); 144 | receipts[1].result.expectErr().expectUint(VAULT_CODES.ERR_UNAUTHORIZED); 145 | }, 146 | }); 147 | 148 | Clarinet.test({ 149 | name: '`vault` - transfer of fungible tokens', 150 | async fn(chain: Chain, accounts: Map, contracts: Map) { 151 | const { init } = executorApi(accounts.get('deployer')!); 152 | const { mint } = ftApi(accounts.get('deployer')!); 153 | const { 154 | depositFt, 155 | getBalanceOf, 156 | transferFt, 157 | } = vaultApi(accounts.get('deployer')!); 158 | const recipient = accounts.get('deployer')!; 159 | const { receipts } = chain.mineBlock([ 160 | init(BOOTSTRAPS.VAULT), 161 | mint(150, recipient.address), 162 | depositFt(FUNGIBLE_TOKENS.FT_MEMBERSHIP, 150), 163 | getBalanceOf(FUNGIBLE_TOKENS.FT_MEMBERSHIP), 164 | transferFt(FUNGIBLE_TOKENS.FT_MEMBERSHIP, 150, recipient.address), 165 | ]); 166 | receipts[0].result.expectOk().expectBool(true); 167 | receipts[1].result.expectOk().expectBool(true); 168 | receipts[2].result.expectOk().expectBool(true); 169 | receipts[3].result.expectOk().expectUint(150); 170 | receipts[4].result.expectErr().expectUint(VAULT_CODES.ERR_UNAUTHORIZED); 171 | }, 172 | }); 173 | 174 | Clarinet.test({ 175 | name: '`vault` - transfer of nfts', 176 | async fn(chain: Chain, accounts: Map, contracts: Map) { 177 | const { init } = executorApi(accounts.get('deployer')!); 178 | const { mint, getOwner } = nftApi(accounts.get('deployer')!); 179 | const { 180 | depositNft, 181 | transferNft, 182 | } = vaultApi(accounts.get('deployer')!); 183 | const recipient = accounts.get('deployer')!; 184 | const { receipts } = chain.mineBlock([ 185 | init(BOOTSTRAPS.VAULT), 186 | mint(recipient.address), 187 | getOwner(1), 188 | depositNft(NON_FUNGIBLE_TOKENS.NFT_MEMBERSHIP, 1), 189 | transferNft(NON_FUNGIBLE_TOKENS.NFT_MEMBERSHIP, 1, recipient.address), 190 | getOwner(1), 191 | ]); 192 | receipts[0].result.expectOk().expectBool(true); 193 | receipts[1].result.expectOk().expectUint(1); 194 | receipts[2].result.expectOk().expectSome().expectPrincipal(recipient.address); 195 | receipts[3].result.expectOk().expectBool(true); 196 | receipts[4].result.expectErr().expectUint(VAULT_CODES.ERR_UNAUTHORIZED); 197 | receipts[5].result.expectOk().expectSome().expectPrincipal(EXTENSIONS.VAULT); 198 | }, 199 | }); --------------------------------------------------------------------------------