diff --git a/src/lib/config/contracts.ts b/src/lib/config/contracts.ts index dee5669..513aad4 100644 --- a/src/lib/config/contracts.ts +++ b/src/lib/config/contracts.ts @@ -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", @@ -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", diff --git a/src/lib/services/stacking.service.ts b/src/lib/services/stacking.service.ts index beadf8b..0aaefc6 100644 --- a/src/lib/services/stacking.service.ts +++ b/src/lib/services/stacking.service.ts @@ -38,6 +38,24 @@ 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 { + 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 @@ -45,7 +63,7 @@ export class StackingService { async getStackingStatus(address: string): Promise { 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 @@ -87,7 +105,9 @@ export class StackingService { startBurnHeight: number, lockPeriod: number ): Promise { - const { address: contractAddress, name: contractName } = parseContractId(this.contracts.POX_4); + const { address: contractAddress, name: contractName } = parseContractId( + await this.getActivePoxContract() + ); const functionArgs: ClarityValue[] = [ uintCV(amount), @@ -123,7 +143,9 @@ export class StackingService { extendCount: number, poxAddress: { version: number; hashbytes: string } ): Promise { - const { address: contractAddress, name: contractName } = parseContractId(this.contracts.POX_4); + const { address: contractAddress, name: contractName } = parseContractId( + await this.getActivePoxContract() + ); const functionArgs: ClarityValue[] = [ uintCV(extendCount), @@ -150,7 +172,9 @@ export class StackingService { account: Account, increaseAmount: bigint ): Promise { - const { address: contractAddress, name: contractName } = parseContractId(this.contracts.POX_4); + const { address: contractAddress, name: contractName } = parseContractId( + await this.getActivePoxContract() + ); const functionArgs: ClarityValue[] = [uintCV(increaseAmount)]; @@ -180,7 +204,9 @@ export class StackingService { untilBurnHeight?: number, poxAddress?: { version: number; hashbytes: string } ): Promise { - const { address: contractAddress, name: contractName } = parseContractId(this.contracts.POX_4); + const { address: contractAddress, name: contractName } = parseContractId( + await this.getActivePoxContract() + ); const functionArgs: ClarityValue[] = [ uintCV(amount), @@ -208,7 +234,9 @@ export class StackingService { * Revoke delegation */ async revokeDelegation(account: Account): Promise { - 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, {