Skip to content

Commit 8857775

Browse files
committed
diffs
1 parent f2f6a77 commit 8857775

10 files changed

Lines changed: 1901 additions & 1 deletion
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
// SPDX-License-Identifier: BUSL-1.1
2+
pragma solidity ^0.8.12;
3+
4+
import {OwnableUpgradeable} from "@openzeppelin-upgrades/contracts/access/OwnableUpgradeable.sol";
5+
import {ISignatureUtils} from "src/contracts/interfaces/ISignatureUtils.sol";
6+
import {IAVSDirectory} from "src/contracts/interfaces/IAVSDirectory.sol";
7+
import {IRewardsCoordinator} from "src/contracts/interfaces/IRewardsCoordinator.sol";
8+
9+
/**
10+
* @title Minimal implementation of a ServiceManager-type contract.
11+
* This contract can be inherited from or simply used as a point-of-reference.
12+
* @author Layr Labs, Inc.
13+
*/
14+
contract ServiceManagerMock is OwnableUpgradeable {
15+
16+
IAVSDirectory internal immutable _avsDirectory;
17+
IRewardsCoordinator internal immutable _rewardsCoordinator;
18+
19+
address[] public restakeableStrategies;
20+
mapping(address => address[]) public operatorRestakedStrategies;
21+
22+
/// @notice Sets the (immutable) `_registryCoordinator` address
23+
constructor(
24+
IAVSDirectory __avsDirectory,
25+
IRewardsCoordinator ___rewardsCoordinator
26+
) {
27+
_avsDirectory = __avsDirectory;
28+
_rewardsCoordinator = ___rewardsCoordinator;
29+
_disableInitializers();
30+
}
31+
32+
function initialize(address _initialOwner) public initializer {
33+
_transferOwnership(_initialOwner);
34+
}
35+
36+
function __ServiceManagerBase_init(address initialOwner) internal virtual onlyInitializing {
37+
_transferOwnership(initialOwner);
38+
}
39+
40+
/**
41+
* @notice Updates the metadata URI for the AVS
42+
* @param _metadataURI is the metadata URI for the AVS
43+
* @dev only callable by the owner
44+
*/
45+
function updateAVSMetadataURI(string memory _metadataURI) public virtual onlyOwner {
46+
_avsDirectory.updateAVSMetadataURI(_metadataURI);
47+
}
48+
49+
/**
50+
* @notice Creates a new range payment on behalf of an AVS, to be split amongst the
51+
* set of stakers delegated to operators who are registered to the `avs`.
52+
* Note that the owner calling this function must have approved the tokens to be transferred to the ServiceManager
53+
* and of course has the required balances.
54+
* @param rewardsSubmissions The range payments being created
55+
* @dev Expected to be called by the ServiceManager of the AVS on behalf of which the payment is being made
56+
* @dev The duration of the `rangePayment` cannot exceed `rewardsCoordinator.MAX_PAYMENT_DURATION()`
57+
* @dev The tokens are sent to the `PaymentCoordinator` contract
58+
* @dev Strategies must be in ascending order of addresses to check for duplicates
59+
* @dev This function will revert if the `rangePayment` is malformed,
60+
* e.g. if the `strategies` and `weights` arrays are of non-equal lengths
61+
*/
62+
function createAVSRewardsSubmission(
63+
IRewardsCoordinator.RewardsSubmission[] calldata rewardsSubmissions
64+
) public virtual onlyOwner {
65+
for (uint256 i = 0; i < rewardsSubmissions.length; ++i) {
66+
// transfer token to ServiceManager and approve PaymentCoordinator to transfer again
67+
// in createAVSRewardsSubmission() call
68+
rewardsSubmissions[i].token.transferFrom(msg.sender, address(this), rewardsSubmissions[i].amount);
69+
uint256 allowance = rewardsSubmissions[i].token.allowance(address(this), address(_rewardsCoordinator));
70+
rewardsSubmissions[i].token.approve(address(_rewardsCoordinator), rewardsSubmissions[i].amount + allowance);
71+
}
72+
73+
_rewardsCoordinator.createAVSRewardsSubmission(rewardsSubmissions);
74+
}
75+
76+
function createOperatorDirectedAVSRewardsSubmission(
77+
IRewardsCoordinator.OperatorDirectedRewardsSubmission[] calldata rewardsSubmissions
78+
) public virtual onlyOwner {
79+
for (uint256 i = 0; i < rewardsSubmissions.length; ++i) {
80+
uint256 amount = 0;
81+
for (uint256 j = 0; j < rewardsSubmissions[i].operatorRewards.length; ++j) {
82+
amount += rewardsSubmissions[i].operatorRewards[j].amount;
83+
}
84+
rewardsSubmissions[i].token.transferFrom(msg.sender, address(this), amount);
85+
uint256 allowance = rewardsSubmissions[i].token.allowance(address(this), address(_rewardsCoordinator));
86+
rewardsSubmissions[i].token.approve(address(_rewardsCoordinator), amount + allowance);
87+
}
88+
89+
_rewardsCoordinator.createOperatorDirectedAVSRewardsSubmission(address(this), rewardsSubmissions);
90+
}
91+
92+
/**
93+
* @notice Forwards a call to EigenLayer's AVSDirectory contract to confirm operator registration with the AVS
94+
* @param operator The address of the operator to register.
95+
* @param operatorSignature The signature, salt, and expiry of the operator's signature.
96+
*/
97+
function registerOperatorToAVS(
98+
address operator,
99+
ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature
100+
) public virtual {
101+
_avsDirectory.registerOperatorToAVS(operator, operatorSignature);
102+
}
103+
104+
/**
105+
* @notice Forwards a call to EigenLayer's AVSDirectory contract to confirm operator deregistration from the AVS
106+
* @param operator The address of the operator to deregister.
107+
*/
108+
function deregisterOperatorFromAVS(address operator) public virtual {
109+
_avsDirectory.deregisterOperatorFromAVS(operator);
110+
}
111+
112+
/**
113+
* @notice Returns the list of strategies that the AVS supports for restaking
114+
* @dev This function is intended to be called off-chain
115+
* @dev No guarantee is made on uniqueness of each element in the returned array.
116+
* The off-chain service should do that validation separately
117+
*/
118+
function getRestakeableStrategies() external view returns (address[] memory) {
119+
return restakeableStrategies;
120+
}
121+
122+
/**
123+
* @notice Returns the list of strategies that the operator has potentially restaked on the AVS
124+
* @param operator The address of the operator to get restaked strategies for
125+
* @dev This function is intended to be called off-chain
126+
* @dev No guarantee is made on whether the operator has shares for a strategy in a quorum or uniqueness
127+
* of each element in the returned array. The off-chain service should do that validation separately
128+
*/
129+
function getOperatorRestakedStrategies(address operator) external view returns (address[] memory) {
130+
return operatorRestakedStrategies[operator];
131+
}
132+
133+
function setRestakeableStrategies(address[] memory strategies) external {
134+
delete restakeableStrategies;
135+
for (uint256 i = 0; i < strategies.length; ++i) {
136+
restakeableStrategies.push(strategies[i]);
137+
}
138+
}
139+
140+
function setOperatorRestakedStrategies(address operator, address[] memory strategies) external {
141+
delete operatorRestakedStrategies[operator];
142+
for (uint256 i = 0; i < strategies.length; ++i) {
143+
operatorRestakedStrategies[operator].push(strategies[i]);
144+
}
145+
}
146+
147+
/// @notice Returns the EigenLayer AVSDirectory contract.
148+
function avsDirectory() external view returns (address) {
149+
return address(_avsDirectory);
150+
}
151+
152+
function rewardsCoordinator() external view returns (address) {
153+
return address(_rewardsCoordinator);
154+
}
155+
156+
// storage gap for upgradeability
157+
// slither-disable-next-line shadowing-state
158+
uint256[48] private __GAP;
159+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// SPDX-License-Identifier: BUSL-1.1
2+
pragma solidity ^0.8.12;
3+
4+
import "@openzeppelin/contracts/token/ERC20/extensions/draft-ERC20Permit.sol";
5+
import "@openzeppelin/contracts/token/ERC20/presets/ERC20PresetFixedSupply.sol";
6+
7+
contract StrategyToken is ERC20PresetFixedSupply, ERC20Permit {
8+
constructor(
9+
string memory name,
10+
string memory symbol,
11+
uint256 initialSupply,
12+
address owner
13+
) ERC20PresetFixedSupply(name, symbol, initialSupply, owner) ERC20Permit(name) {
14+
// solhint-disable-previous-line no-empty-blocks
15+
}
16+
}

0 commit comments

Comments
 (0)