@@ -242,3 +242,137 @@ contract GhoTokenPoolEthereum_upgradeability is GhoTokenPoolRemoteSetup {
242242 assertEq (_getProxyAdminAddress (address (s_pool)), PROXY_ADMIN, "Unauthorized admin change " );
243243 }
244244}
245+
246+ contract GhoTokenPoolRemote_setChainRateLimiterConfig is GhoTokenPoolRemoteSetup {
247+ event ConfigChanged (RateLimiter.Config);
248+ event ChainConfigured (
249+ uint64 chainSelector ,
250+ RateLimiter.Config outboundRateLimiterConfig ,
251+ RateLimiter.Config inboundRateLimiterConfig
252+ );
253+
254+ uint64 internal s_remoteChainSelector;
255+
256+ function setUp () public virtual override {
257+ GhoTokenPoolRemoteSetup.setUp ();
258+ UpgradeableTokenPool.ChainUpdate[] memory chainUpdates = new UpgradeableTokenPool.ChainUpdate [](1 );
259+ s_remoteChainSelector = 123124 ;
260+ chainUpdates[0 ] = UpgradeableTokenPool.ChainUpdate ({
261+ remoteChainSelector: s_remoteChainSelector,
262+ allowed: true ,
263+ outboundRateLimiterConfig: getOutboundRateLimiterConfig (),
264+ inboundRateLimiterConfig: getInboundRateLimiterConfig ()
265+ });
266+ changePrank (AAVE_DAO);
267+ s_pool.applyChainUpdates (chainUpdates);
268+ changePrank (OWNER);
269+ }
270+
271+ function testFuzz_SetChainRateLimiterConfigSuccess (uint128 capacity , uint128 rate , uint32 newTime ) public {
272+ // Cap the lower bound to 4 so 4/2 is still >= 2
273+ vm.assume (capacity >= 4 );
274+ // Cap the lower bound to 2 so 2/2 is still >= 1
275+ rate = uint128 (bound (rate, 2 , capacity - 2 ));
276+ // Bucket updates only work on increasing time
277+ newTime = uint32 (bound (newTime, block .timestamp + 1 , type (uint32 ).max));
278+ vm.warp (newTime);
279+
280+ uint256 oldOutboundTokens = s_pool.getCurrentOutboundRateLimiterState (s_remoteChainSelector).tokens;
281+ uint256 oldInboundTokens = s_pool.getCurrentInboundRateLimiterState (s_remoteChainSelector).tokens;
282+
283+ RateLimiter.Config memory newOutboundConfig = RateLimiter.Config ({isEnabled: true , capacity: capacity, rate: rate});
284+ RateLimiter.Config memory newInboundConfig = RateLimiter.Config ({
285+ isEnabled: true ,
286+ capacity: capacity / 2 ,
287+ rate: rate / 2
288+ });
289+
290+ vm.expectEmit ();
291+ emit ConfigChanged (newOutboundConfig);
292+ vm.expectEmit ();
293+ emit ConfigChanged (newInboundConfig);
294+ vm.expectEmit ();
295+ emit ChainConfigured (s_remoteChainSelector, newOutboundConfig, newInboundConfig);
296+
297+ changePrank (AAVE_DAO);
298+ s_pool.setChainRateLimiterConfig (s_remoteChainSelector, newOutboundConfig, newInboundConfig);
299+
300+ uint256 expectedTokens = RateLimiter._min (newOutboundConfig.capacity, oldOutboundTokens);
301+
302+ RateLimiter.TokenBucket memory bucket = s_pool.getCurrentOutboundRateLimiterState (s_remoteChainSelector);
303+ assertEq (bucket.capacity, newOutboundConfig.capacity);
304+ assertEq (bucket.rate, newOutboundConfig.rate);
305+ assertEq (bucket.tokens, expectedTokens);
306+ assertEq (bucket.lastUpdated, newTime);
307+
308+ expectedTokens = RateLimiter._min (newInboundConfig.capacity, oldInboundTokens);
309+
310+ bucket = s_pool.getCurrentInboundRateLimiterState (s_remoteChainSelector);
311+ assertEq (bucket.capacity, newInboundConfig.capacity);
312+ assertEq (bucket.rate, newInboundConfig.rate);
313+ assertEq (bucket.tokens, expectedTokens);
314+ assertEq (bucket.lastUpdated, newTime);
315+ }
316+
317+ function testOnlyOwnerOrRateLimitAdminSuccess () public {
318+ address rateLimiterAdmin = address (28973509103597907 );
319+
320+ changePrank (AAVE_DAO);
321+ s_pool.setRateLimitAdmin (rateLimiterAdmin);
322+
323+ changePrank (rateLimiterAdmin);
324+
325+ s_pool.setChainRateLimiterConfig (
326+ s_remoteChainSelector,
327+ getOutboundRateLimiterConfig (),
328+ getInboundRateLimiterConfig ()
329+ );
330+
331+ changePrank (AAVE_DAO);
332+
333+ s_pool.setChainRateLimiterConfig (
334+ s_remoteChainSelector,
335+ getOutboundRateLimiterConfig (),
336+ getInboundRateLimiterConfig ()
337+ );
338+ }
339+
340+ // Reverts
341+
342+ function testOnlyOwnerReverts () public {
343+ changePrank (STRANGER);
344+
345+ vm.expectRevert (abi.encodeWithSelector (UpgradeableBurnMintTokenPool.Unauthorized.selector , STRANGER));
346+ s_pool.setChainRateLimiterConfig (
347+ s_remoteChainSelector,
348+ getOutboundRateLimiterConfig (),
349+ getInboundRateLimiterConfig ()
350+ );
351+ }
352+
353+ function testNonExistentChainReverts () public {
354+ uint64 wrongChainSelector = 9084102894 ;
355+
356+ vm.expectRevert (abi.encodeWithSelector (UpgradeableTokenPool.NonExistentChain.selector , wrongChainSelector));
357+ changePrank (AAVE_DAO);
358+ s_pool.setChainRateLimiterConfig (wrongChainSelector, getOutboundRateLimiterConfig (), getInboundRateLimiterConfig ());
359+ }
360+ }
361+
362+ contract GhoTokenPoolRemote_setRateLimitAdmin is GhoTokenPoolRemoteSetup {
363+ function testSetRateLimitAdminSuccess () public {
364+ assertEq (address (0 ), s_pool.getRateLimitAdmin ());
365+ changePrank (AAVE_DAO);
366+ s_pool.setRateLimitAdmin (OWNER);
367+ assertEq (OWNER, s_pool.getRateLimitAdmin ());
368+ }
369+
370+ // Reverts
371+
372+ function testSetRateLimitAdminReverts () public {
373+ vm.startPrank (STRANGER);
374+
375+ vm.expectRevert ("Only callable by owner " );
376+ s_pool.setRateLimitAdmin (STRANGER);
377+ }
378+ }
0 commit comments