Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add SWISE token #2

Merged
merged 1 commit into from
Jun 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .forge-snapshots/SwiseToken_burn.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
51418
1 change: 1 addition & 0 deletions .forge-snapshots/SwiseToken_mint.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
92566
1 change: 1 addition & 0 deletions .forge-snapshots/SwiseToken_permit.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
96845
1 change: 1 addition & 0 deletions .forge-snapshots/SwiseToken_setController.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
69655
68 changes: 68 additions & 0 deletions broadcast/DeploySwiseToken.s.sol/42161/run-latest.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion script/DeployOsToken.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
pragma solidity ^0.8.22;

import {Script, console2} from "forge-std/Script.sol";
import {OsToken} from "../src/OsToken.sol";
import {OsToken} from "../src/tokens/OsToken.sol";

contract DeployOsToken is Script {
function run() external {
Expand Down
22 changes: 22 additions & 0 deletions script/DeploySwiseToken.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// SPDX-License-Identifier: BUSL-1.1

pragma solidity ^0.8.22;

import {Script, console2} from "forge-std/Script.sol";
import {SwiseToken} from "../src/tokens/SwiseToken.sol";

contract DeploySwiseToken is Script {
function run() external {
vm.startBroadcast();
console2.log("Deploying from: ", msg.sender);

// Deploy SwiseToken.
SwiseToken swiseToken = new SwiseToken(msg.sender, "StakeWise", "SWISE");
console2.log("SwiseToken deployed at: ", address(swiseToken));

vm.stopBroadcast();
}

// excludes this contract from coverage report
function test() public {}
}
File renamed without changes.
70 changes: 70 additions & 0 deletions src/tokens/SwiseToken.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// SPDX-License-Identifier: BUSL-1.1

pragma solidity ^0.8.22;

import {Ownable2Step, Ownable} from "@openzeppelin/contracts/access/Ownable2Step.sol";
import {ERC20Permit, ERC20} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol";
import {Errors} from "@stakewise-core/libraries/Errors.sol";

/**
* @title SwiseToken
* @author StakeWise
* @notice SwiseToken is an ERC20 token with permit and minting functionality
*/
contract SwiseToken is Ownable2Step, ERC20Permit {
/**
* @notice Emitted when the controller is updated
* @param newController The address of the new controller
*/
event ControllerUpdated(address newController);

address public controller;

/**
* @dev Constructor
* @param _owner The address of the contract owner
* @param _name The name of the ERC20 token
* @param _symbol The symbol of the ERC20 token
*/
constructor(address _owner, string memory _name, string memory _symbol)
ERC20(_name, _symbol)
ERC20Permit(_name)
Ownable(_owner)
{}

/**
* @dev Throws if called by any account other than the controller.
*/
modifier onlyController() {
if (msg.sender != controller) revert Errors.AccessDenied();
_;
}

/**
* @notice Mint SwiseToken. Can only be called by the controller.
* @param account The address of the account to mint SwiseToken for
* @param value The amount of SwiseToken to mint
*/
function mint(address account, uint256 value) external onlyController {
_mint(account, value);
}

/**
* @notice Burn SwiseToken. Can only be called by the controller.
* @param account The address of the account to burn SwiseToken for
* @param value The amount of SwiseToken to burn
*/
function burn(address account, uint256 value) external onlyController {
_burn(account, value);
}

/**
* @notice Set the controller address. Can only be called by the owner.
* @param newController The address of the new controller
*/
function setController(address newController) external onlyOwner {
if (newController == address(0)) revert Errors.ZeroAddress();
controller = newController;
emit ControllerUpdated(newController);
}
}
4 changes: 2 additions & 2 deletions test/OsToken.t.sol → test/tokens/OsToken.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import {Errors} from "@stakewise-core/libraries/Errors.sol";
import {GasSnapshot} from "forge-gas-snapshot/GasSnapshot.sol";
import {Test} from "forge-std/Test.sol";
import {Vm} from "forge-std/Vm.sol";
import {OsToken, IOsToken} from "../src/OsToken.sol";
import {SigUtils} from "./helpers/SigUtils.sol";
import {OsToken, IOsToken} from "../../src/tokens/OsToken.sol";
import {SigUtils} from "../helpers/SigUtils.sol";

contract OsTokenTest is Test, GasSnapshot {
OsToken osToken;
Expand Down
87 changes: 87 additions & 0 deletions test/tokens/SwiseToken.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
// SPDX-License-Identifier: BUSL-1.1

pragma solidity ^0.8.22;

import {Ownable} from "@openzeppelin/contracts/access/Ownable2Step.sol";
import {Errors} from "@stakewise-core/libraries/Errors.sol";
import {GasSnapshot} from "forge-gas-snapshot/GasSnapshot.sol";
import {Test} from "forge-std/Test.sol";
import {Vm} from "forge-std/Vm.sol";
import {SwiseToken} from "../../src/tokens/SwiseToken.sol";
import {SigUtils} from "../helpers/SigUtils.sol";

contract SwiseTokenTest is Test, GasSnapshot {
SwiseToken swiseToken;

function setUp() public {
swiseToken = new SwiseToken(address(this), "test", "test");
}

function test_setController() public {
vm.expectRevert(abi.encodeWithSelector(Ownable.OwnableUnauthorizedAccount.selector, address(1)));
vm.prank(address(1));
swiseToken.setController(address(1));

vm.expectRevert(abi.encodeWithSelector(Errors.ZeroAddress.selector));
swiseToken.setController(address(0));

vm.expectEmit(false, false, false, true);
emit SwiseToken.ControllerUpdated(address(1));

snapStart("SwiseToken_setController");
swiseToken.setController(address(1));
snapEnd();

assertEq(swiseToken.controller(), address(1));
}

function test_mint() public {
vm.expectRevert(Errors.AccessDenied.selector);
vm.prank(address(1));
swiseToken.mint(address(1), 1);

swiseToken.setController(address(this));

snapStart("SwiseToken_mint");
swiseToken.mint(address(1), 1);
snapEnd();

assertEq(swiseToken.balanceOf(address(1)), 1);
}

function test_burn() public {
vm.expectRevert(Errors.AccessDenied.selector);
vm.prank(address(1));
swiseToken.burn(address(1), 1);

swiseToken.setController(address(this));
swiseToken.mint(address(1), 1);

snapStart("SwiseToken_burn");
swiseToken.burn(address(1), 1);
snapEnd();

assertEq(swiseToken.balanceOf(address(1)), 0);
}

function test_Permit() public {
uint256 ownerPrivateKey = 0xA11CE;
address owner = vm.addr(ownerPrivateKey);
address spender = address(1);

SigUtils sigUtils = new SigUtils(swiseToken.DOMAIN_SEPARATOR());
SigUtils.Permit memory permit =
SigUtils.Permit({owner: owner, spender: spender, value: 1e18, nonce: 0, deadline: 1 days});

bytes32 digest = sigUtils.getTypedDataHash(permit);

(uint8 v, bytes32 r, bytes32 s) = vm.sign(ownerPrivateKey, digest);

snapStart("SwiseToken_permit");
swiseToken.permit(permit.owner, permit.spender, permit.value, permit.deadline, v, r, s);
snapEnd();

assertEq(swiseToken.allowance(owner, spender), 1e18);
assertEq(swiseToken.nonces(owner), 1);
}
}
Loading