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:
-
Our contract (0xeBcB0968C20658B5eF602870D00471E5701DD466) called requestWinnerSelection for internal matchId 0x2c4bbd73e80ef925c8ff4ac239883b425b5d4025058e1724aa0387f003e4c56b.
-
This successfully executed in transaction 0x38952f53e71cf2db263f15c99b142a6f162fb0b82c93ace96864aee597ce8e51.
-
The transaction paid the Pyth fee (0.02 APE) to 0x36825bf3Fbdf5a29E2d5148bfe7Dcf7B5639e320.
-
Our contract emitted RandomnessRequested with sequenceNumber 3533 (0xdcd).
-
Expected: An incoming transaction calling entropyCallback on our contract with sequence number 3533.
-
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]; }

