Missing Entropy Callback on ApeChain Mainnet - Sequence #3533

Hey Guys,

We are using the Pyth Entropy service on ApeChain Mainnet and encountered an issue with one specific randomness request where the callback seems to be missing.

We successfully called requestWinnerSelection on our contract for three different raffles around the same time. Two of the requests (Sequence #3531 and #3532) received their callbacks successfully and the raffles were finalized. However, the callback for the third request (Sequence #3533) never arrived at our contract.

We have confirmed via getMatch on our contract that the state for the corresponding raffle (matchId ending …c56b) still shows isEnded: false and isRandomnessFulfilled: false. We have also searched the transaction history (including internal transactions) for our contract address on Apescan and could not find any failed incoming transaction around the expected callback time for sequence #3533.

Could you please help investigate the status of this specific callback request from your side?


Required Information:

  • Chain: ApeChain Mainnet (Chain ID: 33139)

  • Timestamp of Request: Transaction 0x389…e51 occurred at Block 14004801 (Approx. Apr-19-2025 12:11:28 AM UTC-4

  • Steps to Reproduce:

    1. Our contract (0xeBcB0968C20658B5eF602870D00471E5701DD466) called requestWinnerSelection for internal matchId 0x2c4bbd73e80ef925c8ff4ac239883b425b5d4025058e1724aa0387f003e4c56b.

    2. This successfully executed in transaction 0x38952f53e71cf2db263f15c99b142a6f162fb0b82c93ace96864aee597ce8e51.

    3. The transaction paid the Pyth fee (0.02 APE) to 0x36825bf3Fbdf5a29E2d5148bfe7Dcf7B5639e320.

    4. Our contract emitted RandomnessRequested with sequenceNumber 3533 (0xdcd).

    5. Expected: An incoming transaction calling entropyCallback on our contract with sequence number 3533.

    6. Actual: No successful or visibly failed callback transaction has been observed for sequence number 3533.

  • Supporting Identifiers:

    • Our Consumer Contract Address: 0xeBcB0968C20658B5eF602870D00471E5701DD466

    • Pyth Entropy Contract Addr: 0x36825bf3Fbdf5a29E2d5148bfe7Dcf7B5639e320

    • Pyth Provider Addr Used: 0x52DeaA1c84233F7bb8C8A45baeDE41091c616506

    • Problematic Request Tx Hash: 0x38952f53e71cf2db263f15c99b142a6f162fb0b82c93ace96864aee597ce8e51

    • Problematic Sequence Number: 3533

    • Problematic Raffle ID: 0x2c4bbd73e80ef925c8ff4ac239883b425b5d4025058e1724aa0387f003e4c56b

27: randomnessRequested 0x2c4bbd73e80ef925c8ff4ac239883b425b5d4025058e1724aa0387f003e4c56b bool [ randomnessRequested(bytes32) method Response ] bool : true

13:raffleId (bytes32) 0x2c4bbd73e80ef925c8ff4ac239883b425b5d4025058e1724aa0387f003e4c56b tuple [ getRaffleDetails(bytes32) method Response ] tuple : 0x2c4bbd73e80ef925c8ff4ac239883b425b5d4025058e1724aa0387f003e4c56b,1,2,3,4,5,6,7,8,9,0xaE166293E39d130c37D8a79686958da1F8459282,6,295,1745028001,0x0000000000000000000000000000000000000000,false,false,true,72000000000000000000,false

function entropyCallback(uint64 sequenceNum, address /*originProvider*/, bytes32 randomNumber) internal override nonReentrant { if (_msgSender() != address(entropy)) revert InvalidCallbackOrigin(_msgSender(), address(entropy)); bytes32 raffleId = sequenceNumberToMatchId[sequenceNum]; if (raffleId == bytes32(0)) return; Match storage matchRef = matches[raffleId]; if (!matchRef.exists || matchRef.isEnded || matchRef.isRandomnessFulfilled) { delete sequenceNumberToMatchId[sequenceNum]; return; } matchRef.isRandomnessFulfilled = true; if (matchRef.totalEntries == 0) { matchRef.isEnded = true; try INft(matchRef.nftAddress).ownerOf(matchRef.nftId) returns (address nftOwner) { if (nftOwner == address(this)) { INft(matchRef.nftAddress).safeTransferFrom(address(this), owner(), matchRef.nftId); }} catch {} delete sequenceNumberToMatchId[sequenceNum]; return; } uint winningIndex = uint(randomNumber) % matchRef.totalEntries; address winningParticipant = address(0); uint participantEntries = 0; uint cumulativeCount = 0; Participation[] storage participantList = participations[raffleId]; uint participantCount = participantList.length; for (uint idx = 0; idx < participantCount; idx++) { Participation storage pRecord = participantList[idx]; cumulativeCount += pRecord.entries; if (winningIndex < cumulativeCount) { winningParticipant = pRecord.participant; participantEntries = pRecord.entries; break; } } if (winningParticipant == address(0)) { revert("Internal winner selection logic error: No winner found despite entries."); } matchRef.winner = winningParticipant; matchRef.isEnded = true; emit WinnerSelected(raffleId, winningParticipant, participantEntries); // Emit before potentially failing interactions uint collectedPool = matchRef.fundsCollected; if (collectedPool > 0) { uint feeShare = (collectedPool * FEE_PERCENT) / 100; uint treasuryShare = (collectedPool * TREASURY_PERCENT) / 100; uint opsShare = collectedPool - feeShare - treasuryShare; (bool feeSent,) = feeAccount.call{value:feeShare}(""); (bool tresSent,) = treasuryAccount.call{value:treasuryShare}(""); (bool opsSent,) = operationsAccount.call{value:opsShare}(""); if (feeSent && tresSent && opsSent) { emit FundsDistributed(raffleId, collectedPool, feeShare, treasuryShare, opsShare); } else { emit FundsDistributionFailed(raffleId, feeSent, tresSent, opsSent); } } try INft(matchRef.nftAddress).ownerOf(matchRef.nftId) returns (address currentNftOwner) { if (currentNftOwner == address(this)) { INft(matchRef.nftAddress).safeTransferFrom(address(this), winningParticipant, matchRef.nftId); } else { emit NftTransferFailedDuringCallback(raffleId, winningParticipant, matchRef.nftAddress, matchRef.nftId); } } catch { emit NftTransferFailedDuringCallback(raffleId, winningParticipant, matchRef.nftAddress, matchRef.nftId); } delete sequenceNumberToMatchId[sequenceNum]; }

Thank you for posting the question and providing all the necessary details to help us debug this.

The random number request attached to sequence number 3533 failed due to the gas limit enforced on callback methods.

Our RPC estimated that the callback method in your contract would consume 569816 gas, which exceeds the 500000 gas limit.

Thanks for the quick investigation and confirming that the callback for our Sequence #3533 failed due to exceeding the 500k gas limit in our contract’s callback logic. We really appreciate you pinpointing the cause for us.

We understand that because the callback transaction failed, the process can’t be automatically retried or completed on-chain through the standard Entropy mechanism within our current contract.

Our main goal now is to resolve this specific raffle as fairly as possible for our participants. To help us do that transparently, we were wondering:

Is there any possibility for the Pyth team to share the actual randomNumber (the bytes32 value) that would have been delivered for Sequence #3533?

If we had that original random number, we could perform the winner selection calculation off-chain using our contract’s public logic and the on-chain participation data. We could then publicly document this process and manually distribute the NFT prize to the winner determined by that original randomness. This feels like the fairest approach if the number is accessible on your end.

If the original random number for Seq #3533 isn’t retrievable, perhaps Pyth could assist by generating a verifiable random number specifically tied to resolving this failed request? We could then use that number transparently for our necessary off-chain winner determination.

We totally understand if this isn’t feasible due to how your system handles failed deliveries or internal policies. If retrieving the original number isn’t possible, we’ll proceed with alternative transparent off-chain methods (like using a new randomness source publicly) or potentially re-running the raffle manually.

Thanks.

Hi, we have a tool that can help you manually reveal the random numbers.

It follows the steps described here.
https://docs.pyth.network/entropy/debug-callback-failures

Thanks for pointing us to the Entropy Debugger tool and the documentation

I actually tried using the Debugger Tool earlier for the request associated with Sequence #3533 on ApeChain Mainnet (tx: 0x389…e51).

Unfortunately, the Debugger Tool runs into the same issue we encountered when trying the manual curl/cast method described in the docs: it’s unable to fetch the necessary providerRevelation data. When the tool (or curl) queries the Fortuna API endpoint (…/apechain/revelations/3533), it consistently returns “The request needs additional confirmations before the random value can be retrieved. Try your request again later.” This has been the case for several hours now, well past the usual confirmation time we’d expect.

So, while I understand the manual reveal process outlined in the docs (and how the Debugger tool automates parts of it), we seem to be stuck at the step before we can even call revealWithCallback because the required providerRevelation data hasn’t become available via the API endpoint.

Could you possibly check on your end if there’s a known delay or a specific issue preventing the revelation data for **Sequence #3533 ** from finalizing and becoming accessible via the API? or Let me know if i am doing anything wrong.

[https://fortuna.dourolabs.app/v1/chains/apechain/revelations/3533/]
The request needs additional confirmations before the random value can be retrieved. Try your request again later.

Thank you for pointing that out. We will reply back with a fix soon.

hey hi, Any update yet about the issue?

Can you try again? An update was rolled out recently to address this issue.

1 Like