1616
1717use std:: cmp;
1818use std:: collections:: BTreeMap ;
19+ use std:: sync:: LazyLock ;
1920
21+ use clarity:: types:: Address ;
2022use clarity:: vm:: analysis:: CheckErrors ;
2123use clarity:: vm:: ast:: ASTRules ;
2224use clarity:: vm:: clarity:: { Error as ClarityError , TransactionConnection } ;
@@ -34,6 +36,8 @@ use serde::Deserialize;
3436use stacks_common:: codec:: StacksMessageCodec ;
3537use stacks_common:: types:: chainstate:: { StacksAddress , StacksBlockId } ;
3638use stacks_common:: util:: hash:: { hex_bytes, to_hex} ;
39+ #[ cfg( test) ]
40+ use stacks_common:: util:: tests:: TestFlag ;
3741
3842use crate :: burnchains:: { Burnchain , PoxConstants } ;
3943use crate :: chainstate:: burn:: db:: sortdb:: SortitionDB ;
@@ -77,7 +81,8 @@ pub const SIGNERS_BODY: &str = std::include_str!("signers.clar");
7781pub const SIGNERS_DB_0_BODY : & str = std:: include_str!( "signers-0-xxx.clar" ) ;
7882pub const SIGNERS_DB_1_BODY : & str = std:: include_str!( "signers-1-xxx.clar" ) ;
7983pub const SIGNERS_VOTING_BODY : & str = std:: include_str!( "signers-voting.clar" ) ;
80- pub const SIP_031_BODY : & str = std:: include_str!( "sip-031.clar" ) ;
84+ /// Not public - be sure to use [make_sip_031_body]
85+ const SIP_031_BODY : & str = std:: include_str!( "sip-031.clar" ) ;
8186
8287pub const COSTS_1_NAME : & str = "costs" ;
8388pub const COSTS_2_NAME : & str = "costs-2" ;
@@ -90,6 +95,20 @@ pub const BOOT_TEST_POX_4_AGG_KEY_FNAME: &str = "aggregate-key";
9095
9196pub const MINERS_NAME : & str = "miners" ;
9297
98+ /// The initial recipient address for SIP-031 on mainnet.
99+ pub const SIP_031_MAINNET_ADDR : LazyLock < StacksAddress > = LazyLock :: new ( || {
100+ StacksAddress :: from_string ( "SM1Z6BP8PDKYKXTZXXSKXFEY6NQ7RAM7DAEAYR045" ) . unwrap ( )
101+ } ) ;
102+
103+ /// The initial recipient address for SIP-031 on testnet.
104+ pub const SIP_031_TESTNET_ADDR : LazyLock < StacksAddress > = LazyLock :: new ( || {
105+ StacksAddress :: from_string ( "ST1QCN9YMXMJPJ0Y5EMR627FCWDXQWT1CRK9CWN23" ) . unwrap ( )
106+ } ) ;
107+
108+ #[ cfg( test) ]
109+ pub static TEST_SIP_031_ADDR : LazyLock < TestFlag < Option < StacksAddress > > > =
110+ LazyLock :: new ( TestFlag :: default) ;
111+
93112pub mod docs;
94113
95114lazy_static ! {
@@ -139,6 +158,40 @@ fn make_testnet_cost_voting() -> String {
139158 )
140159}
141160
161+ #[ cfg( test) ]
162+ pub fn get_sip_031_recipient_addr ( is_mainnet : bool ) -> StacksAddress {
163+ if is_mainnet {
164+ SIP_031_MAINNET_ADDR . clone ( )
165+ } else {
166+ TEST_SIP_031_ADDR
167+ . get ( )
168+ . unwrap_or ( SIP_031_TESTNET_ADDR . clone ( ) )
169+ }
170+ }
171+
172+ #[ cfg( not( test) ) ]
173+ pub fn get_sip_031_recipient_addr ( is_mainnet : bool ) -> StacksAddress {
174+ if is_mainnet {
175+ SIP_031_MAINNET_ADDR . clone ( )
176+ } else {
177+ SIP_031_TESTNET_ADDR . clone ( )
178+ }
179+ }
180+
181+ /// Generate the contract body for the SIP-031 contract.
182+ ///
183+ /// When on mainnet, only the constant [SIP_031_MAINNET_ADDR] is used.
184+ /// Otherwise, on testnet, you can provide a configurable address.
185+ pub fn make_sip_031_body ( is_mainnet : bool ) -> String {
186+ let addr = get_sip_031_recipient_addr ( is_mainnet) . to_string ( ) ;
187+
188+ SIP_031_BODY . replacen (
189+ "(define-data-var recipient principal tx-sender)" ,
190+ & format ! ( "(define-data-var recipient principal '{addr})" ) ,
191+ 1 ,
192+ )
193+ }
194+
142195pub fn make_contract_id ( addr : & StacksAddress , name : & str ) -> QualifiedContractIdentifier {
143196 QualifiedContractIdentifier :: new (
144197 StandardPrincipalData :: from ( addr. clone ( ) ) ,
@@ -2631,7 +2684,7 @@ pub mod test {
26312684 )
26322685 (begin
26332686 ;; take the stx from the tx-sender
2634-
2687+
26352688 (unwrap-panic (stx-transfer? amount-ustx tx-sender this-contract))
26362689
26372690 ;; this contract stacks the stx given to it
@@ -5847,5 +5900,34 @@ pub mod test {
58475900 }
58485901 }
58495902
5903+ #[ test]
5904+ fn test_sip031_addrs ( ) {
5905+ assert_eq ! (
5906+ SIP_031_MAINNET_ADDR . to_string( ) ,
5907+ "SM1Z6BP8PDKYKXTZXXSKXFEY6NQ7RAM7DAEAYR045"
5908+ ) ;
5909+ assert_eq ! (
5910+ SIP_031_TESTNET_ADDR . to_string( ) ,
5911+ "ST1QCN9YMXMJPJ0Y5EMR627FCWDXQWT1CRK9CWN23"
5912+ ) ;
5913+
5914+ assert_eq ! (
5915+ get_sip_031_recipient_addr( true ) ,
5916+ SIP_031_MAINNET_ADDR . clone( )
5917+ ) ;
5918+ assert_eq ! (
5919+ get_sip_031_recipient_addr( false ) ,
5920+ SIP_031_TESTNET_ADDR . clone( )
5921+ ) ;
5922+
5923+ let transient = StacksAddress :: from ( StandardPrincipalData :: transient ( ) . clone ( ) ) ;
5924+ TEST_SIP_031_ADDR . set ( Some ( transient. clone ( ) ) ) ;
5925+ assert_eq ! ( get_sip_031_recipient_addr( false ) , transient. clone( ) ) ;
5926+ assert_eq ! (
5927+ get_sip_031_recipient_addr( true ) ,
5928+ SIP_031_MAINNET_ADDR . clone( )
5929+ ) ;
5930+ }
5931+
58505932 // TODO: need Stacking-rejection with a BTC address -- contract name in OP_RETURN? (NEXT)
58515933}
0 commit comments