PoX contract is hardcoded to pox-4 — will silently break on the next upgrade
Right now, every stacking operation in this SDK targets pox-4 because the contract address and name are hardcoded in src/utils/constants.ts L76–L85:
export const poxInfo = {
testnet: { contractAddress: "ST000000000000000000002AMW42H", contractName: "pox-4" },
mainnet: { contractAddress: "SP000000000000000000002Q6VF78", contractName: "pox-4" },
};
This is then referenced in five places across src/services/stacks.service.ts (lines 291, 795, 850, 902, 956) — every stacking-related method (checkDelegationStatus, delegateStx, revokeStxDelegation, allowPoxContractCaller, soloStack) reads from this constant.
What breaks when pox-5 comes
When a new PoX contract activates:
-
All stacking calls go to the old contract. stack-stx, delegate-stx, revoke-delegate-stx, allow-contract-caller — all five call sites target pox-4. The old contract will likely reject new stacking operations with an error, or worse, succeed but have no effect on the new reward set.
-
Signer signatures become invalid. The signer signature domain is pox-4-signer (hardcoded in @stacks/stacking's pox4SignatureMessage()). A pox-5 contract will expect a different domain name. This one will also need updating in the upstream stacks.js lib, but the Fireblocks SDK calls this function in src/utils/helpers.ts L292 and would need to match whatever the new version expects.
-
Delegation status checks return stale data. checkDelegationStatus() calls get-delegation-info on pox-4. Once pox-5 is active, the canonical delegation state lives in the new contract.
-
No warning to the user. The SDK doesn't check whether the contract it's targeting is still the active one, so all of this happens silently.
What the SDK already has (but doesn't use)
The SDK already calls /v2/pox in StacksService.fetchPoxInfo() and the response includes contract_id (the currently active contract) and contract_versions. This data is used for eligibility checks and burn height calculations, but the actual contract address for stacking calls is pulled from the hardcoded constant instead.
Suggested fix
Since pox-5 is not finished yet, and will maybe differ in interface, it's fine to not support it immediately.
For now, I believe the best option is to check the active pox contract against the expected one and throw a failure if they don't match, so users don't work with a wrong contract.
This doesn't fix the problem but at least makes it loud instead of silent.
Affected code
PoX contract is hardcoded to pox-4 — will silently break on the next upgrade
Right now, every stacking operation in this SDK targets
pox-4because the contract address and name are hardcoded insrc/utils/constants.tsL76–L85:This is then referenced in five places across
src/services/stacks.service.ts(lines 291, 795, 850, 902, 956) — every stacking-related method (checkDelegationStatus,delegateStx,revokeStxDelegation,allowPoxContractCaller,soloStack) reads from this constant.What breaks when pox-5 comes
When a new PoX contract activates:
All stacking calls go to the old contract.
stack-stx,delegate-stx,revoke-delegate-stx,allow-contract-caller— all five call sites target pox-4. The old contract will likely reject new stacking operations with an error, or worse, succeed but have no effect on the new reward set.Signer signatures become invalid. The signer signature domain is
pox-4-signer(hardcoded in@stacks/stacking'spox4SignatureMessage()). A pox-5 contract will expect a different domain name. This one will also need updating in the upstream stacks.js lib, but the Fireblocks SDK calls this function insrc/utils/helpers.tsL292 and would need to match whatever the new version expects.Delegation status checks return stale data.
checkDelegationStatus()callsget-delegation-infoon pox-4. Once pox-5 is active, the canonical delegation state lives in the new contract.No warning to the user. The SDK doesn't check whether the contract it's targeting is still the active one, so all of this happens silently.
What the SDK already has (but doesn't use)
The SDK already calls
/v2/poxinStacksService.fetchPoxInfo()and the response includescontract_id(the currently active contract) andcontract_versions. This data is used for eligibility checks and burn height calculations, but the actual contract address for stacking calls is pulled from the hardcoded constant instead.Suggested fix
Since pox-5 is not finished yet, and will maybe differ in interface, it's fine to not support it immediately.
For now, I believe the best option is to check the active pox contract against the expected one and throw a failure if they don't match, so users don't work with a wrong contract.
This doesn't fix the problem but at least makes it loud instead of silent.
Affected code
src/utils/constants.tssrc/services/stacks.service.tscheckDelegationStatussrc/services/stacks.service.tsdelegateStxsrc/services/stacks.service.tsrevokeStxDelegationsrc/services/stacks.service.tsallowPoxContractCallersrc/services/stacks.service.tssoloStacksrc/utils/helpers.tspox4SignatureMessage)