Skip to content

Commit 7ff9f86

Browse files
committed
Merge branch 'lbc-split' into GBI-2875/integrate-openzeppelin-ecdsa-verify
2 parents c141951 + 10b14d1 commit 7ff9f86

28 files changed

+1744
-746
lines changed

README.md

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ This method requests the Bridge contract on RSK a refund for the service.
120120

121121
### **isOperational**
122122

123-
function isOperational(address addr) external view returns (bool)
123+
function isOperational(Flyover.ProviderType providerType, address addr) external view returns (bool)
124124

125125
Checks whether a liquidity provider can deliver a pegin service
126126

@@ -132,10 +132,6 @@ Checks whether a liquidity provider can deliver a pegin service
132132

133133
Whether the liquidity provider is registered and has enough locked collateral
134134

135-
### **isOperationalForPegout**
136-
137-
function isOperationalForPegout(address addr) external view returns (bool)
138-
139135
Checks whether a liquidity provider can deliver a pegout service
140136

141137
#### Parametets

contracts/FlyoverDiscovery.sol

Lines changed: 234 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,234 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity 0.8.25;
3+
4+
/* solhint-disable comprehensive-interface */
5+
6+
import {
7+
AccessControlDefaultAdminRulesUpgradeable
8+
} from "@openzeppelin/contracts-upgradeable/access/extensions/AccessControlDefaultAdminRulesUpgradeable.sol";
9+
import {ICollateralManagement} from "./interfaces/ICollateralManagement.sol";
10+
import {IFlyoverDiscovery} from "./interfaces/IFlyoverDiscovery.sol";
11+
import {Flyover} from "./libraries/Flyover.sol";
12+
13+
/// @title FlyoverDiscovery
14+
/// @notice Registry and discovery of Liquidity Providers (LPs) for Flyover
15+
/// @dev Keeps LP metadata and consults `ICollateralManagement` to decide listing and operational status
16+
contract FlyoverDiscovery is
17+
AccessControlDefaultAdminRulesUpgradeable,
18+
IFlyoverDiscovery
19+
{
20+
21+
// ------------------------------------------------------------
22+
// FlyoverDiscovery State Variables
23+
// ------------------------------------------------------------
24+
25+
mapping(uint => Flyover.LiquidityProvider) private _liquidityProviders;
26+
ICollateralManagement private _collateralManagement;
27+
uint public lastProviderId;
28+
29+
// ------------------------------------------------------------
30+
// FlyoverDiscovery Public Functions and Modifiers
31+
// ------------------------------------------------------------
32+
33+
/// @notice Initializes the contract with admin configuration
34+
/// @dev Uses OZ upgradeable admin rules. Must be called only once
35+
/// @param owner The Default Admin and initial owner address
36+
/// @param initialDelay The initial admin delay for `AccessControlDefaultAdminRulesUpgradeable`
37+
/// @param collateralManagement The address of the `ICollateralManagement` contract
38+
function initialize(
39+
address owner,
40+
uint48 initialDelay,
41+
address collateralManagement
42+
) external initializer {
43+
if (collateralManagement.code.length == 0) revert Flyover.NoContract(collateralManagement);
44+
__AccessControlDefaultAdminRules_init(initialDelay, owner);
45+
_collateralManagement = ICollateralManagement(collateralManagement);
46+
}
47+
48+
/// @inheritdoc IFlyoverDiscovery
49+
function register(
50+
string calldata name,
51+
string calldata apiBaseUrl,
52+
bool status,
53+
Flyover.ProviderType providerType
54+
) external payable returns (uint) {
55+
56+
_validateRegistration(name, apiBaseUrl, providerType, msg.sender, msg.value);
57+
58+
++lastProviderId;
59+
_liquidityProviders[lastProviderId] = Flyover.LiquidityProvider({
60+
id: lastProviderId,
61+
providerAddress: msg.sender,
62+
name: name,
63+
apiBaseUrl: apiBaseUrl,
64+
status: status,
65+
providerType: providerType
66+
});
67+
emit Register(lastProviderId, msg.sender, msg.value);
68+
_addCollateral(providerType, msg.sender, msg.value);
69+
return (lastProviderId);
70+
}
71+
72+
/// @inheritdoc IFlyoverDiscovery
73+
function setProviderStatus(
74+
uint providerId,
75+
bool status
76+
) external {
77+
if (msg.sender != owner() && msg.sender != _liquidityProviders[providerId].providerAddress) {
78+
revert NotAuthorized(msg.sender);
79+
}
80+
_liquidityProviders[providerId].status = status;
81+
emit IFlyoverDiscovery.ProviderStatusSet(providerId, status);
82+
}
83+
84+
/// @inheritdoc IFlyoverDiscovery
85+
function updateProvider(string calldata name, string calldata apiBaseUrl) external {
86+
if (bytes(name).length < 1 || bytes(apiBaseUrl).length < 1) revert InvalidProviderData(name, apiBaseUrl);
87+
Flyover.LiquidityProvider storage lp;
88+
address providerAddress = msg.sender;
89+
for (uint i = 1; i < lastProviderId + 1; ++i) {
90+
lp = _liquidityProviders[i];
91+
if (providerAddress == lp.providerAddress) {
92+
lp.name = name;
93+
lp.apiBaseUrl = apiBaseUrl;
94+
emit IFlyoverDiscovery.ProviderUpdate(providerAddress, lp.name, lp.apiBaseUrl);
95+
return;
96+
}
97+
}
98+
revert Flyover.ProviderNotRegistered(providerAddress);
99+
}
100+
101+
/// @inheritdoc IFlyoverDiscovery
102+
function getProviders() external view returns (Flyover.LiquidityProvider[] memory) {
103+
uint count = 0;
104+
Flyover.LiquidityProvider storage lp;
105+
for (uint i = 1; i < lastProviderId + 1; ++i) {
106+
if (_shouldBeListed(_liquidityProviders[i])) {
107+
++count;
108+
}
109+
}
110+
Flyover.LiquidityProvider[] memory providersToReturn = new Flyover.LiquidityProvider[](count);
111+
count = 0;
112+
for (uint i = 1; i < lastProviderId + 1; ++i) {
113+
lp = _liquidityProviders[i];
114+
if (_shouldBeListed(lp)) {
115+
providersToReturn[count] = lp;
116+
++count;
117+
}
118+
}
119+
return providersToReturn;
120+
}
121+
122+
/// @inheritdoc IFlyoverDiscovery
123+
function getProvider(address providerAddress) external view returns (Flyover.LiquidityProvider memory) {
124+
return _getProvider(providerAddress);
125+
}
126+
127+
/// @inheritdoc IFlyoverDiscovery
128+
function isOperational(Flyover.ProviderType providerType, address addr) external view returns (bool) {
129+
return _getProvider(addr).status &&
130+
_collateralManagement.isCollateralSufficient(providerType, addr);
131+
}
132+
133+
// ------------------------------------------------------------
134+
// Getter Functions
135+
// ------------------------------------------------------------
136+
137+
/// @inheritdoc IFlyoverDiscovery
138+
function getProvidersId() external view returns (uint) {
139+
return lastProviderId;
140+
}
141+
142+
// ------------------------------------------------------------
143+
// FlyoverDiscovery Private Functions
144+
// ------------------------------------------------------------
145+
146+
/// @notice Adds collateral to the collateral management contract based on provider type
147+
/// @dev Distributes collateral between peg-in and peg-out based on provider type
148+
/// @param providerType The type of provider (PegIn, PegOut, or Both)
149+
/// @param providerAddress The address of the provider
150+
/// @param collateralAmount The total amount of collateral to add
151+
function _addCollateral(
152+
Flyover.ProviderType providerType,
153+
address providerAddress,
154+
uint256 collateralAmount
155+
) private {
156+
if (providerType == Flyover.ProviderType.PegIn) {
157+
_collateralManagement.addPegInCollateralTo{value: collateralAmount}(providerAddress);
158+
} else if (providerType == Flyover.ProviderType.PegOut) {
159+
_collateralManagement.addPegOutCollateralTo{value: collateralAmount}(providerAddress);
160+
} else if (providerType == Flyover.ProviderType.Both) {
161+
uint256 halfAmount = collateralAmount / 2;
162+
uint256 remainder = collateralAmount % 2;
163+
_collateralManagement.addPegInCollateralTo{value: halfAmount + remainder}(providerAddress);
164+
_collateralManagement.addPegOutCollateralTo{value: halfAmount}(providerAddress);
165+
}
166+
}
167+
168+
/// @notice Checks if a liquidity provider should be listed in the public provider list
169+
/// @dev A provider is listed if it is registered and has status enabled
170+
/// @param lp The liquidity provider storage reference
171+
/// @return True if the provider should be listed, false otherwise
172+
function _shouldBeListed(Flyover.LiquidityProvider storage lp) private view returns(bool){
173+
return _collateralManagement.isRegistered(lp.providerType, lp.providerAddress) && lp.status;
174+
}
175+
176+
/// @notice Validates registration parameters and requirements
177+
/// @dev Checks EOA status, data validity, provider type, registration status, and collateral requirements
178+
/// @param name The provider name to validate
179+
/// @param apiBaseUrl The provider API URL to validate
180+
/// @param providerType The provider type to validate
181+
/// @param providerAddress The provider address to validate
182+
/// @param collateralAmount The collateral amount to validate against minimum requirements
183+
function _validateRegistration(
184+
string memory name,
185+
string memory apiBaseUrl,
186+
Flyover.ProviderType providerType,
187+
address providerAddress,
188+
uint256 collateralAmount
189+
) private view {
190+
if (providerAddress != msg.sender || providerAddress.code.length != 0) revert NotEOA(providerAddress);
191+
192+
if (
193+
bytes(name).length < 1 ||
194+
bytes(apiBaseUrl).length < 1
195+
) {
196+
revert InvalidProviderData(name, apiBaseUrl);
197+
}
198+
199+
if (providerType > type(Flyover.ProviderType).max) revert InvalidProviderType(providerType);
200+
201+
if (
202+
_collateralManagement.getPegInCollateral(providerAddress) > 0 ||
203+
_collateralManagement.getPegOutCollateral(providerAddress) > 0 ||
204+
_collateralManagement.getResignationBlock(providerAddress) != 0
205+
) {
206+
revert AlreadyRegistered(providerAddress);
207+
}
208+
209+
// Check minimum collateral requirement
210+
uint256 minCollateral = _collateralManagement.getMinCollateral();
211+
if (providerType == Flyover.ProviderType.Both) {
212+
if (collateralAmount < minCollateral * 2) {
213+
revert InsufficientCollateral(collateralAmount);
214+
}
215+
} else {
216+
if (collateralAmount < minCollateral) {
217+
revert InsufficientCollateral(collateralAmount);
218+
}
219+
}
220+
}
221+
222+
/// @notice Retrieves a liquidity provider by address
223+
/// @dev Searches through all registered providers to find a match
224+
/// @param providerAddress The address of the provider to find
225+
/// @return The liquidity provider record, reverts if not found
226+
function _getProvider(address providerAddress) private view returns (Flyover.LiquidityProvider memory) {
227+
for (uint i = 1; i < lastProviderId + 1; ++i) {
228+
if (_liquidityProviders[i].providerAddress == providerAddress) {
229+
return _liquidityProviders[i];
230+
}
231+
}
232+
revert Flyover.ProviderNotRegistered(providerAddress);
233+
}
234+
}

contracts/PegOutContract.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ contract PegOutContract is
9797
_pegOutQuotes[quoteHash] = quote;
9898
_pegOutRegistry[quoteHash].depositTimestamp = block.timestamp;
9999

100-
emit PegOutDeposit(quoteHash, msg.sender, msg.value, block.timestamp);
100+
emit PegOutDeposit(quoteHash, msg.sender, block.timestamp, msg.value);
101101

102102
if (dustThreshold > msg.value - requiredAmount) {
103103
return;

contracts/interfaces/IFlyoverDiscovery.sol

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,50 @@ interface IFlyoverDiscovery {
1515
error AlreadyRegistered(address from);
1616
error InsufficientCollateral(uint amount);
1717

18+
/// @notice Registers the caller as a Liquidity Provider
19+
/// @dev Reverts if caller is not an EOA, already resigned, provides invalid data, invalid type, or lacks collateral
20+
/// @param name Human-readable LP name
21+
/// @param apiBaseUrl Base URL of the LP public API
22+
/// @param status Initial status flag (enabled/disabled)
23+
/// @param providerType The service type(s) the LP offers
24+
/// @return id The newly assigned LP identifier
1825
function register(
19-
string memory name,
20-
string memory apiBaseUrl,
26+
string calldata name,
27+
string calldata apiBaseUrl,
2128
bool status,
2229
Flyover.ProviderType providerType
2330
) external payable returns (uint);
2431

25-
function updateProvider(string memory name,string memory apiBaseUrl) external;
32+
/// @notice Updates the caller LP metadata
33+
/// @dev Reverts if the caller is not registered or provides invalid fields
34+
/// @param name New LP name
35+
/// @param apiBaseUrl New LP API base URL
36+
function updateProvider(string calldata name, string calldata apiBaseUrl) external;
37+
38+
/// @notice Updates a provider status flag
39+
/// @dev Callable by the LP itself or the contract owner
40+
/// @param providerId The provider identifier
41+
/// @param status The new status value
2642
function setProviderStatus(uint providerId, bool status) external;
43+
44+
/// @notice Lists LPs that should be visible to users
45+
/// @dev A provider is listed if it has sufficient collateral for at least one side and `status` is true
46+
/// @return providersToReturn Array of LP records to display
2747
function getProviders() external view returns (Flyover.LiquidityProvider[] memory);
48+
49+
/// @notice Returns a single LP by address
50+
/// @param providerAddress The LP address
51+
/// @return provider LP record, reverts if not found
2852
function getProvider(address providerAddress) external view returns (Flyover.LiquidityProvider memory);
53+
54+
/// @notice Checks if an LP can operate for a specific type of operation
55+
/// @dev Ignores the first argument as compatibility stub with legacy signature
56+
/// @param providerType The type of provider
57+
/// @param addr The LP address
58+
/// @return isOp True if registered and peg-in collateral >= min
2959
function isOperational(Flyover.ProviderType providerType, address addr) external view returns (bool);
60+
61+
/// @notice Returns the last assigned provider id
62+
/// @return lastId Last provider id
63+
function getProvidersId() external view returns (uint);
3064
}

contracts/libraries/SignatureValidator.sol

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ library SignatureValidator {
88
using ECDSA for bytes32;
99

1010
error IncorrectSignature(address expectedAddress, bytes32 usedHash, bytes signature);
11+
error ZeroAddress();
1112
/**
1213
@dev Verfies signature against address
1314
@param addr The signing address
@@ -16,6 +17,16 @@ library SignatureValidator {
1617
@return True if the signature is valid, false otherwise.
1718
*/
1819
function verify(address addr, bytes32 quoteHash, bytes memory signature) public pure returns (bool) {
20+
21+
if (addr == address(0)) {
22+
revert ZeroAddress();
23+
}
24+
25+
if (signature.length != 65) {
26+
revert IncorrectSignature(addr, quoteHash, signature);
27+
}
28+
29+
1930
bytes32 r;
2031
bytes32 s;
2132
uint8 v;

0 commit comments

Comments
 (0)