@@ -45,6 +45,19 @@ import {
4545 HERMES_ETH_UNIQUE_EXPO ,
4646 HERMES_ETH_UNIQUE_PRICE ,
4747 HERMES_ETH_UNIQUE_PUBLISH_TIME ,
48+ HERMES_SOL_TON_PYTH_USDT_UPDATE ,
49+ PYTH_PRICE_FEED_ID ,
50+ SOL_PRICE_FEED_ID ,
51+ TON_PRICE_FEED_ID ,
52+ USDT_PRICE_FEED_ID ,
53+ HERMES_SOL_UNIQUE_PUBLISH_TIME ,
54+ HERMES_SOL_UNIQUE_PRICE ,
55+ HERMES_SOL_UNIQUE_CONF ,
56+ HERMES_SOL_UNIQUE_EXPO ,
57+ HERMES_USDT_UNIQUE_PRICE ,
58+ HERMES_USDT_UNIQUE_EXPO ,
59+ HERMES_USDT_UNIQUE_CONF ,
60+ HERMES_USDT_UNIQUE_PUBLISH_TIME ,
4861} from "./utils/pyth" ;
4962import { GUARDIAN_SET_0 , MAINNET_UPGRADE_VAAS } from "./utils/wormhole" ;
5063import { DataSource } from "@pythnetwork/xc-admin-common" ;
@@ -1110,6 +1123,122 @@ describe("PythTest", () => {
11101123 ) ;
11111124 } ) ;
11121125
1126+ it ( "should successfully parse price feed updates with more than 3 price feed ids" , async ( ) => {
1127+ await deployContract ( ) ;
1128+ await updateGuardianSets ( pythTest , deployer ) ;
1129+
1130+ const sentValue = toNano ( "1" ) ;
1131+ const result = await pythTest . sendParsePriceFeedUpdates (
1132+ deployer . getSender ( ) ,
1133+ Buffer . from ( HERMES_SOL_TON_PYTH_USDT_UPDATE , "hex" ) ,
1134+ sentValue ,
1135+ [
1136+ SOL_PRICE_FEED_ID ,
1137+ TON_PRICE_FEED_ID ,
1138+ PYTH_PRICE_FEED_ID ,
1139+ USDT_PRICE_FEED_ID ,
1140+ ] ,
1141+ HERMES_SOL_UNIQUE_PUBLISH_TIME ,
1142+ HERMES_SOL_UNIQUE_PUBLISH_TIME ,
1143+ deployer . address ,
1144+ CUSTOM_PAYLOAD ,
1145+ ) ;
1146+
1147+ // Verify transaction success and message count
1148+ expect ( result . transactions ) . toHaveTransaction ( {
1149+ from : deployer . address ,
1150+ to : pythTest . address ,
1151+ success : true ,
1152+ outMessagesCount : 1 ,
1153+ } ) ;
1154+
1155+ // Get the output message
1156+ const outMessage = result . transactions [ 1 ] . outMessages . values ( ) [ 0 ] ;
1157+
1158+ // Verify excess value is returned
1159+ expect (
1160+ ( outMessage . info as CommonMessageInfoInternal ) . value . coins ,
1161+ ) . toBeGreaterThan ( 0 ) ;
1162+
1163+ const cs = outMessage . body . beginParse ( ) ;
1164+
1165+ // Verify message header
1166+ const op = cs . loadUint ( 32 ) ;
1167+ expect ( op ) . toBe ( 5 ) ; // OP_PARSE_PRICE_FEED_UPDATES
1168+
1169+ // Verify number of price feeds
1170+ const numPriceFeeds = cs . loadUint ( 8 ) ;
1171+ expect ( numPriceFeeds ) . toBe ( 4 ) ; // We expect SOL, TON, PYTH and USDT price feeds
1172+
1173+ // Load and verify price feeds
1174+ const priceFeedsCell = cs . loadRef ( ) ;
1175+ let currentCell = priceFeedsCell ;
1176+
1177+ // First price feed (SOL)
1178+ const solCs = currentCell . beginParse ( ) ;
1179+ const solPriceId =
1180+ "0x" + solCs . loadUintBig ( 256 ) . toString ( 16 ) . padStart ( 64 , "0" ) ;
1181+ expect ( solPriceId ) . toBe ( SOL_PRICE_FEED_ID ) ;
1182+
1183+ const solPriceFeedCell = solCs . loadRef ( ) ;
1184+ const solPriceFeedSlice = solPriceFeedCell . beginParse ( ) ;
1185+
1186+ // Verify SOL current price
1187+ const solCurrentPriceCell = solPriceFeedSlice . loadRef ( ) ;
1188+ const solCurrentPrice = solCurrentPriceCell . beginParse ( ) ;
1189+ expect ( solCurrentPrice . loadInt ( 64 ) ) . toBe ( HERMES_SOL_UNIQUE_PRICE ) ;
1190+ expect ( solCurrentPrice . loadUint ( 64 ) ) . toBe ( HERMES_SOL_UNIQUE_CONF ) ;
1191+ expect ( solCurrentPrice . loadInt ( 32 ) ) . toBe ( HERMES_SOL_UNIQUE_EXPO ) ;
1192+ expect ( solCurrentPrice . loadUint ( 64 ) ) . toBe ( HERMES_SOL_UNIQUE_PUBLISH_TIME ) ;
1193+
1194+ // Move through TON and PYTH price feeds to reach USDT
1195+ currentCell = solCs . loadRef ( ) ; // Move to TON
1196+ const tonCs = currentCell . beginParse ( ) ;
1197+ tonCs . loadUintBig ( 256 ) ; // Skip TON price ID
1198+ tonCs . loadRef ( ) ; // Skip TON price data
1199+
1200+ currentCell = tonCs . loadRef ( ) ; // Move to PYTH
1201+ const pythCs = currentCell . beginParse ( ) ;
1202+ pythCs . loadUintBig ( 256 ) ; // Skip PYTH price ID
1203+ pythCs . loadRef ( ) ; // Skip PYTH price data
1204+
1205+ currentCell = pythCs . loadRef ( ) ; // Move to USDT
1206+ const usdtCs = currentCell . beginParse ( ) ;
1207+ const usdtPriceId =
1208+ "0x" + usdtCs . loadUintBig ( 256 ) . toString ( 16 ) . padStart ( 64 , "0" ) ;
1209+ expect ( usdtPriceId ) . toBe ( USDT_PRICE_FEED_ID ) ;
1210+
1211+ const usdtPriceFeedCell = usdtCs . loadRef ( ) ;
1212+ const usdtPriceFeedSlice = usdtPriceFeedCell . beginParse ( ) ;
1213+
1214+ // Verify USDT current price
1215+ const usdtCurrentPriceCell = usdtPriceFeedSlice . loadRef ( ) ;
1216+ const usdtCurrentPrice = usdtCurrentPriceCell . beginParse ( ) ;
1217+ expect ( usdtCurrentPrice . loadInt ( 64 ) ) . toBe ( HERMES_USDT_UNIQUE_PRICE ) ;
1218+ expect ( usdtCurrentPrice . loadUint ( 64 ) ) . toBe ( HERMES_USDT_UNIQUE_CONF ) ;
1219+ expect ( usdtCurrentPrice . loadInt ( 32 ) ) . toBe ( HERMES_USDT_UNIQUE_EXPO ) ;
1220+ expect ( usdtCurrentPrice . loadUint ( 64 ) ) . toBe ( HERMES_USDT_UNIQUE_PUBLISH_TIME ) ;
1221+
1222+ // Verify this is the end of the chain
1223+ expect ( usdtCs . remainingRefs ) . toBe ( 0 ) ;
1224+
1225+ // Verify sender address
1226+ const senderAddress = cs . loadAddress ( ) ;
1227+ expect ( senderAddress ?. toString ( ) ) . toBe (
1228+ deployer . getSender ( ) . address . toString ( ) ,
1229+ ) ;
1230+
1231+ // Verify custom payload
1232+ const customPayloadCell = cs . loadRef ( ) ;
1233+ const customPayloadSlice = customPayloadCell . beginParse ( ) ;
1234+ const receivedPayload = Buffer . from (
1235+ customPayloadSlice . loadBuffer ( CUSTOM_PAYLOAD . length ) ,
1236+ ) ;
1237+ expect ( receivedPayload . toString ( "hex" ) ) . toBe (
1238+ CUSTOM_PAYLOAD . toString ( "hex" ) ,
1239+ ) ;
1240+ } ) ;
1241+
11131242 it ( "should successfully parse unique price feed updates" , async ( ) => {
11141243 await deployContract ( ) ;
11151244 await updateGuardianSets ( pythTest , deployer ) ;
@@ -1229,6 +1358,122 @@ describe("PythTest", () => {
12291358 ) ;
12301359 } ) ;
12311360
1361+ it ( "should successfully parse unique price feed updates with more than 3 price feed ids" , async ( ) => {
1362+ await deployContract ( ) ;
1363+ await updateGuardianSets ( pythTest , deployer ) ;
1364+
1365+ const sentValue = toNano ( "1" ) ;
1366+ const result = await pythTest . sendParseUniquePriceFeedUpdates (
1367+ deployer . getSender ( ) ,
1368+ Buffer . from ( HERMES_SOL_TON_PYTH_USDT_UPDATE , "hex" ) ,
1369+ sentValue ,
1370+ [
1371+ SOL_PRICE_FEED_ID ,
1372+ TON_PRICE_FEED_ID ,
1373+ PYTH_PRICE_FEED_ID ,
1374+ USDT_PRICE_FEED_ID ,
1375+ ] ,
1376+ HERMES_SOL_UNIQUE_PUBLISH_TIME ,
1377+ 60 ,
1378+ deployer . address ,
1379+ CUSTOM_PAYLOAD ,
1380+ ) ;
1381+
1382+ // Verify transaction success and message count
1383+ expect ( result . transactions ) . toHaveTransaction ( {
1384+ from : deployer . address ,
1385+ to : pythTest . address ,
1386+ success : true ,
1387+ outMessagesCount : 1 ,
1388+ } ) ;
1389+
1390+ // Get the output message
1391+ const outMessage = result . transactions [ 1 ] . outMessages . values ( ) [ 0 ] ;
1392+
1393+ // Verify excess value is returned
1394+ expect (
1395+ ( outMessage . info as CommonMessageInfoInternal ) . value . coins ,
1396+ ) . toBeGreaterThan ( 0 ) ;
1397+
1398+ const cs = outMessage . body . beginParse ( ) ;
1399+
1400+ // Verify message header
1401+ const op = cs . loadUint ( 32 ) ;
1402+ expect ( op ) . toBe ( 6 ) ; // OP_PARSE_UNIQUE_PRICE_FEED_UPDATES
1403+
1404+ // Verify number of price feeds
1405+ const numPriceFeeds = cs . loadUint ( 8 ) ;
1406+ expect ( numPriceFeeds ) . toBe ( 4 ) ; // We expect SOL, TON, PYTH and USDT price feeds
1407+
1408+ // Load and verify price feeds
1409+ const priceFeedsCell = cs . loadRef ( ) ;
1410+ let currentCell = priceFeedsCell ;
1411+
1412+ // First price feed (SOL)
1413+ const solCs = currentCell . beginParse ( ) ;
1414+ const solPriceId =
1415+ "0x" + solCs . loadUintBig ( 256 ) . toString ( 16 ) . padStart ( 64 , "0" ) ;
1416+ expect ( solPriceId ) . toBe ( SOL_PRICE_FEED_ID ) ;
1417+
1418+ const solPriceFeedCell = solCs . loadRef ( ) ;
1419+ const solPriceFeedSlice = solPriceFeedCell . beginParse ( ) ;
1420+
1421+ // Verify SOL current price
1422+ const solCurrentPriceCell = solPriceFeedSlice . loadRef ( ) ;
1423+ const solCurrentPrice = solCurrentPriceCell . beginParse ( ) ;
1424+ expect ( solCurrentPrice . loadInt ( 64 ) ) . toBe ( HERMES_SOL_UNIQUE_PRICE ) ;
1425+ expect ( solCurrentPrice . loadUint ( 64 ) ) . toBe ( HERMES_SOL_UNIQUE_CONF ) ;
1426+ expect ( solCurrentPrice . loadInt ( 32 ) ) . toBe ( HERMES_SOL_UNIQUE_EXPO ) ;
1427+ expect ( solCurrentPrice . loadUint ( 64 ) ) . toBe ( HERMES_SOL_UNIQUE_PUBLISH_TIME ) ;
1428+
1429+ // Move through TON and PYTH price feeds to reach USDT
1430+ currentCell = solCs . loadRef ( ) ; // Move to TON
1431+ const tonCs = currentCell . beginParse ( ) ;
1432+ tonCs . loadUintBig ( 256 ) ; // Skip TON price ID
1433+ tonCs . loadRef ( ) ; // Skip TON price data
1434+
1435+ currentCell = tonCs . loadRef ( ) ; // Move to PYTH
1436+ const pythCs = currentCell . beginParse ( ) ;
1437+ pythCs . loadUintBig ( 256 ) ; // Skip PYTH price ID
1438+ pythCs . loadRef ( ) ; // Skip PYTH price data
1439+
1440+ currentCell = pythCs . loadRef ( ) ; // Move to USDT
1441+ const usdtCs = currentCell . beginParse ( ) ;
1442+ const usdtPriceId =
1443+ "0x" + usdtCs . loadUintBig ( 256 ) . toString ( 16 ) . padStart ( 64 , "0" ) ;
1444+ expect ( usdtPriceId ) . toBe ( USDT_PRICE_FEED_ID ) ;
1445+
1446+ const usdtPriceFeedCell = usdtCs . loadRef ( ) ;
1447+ const usdtPriceFeedSlice = usdtPriceFeedCell . beginParse ( ) ;
1448+
1449+ // Verify USDT current price
1450+ const usdtCurrentPriceCell = usdtPriceFeedSlice . loadRef ( ) ;
1451+ const usdtCurrentPrice = usdtCurrentPriceCell . beginParse ( ) ;
1452+ expect ( usdtCurrentPrice . loadInt ( 64 ) ) . toBe ( HERMES_USDT_UNIQUE_PRICE ) ;
1453+ expect ( usdtCurrentPrice . loadUint ( 64 ) ) . toBe ( HERMES_USDT_UNIQUE_CONF ) ;
1454+ expect ( usdtCurrentPrice . loadInt ( 32 ) ) . toBe ( HERMES_USDT_UNIQUE_EXPO ) ;
1455+ expect ( usdtCurrentPrice . loadUint ( 64 ) ) . toBe ( HERMES_USDT_UNIQUE_PUBLISH_TIME ) ;
1456+
1457+ // Verify this is the end of the chain
1458+ expect ( usdtCs . remainingRefs ) . toBe ( 0 ) ;
1459+
1460+ // Verify sender address
1461+ const senderAddress = cs . loadAddress ( ) ;
1462+ expect ( senderAddress ?. toString ( ) ) . toBe (
1463+ deployer . getSender ( ) . address . toString ( ) ,
1464+ ) ;
1465+
1466+ // Verify custom payload
1467+ const customPayloadCell = cs . loadRef ( ) ;
1468+ const customPayloadSlice = customPayloadCell . beginParse ( ) ;
1469+ const receivedPayload = Buffer . from (
1470+ customPayloadSlice . loadBuffer ( CUSTOM_PAYLOAD . length ) ,
1471+ ) ;
1472+ expect ( receivedPayload . toString ( "hex" ) ) . toBe (
1473+ CUSTOM_PAYLOAD . toString ( "hex" ) ,
1474+ ) ;
1475+ } ) ;
1476+
12321477 it ( "should fail to parse invalid price feed updates" , async ( ) => {
12331478 await deployContract ( ) ;
12341479 await updateGuardianSets ( pythTest , deployer ) ;
0 commit comments