Skip to content

Commit

Permalink
feat: sysstia (#8941)
Browse files Browse the repository at this point in the history
Fixes #8136.
  • Loading branch information
LHerskind authored Oct 11, 2024
1 parent b75d4c8 commit 2da2fe2
Show file tree
Hide file tree
Showing 6 changed files with 137 additions and 0 deletions.
44 changes: 44 additions & 0 deletions l1-contracts/src/governance/Sysstia.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2023 Aztec Labs.
pragma solidity >=0.8.27;

import {IERC20} from "@oz/token/ERC20/IERC20.sol";
import {SafeERC20} from "@oz/token/ERC20/utils/SafeERC20.sol";

import {IRegistry} from "@aztec/governance/interfaces/IRegistry.sol";
import {ISysstia} from "@aztec/governance/interfaces/ISysstia.sol";

import {Errors} from "@aztec/governance/libraries/Errors.sol";

contract Sysstia is ISysstia {
using SafeERC20 for IERC20;

// This value is pulled out my ass. Don't take it seriously
uint256 public constant BLOCK_REWARD = 50e18;

IERC20 public immutable TST;
IRegistry public immutable REGISTRY;

constructor(IERC20 _tst, IRegistry _registry) {
TST = _tst;
REGISTRY = _registry;
}

/**
* @notice Simple claim of a block reward
* Note especially that it can be called any number of times.
* Essentially a placeholder until more nuanced logic is designed.
*
* @dev Does not check if the tokens are actually available first.
*
* @param _to - The address to receive the reward
*
* @return - the amount claimed
*/
function claim(address _to) external override(ISysstia) returns (uint256) {
address canonical = REGISTRY.getRollup();
require(msg.sender == canonical, Errors.Sysstia__InvalidCaller(msg.sender, canonical));
TST.safeTransfer(_to, BLOCK_REWARD);
return BLOCK_REWARD;
}
}
6 changes: 6 additions & 0 deletions l1-contracts/src/governance/interfaces/ISysstia.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity >=0.8.27;

interface ISysstia {
function claim(address _to) external returns (uint256);
}
2 changes: 2 additions & 0 deletions l1-contracts/src/governance/libraries/Errors.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,6 @@ library Errors {

error Registry__RollupAlreadyRegistered(address rollup); // 0x3c34eabf
error Registry__RollupNotRegistered(address rollup); // 0xa1fee4cf

error Sysstia__InvalidCaller(address caller, address canonical); // 0xb95e39f6
}
23 changes: 23 additions & 0 deletions l1-contracts/test/governance/sysstia/Base.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.8.27;

import {Test} from "forge-std/Test.sol";

import {IMintableERC20} from "@aztec/governance/interfaces/IMintableERC20.sol";

import {Registry} from "@aztec/governance/Registry.sol";
import {Sysstia} from "@aztec/governance/Sysstia.sol";

import {TestERC20} from "@aztec/mock/TestERC20.sol";

contract SysstiaBase is Test {
IMintableERC20 internal token;
Registry internal registry;
Sysstia internal sysstia;

function setUp() public {
token = IMintableERC20(address(new TestERC20()));
registry = new Registry(address(this));
sysstia = new Sysstia(token, registry);
}
}
53 changes: 53 additions & 0 deletions l1-contracts/test/governance/sysstia/claim.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.8.27;

import {SysstiaBase} from "./Base.t.sol";

import {IERC20Errors} from "@oz/interfaces/draft-IERC6093.sol";

import {Errors} from "@aztec/governance/libraries/Errors.sol";

contract ClaimTest is SysstiaBase {
address internal caller;

function test_WhenCallerIsNotCanonical(address _caller) external {
// it reverts
vm.assume(_caller != address(0xdead));

vm.expectRevert(
abi.encodeWithSelector(Errors.Sysstia__InvalidCaller.selector, _caller, address(0xdead))
);
vm.prank(_caller);
sysstia.claim(_caller);
}

modifier whenCallerIsCanonical() {
caller = address(0xdead);
_;
}

function test_GivenBalanceSmallerThanReward() external whenCallerIsCanonical {
// it reverts
uint256 needed = sysstia.BLOCK_REWARD();
vm.prank(caller);
vm.expectRevert(
abi.encodeWithSelector(
IERC20Errors.ERC20InsufficientBalance.selector, address(sysstia), 0, needed
)
);
sysstia.claim(caller);
}

function test_GivenBalanceLargerOrEqualReward(uint256 _balance) external whenCallerIsCanonical {
// it transfers block reward of asset
// it returns block reward value
uint256 balance = bound(_balance, sysstia.BLOCK_REWARD(), type(uint256).max);
token.mint(address(sysstia), balance);

uint256 callerBalance = token.balanceOf(caller);
vm.prank(caller);
sysstia.claim(caller);

assertEq(token.balanceOf(caller), callerBalance + sysstia.BLOCK_REWARD());
}
}
9 changes: 9 additions & 0 deletions l1-contracts/test/governance/sysstia/claim.tree
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
ClaimTest
├── when caller is not canonical
│ └── it reverts
└── when caller is canonical
├── given balance smaller than reward
│ └── it reverts
└── given balance larger or equal reward
├── it transfers block reward of asset
└── it returns block reward value

0 comments on commit 2da2fe2

Please sign in to comment.