Skip to content

Commit

Permalink
Merge branch 'main' into feat/deployer_cli
Browse files Browse the repository at this point in the history
  • Loading branch information
akhercha authored Sep 24, 2024
2 parents 4b21444 + cbf790b commit 76c71b6
Show file tree
Hide file tree
Showing 11 changed files with 195 additions and 79 deletions.
18 changes: 18 additions & 0 deletions .github/workflows/solidity-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -135,3 +135,21 @@ jobs:
with:
name: gas-report
path: ${{ env.working-directory }}/previous_gas_report.txt

- name: Static analysis
uses: crytic/slither-action@v0.4.0
id: slither
with:
target: 'solidity/'
slither-config: 'solidity/slither.config.json'
slither-args: --exclude incorrect-exponentiation
sarif: results.sarif
fail-on: none
compile-command: |
forge build
ignore-compile: false

- name: Upload SARIF file
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: ${{ steps.slither.outputs.sarif }}
6 changes: 6 additions & 0 deletions solidity/slither.config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"filter_paths": "lib|node_modules|test|Mock*|Test*",
"compile_force_framework": "foundry",
"exclude_informational": true,
"no_fail": true
}
17 changes: 15 additions & 2 deletions solidity/src/Pragma.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import "./PragmaDecoder.sol";
import "./libraries/EventsLib.sol";
import "./libraries/ErrorsLib.sol";
import "./interfaces/PragmaStructs.sol";
import "./libraries/DataParser.sol";

/// @title Pragma
/// @author Pragma Labs
Expand All @@ -16,7 +17,6 @@ contract Pragma is IPragma, PragmaDecoder {
/* STORAGE */
uint256 public validTimePeriodSeconds;
uint256 public singleUpdateFeeInWei;
mapping(bytes32 => uint64) public latestDataInfoPublishTime;

constructor(
address _hyperlane,
Expand Down Expand Up @@ -111,7 +111,20 @@ contract Pragma is IPragma, PragmaDecoder {

/// @inheritdoc IPragma
function dataFeedExists(bytes32 id) external view returns (bool) {
return (latestDataInfoPublishTime[id] != 0);
FeedType feedType = DataParser.safeCastToFeedType(uint8(id[0]));
if (feedType == FeedType.SpotMedian) {
return (spotMedianFeeds[id].metadata.timestamp != 0);
} else if (feedType == FeedType.Twap) {
return (twapFeeds[id].metadata.timestamp != 0);
} else if (feedType == FeedType.RealizedVolatility) {
return (rvFeeds[id].metadata.timestamp != 0);
} else if (feedType == FeedType.Options) {
return (optionsFeeds[id].metadata.timestamp != 0);
} else if (feedType == FeedType.Perpetuals) {
return (perpFeeds[id].metadata.timestamp != 0);
} else {
revert ErrorsLib.InvalidDataFeedType();
}
}

function getValidTimePeriod() public view returns (uint256) {
Expand Down
2 changes: 1 addition & 1 deletion solidity/src/PragmaDecoder.sol
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ contract PragmaDecoder {
virtual
returns (bool valid, uint256 endOffset)
{
return MerkleTree.isProofValid(encodedProof, offset, root, leafData);
(valid, endOffset) = MerkleTree.isProofValid(encodedProof, offset, root, leafData);
}

function extractDataInfoFromUpdate(bytes calldata encoded, uint256 offset, bytes32 checkpointRoot)
Expand Down
71 changes: 69 additions & 2 deletions solidity/src/interfaces/PragmaStructs.sol
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,8 @@ struct RealizedVolatility {
uint256 timePeriod;
uint256 startPrice;
uint256 endPrice;
uint256 high_price;
uint256 low_price;
uint256 highPrice;
uint256 lowPrice;
uint256 numberOfDataPoints;
}

Expand Down Expand Up @@ -109,3 +109,70 @@ enum FeedType {
Options,
Perpetuals
}

library StructsInitializers {
function initializeParsedData() internal pure returns (ParsedData memory) {
return ParsedData({
dataType: FeedType.SpotMedian,
spot: initializeSpotMedian(),
twap: initializeTwap(),
rv: initializeRV(),
options: initializeOptions(),
perp: initializePerpetuals()
});
}

function initializeMetadata() internal pure returns (Metadata memory) {
return Metadata({feedId: 0, timestamp: 0, numberOfSources: 0, decimals: 0});
}

function initializeSpotMedian() internal pure returns (SpotMedian memory) {
return SpotMedian({metadata: initializeMetadata(), price: 0, volume: 0});
}

function initializeTwap() internal pure returns (TWAP memory) {
return TWAP({
metadata: initializeMetadata(),
twapPrice: 0,
timePeriod: 0,
startPrice: 0,
endPrice: 0,
totalVolume: 0,
numberOfDataPoints: 0
});
}

function initializeRV() internal pure returns (RealizedVolatility memory) {
return RealizedVolatility({
metadata: initializeMetadata(),
volatility: 0,
timePeriod: 0,
startPrice: 0,
endPrice: 0,
highPrice: 0,
lowPrice: 0,
numberOfDataPoints: 0
});
}

function initializeOptions() internal pure returns (Options memory) {
return Options({
metadata: initializeMetadata(),
strikePrice: 0,
impliedVolatility: 0,
timeToExpiry: 0,
isCall: false,
underlyingPrice: 0,
optionPrice: 0,
delta: 0,
gamma: 0,
vega: 0,
theta: 0,
rho: 0
});
}

function initializePerpetuals() internal pure returns (Perp memory) {
return Perp({metadata: initializeMetadata(), markPrice: 0, fundingRate: 0, openInterest: 0, volume: 0});
}
}
24 changes: 12 additions & 12 deletions solidity/src/libraries/DataParser.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ library DataParser {

function parse(bytes memory data) internal pure returns (ParsedData memory) {
uint8 offset = 2; // type feed stored after asset class
uint16 rawDataType = data.toUint16(offset);
uint8 rawDataType = data.toUint8(offset);
FeedType dataType = safeCastToFeedType(rawDataType);

ParsedData memory parsedData;
ParsedData memory parsedData = StructsInitializers.initializeParsedData();
parsedData.dataType = dataType;
if (dataType == FeedType.SpotMedian) {
parsedData.spot = parseSpotData(data);
Expand All @@ -32,16 +32,16 @@ library DataParser {
return parsedData;
}

function safeCastToFeedType(uint16 rawDataType) internal pure returns (FeedType) {
if (rawDataType <= uint16(type(FeedType).max)) {
function safeCastToFeedType(uint8 rawDataType) internal pure returns (FeedType) {
if (rawDataType <= uint8(type(FeedType).max)) {
return FeedType(rawDataType);
} else {
revert ErrorsLib.InvalidDataFeedType();
}
}

function parseMetadata(bytes memory data, uint256 startIndex) internal pure returns (Metadata memory, uint256) {
Metadata memory metadata;
Metadata memory metadata = StructsInitializers.initializeMetadata();
uint256 index = startIndex;

metadata.feedId = bytes32(data.toUint256(index));
Expand All @@ -60,7 +60,7 @@ library DataParser {
}

function parseSpotData(bytes memory data) internal pure returns (SpotMedian memory) {
SpotMedian memory entry;
SpotMedian memory entry = StructsInitializers.initializeSpotMedian();
uint256 index = 0;

(entry.metadata, index) = parseMetadata(data, index);
Expand All @@ -74,7 +74,7 @@ library DataParser {
}

function parseTWAPData(bytes memory data) internal pure returns (TWAP memory) {
TWAP memory entry;
TWAP memory entry = StructsInitializers.initializeTwap();
uint256 index = 0;

(entry.metadata, index) = parseMetadata(data, index);
Expand All @@ -100,7 +100,7 @@ library DataParser {
}

function parseRealizedVolatilityData(bytes memory data) internal pure returns (RealizedVolatility memory) {
RealizedVolatility memory entry;
RealizedVolatility memory entry = StructsInitializers.initializeRV();
uint256 index = 0;

(entry.metadata, index) = parseMetadata(data, index);
Expand All @@ -117,10 +117,10 @@ library DataParser {
entry.endPrice = data.toUint256(index);
index += 32;

entry.high_price = data.toUint256(index);
entry.highPrice = data.toUint256(index);
index += 32;

entry.low_price = data.toUint256(index);
entry.lowPrice = data.toUint256(index);
index += 32;

entry.numberOfDataPoints = data.toUint256(index);
Expand All @@ -129,7 +129,7 @@ library DataParser {
}

function parseOptionsData(bytes memory data) internal pure returns (Options memory) {
Options memory entry;
Options memory entry = StructsInitializers.initializeOptions();
uint256 index = 0;

(entry.metadata, index) = parseMetadata(data, index);
Expand Down Expand Up @@ -170,7 +170,7 @@ library DataParser {
}

function parsePerpData(bytes memory data) internal pure returns (Perp memory) {
Perp memory entry;
Perp memory entry = StructsInitializers.initializePerpetuals();
uint256 index = 0;

(entry.metadata, index) = parseMetadata(data, index);
Expand Down
26 changes: 16 additions & 10 deletions solidity/test/DataParser.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ contract DataParserTest is Test {
abi.encodePacked(
uint16(0),
///CRYPTO
uint16(0), //SPOT
uint8(0), //SPOT
uint8(0), //VARIANT
bytes32("BTC/USD")
)
);
Expand Down Expand Up @@ -40,7 +41,8 @@ contract DataParserTest is Test {
abi.encodePacked(
uint16(0),
///CRYPTO
uint16(1), //TWAP
uint8(1), //TWAP
uint8(0), //VARIANT
bytes32("ETH/USD")
)
);
Expand Down Expand Up @@ -77,7 +79,8 @@ contract DataParserTest is Test {
abi.encodePacked(
uint16(0),
///CRYPTO
uint16(2), //RV
uint8(2), //RV
uint8(0), //VARIANT
bytes32("BTC/USD")
)
);
Expand All @@ -90,8 +93,8 @@ contract DataParserTest is Test {
uint256(86400), // timePeriod
uint256(34000 ether), // startPrice
uint256(36000 ether), // endPrice
uint256(37000 ether), // high_price
uint256(33000 ether), // low_price
uint256(37000 ether), // highPrice
uint256(33000 ether), // lowPrice
uint256(1440) // numberOfDataPoints
);

Expand All @@ -106,8 +109,8 @@ contract DataParserTest is Test {
assertEq(result.rv.timePeriod, 86400);
assertEq(result.rv.startPrice, 34000 ether);
assertEq(result.rv.endPrice, 36000 ether);
assertEq(result.rv.high_price, 37000 ether);
assertEq(result.rv.low_price, 33000 ether);
assertEq(result.rv.highPrice, 37000 ether);
assertEq(result.rv.lowPrice, 33000 ether);
assertEq(result.rv.numberOfDataPoints, 1440);
}

Expand All @@ -116,7 +119,8 @@ contract DataParserTest is Test {
abi.encodePacked(
uint16(0),
///CRYPTO
uint16(3), //Option
uint8(3), //Option
uint8(0), //VARIANT
bytes32("ETH/USD")
)
);
Expand Down Expand Up @@ -163,7 +167,8 @@ contract DataParserTest is Test {
abi.encodePacked(
uint16(0),
///CRYPTO
uint16(4), //PERP
uint8(4), //PERP
uint8(0), //VARIANT
bytes32("BTC/USD")
)
);
Expand Down Expand Up @@ -196,7 +201,8 @@ contract DataParserTest is Test {
abi.encodePacked(
uint16(0),
///CRYPTO
uint16(10), //Unkown data type
uint8(20), //Unkown data type
uint8(0),
bytes32("BTC/USD")
)
);
Expand Down
Loading

0 comments on commit 76c71b6

Please sign in to comment.