diff --git a/news/Clarinet.toml b/news/Clarinet.toml index 1fc6c73..16b25fb 100644 --- a/news/Clarinet.toml +++ b/news/Clarinet.toml @@ -6,6 +6,11 @@ cache_dir = './.cache' [[project.requirements]] contract_id = 'STV9K21TBFAK4KNRJXF5DFP8N7W46G4V9RJ5XDY2.sbtc-token' +# Our own mock sBTC, deployed to testnet after the 2026-07-30 reset wiped the +# one above. v6 uses this; v3/v4/v5 still reference the old one. +[[project.requirements]] +contract_id = 'ST2VN1G6EBXPMMAJKCSY1HR50YQCVFSK68KKP9SKW.sbtc-token' + [contracts.news-treasury] path = 'contracts/news-treasury.clar' clarity_version = 3 diff --git a/news/contracts/news-treasury-v6.clar b/news/contracts/news-treasury-v6.clar index dee6284..6ee2493 100644 --- a/news/contracts/news-treasury-v6.clar +++ b/news/contracts/news-treasury-v6.clar @@ -1,8 +1,10 @@ ;; news-treasury-v6 -;; sBTC token +;; sBTC token. This is OUR OWN mock (contracts/sbtc-token.clar), deployed to +;; testnet after the 2026-07-30 reset wiped the third-party one we used before. ;; MAINNET DEPLOY: swap this and the literal at every contract-call site below -(define-constant SBTC 'STV9K21TBFAK4KNRJXF5DFP8N7W46G4V9RJ5XDY2.sbtc-token) +;; for 'SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-token +(define-constant SBTC 'ST2VN1G6EBXPMMAJKCSY1HR50YQCVFSK68KKP9SKW.sbtc-token) (define-constant DEPLOYER tx-sender) @@ -94,7 +96,7 @@ (begin (asserts! (is-gov contract-caller) ERR_UNAUTHORIZED) (asserts! (> amount u0) ERR_ZERO_AMOUNT) - (try! (contract-call? 'STV9K21TBFAK4KNRJXF5DFP8N7W46G4V9RJ5XDY2.sbtc-token transfer amount tx-sender current-contract none)) + (try! (contract-call? 'ST2VN1G6EBXPMMAJKCSY1HR50YQCVFSK68KKP9SKW.sbtc-token transfer amount tx-sender current-contract none)) (var-set Balance (+ (var-get Balance) amount)) (var-set WeightedBalance (+ (var-get WeightedBalance) amount)) (print { @@ -118,7 +120,7 @@ (asserts! (is-some (var-get Gov)) ERR_NOT_WIRED) (asserts! (>= amount MIN_SPONSOR) ERR_BELOW_MIN) (asserts! (> (len name) u0) ERR_EMPTY_NAME) - (try! (contract-call? 'STV9K21TBFAK4KNRJXF5DFP8N7W46G4V9RJ5XDY2.sbtc-token transfer amount tx-sender current-contract none)) + (try! (contract-call? 'ST2VN1G6EBXPMMAJKCSY1HR50YQCVFSK68KKP9SKW.sbtc-token transfer amount tx-sender current-contract none)) (var-set Balance (+ (var-get Balance) amount)) (print { event: "sponsor-in", @@ -157,8 +159,8 @@ (var-set Balance (- bal amount)) (var-set WeightedBalance (- weighted (/ (* weighted amount) bal))) - (try! (as-contract? ((with-ft 'STV9K21TBFAK4KNRJXF5DFP8N7W46G4V9RJ5XDY2.sbtc-token "sbtc-token" amount)) - (try! (contract-call? 'STV9K21TBFAK4KNRJXF5DFP8N7W46G4V9RJ5XDY2.sbtc-token transfer amount tx-sender recipient none)))) + (try! (as-contract? ((with-ft 'ST2VN1G6EBXPMMAJKCSY1HR50YQCVFSK68KKP9SKW.sbtc-token "sbtc-token" amount)) + (try! (contract-call? 'ST2VN1G6EBXPMMAJKCSY1HR50YQCVFSK68KKP9SKW.sbtc-token transfer amount tx-sender recipient none)))) (print { event: "execute-payout", diff --git a/news/contracts/sbtc-token.clar b/news/contracts/sbtc-token.clar new file mode 100644 index 0000000..5035b0c --- /dev/null +++ b/news/contracts/sbtc-token.clar @@ -0,0 +1,94 @@ +;; sbtc-token +;; Mock sBTC for testnet only. Vendored from the Faktory token that the Stacks +;; testnet reset of 2026-07-30 wiped, so the legion no longer depends on a third +;; party republishing it. NEVER deploy this to mainnet; mainnet uses the real +;; sBTC at SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-token. +;; +;; ONE CHANGE from the original: the recipient guard in `transfer` used +;; (as-contract tx-sender), which is unresolved at Clarity 4+ and aborts on +;; publish. Replaced with the `current-contract` keyword, which returns the same +;; principal. Everything else is verbatim. + +;; title: Mock sBTC Token +;; version: 1.0 +;; summary: Mock implementation of sBTC for local testing +;; description: Implements SIP-010 trait and mimics mainnet sBTC token functionality + +;; traits +;; + +;; token definitions +(define-fungible-token sbtc-token) + +;; constants +(define-constant ERR_NOT_OWNER (err u4)) +(define-constant ERR_INVALID_SENDER (err u5)) +(define-constant ERR_INVALID_RECIPIENT (err u6)) +(define-constant ERR_INSUFFICIENT_BALANCE (err u7)) +(define-constant token-decimals u8) +(define-constant INITIAL_SUPPLY u2100000000000000) ;; 21m sBTC with 8 decimals for testing + +;; data vars +(define-data-var token-name (string-ascii 32) "sBTC") +(define-data-var token-symbol (string-ascii 10) "sBTC") +(define-data-var token-uri (optional (string-utf8 256)) (some u"https://ipfs.io/ipfs/bafkreibqnozdui4ntgoh3oo437lvhg7qrsccmbzhgumwwjf2smb3eegyqu")) + +;; data maps +;; + +;; public functions +(define-public (transfer (amount uint) (sender principal) (recipient principal) (memo (optional (buff 34)))) +(begin +;; Authorization check +(asserts! (or (is-eq tx-sender sender) (is-eq contract-caller sender)) ERR_NOT_OWNER) +;; Sender validation +(asserts! (not (is-eq sender recipient)) ERR_INVALID_SENDER) +;; Balance check +(asserts! (<= amount (ft-get-balance sbtc-token sender)) ERR_INSUFFICIENT_BALANCE) +;; Recipient validation - ensure not burning tokens +(asserts! (not (is-eq recipient current-contract)) ERR_INVALID_RECIPIENT) +;; Perform transfer +(try! (ft-transfer? sbtc-token amount sender recipient)) +;; Handle memo if provided +(match memo to-print (print to-print) 0x) +(ok true) +) +) +;; faucet function for testing +(define-public (faucet) +(begin +(try! (ft-mint? sbtc-token u690000000 tx-sender)) ;; Mint 6.9 sBTC to tx-sender +(ok true) +) + +) +;; read only functions +(define-read-only (get-name) +(ok (var-get token-name)) +) +(define-read-only (get-symbol) +(ok (var-get token-symbol)) + +) +(define-read-only (get-decimals) +(ok token-decimals) +) + +(define-read-only (get-balance (who principal)) +(ok (ft-get-balance sbtc-token who)) +) + +(define-read-only (get-total-supply) +(ok (ft-get-supply sbtc-token)) +) + +(define-read-only (get-token-uri) +(ok (var-get token-uri)) +) + +;; initialize contract +(begin +;; Mint initial supply to contract deployer + +(try! (ft-mint? sbtc-token INITIAL_SUPPLY tx-sender)) +) \ No newline at end of file diff --git a/news/deployments/default.simnet-plan.yaml b/news/deployments/default.simnet-plan.yaml index fa61bd0..a1277f2 100644 --- a/news/deployments/default.simnet-plan.yaml +++ b/news/deployments/default.simnet-plan.yaml @@ -111,6 +111,11 @@ plan: epoch: '3.0' - id: 1 transactions: + - transaction-type: emulated-contract-publish + contract-name: sbtc-token + emulated-sender: ST2VN1G6EBXPMMAJKCSY1HR50YQCVFSK68KKP9SKW + path: .cache/requirements/ST2VN1G6EBXPMMAJKCSY1HR50YQCVFSK68KKP9SKW.sbtc-token.clar + clarity-version: 4 - transaction-type: emulated-contract-publish contract-name: news-treasury-v6 emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM diff --git a/news/tests/news-v6-economics.test.ts b/news/tests/news-v6-economics.test.ts index 538286a..cbbdcc2 100644 --- a/news/tests/news-v6-economics.test.ts +++ b/news/tests/news-v6-economics.test.ts @@ -18,7 +18,7 @@ const anyone = accounts.get("wallet_5")!; const TREASURY = "news-treasury-v6"; const GOV = "news-gov-v6"; -const SBTC = "STV9K21TBFAK4KNRJXF5DFP8N7W46G4V9RJ5XDY2.sbtc-token"; +const SBTC = "ST2VN1G6EBXPMMAJKCSY1HR50YQCVFSK68KKP9SKW.sbtc-token"; const VOTING_DELAY = 2; const VOTE_WINDOW = 30; diff --git a/news/tests/news-v6.test.ts b/news/tests/news-v6.test.ts index 1325b49..ef6dd65 100644 --- a/news/tests/news-v6.test.ts +++ b/news/tests/news-v6.test.ts @@ -26,7 +26,7 @@ const GOV = "news-gov-v6"; const govPrincipal = `${deployer}.${GOV}`; // The REAL testnet sBTC token, pulled into simnet via [[project.requirements]]. -const SBTC = "STV9K21TBFAK4KNRJXF5DFP8N7W46G4V9RJ5XDY2.sbtc-token"; +const SBTC = "ST2VN1G6EBXPMMAJKCSY1HR50YQCVFSK68KKP9SKW.sbtc-token"; // Must match news-gov-v6.clar (burn blocks). No VETO_WINDOW in v6. const VOTING_DELAY = 2;