From 31bb550ead3d26082bc82b99c4e102ccc956af0c Mon Sep 17 00:00:00 2001 From: Brice Dobry <232827048+brice-stacks@users.noreply.github.com> Date: Tue, 27 Jan 2026 13:50:27 -0500 Subject: [PATCH 01/23] feat: add Clarity 5 SIP (epoch 3.4) --- sips/sip-clarity5/sip-clarity5.md | 132 ++++++++++++++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100644 sips/sip-clarity5/sip-clarity5.md diff --git a/sips/sip-clarity5/sip-clarity5.md b/sips/sip-clarity5/sip-clarity5.md new file mode 100644 index 00000000..71faf0c6 --- /dev/null +++ b/sips/sip-clarity5/sip-clarity5.md @@ -0,0 +1,132 @@ +# Preamble + +SIP Number: TBD + +Title: Clarity 5: Fixing known issues in Clarity + +Author(s): + +- Brice Dobry + +Status: Draft + +Consideration: Governance, Technical + +Type: Consensus + +Layer: Consensus + +Created: 2025-01-16 + +License: BSD-2-Clause + +Sign-off: + +Discussions-To: + +- Link to where previous discussions took place. For example a mailing list or a + Stacks Forum thread. + +# Abstract + +The goal of this version of Clarity is not to add any new features, but to +resolve known issues with existing functionality, specifically those that +require a hard-fork to change. The implementation for this SIP should only +resolve problems in the current Clarity implementation or make beneficial +changes to under-specified aspects of the Clarity language and virtual machine +(VM). + +# Copyright + +This SIP is made available under the terms of the BSD-2-Clause license, +available at https://opensource.org/licenses/BSD-2-Clause. This SIP’s copyright +is held by the Stacks Open Internet Foundation. + +# Introduction + +This SIP intends to solve the known issues in the implementation of the Clarity +VM, without making any changes to its intended behavior. + +# Specification + +## Resolve the discrepancy in `secp256r1-verify` described in SIP-035 + +In Clarity 5 and above, `secp256r1-verify` will no longer double-hash its input. + +## Runtime error when passing an empty buffer to `from-consensus-buff?` (see issue [#6683](https://github.com/stacks-network/stacks-core/issues/6683)) + +Beginning in epoch 3.4, computing the cost of passing an empty buffer to +`from-consensus-buff?` will no longer trigger a runtime error. Instead, the cost +will be charged appropriately, and the expression will return `none`, as +originally intended. + +## Bug with `burn-block-height` inside an `at-block` expression (see issue [#6123](https://github.com/stacks-network/stacks-core/issues/6123)) + +In Clarity 5 and above, `burn-block-height` will return the correct value when +used inside of an `at-block` expression. + +## Increased stack depth + +Currently, the Clarity VM limits the call stack of a transaction execution to a +depth of 64 and several user applications have been hitting this limit recently. +This value was not specified in any previous SIPs, but was chosen to constrain +memory usage by the VM. Upon further testing, it has been determined that this +value can safely be increased to 128 without imposing u nreasonable requirements +on Stacks node runners. Effective in Clarity 5, the stack depth will be set +to 128. + +## Rejectable transactions + +Several kinds of errors have been avoided in the Clarity VM via a soft-fork +mechanism, causing transactions that trigger these problematic situations to be +rejected, not allowed to be included in a block. This strategy is useful for +quickly patching issues without requiring a hard-fork. However, once the +soft-fork is in place, the next time a hard-fork is executed, these errors can +all be transitioned to errors that can be included in a block. This is much +better for the network, since not including a transaction in a block has several +downsides: + +- Miners cannot charge a fee for processing the transaction +- Users may be confused as to why their transaction is not being included, + causing that transaction and all later transactions (with higher nonces) to + stall +- These unmineable transactions remain in the mempool, unprocessed, until they + age out + +With the upgrade to Clarity 5, all outstanding "rejectable" errors will +transitioned to includable errors. + +# Related Work + +This SIP is focused on fixing consensus issues discovered in previous +implementations of Clarity, or improving behavior which is unspecified in prior +SIPs. The existing SIPs defining Clarity are: + +- [SIP-002 (Clarity)](../sip-002/sip-002-smart-contract-language.md) +- [SIP-015 (Clarity 2)](../sip-015/sip-015-network-upgrade.md) +- [SIP-021 (Clarity 3)](../sip-021/sip-021-nakamoto.md) +- [SIP-033 (Clarity 4)](../sip-033/sip-033-clarity4.md) + +# Backwards Compatibility + +Clarity 5 will be implemented with these changes while maintaining backwards +compatibility for previous versions of Clarity. Existing contracts will continue +to execute with the existing behavior, but new contracts will default to +Clarity 5. + +# Activation + +Since this SIP only proposes fixes to the existing Clarity designs, it will not +require a community vote. In order to activate epoch 3.4 and Clarity 5, this SIP +must be approved by the Technical CAB and the Steering Committee. Once approved, +an activation height must be selected, allowing ample time for the changes to be +implemented, a release published, and community members to update. This block +height may be decided jointly by the Steering Committee, Technical CAB, and +Stacks core engineers implementing the changes. + +# Reference Implementation + +At the time of this writing, only one of these items has a public implementation +available: + +- [`secp256r1-verify?` change](https://github.com/stacks-network/stacks-core/pull/6763) From 0bcd7a0de052c55e2d39f1cb37ccc82c8926bb72 Mon Sep 17 00:00:00 2001 From: Brice Dobry <232827048+brice-stacks@users.noreply.github.com> Date: Tue, 27 Jan 2026 15:06:55 -0500 Subject: [PATCH 02/23] fix: make `from-consensus-buff?` change Clarity-gated Originally, this was going to be epoch-gated, but it makes more sense to keep the existing behavior in existing contracts and only fix it in new versions of Clarity. --- sips/sip-clarity5/sip-clarity5.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sips/sip-clarity5/sip-clarity5.md b/sips/sip-clarity5/sip-clarity5.md index 71faf0c6..530a16cd 100644 --- a/sips/sip-clarity5/sip-clarity5.md +++ b/sips/sip-clarity5/sip-clarity5.md @@ -55,7 +55,7 @@ In Clarity 5 and above, `secp256r1-verify` will no longer double-hash its input. ## Runtime error when passing an empty buffer to `from-consensus-buff?` (see issue [#6683](https://github.com/stacks-network/stacks-core/issues/6683)) -Beginning in epoch 3.4, computing the cost of passing an empty buffer to +Beginning in Clarity 5, computing the cost of passing an empty buffer to `from-consensus-buff?` will no longer trigger a runtime error. Instead, the cost will be charged appropriately, and the expression will return `none`, as originally intended. From 05a058cc8f61b485366b5b45494e357f1ecf9973 Mon Sep 17 00:00:00 2001 From: Brice Dobry <232827048+brice-stacks@users.noreply.github.com> Date: Tue, 27 Jan 2026 15:27:34 -0500 Subject: [PATCH 03/23] feat: add `from-consensus-buff?` PR --- sips/sip-clarity5/sip-clarity5.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sips/sip-clarity5/sip-clarity5.md b/sips/sip-clarity5/sip-clarity5.md index 530a16cd..98cd2b67 100644 --- a/sips/sip-clarity5/sip-clarity5.md +++ b/sips/sip-clarity5/sip-clarity5.md @@ -126,7 +126,8 @@ Stacks core engineers implementing the changes. # Reference Implementation -At the time of this writing, only one of these items has a public implementation -available: +At the time of this writing, the following public implementations are available +so far: - [`secp256r1-verify?` change](https://github.com/stacks-network/stacks-core/pull/6763) +- [`from-consensus-buff?` change](https://github.com/stacks-network/stacks-core/pull/6820) From ae7c06baac85ad1d0701bcb5e8fc2c1c44c24653 Mon Sep 17 00:00:00 2001 From: Brice Dobry <232827048+brice-stacks@users.noreply.github.com> Date: Tue, 27 Jan 2026 17:15:32 -0500 Subject: [PATCH 04/23] fix: stack depth change must be epoch-gated --- sips/sip-clarity5/sip-clarity5.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sips/sip-clarity5/sip-clarity5.md b/sips/sip-clarity5/sip-clarity5.md index 98cd2b67..a9cfa390 100644 --- a/sips/sip-clarity5/sip-clarity5.md +++ b/sips/sip-clarity5/sip-clarity5.md @@ -72,7 +72,7 @@ depth of 64 and several user applications have been hitting this limit recently. This value was not specified in any previous SIPs, but was chosen to constrain memory usage by the VM. Upon further testing, it has been determined that this value can safely be increased to 128 without imposing u nreasonable requirements -on Stacks node runners. Effective in Clarity 5, the stack depth will be set +on Stacks node runners. Effective in epoch 3.4, the stack depth will be set to 128. ## Rejectable transactions From b399e6eee5c923517adbb421fb4c1dc829a4d804 Mon Sep 17 00:00:00 2001 From: Brice Dobry <232827048+brice-stacks@users.noreply.github.com> Date: Tue, 3 Feb 2026 16:28:54 -0500 Subject: [PATCH 05/23] chore: add link to SIP-035 and clarify errors --- sips/sip-clarity5/sip-clarity5.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sips/sip-clarity5/sip-clarity5.md b/sips/sip-clarity5/sip-clarity5.md index a9cfa390..ecc24fb6 100644 --- a/sips/sip-clarity5/sip-clarity5.md +++ b/sips/sip-clarity5/sip-clarity5.md @@ -52,6 +52,7 @@ VM, without making any changes to its intended behavior. ## Resolve the discrepancy in `secp256r1-verify` described in SIP-035 In Clarity 5 and above, `secp256r1-verify` will no longer double-hash its input. +See [SIP-035](/sips/sip-035/sip-secp256r1-verify.md) for details. ## Runtime error when passing an empty buffer to `from-consensus-buff?` (see issue [#6683](https://github.com/stacks-network/stacks-core/issues/6683)) @@ -93,8 +94,8 @@ downsides: - These unmineable transactions remain in the mempool, unprocessed, until they age out -With the upgrade to Clarity 5, all outstanding "rejectable" errors will -transitioned to includable errors. +With the upgrade to epoch 3.4, all reachable "rejectable" errors, will become +includable errors. # Related Work From fc8aec0b1bec9fcb2bd3a040f834818644351032 Mon Sep 17 00:00:00 2001 From: Brice Dobry <232827048+brice-stacks@users.noreply.github.com> Date: Fri, 6 Feb 2026 14:08:10 -0500 Subject: [PATCH 06/23] chore: improve wording --- sips/sip-clarity5/sip-clarity5.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sips/sip-clarity5/sip-clarity5.md b/sips/sip-clarity5/sip-clarity5.md index ecc24fb6..9b8d073f 100644 --- a/sips/sip-clarity5/sip-clarity5.md +++ b/sips/sip-clarity5/sip-clarity5.md @@ -94,8 +94,8 @@ downsides: - These unmineable transactions remain in the mempool, unprocessed, until they age out -With the upgrade to epoch 3.4, all reachable "rejectable" errors, will become -includable errors. +With the upgrade to epoch 3.4, all known reachable "rejectable" errors, will +become includable errors. # Related Work From 6f904724d29efb0018ad8652ed156417c34d6694 Mon Sep 17 00:00:00 2001 From: Brice Dobry <232827048+brice-stacks@users.noreply.github.com> Date: Fri, 6 Feb 2026 14:46:59 -0500 Subject: [PATCH 07/23] add forum link --- sips/sip-clarity5/sip-clarity5.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/sips/sip-clarity5/sip-clarity5.md b/sips/sip-clarity5/sip-clarity5.md index 9b8d073f..19aac21b 100644 --- a/sips/sip-clarity5/sip-clarity5.md +++ b/sips/sip-clarity5/sip-clarity5.md @@ -24,8 +24,7 @@ Sign-off: Discussions-To: -- Link to where previous discussions took place. For example a mailing list or a - Stacks Forum thread. +- https://forum.stacks.org/t/clarity-5-and-epoch-3-4/18659 # Abstract @@ -72,7 +71,7 @@ Currently, the Clarity VM limits the call stack of a transaction execution to a depth of 64 and several user applications have been hitting this limit recently. This value was not specified in any previous SIPs, but was chosen to constrain memory usage by the VM. Upon further testing, it has been determined that this -value can safely be increased to 128 without imposing u nreasonable requirements +value can safely be increased to 128 without imposing unreasonable requirements on Stacks node runners. Effective in epoch 3.4, the stack depth will be set to 128. From 4284fa9d833057a96191207cb9dfb7ce00231b25 Mon Sep 17 00:00:00 2001 From: Brice <232827048+brice-stacks@users.noreply.github.com> Date: Wed, 11 Feb 2026 09:58:37 -0500 Subject: [PATCH 08/23] set SIP number Co-authored-by: wileyj <2847772+wileyj@users.noreply.github.com> --- sips/sip-clarity5/sip-clarity5.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sips/sip-clarity5/sip-clarity5.md b/sips/sip-clarity5/sip-clarity5.md index 19aac21b..3a93bdf9 100644 --- a/sips/sip-clarity5/sip-clarity5.md +++ b/sips/sip-clarity5/sip-clarity5.md @@ -1,6 +1,6 @@ # Preamble -SIP Number: TBD +SIP Number: 039 Title: Clarity 5: Fixing known issues in Clarity From e9b47af5264869f26c0f4291ed5503677a7bb35d Mon Sep 17 00:00:00 2001 From: Brice Dobry <232827048+brice-stacks@users.noreply.github.com> Date: Wed, 11 Feb 2026 10:03:06 -0500 Subject: [PATCH 09/23] adjust file structure for new SIP number --- .../{sip-clarity5/sip-clarity5.md => sip-039/sip-039-clarity5.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename sips/{sip-clarity5/sip-clarity5.md => sip-039/sip-039-clarity5.md} (100%) diff --git a/sips/sip-clarity5/sip-clarity5.md b/sips/sip-039/sip-039-clarity5.md similarity index 100% rename from sips/sip-clarity5/sip-clarity5.md rename to sips/sip-039/sip-039-clarity5.md From d4ab493cc4386c170f8d6abc5f9160d9e6dd3376 Mon Sep 17 00:00:00 2001 From: Brice Dobry <232827048+brice-stacks@users.noreply.github.com> Date: Wed, 11 Feb 2026 10:05:03 -0500 Subject: [PATCH 10/23] add explanation of `burn-block-height` bug --- sips/sip-039/sip-039-clarity5.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sips/sip-039/sip-039-clarity5.md b/sips/sip-039/sip-039-clarity5.md index 3a93bdf9..e018ad75 100644 --- a/sips/sip-039/sip-039-clarity5.md +++ b/sips/sip-039/sip-039-clarity5.md @@ -62,6 +62,12 @@ originally intended. ## Bug with `burn-block-height` inside an `at-block` expression (see issue [#6123](https://github.com/stacks-network/stacks-core/issues/6123)) +From issue [#6123](https://github.com/stacks-network/stacks-core/issues/6123): + +> Epoch 3 introduced a bug which causes `burn-block-height` to always return the +> current burn block height, even if inside of an `at-block` expression. This +> should be fixed to behave as expected in the next hard-fork. + In Clarity 5 and above, `burn-block-height` will return the correct value when used inside of an `at-block` expression. From 4b158fe61b9006ced141d9701e6921b8dcdb2f3e Mon Sep 17 00:00:00 2001 From: Brice Dobry <232827048+brice-stacks@users.noreply.github.com> Date: Wed, 11 Feb 2026 16:13:19 -0500 Subject: [PATCH 11/23] add ame-contract rait use to SIP --- sips/sip-039/sip-039-clarity5.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/sips/sip-039/sip-039-clarity5.md b/sips/sip-039/sip-039-clarity5.md index e018ad75..00f1f36a 100644 --- a/sips/sip-039/sip-039-clarity5.md +++ b/sips/sip-039/sip-039-clarity5.md @@ -102,6 +102,27 @@ downsides: With the upgrade to epoch 3.4, all known reachable "rejectable" errors, will become includable errors. +## Allow trait use in same contract (see issue [6831](https://github.com/stacks-network/stacks-core/issues/6831)) + +Currently, a trait defined in a contract cannot be used at the top-level of that +contract. For example, the code below will result in a `NoSuchContract` error. + +```clarity +(define-trait trait-1 ( + (foo + () + (response int int) + ) +)) +(define-private (bar (F )) + (unwrap-panic (contract-call? F foo)) +) +(bar .c-foo) +``` + +This behavior is a bit surprising. Beginning in Clarity 5, this usage will be +supported. + # Related Work This SIP is focused on fixing consensus issues discovered in previous From ff022aae244587056b874119a918009cf5f0324b Mon Sep 17 00:00:00 2001 From: Brice <232827048+brice-stacks@users.noreply.github.com> Date: Wed, 11 Feb 2026 16:29:03 -0500 Subject: [PATCH 12/23] add hard fork label Co-authored-by: wileyj <2847772+wileyj@users.noreply.github.com> --- sips/sip-039/sip-039-clarity5.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sips/sip-039/sip-039-clarity5.md b/sips/sip-039/sip-039-clarity5.md index 00f1f36a..4334d420 100644 --- a/sips/sip-039/sip-039-clarity5.md +++ b/sips/sip-039/sip-039-clarity5.md @@ -14,7 +14,7 @@ Consideration: Governance, Technical Type: Consensus -Layer: Consensus +Layer: Consensus (hard fork) Created: 2025-01-16 From 0b1c17347c70be7d8f6a7e11115cfe059151d5f6 Mon Sep 17 00:00:00 2001 From: Brice <232827048+brice-stacks@users.noreply.github.com> Date: Fri, 13 Feb 2026 16:16:06 -0500 Subject: [PATCH 13/23] remove extraneous comma Co-authored-by: wileyj <2847772+wileyj@users.noreply.github.com> --- sips/sip-039/sip-039-clarity5.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sips/sip-039/sip-039-clarity5.md b/sips/sip-039/sip-039-clarity5.md index 4334d420..5f873215 100644 --- a/sips/sip-039/sip-039-clarity5.md +++ b/sips/sip-039/sip-039-clarity5.md @@ -99,7 +99,7 @@ downsides: - These unmineable transactions remain in the mempool, unprocessed, until they age out -With the upgrade to epoch 3.4, all known reachable "rejectable" errors, will +With the upgrade to epoch 3.4, all known reachable "rejectable" errors will become includable errors. ## Allow trait use in same contract (see issue [6831](https://github.com/stacks-network/stacks-core/issues/6831)) From 9f9c6194104e6504d5fc7427fac497569e567192 Mon Sep 17 00:00:00 2001 From: Brice Dobry <232827048+brice-stacks@users.noreply.github.com> Date: Fri, 13 Feb 2026 16:35:27 -0500 Subject: [PATCH 14/23] remove issue from titles --- sips/sip-039/sip-039-clarity5.md | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/sips/sip-039/sip-039-clarity5.md b/sips/sip-039/sip-039-clarity5.md index 5f873215..e567de61 100644 --- a/sips/sip-039/sip-039-clarity5.md +++ b/sips/sip-039/sip-039-clarity5.md @@ -53,14 +53,15 @@ VM, without making any changes to its intended behavior. In Clarity 5 and above, `secp256r1-verify` will no longer double-hash its input. See [SIP-035](/sips/sip-035/sip-secp256r1-verify.md) for details. -## Runtime error when passing an empty buffer to `from-consensus-buff?` (see issue [#6683](https://github.com/stacks-network/stacks-core/issues/6683)) +## Runtime error when passing an empty buffer to `from-consensus-buff?` Beginning in Clarity 5, computing the cost of passing an empty buffer to `from-consensus-buff?` will no longer trigger a runtime error. Instead, the cost will be charged appropriately, and the expression will return `none`, as -originally intended. +originally intended. See issue +[#6683](https://github.com/stacks-network/stacks-core/issues/6683). -## Bug with `burn-block-height` inside an `at-block` expression (see issue [#6123](https://github.com/stacks-network/stacks-core/issues/6123)) +## Bug with `burn-block-height` inside an `at-block` expression From issue [#6123](https://github.com/stacks-network/stacks-core/issues/6123): @@ -102,7 +103,7 @@ downsides: With the upgrade to epoch 3.4, all known reachable "rejectable" errors will become includable errors. -## Allow trait use in same contract (see issue [6831](https://github.com/stacks-network/stacks-core/issues/6831)) +## Allow trait use in same contract Currently, a trait defined in a contract cannot be used at the top-level of that contract. For example, the code below will result in a `NoSuchContract` error. @@ -121,7 +122,8 @@ contract. For example, the code below will result in a `NoSuchContract` error. ``` This behavior is a bit surprising. Beginning in Clarity 5, this usage will be -supported. +supported. See issue +[6831](https://github.com/stacks-network/stacks-core/issues/6831). # Related Work From e5af10d19ef96cb06003743e543ea2570638ad89 Mon Sep 17 00:00:00 2001 From: Brice Dobry <232827048+brice-stacks@users.noreply.github.com> Date: Tue, 17 Feb 2026 10:53:52 -0500 Subject: [PATCH 15/23] chore: minor changes from review --- sips/sip-039/sip-039-clarity5.md | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/sips/sip-039/sip-039-clarity5.md b/sips/sip-039/sip-039-clarity5.md index e567de61..16d466a8 100644 --- a/sips/sip-039/sip-039-clarity5.md +++ b/sips/sip-039/sip-039-clarity5.md @@ -28,12 +28,11 @@ Discussions-To: # Abstract -The goal of this version of Clarity is not to add any new features, but to -resolve known issues with existing functionality, specifically those that -require a hard-fork to change. The implementation for this SIP should only -resolve problems in the current Clarity implementation or make beneficial -changes to under-specified aspects of the Clarity language and virtual machine -(VM). +This version of Clarity is being proposed solely to address and resolve +documented issues with existing functionality, specifically those that require a +hard-fork to change. The implementation for this SIP should only resolve +problems in the current Clarity implementation or make beneficial changes to +under-specified aspects of the Clarity language and virtual machine (VM). # Copyright @@ -44,14 +43,14 @@ is held by the Stacks Open Internet Foundation. # Introduction This SIP intends to solve the known issues in the implementation of the Clarity -VM, without making any changes to its intended behavior. +VM, without making any changes to the intended behavior of the Clarity language. # Specification ## Resolve the discrepancy in `secp256r1-verify` described in SIP-035 In Clarity 5 and above, `secp256r1-verify` will no longer double-hash its input. -See [SIP-035](/sips/sip-035/sip-secp256r1-verify.md) for details. +See [SIP-035](./sips/sip-035/sip-secp256r1-verify.md) for details. ## Runtime error when passing an empty buffer to `from-consensus-buff?` From ffbbbbdb7e71b2ef433521bfe634b502dc346041 Mon Sep 17 00:00:00 2001 From: Brice Dobry <232827048+brice-stacks@users.noreply.github.com> Date: Sat, 21 Feb 2026 11:58:16 -0500 Subject: [PATCH 16/23] feat: add contract call with constant --- sips/sip-039/sip-039-clarity5.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/sips/sip-039/sip-039-clarity5.md b/sips/sip-039/sip-039-clarity5.md index 16d466a8..9f6fe1b5 100644 --- a/sips/sip-039/sip-039-clarity5.md +++ b/sips/sip-039/sip-039-clarity5.md @@ -124,6 +124,22 @@ This behavior is a bit surprising. Beginning in Clarity 5, this usage will be supported. See issue [6831](https://github.com/stacks-network/stacks-core/issues/6831). +## Allow `contract-call?` to constant + +Effective in Clarity 2, the type-checker does not complain about using a +constant as the target of a `contract-call?`, for example: + +```clarity +(define-constant MY_CONTRACT .contract-a) +(define-public (call-foo) + (contract-call? MY_CONTRACT foo) +) +``` + +Despite passing type-checking, this contract would fail during runtime, with an +error, `RuntimeCheckErrorKind::ContractCallExpectName`. This again is surprising +behavior. Beginning in epoch 3.4, this usage will be supported. + # Related Work This SIP is focused on fixing consensus issues discovered in previous From c48933e3adc451e3382594edb6b51d904edffdb5 Mon Sep 17 00:00:00 2001 From: Brice Dobry <232827048+brice-stacks@users.noreply.github.com> Date: Fri, 27 Feb 2026 10:19:45 -0500 Subject: [PATCH 17/23] fix: add `stx-account` and `stx-get-balance` to `at-block` bug --- sips/sip-039/sip-039-clarity5.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/sips/sip-039/sip-039-clarity5.md b/sips/sip-039/sip-039-clarity5.md index 9f6fe1b5..ed449c37 100644 --- a/sips/sip-039/sip-039-clarity5.md +++ b/sips/sip-039/sip-039-clarity5.md @@ -60,7 +60,7 @@ will be charged appropriately, and the expression will return `none`, as originally intended. See issue [#6683](https://github.com/stacks-network/stacks-core/issues/6683). -## Bug with `burn-block-height` inside an `at-block` expression +## Bug inside `at-block` expressions From issue [#6123](https://github.com/stacks-network/stacks-core/issues/6123): @@ -68,6 +68,11 @@ From issue [#6123](https://github.com/stacks-network/stacks-core/issues/6123): > current burn block height, even if inside of an `at-block` expression. This > should be fixed to behave as expected in the next hard-fork. +In addition to `burn-block-height`, it was also determined that this same error +effects `stx-account` and `stx-get-balance`. These two functions can return an +incorrect value inside of an `at-block` since the incorrect burn block height is +used to determine the locked status of the STX. + In Clarity 5 and above, `burn-block-height` will return the correct value when used inside of an `at-block` expression. From 9ba28670033052ede38ee184c2ecefef5de09222 Mon Sep 17 00:00:00 2001 From: Brice Dobry <232827048+brice-stacks@users.noreply.github.com> Date: Fri, 27 Feb 2026 13:50:05 -0500 Subject: [PATCH 18/23] chore: updated activation section for vote --- sips/sip-039/sip-039-clarity5.md | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/sips/sip-039/sip-039-clarity5.md b/sips/sip-039/sip-039-clarity5.md index ed449c37..959170d2 100644 --- a/sips/sip-039/sip-039-clarity5.md +++ b/sips/sip-039/sip-039-clarity5.md @@ -165,13 +165,15 @@ Clarity 5. # Activation -Since this SIP only proposes fixes to the existing Clarity designs, it will not -require a community vote. In order to activate epoch 3.4 and Clarity 5, this SIP -must be approved by the Technical CAB and the Steering Committee. Once approved, -an activation height must be selected, allowing ample time for the changes to be -implemented, a release published, and community members to update. This block -height may be decided jointly by the Steering Committee, Technical CAB, and -Stacks core engineers implementing the changes. +In order for this SIP to activate, the following criteria must be met: + +- At least 80 million stacked STX must vote, with at least 80% of all stacked + STX committed by voting must be in favor of the proposal (vote "yes"). +- At least 80% of all liquid STX committed by voting must be in favor of the + proposal (vote "yes"). + +If the SIP is approved, epoch 3.4 will activate at Bitcoin block height 943000, +targeting March 30, 2026. # Reference Implementation From 85ccf1b71834809a780f70980bb8f58f7c081d59 Mon Sep 17 00:00:00 2001 From: wileyj <2847772+wileyj@users.noreply.github.com> Date: Thu, 5 Mar 2026 09:59:18 -0800 Subject: [PATCH 19/23] Set status to accepted --- sips/sip-039/sip-039-clarity5.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sips/sip-039/sip-039-clarity5.md b/sips/sip-039/sip-039-clarity5.md index 959170d2..b4fbe63c 100644 --- a/sips/sip-039/sip-039-clarity5.md +++ b/sips/sip-039/sip-039-clarity5.md @@ -8,7 +8,7 @@ Author(s): - Brice Dobry -Status: Draft +Status: Accepted Consideration: Governance, Technical From 8fb11a03cb63b44cfe343543a5b573f16cb8773f Mon Sep 17 00:00:00 2001 From: Brice Dobry <232827048+brice-stacks@users.noreply.github.com> Date: Thu, 5 Mar 2026 14:12:23 -0500 Subject: [PATCH 20/23] feat: add `sip-address` script Used to generate addresses for voting. See README for details. --- .gitignore | 2 + sip-address/README.md | 18 +++++++++ sip-address/package-lock.json | 73 +++++++++++++++++++++++++++++++++++ sip-address/package.json | 16 ++++++++ sip-address/sip-address.js | 54 ++++++++++++++++++++++++++ 5 files changed, 163 insertions(+) create mode 100644 sip-address/README.md create mode 100644 sip-address/package-lock.json create mode 100644 sip-address/package.json create mode 100644 sip-address/sip-address.js diff --git a/.gitignore b/.gitignore index 19d57931..ac8988c7 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,5 @@ *.rej .aider* + +node_modules/ diff --git a/sip-address/README.md b/sip-address/README.md new file mode 100644 index 00000000..d8b3d896 --- /dev/null +++ b/sip-address/README.md @@ -0,0 +1,18 @@ +# sip-address + +Generate deterministic BTC and STX vote addresses for a given SIP number. + +Each address embeds a human-readable ASCII payload (`yes-sip-N` / `no-sip-N`) right-aligned in the 20-byte hash, making the vote intent verifiable on-chain. + +## Usage + +``` +npm install +node sip-address.js +``` + +Example: + +``` +$ node sip-address.js 29 +``` diff --git a/sip-address/package-lock.json b/sip-address/package-lock.json new file mode 100644 index 00000000..21660093 --- /dev/null +++ b/sip-address/package-lock.json @@ -0,0 +1,73 @@ +{ + "name": "sip-address", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "sip-address", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "bs58check": "^4.0.0", + "c32check": "^2.0.0" + } + }, + "node_modules/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/base-x": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-5.0.1.tgz", + "integrity": "sha512-M7uio8Zt++eg3jPj+rHMfCC+IuygQHHCOU+IYsVtik6FWjuYpVt/+MRKcgsAMHh8mMFAwnB+Bs+mTrFiXjMzKg==", + "license": "MIT" + }, + "node_modules/bs58": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-6.0.0.tgz", + "integrity": "sha512-PD0wEnEYg6ijszw/u8s+iI3H17cTymlrwkKhDhPZq+Sokl3AU4htyBFTjAeNAlCCmg0f53g6ih3jATyCKftTfw==", + "license": "MIT", + "dependencies": { + "base-x": "^5.0.0" + } + }, + "node_modules/bs58check": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-4.0.0.tgz", + "integrity": "sha512-FsGDOnFg9aVI9erdriULkd/JjEWONV/lQE5aYziB5PoBsXRind56lh8doIZIc9X4HoxT5x4bLjMWN1/NB8Zp5g==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "^1.2.0", + "bs58": "^6.0.0" + } + }, + "node_modules/c32check": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/c32check/-/c32check-2.0.0.tgz", + "integrity": "sha512-rpwfAcS/CMqo0oCqDf3r9eeLgScRE3l/xHDCXhM3UyrfvIn7PrLq63uHh7yYbv8NzaZn5MVsVhIRpQ+5GZ5HyA==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "^1.1.2", + "base-x": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/c32check/node_modules/base-x": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-4.0.1.tgz", + "integrity": "sha512-uAZ8x6r6S3aUM9rbHGVOIsR15U/ZSc82b3ymnCPsT45Gk1DDvhDPdIgB5MrhirZWt+5K0EEPQH985kNqZgNPFw==", + "license": "MIT" + } + } +} diff --git a/sip-address/package.json b/sip-address/package.json new file mode 100644 index 00000000..bba88c04 --- /dev/null +++ b/sip-address/package.json @@ -0,0 +1,16 @@ +{ + "name": "sip-address", + "version": "1.0.0", + "description": "", + "license": "ISC", + "author": "", + "type": "module", + "main": "sip-address.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "dependencies": { + "bs58check": "^4.0.0", + "c32check": "^2.0.0" + } +} diff --git a/sip-address/sip-address.js b/sip-address/sip-address.js new file mode 100644 index 00000000..a8de7190 --- /dev/null +++ b/sip-address/sip-address.js @@ -0,0 +1,54 @@ +import { c32address } from "c32check"; +import bs58check from "bs58check"; + +const sipNumber = parseInt(process.argv[2], 10); +if (!sipNumber || sipNumber < 1) { + console.error("Usage: node sip-address.js "); + process.exit(1); +} +const VERSION_SP_MAINNET = 22; + +// Always make a 20-byte "hash": [00...00 | ASCII("yes-sip-N"|"no-sip-N")] +function makeHashHex(msg) { + const ascii = Buffer.from(msg, "ascii"); // explicit ASCII + if (ascii.length > 20) { + throw new Error(`Message too long for 20-byte embed: ${msg}`); + } + const zeros = 20 - ascii.length; + return Buffer.concat([Buffer.alloc(zeros, 0x00), ascii]).toString("hex"); // 40 hex chars +} + +function btcAddressFromHashHex(hashHex) { + const payload20 = Buffer.from(hashHex, "hex"); + return bs58check.encode(Buffer.concat([Buffer.from([0x00]), payload20])); // P2PKH mainnet +} + +function stacksAddressFromHashHex(hashHex) { + return c32address(VERSION_SP_MAINNET, hashHex); // expects 40-char hex (20 bytes) +} + +const yesMsg = `yes-sip-${sipNumber}`; +const noMsg = `no-sip-${sipNumber}`; + +const yesHashHex = makeHashHex(yesMsg); +const noHashHex = makeHashHex(noMsg); + +const yesBTC = btcAddressFromHashHex(yesHashHex); +const noBTC = btcAddressFromHashHex(noHashHex); + +const yesSTX = stacksAddressFromHashHex(yesHashHex); +const noSTX = stacksAddressFromHashHex(noHashHex); + +console.log({ + sipNumber, + yesMsg, + noMsg, + yesAsciiHex: Buffer.from(yesMsg, "ascii").toString("hex"), + noAsciiHex: Buffer.from(noMsg, "ascii").toString("hex"), + yesHashHex, + noHashHex, + yesBTC, + noBTC, + yesSTX, + noSTX, +}); \ No newline at end of file From 9de700b100439f71dd87c787bd7722622b487ee0 Mon Sep 17 00:00:00 2001 From: Brice Dobry <232827048+brice-stacks@users.noreply.github.com> Date: Thu, 5 Mar 2026 17:11:07 -0500 Subject: [PATCH 21/23] Revert "feat: add `sip-address` script" This reverts commit 8fb11a03cb63b44cfe343543a5b573f16cb8773f. --- .gitignore | 2 - sip-address/README.md | 18 --------- sip-address/package-lock.json | 73 ----------------------------------- sip-address/package.json | 16 -------- sip-address/sip-address.js | 54 -------------------------- 5 files changed, 163 deletions(-) delete mode 100644 sip-address/README.md delete mode 100644 sip-address/package-lock.json delete mode 100644 sip-address/package.json delete mode 100644 sip-address/sip-address.js diff --git a/.gitignore b/.gitignore index ac8988c7..19d57931 100644 --- a/.gitignore +++ b/.gitignore @@ -4,5 +4,3 @@ *.rej .aider* - -node_modules/ diff --git a/sip-address/README.md b/sip-address/README.md deleted file mode 100644 index d8b3d896..00000000 --- a/sip-address/README.md +++ /dev/null @@ -1,18 +0,0 @@ -# sip-address - -Generate deterministic BTC and STX vote addresses for a given SIP number. - -Each address embeds a human-readable ASCII payload (`yes-sip-N` / `no-sip-N`) right-aligned in the 20-byte hash, making the vote intent verifiable on-chain. - -## Usage - -``` -npm install -node sip-address.js -``` - -Example: - -``` -$ node sip-address.js 29 -``` diff --git a/sip-address/package-lock.json b/sip-address/package-lock.json deleted file mode 100644 index 21660093..00000000 --- a/sip-address/package-lock.json +++ /dev/null @@ -1,73 +0,0 @@ -{ - "name": "sip-address", - "version": "1.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "sip-address", - "version": "1.0.0", - "license": "ISC", - "dependencies": { - "bs58check": "^4.0.0", - "c32check": "^2.0.0" - } - }, - "node_modules/@noble/hashes": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", - "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", - "license": "MIT", - "engines": { - "node": "^14.21.3 || >=16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/base-x": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/base-x/-/base-x-5.0.1.tgz", - "integrity": "sha512-M7uio8Zt++eg3jPj+rHMfCC+IuygQHHCOU+IYsVtik6FWjuYpVt/+MRKcgsAMHh8mMFAwnB+Bs+mTrFiXjMzKg==", - "license": "MIT" - }, - "node_modules/bs58": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/bs58/-/bs58-6.0.0.tgz", - "integrity": "sha512-PD0wEnEYg6ijszw/u8s+iI3H17cTymlrwkKhDhPZq+Sokl3AU4htyBFTjAeNAlCCmg0f53g6ih3jATyCKftTfw==", - "license": "MIT", - "dependencies": { - "base-x": "^5.0.0" - } - }, - "node_modules/bs58check": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-4.0.0.tgz", - "integrity": "sha512-FsGDOnFg9aVI9erdriULkd/JjEWONV/lQE5aYziB5PoBsXRind56lh8doIZIc9X4HoxT5x4bLjMWN1/NB8Zp5g==", - "license": "MIT", - "dependencies": { - "@noble/hashes": "^1.2.0", - "bs58": "^6.0.0" - } - }, - "node_modules/c32check": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/c32check/-/c32check-2.0.0.tgz", - "integrity": "sha512-rpwfAcS/CMqo0oCqDf3r9eeLgScRE3l/xHDCXhM3UyrfvIn7PrLq63uHh7yYbv8NzaZn5MVsVhIRpQ+5GZ5HyA==", - "license": "MIT", - "dependencies": { - "@noble/hashes": "^1.1.2", - "base-x": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/c32check/node_modules/base-x": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/base-x/-/base-x-4.0.1.tgz", - "integrity": "sha512-uAZ8x6r6S3aUM9rbHGVOIsR15U/ZSc82b3ymnCPsT45Gk1DDvhDPdIgB5MrhirZWt+5K0EEPQH985kNqZgNPFw==", - "license": "MIT" - } - } -} diff --git a/sip-address/package.json b/sip-address/package.json deleted file mode 100644 index bba88c04..00000000 --- a/sip-address/package.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "name": "sip-address", - "version": "1.0.0", - "description": "", - "license": "ISC", - "author": "", - "type": "module", - "main": "sip-address.js", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "dependencies": { - "bs58check": "^4.0.0", - "c32check": "^2.0.0" - } -} diff --git a/sip-address/sip-address.js b/sip-address/sip-address.js deleted file mode 100644 index a8de7190..00000000 --- a/sip-address/sip-address.js +++ /dev/null @@ -1,54 +0,0 @@ -import { c32address } from "c32check"; -import bs58check from "bs58check"; - -const sipNumber = parseInt(process.argv[2], 10); -if (!sipNumber || sipNumber < 1) { - console.error("Usage: node sip-address.js "); - process.exit(1); -} -const VERSION_SP_MAINNET = 22; - -// Always make a 20-byte "hash": [00...00 | ASCII("yes-sip-N"|"no-sip-N")] -function makeHashHex(msg) { - const ascii = Buffer.from(msg, "ascii"); // explicit ASCII - if (ascii.length > 20) { - throw new Error(`Message too long for 20-byte embed: ${msg}`); - } - const zeros = 20 - ascii.length; - return Buffer.concat([Buffer.alloc(zeros, 0x00), ascii]).toString("hex"); // 40 hex chars -} - -function btcAddressFromHashHex(hashHex) { - const payload20 = Buffer.from(hashHex, "hex"); - return bs58check.encode(Buffer.concat([Buffer.from([0x00]), payload20])); // P2PKH mainnet -} - -function stacksAddressFromHashHex(hashHex) { - return c32address(VERSION_SP_MAINNET, hashHex); // expects 40-char hex (20 bytes) -} - -const yesMsg = `yes-sip-${sipNumber}`; -const noMsg = `no-sip-${sipNumber}`; - -const yesHashHex = makeHashHex(yesMsg); -const noHashHex = makeHashHex(noMsg); - -const yesBTC = btcAddressFromHashHex(yesHashHex); -const noBTC = btcAddressFromHashHex(noHashHex); - -const yesSTX = stacksAddressFromHashHex(yesHashHex); -const noSTX = stacksAddressFromHashHex(noHashHex); - -console.log({ - sipNumber, - yesMsg, - noMsg, - yesAsciiHex: Buffer.from(yesMsg, "ascii").toString("hex"), - noAsciiHex: Buffer.from(noMsg, "ascii").toString("hex"), - yesHashHex, - noHashHex, - yesBTC, - noBTC, - yesSTX, - noSTX, -}); \ No newline at end of file From e68faee81370c7d30a69bba64f8627d166bbadfc Mon Sep 17 00:00:00 2001 From: Brice Dobry <232827048+brice-stacks@users.noreply.github.com> Date: Mon, 9 Mar 2026 11:23:31 -0400 Subject: [PATCH 22/23] add voting information --- sips/sip-039/sip-039-clarity5.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/sips/sip-039/sip-039-clarity5.md b/sips/sip-039/sip-039-clarity5.md index b4fbe63c..e2ddbbcf 100644 --- a/sips/sip-039/sip-039-clarity5.md +++ b/sips/sip-039/sip-039-clarity5.md @@ -172,6 +172,23 @@ In order for this SIP to activate, the following criteria must be met: - At least 80% of all liquid STX committed by voting must be in favor of the proposal (vote "yes"). +All STX holders vote by sending Stacks dust to the corresponding Stacks address +from the account where their Stacks are held (stacked or liquid). To simplify +things, users can create their votes by visiting the +[ballot.gg](https://ballot.gg/67a34537-0375-4046-a4b7-432e8dfd4eb3/1MP9LjMBZRKXWq3tRio6nGwFyUoboozEQx) +platform. Voting power is determined by a snapshot of the amount of STX (stacked +and unstacked) at the block height at which the voting started (preventing the +same STX from being transferred between accounts and used to effectively double +vote). The voting addresses are also shared below. + +Solo stackers only can also vote by sending a bitcoin dust transaction (6000 +sats) to the corresponding bitcoin address. + +| Vote | Bitcoin | Stacks | ASCII Encoding | Msg | +| ---- | ------------------------------ | ----------------------------------- | ---------------------------------------- | ---------- | +| yes | 11111111111mdWK2VXcrA1eceSntcp | SP00000000001WPAWSDEDMQ0B9K76XTZ79N | 000000000000000000007965732d7369702d3339 | yes-sip-39 | +| no | 111111111111ACW5wa4RwyepZ84byy | SP000000000006WVSDEDMQ0B9K76JZVAKY | 00000000000000000000006e6f2d7369702d3339 | no-sip-39 | + If the SIP is approved, epoch 3.4 will activate at Bitcoin block height 943000, targeting March 30, 2026. From abadf1722389dcca6a6d38403b5d541d9727671c Mon Sep 17 00:00:00 2001 From: wileyj <2847772+wileyj@users.noreply.github.com> Date: Mon, 9 Mar 2026 13:44:40 -0700 Subject: [PATCH 23/23] Move to Activation-In-Progress --- sips/sip-039/sip-039-clarity5.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sips/sip-039/sip-039-clarity5.md b/sips/sip-039/sip-039-clarity5.md index e2ddbbcf..700040b2 100644 --- a/sips/sip-039/sip-039-clarity5.md +++ b/sips/sip-039/sip-039-clarity5.md @@ -8,7 +8,7 @@ Author(s): - Brice Dobry -Status: Accepted +Status: Activation-In-Progress Consideration: Governance, Technical