Skip to content

Commit

Permalink
review: oliver
Browse files Browse the repository at this point in the history
* don't use associated functions when the operation is not associated
* factor out _validateTokens
* use A/B when unsorted; 0/1 when sorted
* avoid unnecessary temporary array
* update gas snapshot
* fix: collapse validation logic
* refactor: rename FlagsLib into RoutesLib
* fix: process 2 hop route before 3 hop route
* gas: update snapshot
---------
Co-authored-by: A.L. <[email protected]>
  • Loading branch information
OliverNChalk authored Jul 7, 2024
1 parent b3ee4b2 commit f7a709c
Show file tree
Hide file tree
Showing 6 changed files with 105 additions and 106 deletions.
102 changes: 51 additions & 51 deletions .gas-snapshot
Original file line number Diff line number Diff line change
@@ -1,74 +1,74 @@
FlagsLibTest:testGetDecimalDifference() (gas: 3974)
FlagsLibTest:testIsCompositeRoute() (gas: 4341)
FlagsLibTest:testPackSimplePrice(int8,uint256) (runs: 256, μ: 7791, ~: 7555)
QueryProcessorTest:testFindNearestSample_CanFindExactValue(uint32,uint256,uint256,uint256) (runs: 256, μ: 67735642, ~: 76032605)
QueryProcessorTest:testFindNearestSample_CanFindIntermediateValue(uint32,uint256,uint256,uint256) (runs: 256, μ: 65799154, ~: 75921271)
QueryProcessorTest:testFindNearestSample_CanFindExactValue(uint32,uint256,uint256,uint256) (runs: 256, μ: 67585746, ~: 76007063)
QueryProcessorTest:testFindNearestSample_CanFindIntermediateValue(uint32,uint256,uint256,uint256) (runs: 256, μ: 67051023, ~: 76087612)
QueryProcessorTest:testFindNearestSample_NotInitialized() (gas: 1056945756)
QueryProcessorTest:testFindNearestSample_OneSample(uint256) (runs: 256, μ: 80323, ~: 80360)
QueryProcessorTest:testFindNearestSample_OneSample(uint256) (runs: 256, μ: 80325, ~: 80360)
QueryProcessorTest:testGetInstantValue() (gas: 124248)
QueryProcessorTest:testGetInstantValue_NotInitialized(uint256) (runs: 256, μ: 19397, ~: 19397)
QueryProcessorTest:testGetInstantValue_NotInitialized_BeyondBufferSize(uint8,uint16) (runs: 256, μ: 68389656, ~: 68389600)
QueryProcessorTest:testGetPastAccumulator_BufferEmpty(uint8) (runs: 256, μ: 27031, ~: 27087)
QueryProcessorTest:testGetPastAccumulator_ExactMatch(uint32,uint256,uint256,uint16) (runs: 256, μ: 69753539, ~: 80758108)
QueryProcessorTest:testGetPastAccumulator_ExactMatch_LatestAccumulator(uint32,uint256,uint256) (runs: 256, μ: 69259342, ~: 79254030)
QueryProcessorTest:testGetPastAccumulator_ExactMatch_OldestAccumulator(uint32,uint256,uint256) (runs: 256, μ: 69289298, ~: 79285630)
QueryProcessorTest:testGetPastAccumulator_ExtrapolatesBeyondLatest(uint32,uint256,uint256,uint256) (runs: 256, μ: 65772814, ~: 75892463)
QueryProcessorTest:testGetPastAccumulator_InterpolatesBetweenPastAccumulators(uint32,uint256,uint256,uint256) (runs: 256, μ: 65806837, ~: 75927279)
QueryProcessorTest:testGetPastAccumulator_InvalidAgo(uint32,uint256,uint256,uint256) (runs: 256, μ: 65764408, ~: 75884174)
QueryProcessorTest:testGetPastAccumulator_QueryTooOld(uint32,uint256,uint256,uint256) (runs: 256, μ: 65775927, ~: 75894057)
QueryProcessorTest:testGetTimeWeightedAverage(uint32,uint256,uint256,uint256,uint256) (runs: 256, μ: 107971505, ~: 117069798)
QueryProcessorTest:testGetInstantValue_NotInitialized_BeyondBufferSize(uint8,uint16) (runs: 256, μ: 68389647, ~: 68389600)
QueryProcessorTest:testGetPastAccumulator_BufferEmpty(uint8) (runs: 256, μ: 27017, ~: 27087)
QueryProcessorTest:testGetPastAccumulator_ExactMatch(uint32,uint256,uint256,uint16) (runs: 256, μ: 69289018, ~: 79307245)
QueryProcessorTest:testGetPastAccumulator_ExactMatch_LatestAccumulator(uint32,uint256,uint256) (runs: 256, μ: 70900090, ~: 79224986)
QueryProcessorTest:testGetPastAccumulator_ExactMatch_OldestAccumulator(uint32,uint256,uint256) (runs: 256, μ: 70930212, ~: 79256586)
QueryProcessorTest:testGetPastAccumulator_ExtrapolatesBeyondLatest(uint32,uint256,uint256,uint256) (runs: 256, μ: 67024575, ~: 76058923)
QueryProcessorTest:testGetPastAccumulator_InterpolatesBetweenPastAccumulators(uint32,uint256,uint256,uint256) (runs: 256, μ: 67058609, ~: 76093620)
QueryProcessorTest:testGetPastAccumulator_InvalidAgo(uint32,uint256,uint256,uint256) (runs: 256, μ: 67016184, ~: 76050634)
QueryProcessorTest:testGetPastAccumulator_QueryTooOld(uint32,uint256,uint256,uint256) (runs: 256, μ: 67027596, ~: 76060517)
QueryProcessorTest:testGetTimeWeightedAverage(uint32,uint256,uint256,uint256,uint256) (runs: 256, μ: 101761121, ~: 108597954)
QueryProcessorTest:testGetTimeWeightedAverage_BadSecs() (gas: 10995)
ReservoirPriceOracleTest:testClearRoute() (gas: 52085)
ReservoirPriceOracleTest:testClearRoute_AllWordsCleared() (gas: 155034)
ReservoirPriceOracleTest:testClearRoute() (gas: 50974)
ReservoirPriceOracleTest:testClearRoute_AllWordsCleared() (gas: 151907)
ReservoirPriceOracleTest:testDesignatePair() (gas: 29091)
ReservoirPriceOracleTest:testDesignatePair_IncorrectPair() (gas: 21111)
ReservoirPriceOracleTest:testDesignatePair_NotOwner() (gas: 17531)
ReservoirPriceOracleTest:testDesignatePair_TokenOrderReversed() (gas: 30729)
ReservoirPriceOracleTest:testGasBountyAvailable(uint256) (runs: 256, μ: 9929, ~: 9925)
ReservoirPriceOracleTest:testGasBountyAvailable_Zero() (gas: 8961)
ReservoirPriceOracleTest:testGetLatest(uint32) (runs: 256, μ: 92679, ~: 92614)
ReservoirPriceOracleTest:testGetLatest(uint32) (runs: 256, μ: 92685, ~: 92614)
ReservoirPriceOracleTest:testGetLatest_Inverted() (gas: 96786)
ReservoirPriceOracleTest:testGetQuote(uint256,uint256) (runs: 256, μ: 35782, ~: 35886)
ReservoirPriceOracleTest:testGetQuote(uint256,uint256) (runs: 256, μ: 35198, ~: 35302)
ReservoirPriceOracleTest:testGetQuote_AmountInTooLarge() (gas: 12963)
ReservoirPriceOracleTest:testGetQuote_BaseIsVault(uint256) (runs: 256, μ: 418221, ~: 417982)
ReservoirPriceOracleTest:testGetQuote_ComplicatedDecimals() (gas: 10352967)
ReservoirPriceOracleTest:testGetQuote_Inverse(uint256,uint256) (runs: 256, μ: 37892, ~: 38058)
ReservoirPriceOracleTest:testGetQuote_MultipleHops() (gas: 114257)
ReservoirPriceOracleTest:testGetQuote_MultipleHops_Inverse() (gas: 114512)
ReservoirPriceOracleTest:testGetQuote_MultipleHops_PriceZero() (gas: 126984)
ReservoirPriceOracleTest:testGetQuote_NoFallbackOracle() (gas: 21084)
ReservoirPriceOracleTest:testGetQuote_PriceZero() (gas: 16486)
ReservoirPriceOracleTest:testGetQuote_RandomizeAllParam_1HopRoute(uint256,uint256,address,address,uint8,uint8) (runs: 256, μ: 5327988, ~: 5328070)
ReservoirPriceOracleTest:testGetQuote_RandomizeAllParam_2HopRoute(uint256,uint256,uint256,address,address,address,uint8,uint8,uint8) (runs: 256, μ: 10493634, ~: 10493649)
ReservoirPriceOracleTest:testGetQuote_BaseIsVault(uint256) (runs: 256, μ: 417430, ~: 417188)
ReservoirPriceOracleTest:testGetQuote_ComplicatedDecimals() (gas: 10350840)
ReservoirPriceOracleTest:testGetQuote_Inverse(uint256,uint256) (runs: 256, μ: 37311, ~: 37474)
ReservoirPriceOracleTest:testGetQuote_MultipleHops() (gas: 113391)
ReservoirPriceOracleTest:testGetQuote_MultipleHops_Inverse() (gas: 113646)
ReservoirPriceOracleTest:testGetQuote_MultipleHops_PriceZero() (gas: 125259)
ReservoirPriceOracleTest:testGetQuote_NoFallbackOracle() (gas: 20875)
ReservoirPriceOracleTest:testGetQuote_PriceZero() (gas: 15902)
ReservoirPriceOracleTest:testGetQuote_RandomizeAllParam_1HopRoute(uint256,uint256,address,address,uint8,uint8) (runs: 256, μ: 5327381, ~: 5327411)
ReservoirPriceOracleTest:testGetQuote_RandomizeAllParam_2HopRoute(uint256,uint256,uint256,address,address,address,uint8,uint8,uint8) (runs: 256, μ: 10492723, ~: 10492862)
ReservoirPriceOracleTest:testGetQuote_SameBaseQuote(uint256,address) (runs: 256, μ: 8963, ~: 8963)
ReservoirPriceOracleTest:testGetQuote_UseFallback() (gas: 38730)
ReservoirPriceOracleTest:testGetQuote_ZeroIn() (gas: 39315)
ReservoirPriceOracleTest:testGetQuotes(uint256,uint256) (runs: 256, μ: 33271, ~: 33375)
ReservoirPriceOracleTest:testGetQuote_UseFallback() (gas: 38312)
ReservoirPriceOracleTest:testGetQuote_ZeroIn() (gas: 38147)
ReservoirPriceOracleTest:testGetQuotes(uint256,uint256) (runs: 256, μ: 32687, ~: 32791)
ReservoirPriceOracleTest:testGetTimeWeightedAverage() (gas: 141765)
ReservoirPriceOracleTest:testGetTimeWeightedAverage_Inverted() (gas: 120958)
ReservoirPriceOracleTest:testSetFallbackOracle_NotOwner() (gas: 10938)
ReservoirPriceOracleTest:testSetRoute() (gas: 58807)
ReservoirPriceOracleTest:testSetRoute_InvalidRoute() (gas: 18004)
ReservoirPriceOracleTest:testSetRoute_InvalidRouteLength() (gas: 17633)
ReservoirPriceOracleTest:testSetRoute_MultipleHops() (gas: 196034)
ReservoirPriceOracleTest:testSetRoute_NotSorted() (gas: 12095)
ReservoirPriceOracleTest:testSetRoute_OverwriteExisting() (gas: 162438)
ReservoirPriceOracleTest:testSetRoute_SameToken() (gas: 12070)
ReservoirPriceOracleTest:testSetRoute() (gas: 58216)
ReservoirPriceOracleTest:testSetRoute_InvalidRoute() (gas: 17990)
ReservoirPriceOracleTest:testSetRoute_InvalidRouteLength() (gas: 17619)
ReservoirPriceOracleTest:testSetRoute_MultipleHops() (gas: 193395)
ReservoirPriceOracleTest:testSetRoute_NotSorted() (gas: 12102)
ReservoirPriceOracleTest:testSetRoute_OverwriteExisting() (gas: 160967)
ReservoirPriceOracleTest:testSetRoute_SameToken() (gas: 12115)
ReservoirPriceOracleTest:testUndesignatePair() (gas: 30257)
ReservoirPriceOracleTest:testUndesignatePair_NotOwner() (gas: 15288)
ReservoirPriceOracleTest:testUpdatePriceDeviationThreshold(uint256) (runs: 256, μ: 21331, ~: 21085)
ReservoirPriceOracleTest:testUpdatePrice_BeyondThreshold() (gas: 214357)
ReservoirPriceOracleTest:testUpdatePrice_BeyondThreshold_InsufficientReward(uint256) (runs: 256, μ: 203578, ~: 203794)
ReservoirPriceOracleTest:testUpdatePrice_BeyondThreshold_ZeroRecipient() (gas: 196179)
ReservoirPriceOracleTest:testUpdatePrice_FirstUpdate() (gas: 203806)
ReservoirPriceOracleTest:testUpdatePrice_IntermediateRoutes() (gas: 15868736)
ReservoirPriceOracleTest:testUpdatePrice_PriceOutOfRange() (gas: 5351311)
ReservoirPriceOracleTest:testUpdatePrice_WithinThreshold() (gas: 204695)
ReservoirPriceOracleTest:testUpdatePriceDeviationThreshold(uint256) (runs: 256, μ: 21328, ~: 21085)
ReservoirPriceOracleTest:testUpdatePrice_BeyondThreshold() (gas: 213770)
ReservoirPriceOracleTest:testUpdatePrice_BeyondThreshold_InsufficientReward(uint256) (runs: 256, μ: 202989, ~: 203067)
ReservoirPriceOracleTest:testUpdatePrice_BeyondThreshold_ZeroRecipient() (gas: 195593)
ReservoirPriceOracleTest:testUpdatePrice_FirstUpdate() (gas: 203220)
ReservoirPriceOracleTest:testUpdatePrice_IntermediateRoutes() (gas: 15867847)
ReservoirPriceOracleTest:testUpdatePrice_PriceOutOfRange() (gas: 5350717)
ReservoirPriceOracleTest:testUpdatePrice_WithinThreshold() (gas: 204109)
ReservoirPriceOracleTest:testUpdateRewardGasAmount() (gas: 19033)
ReservoirPriceOracleTest:testUpdateRewardGasAmount_NotOwner() (gas: 10984)
ReservoirPriceOracleTest:testUpdateTwapPeriod(uint256) (runs: 256, μ: 21743, ~: 21828)
ReservoirPriceOracleTest:testUpdateTwapPeriod_InvalidTwapPeriod(uint256) (runs: 256, μ: 17863, ~: 18164)
ReservoirPriceOracleTest:testWritePriceCache(uint256) (runs: 256, μ: 29936, ~: 29697)
ReservoirPriceOracleTest:testUpdateTwapPeriod(uint256) (runs: 256, μ: 21745, ~: 21828)
ReservoirPriceOracleTest:testUpdateTwapPeriod_InvalidTwapPeriod(uint256) (runs: 256, μ: 17861, ~: 18164)
ReservoirPriceOracleTest:testWritePriceCache(uint256) (runs: 256, μ: 29939, ~: 29697)
RoutesLibTest:testGetDecimalDifference() (gas: 3974)
RoutesLibTest:testIsCompositeRoute() (gas: 4341)
RoutesLibTest:testPackSimplePrice(int8,uint256) (runs: 256, μ: 7786, ~: 7555)
SamplesTest:testAccumulator() (gas: 3959)
SamplesTest:testAccumulator_BadVariableRequest() (gas: 3523)
SamplesTest:testInstant() (gas: 3909)
Expand Down
74 changes: 35 additions & 39 deletions src/ReservoirPriceOracle.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@ import { ReentrancyGuard } from "lib/amm-core/lib/solmate/src/utils/ReentrancyGu
import { FixedPointMathLib } from "lib/amm-core/lib/solady/src/utils/FixedPointMathLib.sol";
import { LibSort } from "lib/solady/src/utils/LibSort.sol";
import { Constants } from "src/libraries/Constants.sol";
import { FlagsLib } from "src/libraries/FlagsLib.sol";
import { RoutesLib } from "src/libraries/RoutesLib.sol";

contract ReservoirPriceOracle is IPriceOracle, IReservoirPriceOracle, Owned(msg.sender), ReentrancyGuard {
using FixedPointMathLib for uint256;
using LibSort for address[];
using FlagsLib for *;
using RoutesLib for bytes32;
using QueryProcessor for ReservoirPair;

///////////////////////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -192,10 +192,14 @@ contract ReservoirPriceOracle is IPriceOracle, IReservoirPriceOracle, Owned(msg.
// INTERNAL FUNCTIONS //
///////////////////////////////////////////////////////////////////////////////////////////////

function _validatePair(ReservoirPair aPair) internal pure {
function _validatePair(ReservoirPair aPair) private pure {
if (address(aPair) == address(0)) revert OracleErrors.NoDesignatedPair();
}

function _validateTokens(address aToken0, address aToken1) private pure {
if (aToken1 <= aToken0) revert OracleErrors.InvalidTokensProvided();
}

function _getTimeWeightedAverageSingle(OracleAverageQuery memory aQuery) internal view returns (uint256 rResult) {
ReservoirPair lPair = pairs[aQuery.base][aQuery.quote];
_validatePair(lPair);
Expand Down Expand Up @@ -248,71 +252,65 @@ contract ReservoirPriceOracle is IPriceOracle, IReservoirPriceOracle, Owned(msg.
view
returns (address[] memory rRoute, int256 rDecimalDiff, uint256 rPrice)
{
address[] memory lResults = new address[](Constants.MAX_ROUTE_LENGTH);
bytes32 lSlot = Utils.calculateSlot(aToken0, aToken1);

bytes32 lFirstWord;
uint256 lRouteLength;
assembly {
lFirstWord := sload(lSlot)
}

// simple route
if (lFirstWord.isSimplePrice()) {
lResults[0] = aToken0;
lResults[1] = aToken1;
lRouteLength = 2;
rRoute = new address[](2);
rRoute[0] = aToken0;
rRoute[1] = aToken1;
rDecimalDiff = lFirstWord.getDecimalDifference();
rPrice = lFirstWord.getPrice();
}
// composite route
else if (lFirstWord.isCompositeRoute()) {
address lSecondToken = lFirstWord.getTokenFirstWord();

lResults[0] = aToken0;
lResults[1] = lSecondToken;

if (lFirstWord.is3HopRoute()) {
if (lFirstWord.is2HopRoute()) {
rRoute = new address[](3);
rRoute[2] = aToken1;
} else {
assert(lFirstWord.is3HopRoute());
bytes32 lSecondWord;
assembly {
lSecondWord := sload(add(lSlot, 1))
}
address lThirdToken = lSecondWord.getThirdToken();

lResults[2] = lThirdToken;
lResults[3] = aToken1;
lRouteLength = 4;
} else {
lResults[2] = aToken1;
lRouteLength = 3;
rRoute = new address[](4);
rRoute[2] = lThirdToken;
rRoute[3] = aToken1;
}

rRoute[0] = aToken0;
rRoute[1] = lSecondToken;
}
// no route
// solhint-disable-next-line no-empty-blocks
else if (lFirstWord.isUninitialized()) { }

rRoute = new address[](lRouteLength);
for (uint256 i = 0; i < lRouteLength; ++i) {
rRoute[i] = lResults[i];
else if (lFirstWord.isUninitialized()) {
rRoute = new address[](0);
}
}

/// Calculate the storage slot for this intermediate segment and read it to see if there is an existing
/// route. If there isn't an existing route, we write it as well.
/// @dev assumed that aToken0 and aToken1 are not necessarily sorted
function _checkAndPopulateIntermediateRoute(address aToken0, address aToken1) internal {
(address lLowerToken, address lHigherToken) = Utils.sortTokens(aToken0, aToken1);
function _checkAndPopulateIntermediateRoute(address aTokenA, address aTokenB) private {
(address lToken0, address lToken1) = Utils.sortTokens(aTokenA, aTokenB);

bytes32 lSlot = Utils.calculateSlot(lLowerToken, lHigherToken);
bytes32 lSlot = Utils.calculateSlot(lToken0, lToken1);
bytes32 lData;
assembly {
lData := sload(lSlot)
}
if (lData == bytes32(0)) {
address[] memory lIntermediateRoute = new address[](2);
lIntermediateRoute[0] = lLowerToken;
lIntermediateRoute[1] = lHigherToken;
setRoute(lLowerToken, lHigherToken, lIntermediateRoute);
lIntermediateRoute[0] = lToken0;
lIntermediateRoute[1] = lToken1;
setRoute(lToken0, lToken1, lIntermediateRoute);
}
}

Expand Down Expand Up @@ -346,7 +344,7 @@ contract ReservoirPriceOracle is IPriceOracle, IReservoirPriceOracle, Owned(msg.

int256 lDiff = lData.getDecimalDifference();

lData = lDiff.packSimplePrice(aNewPrice);
lData = RoutesLib.packSimplePrice(lDiff, aNewPrice);
assembly {
sstore(lSlot, lData)
}
Expand Down Expand Up @@ -498,8 +496,7 @@ contract ReservoirPriceOracle is IPriceOracle, IReservoirPriceOracle, Owned(msg.
function setRoute(address aToken0, address aToken1, address[] memory aRoute) public onlyOwner {
uint256 lRouteLength = aRoute.length;

if (aToken0 == aToken1) revert OracleErrors.SameToken();
if (aToken1 < aToken0) revert OracleErrors.TokensUnsorted();
_validateTokens(aToken0, aToken1);
if (lRouteLength > Constants.MAX_ROUTE_LENGTH || lRouteLength < 2) revert OracleErrors.InvalidRouteLength();
if (aRoute[0] != aToken0 || aRoute[lRouteLength - 1] != aToken1) revert OracleErrors.InvalidRoute();

Expand All @@ -513,7 +510,7 @@ contract ReservoirPriceOracle is IPriceOracle, IReservoirPriceOracle, Owned(msg.

int256 lDiff = int256(lToken1Decimals) - int256(lToken0Decimals);

bytes32 lData = lDiff.packSimplePrice(0);
bytes32 lData = RoutesLib.packSimplePrice(lDiff, 0);
assembly {
// Write data to storage.
sstore(lSlot, lData)
Expand All @@ -525,12 +522,12 @@ contract ReservoirPriceOracle is IPriceOracle, IReservoirPriceOracle, Owned(msg.
address lThirdToken = aRoute[2];

if (lRouteLength == 3) {
bytes32 lData = lSecondToken.pack2HopRoute();
bytes32 lData = RoutesLib.pack2HopRoute(lSecondToken);
assembly {
sstore(lSlot, lData)
}
} else if (lRouteLength == 4) {
(bytes32 lFirstWord, bytes32 lSecondWord) = lSecondToken.pack3HopRoute(lThirdToken);
(bytes32 lFirstWord, bytes32 lSecondWord) = RoutesLib.pack3HopRoute(lSecondToken, lThirdToken);

// Write two words to storage.
assembly {
Expand All @@ -546,8 +543,7 @@ contract ReservoirPriceOracle is IPriceOracle, IReservoirPriceOracle, Owned(msg.
}

function clearRoute(address aToken0, address aToken1) external onlyOwner {
if (aToken0 == aToken1) revert OracleErrors.SameToken();
if (aToken1 < aToken0) revert OracleErrors.TokensUnsorted();
_validateTokens(aToken0, aToken1);

(address[] memory lRoute,,) = _getRouteDecimalDifferencePrice(aToken0, aToken1);

Expand Down
3 changes: 1 addition & 2 deletions src/libraries/OracleErrors.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,10 @@ library OracleErrors {
error IncorrectTokensDesignatePair();
error InvalidRoute();
error InvalidRouteLength();
error InvalidTokensProvided();
error InvalidTwapPeriod();
error NoDesignatedPair();
error PriceDeviationThresholdTooHigh();
error SameToken();
error TokensUnsorted();
error UnsupportedTokenDecimals();

// query errors
Expand Down
6 changes: 5 additions & 1 deletion src/libraries/FlagsLib.sol → src/libraries/RoutesLib.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.0;

library FlagsLib {
library RoutesLib {
bytes32 public constant FLAG_UNINITIALIZED = bytes32(hex"00");
bytes32 public constant FLAG_SIMPLE_PRICE = bytes32(hex"01");
bytes32 public constant FLAG_2_HOP_ROUTE = bytes32(hex"02");
Expand All @@ -19,6 +19,10 @@ library FlagsLib {
return aData[0] & hex"02" > 0;
}

function is2HopRoute(bytes32 aData) internal pure returns (bool) {
return aData[0] == FLAG_2_HOP_ROUTE;
}

function is3HopRoute(bytes32 aData) internal pure returns (bool) {
return aData[0] == FLAG_3_HOP_ROUTE;
}
Expand Down
Loading

0 comments on commit f7a709c

Please sign in to comment.