SDK & Developer Tools
Everything you need to integrate Halo Protocol into your application. Connect wallets, call contracts, and build on decentralized credit.
Core Packages
@stacks/connect
v8.x
Wallet integration for Leather and Xverse. Handles authentication, transaction signing, and message signing in the browser. Required for all user-facing interactions.
@stacks/transactions
v7.x
Build, sign, and broadcast Stacks transactions. Call smart contract functions, construct post-conditions, and read on-chain state. Server-side and client-side compatible.
@stacks/network
v7.x
Network configuration for testnet and mainnet. Use networkFromName() to get the correct API endpoints and chain ID for your target environment.
Getting Started
1. Install Dependencies
npm install @stacks/connect @stacks/transactions @stacks/network
2. Configure Network
Set up the Stacks network for your target environment. The v7 SDK uses factory functions instead of class constructors.
import { networkFromName } from "@stacks/network";
// For testnet development
const network = networkFromName("testnet");
// For mainnet production
// const network = networkFromName("mainnet");
// Deployer address (set via environment variable)
const DEPLOYER = process.env.NEXT_PUBLIC_DEPLOYER_ADDRESS;3. Set Environment Variables
# .env.local NEXT_PUBLIC_DEPLOYER_ADDRESS=ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM NEXT_PUBLIC_STACKS_NETWORK=testnet
Wallet Connection
Use @stacks/connect to prompt users to connect their Leather or Xverse wallet. The component must use "use client" and dynamic imports to avoid SSR errors.
"use client";
import { showConnect } from "@stacks/connect";
function ConnectWallet() {
const handleConnect = () => {
showConnect({
appDetails: {
name: "Halo Protocol",
icon: "/logo.png",
},
onFinish: (data) => {
const address = data.userSession
.loadUserData()
.profile.stxAddress.testnet;
console.log("Connected:", address);
},
onCancel: () => {
console.log("User cancelled");
},
});
};
return (
<button onClick={handleConnect}>
Connect Wallet
</button>
);
}Important: SSR Compatibility
@stacks/connect requires browser APIs and will crash during server-side rendering. Always use "use client" at the top of wallet components. For Next.js dynamic imports, use dynamic(() => import("..."), { ssr: false }).
Smart Contract Interactions
Read-Only Contract Calls
Read on-chain state without broadcasting a transaction. The v7 SDK uses fetchCallReadOnlyFunction (the old callReadOnlyFunction was removed).
import {
fetchCallReadOnlyFunction,
cvToJSON,
principalCV,
} from "@stacks/transactions";
import { networkFromName } from "@stacks/network";
async function getCreditScore(address: string) {
const network = networkFromName("testnet");
const DEPLOYER = process.env.NEXT_PUBLIC_DEPLOYER_ADDRESS!;
const result = await fetchCallReadOnlyFunction({
network,
contractAddress: DEPLOYER,
contractName: "halo-credit",
functionName: "get-credit-score",
functionArgs: [principalCV(address)],
senderAddress: address,
});
const json = cvToJSON(result);
return json.value?.score?.value ?? 300;
}Write Transactions (Contract Calls)
Broadcast state-changing transactions to the blockchain. The v7 SDK removed AnchorMode—simply omit it from the options object.
import { openContractCall } from "@stacks/connect";
import { uintCV, stringUtf8CV } from "@stacks/transactions";
async function joinCircle(circleId: number) {
const DEPLOYER = process.env.NEXT_PUBLIC_DEPLOYER_ADDRESS!;
await openContractCall({
contractAddress: DEPLOYER,
contractName: "halo-circle",
functionName: "join-circle",
functionArgs: [uintCV(circleId)],
onFinish: (data) => {
console.log("TX broadcast:", data.txId);
},
onCancel: () => {
console.log("User rejected transaction");
},
});
}Post-Conditions
Post-conditions protect users by ensuring a transaction only succeeds if specified conditions are met. The v7 SDK uses the fluent Pc builder (the old makeStandardSTXPostCondition was removed).
import { Pc } from "@stacks/transactions";
import { openContractCall } from "@stacks/connect";
async function contributeToCircle(
circleId: number,
amount: number,
senderAddress: string,
) {
const DEPLOYER = process.env.NEXT_PUBLIC_DEPLOYER_ADDRESS!;
// Ensure the user sends exactly the contribution amount
const postConditions = [
Pc.principal(senderAddress)
.willSendEq(amount)
.ustx(),
];
await openContractCall({
contractAddress: DEPLOYER,
contractName: "halo-circle",
functionName: "contribute",
functionArgs: [uintCV(circleId)],
postConditions,
onFinish: (data) => {
console.log("Contribution TX:", data.txId);
},
});
}Contract Reference
Key public functions available on the Halo Protocol contracts. All contracts are deployed by the deployer address and use Clarity 3 (Epoch 3.0).
halo-identity
register-identity (name)Register a new on-chain identity with a display name.
get-identity (principal)Look up an identity by Stacks address.
halo-credit
record-payment (user, circle-id, amount, on-time)Record a circle contribution. Authorized via contract-caller. Updates credit score components.
get-credit-score (principal)Retrieve the composite credit score (300-850) for a user.
halo-circle
create-circle (name, contribution, total-members, token-type)Create a new lending circle with specified parameters.
join-circle (circle-id)Join an existing circle that is still in formation.
contribute (circle-id)Make a contribution for the current round. Transfers tokens to the vault.
get-circle (circle-id)Retrieve circle details including status, members, and current round.
halo-sbtc-staking
stake (amount)Stake sBTC for yield and credit score boost.
unstake (amount)Withdraw staked sBTC with accrued yield.
Common Pitfalls
v7 Breaking Changes
@stacks/transactions v7 removed several APIs. callReadOnlyFunction is replaced by fetchCallReadOnlyFunction. makeStandardSTXPostCondition is replaced by the Pc fluent builder. AnchorMode is removed entirely.
Network Constructor Removal
@stacks/network v7 removed class constructors like new StacksTestnet(). Use networkFromName("testnet") instead.
Clarity Map Field Names
Clarity uses kebab-case for map field names (e.g., total-members). In JavaScript, access these with bracket notation: result["total-members"].
Credit Contract Authorization
The halo-credit contract's record-payment function uses contract-caller for authorization, not tx-sender. Only the authorized circle contract can record payments.