Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions src/lib/config/contracts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ export const MAINNET_CONTRACTS = {

// Stacking
POX_4: "SP000000000000000000002Q6VF78.pox-4",
// Epoch 4.0 hard fork (stacks-core 4.0.1): pox-5 replaces pox-4 at the same
// boot-contract address, following the pox-2/pox-3/pox-4 deployment pattern.
// Prefer resolving the active PoX contract dynamically via
// StackingService.getActivePoxContract() (reads /v2/pox contract_id);
// this is the static fallback if that lookup fails.
POX_5: "SP000000000000000000002Q6VF78.pox-5",

// ALEX DEX (SDK handles most operations, but we need pool contract for queries)
ALEX_AMM_POOL: "SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.amm-swap-pool-v1-1",
Expand Down Expand Up @@ -167,6 +173,7 @@ export const TESTNET_CONTRACTS = {

// Stacking
POX_4: "ST000000000000000000002AMW42H.pox-4",
POX_5: "ST000000000000000000002AMW42H.pox-5",

// ERC-8004 Identity & Reputation
IDENTITY_REGISTRY: "ST3YT0XW92E6T2FE59B2G5N2WNNFSBZ6MZKQS5D18.identity-registry-v2",
Expand Down
40 changes: 34 additions & 6 deletions src/lib/services/stacking.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,32 @@ export class StackingService {
return this.hiro.getPoxInfo();
}

/**
* Resolve the currently active PoX contract (e.g. pox-4, pox-5) from the
* node's /v2/pox response, instead of hardcoding a version. Falls back to
* the static POX_5 contract if the lookup fails, so stacking keeps working
* across future PoX version bumps without a code change.
*/
private async getActivePoxContract(): Promise<string> {
try {
const poxInfo = await this.hiro.getPoxInfo();
if (poxInfo?.contract_id) {
return poxInfo.contract_id;
}
} catch {
// Fall through to static fallback
}
return this.contracts.POX_5;
}

/**
* Get stacking status for an address
* Note: Returns whether the address is stacking, but detailed amounts require proper CV parsing
*/
async getStackingStatus(address: string): Promise<StackingStatus> {
try {
const result = await this.hiro.callReadOnlyFunction(
this.contracts.POX_4,
await this.getActivePoxContract(),
"get-stacker-info",
[{ type: "principal", value: address } as unknown as ClarityValue],
address
Expand Down Expand Up @@ -87,7 +105,9 @@ export class StackingService {
startBurnHeight: number,
lockPeriod: number
): Promise<TransferResult> {
const { address: contractAddress, name: contractName } = parseContractId(this.contracts.POX_4);
const { address: contractAddress, name: contractName } = parseContractId(
await this.getActivePoxContract()
);

const functionArgs: ClarityValue[] = [
uintCV(amount),
Expand Down Expand Up @@ -123,7 +143,9 @@ export class StackingService {
extendCount: number,
poxAddress: { version: number; hashbytes: string }
): Promise<TransferResult> {
const { address: contractAddress, name: contractName } = parseContractId(this.contracts.POX_4);
const { address: contractAddress, name: contractName } = parseContractId(
await this.getActivePoxContract()
);

const functionArgs: ClarityValue[] = [
uintCV(extendCount),
Expand All @@ -150,7 +172,9 @@ export class StackingService {
account: Account,
increaseAmount: bigint
): Promise<TransferResult> {
const { address: contractAddress, name: contractName } = parseContractId(this.contracts.POX_4);
const { address: contractAddress, name: contractName } = parseContractId(
await this.getActivePoxContract()
);

const functionArgs: ClarityValue[] = [uintCV(increaseAmount)];

Expand Down Expand Up @@ -180,7 +204,9 @@ export class StackingService {
untilBurnHeight?: number,
poxAddress?: { version: number; hashbytes: string }
): Promise<TransferResult> {
const { address: contractAddress, name: contractName } = parseContractId(this.contracts.POX_4);
const { address: contractAddress, name: contractName } = parseContractId(
await this.getActivePoxContract()
);

const functionArgs: ClarityValue[] = [
uintCV(amount),
Expand Down Expand Up @@ -208,7 +234,9 @@ export class StackingService {
* Revoke delegation
*/
async revokeDelegation(account: Account): Promise<TransferResult> {
const { address: contractAddress, name: contractName } = parseContractId(this.contracts.POX_4);
const { address: contractAddress, name: contractName } = parseContractId(
await this.getActivePoxContract()
);

// No assets moved from sender (revokes delegation permission)
return callContract(account, {
Expand Down
Loading