Skip to content

Commit 1b01a7a

Browse files
committed
feat: implement TWAP message creation and update data generation in Pyth contract tests
1 parent 8a6f154 commit 1b01a7a

File tree

2 files changed

+106
-40
lines changed

2 files changed

+106
-40
lines changed

target_chains/ethereum/contracts/forge-test/Pyth.t.sol

Lines changed: 52 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -390,56 +390,68 @@ contract PythTest is Test, WormholeTestUtils, PythTestUtils {
390390
bytes32[] memory priceIds = new bytes32[](numMessages);
391391
priceIds[0] = bytes32(uint256(1));
392392

393-
// Create two PriceFeedMessage instances for the start and end points
394-
PriceFeedMessage[] memory messages = new PriceFeedMessage[](2);
395-
396-
// Start message
397-
messages[0].priceId = priceIds[0];
398-
messages[0].price = 100;
399-
messages[0].conf = 10;
400-
messages[0].expo = -8;
401-
messages[0].publishTime = 1000;
402-
messages[0].prevPublishTime = 900;
403-
messages[0].emaPrice = 100;
404-
messages[0].emaConf = 10;
393+
// Create start and end TWAP messages directly
394+
TwapPriceFeedMessage[]
395+
memory startTwapMessages = new TwapPriceFeedMessage[](1);
396+
startTwapMessages[0].priceId = priceIds[0];
397+
startTwapMessages[0].cumulativePrice = 100_000; // Base cumulative value
398+
startTwapMessages[0].cumulativeConf = 10_000; // Base cumulative conf
399+
startTwapMessages[0].numDownSlots = 0;
400+
startTwapMessages[0].expo = -8;
401+
startTwapMessages[0].publishTime = 1000;
402+
startTwapMessages[0].prevPublishTime = 900;
403+
startTwapMessages[0].publishSlot = 1000;
405404

406-
// End message
407-
messages[1].priceId = priceIds[0];
408-
messages[1].price = 110;
409-
messages[1].conf = 8;
410-
messages[1].expo = -8;
411-
messages[1].publishTime = 1100;
412-
messages[1].prevPublishTime = 1000;
413-
messages[1].emaPrice = 110;
414-
messages[1].emaConf = 8;
405+
TwapPriceFeedMessage[]
406+
memory endTwapMessages = new TwapPriceFeedMessage[](1);
407+
endTwapMessages[0].priceId = priceIds[0];
408+
endTwapMessages[0].cumulativePrice = 210_000; // Increased by 110_000
409+
endTwapMessages[0].cumulativeConf = 18_000; // Increased by 8_000
410+
endTwapMessages[0].numDownSlots = 0;
411+
endTwapMessages[0].expo = -8;
412+
endTwapMessages[0].publishTime = 1100;
413+
endTwapMessages[0].prevPublishTime = 1000;
414+
endTwapMessages[0].publishSlot = 1100;
415+
416+
// Create update data directly from TWAP messages
417+
bytes[] memory updateData = new bytes[](2);
418+
updateData[0] = generateWhMerkleTwapUpdateWithSource(
419+
startTwapMessages,
420+
MerkleUpdateConfig(
421+
MERKLE_TREE_DEPTH,
422+
NUM_GUARDIAN_SIGNERS,
423+
SOURCE_EMITTER_CHAIN_ID,
424+
SOURCE_EMITTER_ADDRESS,
425+
false
426+
)
427+
);
428+
updateData[1] = generateWhMerkleTwapUpdateWithSource(
429+
endTwapMessages,
430+
MerkleUpdateConfig(
431+
MERKLE_TREE_DEPTH,
432+
NUM_GUARDIAN_SIGNERS,
433+
SOURCE_EMITTER_CHAIN_ID,
434+
SOURCE_EMITTER_ADDRESS,
435+
false
436+
)
437+
);
415438

416-
// Create update data for TWAP calculation
417-
(
418-
bytes[] memory updateData,
419-
uint updateFee
420-
) = createBatchedTwapUpdateDataFromMessages(messages);
439+
uint updateFee = pyth.getUpdateFee(updateData);
421440

422441
// Parse the TWAP updates
423442
PythStructs.TwapPriceFeed[] memory twapPriceFeeds = pyth
424443
.parseTwapPriceFeedUpdates{value: updateFee}(updateData, priceIds);
425444

426-
// Validate basic properties
445+
// Validate results
427446
assertEq(twapPriceFeeds[0].id, priceIds[0]);
428-
assertEq(twapPriceFeeds[0].startTime, uint64(1000)); // publishTime start
429-
assertEq(twapPriceFeeds[0].endTime, uint64(1100)); // publishTime end
430-
assertEq(twapPriceFeeds[0].twap.expo, int32(-8)); // expo
431-
432-
// Expected TWAP price calculation:
433-
// (endCumulativePrice - startCumulativePrice) / (endSlot - startSlot)
434-
// ((110 * 1000 + 100 * 1000) - (100 * 1000)) / (1100 - 1000)
435-
// = (210000 - 100000) / 100 = 1100
436-
// The smart contract will convert this to int64, and our calculation simplified for clarity
447+
assertEq(twapPriceFeeds[0].startTime, uint64(1000));
448+
assertEq(twapPriceFeeds[0].endTime, uint64(1100));
449+
assertEq(twapPriceFeeds[0].twap.expo, int32(-8));
450+
451+
// Expected TWAP price: (210_000 - 100_000) / (1100 - 1000) = 1100
437452
assertEq(twapPriceFeeds[0].twap.price, int64(1100));
438453

439-
// Expected TWAP conf calculation:
440-
// (endCumulativeConf - startCumulativeConf) / (endSlot - startSlot)
441-
// ((8 * 1000 + 10 * 1000) - (10 * 1000)) / (1100 - 1000)
442-
// = (18000 - 10000) / 100 = 80
454+
// Expected TWAP conf: (18_000 - 10_000) / (1100 - 1000) = 80
443455
assertEq(twapPriceFeeds[0].twap.conf, uint64(80));
444456

445457
// Validate the downSlotsRatio is 0 in our test implementation

target_chains/ethereum/sdk/solidity/abis/MockPyth.json

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,60 @@
183183
"stateMutability": "pure",
184184
"type": "function"
185185
},
186+
{
187+
"inputs": [
188+
{
189+
"internalType": "bytes32",
190+
"name": "id",
191+
"type": "bytes32"
192+
},
193+
{
194+
"internalType": "int128",
195+
"name": "cumulativePrice",
196+
"type": "int128"
197+
},
198+
{
199+
"internalType": "uint128",
200+
"name": "cumulativeConf",
201+
"type": "uint128"
202+
},
203+
{
204+
"internalType": "uint64",
205+
"name": "numDownSlots",
206+
"type": "uint64"
207+
},
208+
{
209+
"internalType": "int32",
210+
"name": "expo",
211+
"type": "int32"
212+
},
213+
{
214+
"internalType": "uint64",
215+
"name": "publishTime",
216+
"type": "uint64"
217+
},
218+
{
219+
"internalType": "uint64",
220+
"name": "prevPublishTime",
221+
"type": "uint64"
222+
},
223+
{
224+
"internalType": "uint64",
225+
"name": "publishSlot",
226+
"type": "uint64"
227+
}
228+
],
229+
"name": "createTwapPriceFeedUpdateData",
230+
"outputs": [
231+
{
232+
"internalType": "bytes",
233+
"name": "twapData",
234+
"type": "bytes"
235+
}
236+
],
237+
"stateMutability": "pure",
238+
"type": "function"
239+
},
186240
{
187241
"inputs": [
188242
{

0 commit comments

Comments
 (0)