@@ -6,7 +6,11 @@ import "../extension/Multicall.sol";
6
6
import "../extension/Ownable.sol " ;
7
7
import "../extension/Staking1155.sol " ;
8
8
9
+ import "../eip/ERC165.sol " ;
9
10
import "../eip/interface/IERC20.sol " ;
11
+ import "../eip/interface/IERC1155Receiver.sol " ;
12
+
13
+ import { CurrencyTransferLib } from "../lib/CurrencyTransferLib.sol " ;
10
14
11
15
/**
12
16
*
@@ -31,56 +35,146 @@ import "../eip/interface/IERC20.sol";
31
35
* - Multicall capability to perform multiple actions atomically.
32
36
*
33
37
*/
34
- contract Staking1155Base is ContractMetadata , Multicall , Ownable , Staking1155 {
38
+
39
+ /// note: This contract is provided as a base contract.
40
+ // This is to support a variety of use-cases that can be build on top of this base.
41
+ //
42
+ // Additional functionality such as deposit functions, reward-minting, etc.
43
+ // must be implemented by the deployer of this contract, as needed for their use-case.
44
+
45
+ contract Staking1155Base is ContractMetadata , Multicall , Ownable , Staking1155 , ERC165 , IERC1155Receiver {
35
46
/// @dev ERC20 Reward Token address. See {_mintRewards} below.
36
47
address public rewardToken;
37
48
49
+ /// @dev The address of the native token wrapper contract.
50
+ address internal immutable nativeTokenWrapper;
51
+
52
+ /// @dev Total amount of reward tokens in the contract.
53
+ uint256 private rewardTokenBalance;
54
+
38
55
constructor (
39
56
uint256 _defaultTimeUnit ,
40
57
uint256 _defaultRewardsPerUnitTime ,
41
58
address _stakingToken ,
42
- address _rewardToken
59
+ address _rewardToken ,
60
+ address _nativeTokenWrapper
43
61
) Staking1155 (_stakingToken) {
44
62
_setupOwner (msg .sender );
45
63
_setDefaultStakingCondition (_defaultTimeUnit, _defaultRewardsPerUnitTime);
46
64
47
65
rewardToken = _rewardToken;
66
+ nativeTokenWrapper = _nativeTokenWrapper;
67
+ }
68
+
69
+ /// @dev Lets the contract receive ether to unwrap native tokens.
70
+ receive () external payable virtual {
71
+ require (msg .sender == nativeTokenWrapper, "caller not native token wrapper. " );
72
+ }
73
+
74
+ /// @dev Admin deposits reward tokens.
75
+ function depositRewardTokens (uint256 _amount ) external payable nonReentrant {
76
+ _depositRewardTokens (_amount); // override this for custom logic.
77
+ }
78
+
79
+ /// @dev Admin can withdraw excess reward tokens.
80
+ function withdrawRewardTokens (uint256 _amount ) external nonReentrant {
81
+ _withdrawRewardTokens (_amount); // override this for custom logic.
48
82
}
49
83
50
84
/// @notice View total rewards available in the staking contract.
51
- function getRewardTokenBalance () external view virtual override returns (uint256 _rewardsAvailableInContract ) {
52
- return IERC20 (rewardToken).balanceOf (address (this ));
85
+ function getRewardTokenBalance () external view virtual override returns (uint256 ) {
86
+ return rewardTokenBalance;
87
+ }
88
+
89
+ /*///////////////////////////////////////////////////////////////
90
+ ERC 165 / 721 logic
91
+ //////////////////////////////////////////////////////////////*/
92
+
93
+ function onERC1155Received (
94
+ address ,
95
+ address ,
96
+ uint256 ,
97
+ uint256 ,
98
+ bytes calldata
99
+ ) external returns (bytes4 ) {
100
+ require (isStaking == 2 , "Direct transfer " );
101
+ return this .onERC1155Received.selector ;
102
+ }
103
+
104
+ function onERC1155BatchReceived (
105
+ address operator ,
106
+ address from ,
107
+ uint256 [] calldata ids ,
108
+ uint256 [] calldata values ,
109
+ bytes calldata data
110
+ ) external returns (bytes4 ) {}
111
+
112
+ function supportsInterface (bytes4 interfaceId ) public view override (ERC165 , IERC165 ) returns (bool ) {
113
+ return interfaceId == type (IERC1155Receiver ).interfaceId || super .supportsInterface (interfaceId);
53
114
}
54
115
55
116
/*//////////////////////////////////////////////////////////////
56
117
Minting logic
57
118
//////////////////////////////////////////////////////////////*/
58
119
59
120
/**
60
- * @dev Mint ERC20 rewards to the staker. Must override .
121
+ * @dev Mint ERC20 rewards to the staker. Override for custom logic .
61
122
*
62
123
* @param _staker Address for which to calculated rewards.
63
124
* @param _rewards Amount of tokens to be given out as reward.
64
125
*
65
126
*/
66
127
function _mintRewards (address _staker , uint256 _rewards ) internal virtual override {
67
- // Mint or transfer reward-tokens here.
68
- // e.g.
69
- //
70
- // IERC20(rewardToken).transfer(_staker, _rewards);
71
- //
72
- // OR
73
- //
74
- // Use a mintable ERC20, such as thirdweb's `TokenERC20.sol`
75
- //
76
- // TokenERC20(rewardToken).mintTo(_staker, _rewards);
77
- // note: The staking contract should have minter role to mint tokens.
128
+ require (_rewards <= rewardTokenBalance, "Not enough reward tokens " );
129
+ rewardTokenBalance -= _rewards;
130
+ CurrencyTransferLib.transferCurrencyWithWrapper (
131
+ rewardToken,
132
+ address (this ),
133
+ _staker,
134
+ _rewards,
135
+ nativeTokenWrapper
136
+ );
78
137
}
79
138
80
139
/*//////////////////////////////////////////////////////////////
81
140
Other Internal functions
82
141
//////////////////////////////////////////////////////////////*/
83
142
143
+ /// @dev Admin deposits reward tokens -- override for custom logic.
144
+ function _depositRewardTokens (uint256 _amount ) internal virtual {
145
+ require (msg .sender == owner (), "Not authorized " );
146
+
147
+ address _rewardToken = rewardToken == CurrencyTransferLib.NATIVE_TOKEN ? nativeTokenWrapper : rewardToken;
148
+
149
+ uint256 balanceBefore = IERC20 (_rewardToken).balanceOf (address (this ));
150
+ CurrencyTransferLib.transferCurrencyWithWrapper (
151
+ rewardToken,
152
+ msg .sender ,
153
+ address (this ),
154
+ _amount,
155
+ nativeTokenWrapper
156
+ );
157
+ uint256 actualAmount = IERC20 (_rewardToken).balanceOf (address (this )) - balanceBefore;
158
+
159
+ rewardTokenBalance += actualAmount;
160
+ }
161
+
162
+ /// @dev Admin can withdraw excess reward tokens -- override for custom logic.
163
+ function _withdrawRewardTokens (uint256 _amount ) internal virtual {
164
+ require (msg .sender == owner (), "Not authorized " );
165
+
166
+ // to prevent locking of direct-transferred tokens
167
+ rewardTokenBalance = _amount > rewardTokenBalance ? 0 : rewardTokenBalance - _amount;
168
+
169
+ CurrencyTransferLib.transferCurrencyWithWrapper (
170
+ rewardToken,
171
+ address (this ),
172
+ msg .sender ,
173
+ _amount,
174
+ nativeTokenWrapper
175
+ );
176
+ }
177
+
84
178
/// @dev Returns whether staking restrictions can be set in given execution context.
85
179
function _canSetStakeConditions () internal view virtual override returns (bool ) {
86
180
return msg .sender == owner ();
0 commit comments