chore: introduce SNT V2 (#1)
This introduces an SNT V2 token implementation. It inherits from `MiniMeToken` and also comes with an `SNTTestnetController` that can be used on test networks for allowing minting of tokens by anyone. This makes the token controller more general and introduces an `open` property to enable/disable the faucet. Also adds a `destroyTokens()` function for completeness' sake.
This commit is contained in:
parent
3f2175ac56
commit
23de68feb5
|
@ -1 +1,10 @@
|
||||||
FooTest:test_Example() (gas: 8662)
|
TestDestroyTokens:testDeployment() (gas: 47764)
|
||||||
|
TestDestroyTokens:test_DestroyTokenFaucetIsOpen() (gas: 133862)
|
||||||
|
TestDestroyTokens:test_DestroyTokensAsOwner() (gas: 131266)
|
||||||
|
TestDestroyTokens:test_RevertWhen_FaucetIsClosed() (gas: 16257)
|
||||||
|
TestDestroyTokens:test_RevertWhen_NotEnoughBalance() (gas: 29029)
|
||||||
|
TestGenerateTokens:testDeployment() (gas: 47719)
|
||||||
|
TestGenerateTokens:test_GenerateTokensAsOwner() (gas: 119330)
|
||||||
|
TestGenerateTokens:test_GenerateTokensOpenFaucet() (gas: 122001)
|
||||||
|
TestGenerateTokens:test_RevertWhen_FaucetIsClosed() (gas: 16311)
|
||||||
|
TestSNTV2:testDeployment() (gas: 47764)
|
|
@ -2,3 +2,9 @@
|
||||||
branch = "v1"
|
branch = "v1"
|
||||||
path = lib/forge-std
|
path = lib/forge-std
|
||||||
url = https://github.com/foundry-rs/forge-std
|
url = https://github.com/foundry-rs/forge-std
|
||||||
|
[submodule "lib/minime"]
|
||||||
|
path = lib/minime
|
||||||
|
url = https://github.com/vacp2p/minime
|
||||||
|
[submodule "lib/openzeppelin-contracts"]
|
||||||
|
path = lib/openzeppelin-contracts
|
||||||
|
url = https://github.com/OpenZeppelin/openzeppelin-contracts
|
||||||
|
|
103
README.md
103
README.md
|
@ -1,4 +1,4 @@
|
||||||
# Foundry Template [![Github Actions][gha-badge]][gha] [![Foundry][foundry-badge]][foundry] [![License: MIT][license-badge]][license]
|
# Status Network Token V2 [![Github Actions][gha-badge]][gha] [![Foundry][foundry-badge]][foundry] [![License: MIT][license-badge]][license]
|
||||||
|
|
||||||
[gha]: https://github.com/status-im/status-network-token-v2/actions
|
[gha]: https://github.com/status-im/status-network-token-v2/actions
|
||||||
[gha-badge]: https://github.com/status-im/status-network-token-v2/actions/workflows/ci.yml/badge.svg
|
[gha-badge]: https://github.com/status-im/status-network-token-v2/actions/workflows/ci.yml/badge.svg
|
||||||
|
@ -7,93 +7,9 @@
|
||||||
[license]: https://opensource.org/licenses/MIT
|
[license]: https://opensource.org/licenses/MIT
|
||||||
[license-badge]: https://img.shields.io/badge/License-MIT-blue.svg
|
[license-badge]: https://img.shields.io/badge/License-MIT-blue.svg
|
||||||
|
|
||||||
A Foundry-based template for developing Solidity smart contracts, with sensible defaults.
|
This is the second iteration of [Status Network Token](https://github.com/status-im/status-network-token). The original
|
||||||
|
version of the token uses a lot of legacy code. This repository implements a more modern version based on our
|
||||||
This is a fork of [PaulRBerg's template](https://github.com/PaulRBerg/foundry-template) and adjusted to Vac's smart
|
[MiniMeToken](https://github.com/vacp2p/minime) fork.
|
||||||
contracts unit's needs. See [Upstream differences](#upstream-differences) to learn more about how this template differs
|
|
||||||
from Paul's.
|
|
||||||
|
|
||||||
## What's Inside
|
|
||||||
|
|
||||||
- [Forge](https://github.com/foundry-rs/foundry/blob/master/forge): compile, test, fuzz, format, and deploy smart
|
|
||||||
contracts
|
|
||||||
- [Forge Std](https://github.com/foundry-rs/forge-std): collection of helpful contracts and cheatcodes for testing
|
|
||||||
- [Solhint Community](https://github.com/solhint-community/solhint-community): linter for Solidity code
|
|
||||||
|
|
||||||
## Getting Started
|
|
||||||
|
|
||||||
Click the [`Use this template`](https://github.com/vacp2p/foundry-template/generate) button at the top of the page to
|
|
||||||
create a new repository with this repo as the initial state.
|
|
||||||
|
|
||||||
Or, if you prefer to install the template manually:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
$ mkdir my-project
|
|
||||||
$ cd my-project
|
|
||||||
$ forge init --template vacp2p/foundry-template
|
|
||||||
$ pnpm install # install Solhint, Prettier, and other Node.js deps
|
|
||||||
```
|
|
||||||
|
|
||||||
If this is your first time with Foundry, check out the
|
|
||||||
[installation](https://github.com/foundry-rs/foundry#installation) instructions.
|
|
||||||
|
|
||||||
## Features
|
|
||||||
|
|
||||||
This template builds upon the frameworks and libraries mentioned above, so for details about their specific features,
|
|
||||||
please consult their respective documentation.
|
|
||||||
|
|
||||||
For example, if you're interested in exploring Foundry in more detail, you should look at the
|
|
||||||
[Foundry Book](https://book.getfoundry.sh/). In particular, you may be interested in reading the
|
|
||||||
[Writing Tests](https://book.getfoundry.sh/forge/writing-tests.html) tutorial.
|
|
||||||
|
|
||||||
### Upstream differences
|
|
||||||
|
|
||||||
As mentioned above, this template is a fork with adjustments specific to the needs of Vac's smart contract service unit.
|
|
||||||
These differences are:
|
|
||||||
|
|
||||||
- **Removal of [PRBTest](https://github.com/PaulRBerg/prb-test)** - In an attempt to keep dependence on third-party code
|
|
||||||
low, we've decided to remove this library as a standard dependency of every project within Vac. If we do see a need
|
|
||||||
for it, we might bring it back in the future.
|
|
||||||
- **PROPERTIES.md** - For invariant testing and formal verification, we've introduced a `PROPERTIES.md` to document all
|
|
||||||
protocol properties that must hold true.
|
|
||||||
|
|
||||||
### Sensible Defaults
|
|
||||||
|
|
||||||
This template comes with a set of sensible default configurations for you to use. These defaults can be found in the
|
|
||||||
following files:
|
|
||||||
|
|
||||||
```text
|
|
||||||
├── .editorconfig
|
|
||||||
├── .gitignore
|
|
||||||
├── .prettierignore
|
|
||||||
├── .prettierrc.yml
|
|
||||||
├── .solhint.json
|
|
||||||
├── foundry.toml
|
|
||||||
├── remappings.txt
|
|
||||||
└── slither.config.json
|
|
||||||
```
|
|
||||||
|
|
||||||
### VSCode Integration
|
|
||||||
|
|
||||||
This template is IDE agnostic, but for the best user experience, you may want to use it in VSCode alongside Nomic
|
|
||||||
Foundation's [Solidity extension](https://marketplace.visualstudio.com/items?itemName=NomicFoundation.hardhat-solidity).
|
|
||||||
|
|
||||||
For guidance on how to integrate a Foundry project in VSCode, please refer to this
|
|
||||||
[guide](https://book.getfoundry.sh/config/vscode).
|
|
||||||
|
|
||||||
### GitHub Actions
|
|
||||||
|
|
||||||
This template comes with GitHub Actions pre-configured. Your contracts will be linted and tested on every push and pull
|
|
||||||
request made to the `main` branch.
|
|
||||||
|
|
||||||
You can edit the CI script in [.github/workflows/ci.yml](./.github/workflows/ci.yml).
|
|
||||||
|
|
||||||
## Writing Tests
|
|
||||||
|
|
||||||
If you would like to view the logs in the terminal output you can add the `-vvv` flag and use
|
|
||||||
[console.log](https://book.getfoundry.sh/faq?highlight=console.log#how-do-i-use-consolelog).
|
|
||||||
|
|
||||||
This template comes with an example test contract [Foo.t.sol](./test/Foo.t.sol)
|
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
|
@ -188,14 +104,3 @@ $ forge test
|
||||||
[guide](https://book.getfoundry.sh/projects/dependencies.html) in the book
|
[guide](https://book.getfoundry.sh/projects/dependencies.html) in the book
|
||||||
2. You don't have to create a `.env` file, but filling in the environment variables may be useful when debugging and
|
2. You don't have to create a `.env` file, but filling in the environment variables may be useful when debugging and
|
||||||
testing against a fork.
|
testing against a fork.
|
||||||
|
|
||||||
## Related Efforts
|
|
||||||
|
|
||||||
- [abigger87/femplate](https://github.com/abigger87/femplate)
|
|
||||||
- [cleanunicorn/ethereum-smartcontract-template](https://github.com/cleanunicorn/ethereum-smartcontract-template)
|
|
||||||
- [foundry-rs/forge-template](https://github.com/foundry-rs/forge-template)
|
|
||||||
- [FrankieIsLost/forge-template](https://github.com/FrankieIsLost/forge-template)
|
|
||||||
|
|
||||||
## License
|
|
||||||
|
|
||||||
This project is licensed under MIT.
|
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 6d9d4f54876c2095f5aa79210869c8e17e30f55e
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit fd81a96f01cc42ef1c9a5399364968d0e07e9e90
|
|
@ -1 +1,3 @@
|
||||||
forge-std/=lib/forge-std/src/
|
forge-std/=lib/forge-std/src/
|
||||||
|
@vacp2p/minime/contracts/=lib/minime/contracts/
|
||||||
|
@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/
|
||||||
|
|
|
@ -1,13 +1,24 @@
|
||||||
// SPDX-License-Identifier: UNLICENSED
|
// SPDX-License-Identifier: UNLICENSED
|
||||||
pragma solidity >=0.8.19 <=0.9.0;
|
pragma solidity >=0.8.19 <=0.9.0;
|
||||||
|
|
||||||
import { Foo } from "../src/Foo.sol";
|
|
||||||
import { BaseScript } from "./Base.s.sol";
|
import { BaseScript } from "./Base.s.sol";
|
||||||
import { DeploymentConfig } from "./DeploymentConfig.s.sol";
|
import { DeploymentConfig } from "./DeploymentConfig.s.sol";
|
||||||
|
|
||||||
|
import { SNTV2 } from "../src/SNTV2.sol";
|
||||||
|
import { SNTTokenController } from "../src/SNTTokenController.sol";
|
||||||
|
|
||||||
contract Deploy is BaseScript {
|
contract Deploy is BaseScript {
|
||||||
function run() public returns (Foo foo, DeploymentConfig deploymentConfig) {
|
function run() public returns (SNTV2, SNTTokenController, DeploymentConfig) {
|
||||||
deploymentConfig = new DeploymentConfig(broadcaster);
|
DeploymentConfig deploymentConfig = new DeploymentConfig(broadcaster);
|
||||||
foo = new Foo();
|
(, string memory tokenName, string memory tokenSymbol, uint8 decimalUnits) =
|
||||||
|
deploymentConfig.activeNetworkConfig();
|
||||||
|
|
||||||
|
vm.startBroadcast(broadcaster);
|
||||||
|
SNTV2 sntV2 = new SNTV2(tokenName, decimalUnits, tokenSymbol);
|
||||||
|
SNTTokenController controller = new SNTTokenController(payable(address(sntV2)), false);
|
||||||
|
sntV2.changeController(payable(address(controller)));
|
||||||
|
vm.stopBroadcast();
|
||||||
|
|
||||||
|
return (sntV2, controller, deploymentConfig);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,9 @@ contract DeploymentConfig is Script {
|
||||||
|
|
||||||
struct NetworkConfig {
|
struct NetworkConfig {
|
||||||
address deployer;
|
address deployer;
|
||||||
|
string tokenName;
|
||||||
|
string tokenSymbol;
|
||||||
|
uint8 decimalUnits;
|
||||||
}
|
}
|
||||||
|
|
||||||
NetworkConfig public activeNetworkConfig;
|
NetworkConfig public activeNetworkConfig;
|
||||||
|
@ -27,7 +30,12 @@ contract DeploymentConfig is Script {
|
||||||
}
|
}
|
||||||
|
|
||||||
function getOrCreateAnvilEthConfig() public view returns (NetworkConfig memory) {
|
function getOrCreateAnvilEthConfig() public view returns (NetworkConfig memory) {
|
||||||
return NetworkConfig({ deployer: deployer });
|
return NetworkConfig({
|
||||||
|
deployer: deployer,
|
||||||
|
tokenName: "Status Network Token",
|
||||||
|
tokenSymbol: "SNT",
|
||||||
|
decimalUnits: 18
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function is a hack to have it excluded by `forge coverage` until
|
// This function is a hack to have it excluded by `forge coverage` until
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
// SPDX-License-Identifier: UNLICENSED
|
|
||||||
pragma solidity >=0.8.19;
|
|
||||||
|
|
||||||
contract Foo {
|
|
||||||
function id(uint256 value) external pure returns (uint256) {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,74 @@
|
||||||
|
// SPDX-License-Identifier: UNLICENSED
|
||||||
|
pragma solidity ^0.8.19;
|
||||||
|
|
||||||
|
import { MiniMeBase } from "@vacp2p/minime/contracts/MiniMeBase.sol";
|
||||||
|
import { TokenController } from "@vacp2p/minime/contracts/TokenController.sol";
|
||||||
|
import { Ownable2Step } from "@openzeppelin/contracts/access/Ownable2Step.sol";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @title SNTController
|
||||||
|
* @author r4bbit <r4bbit@status.im>
|
||||||
|
* @dev Controller contract for SNTV2 token.
|
||||||
|
* It's a no operation contract that can be replaced by controllers with more privileges.
|
||||||
|
*/
|
||||||
|
contract SNTController is TokenController, Ownable2Step {
|
||||||
|
MiniMeBase public snt;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param _snt The address of the SNT token
|
||||||
|
*/
|
||||||
|
constructor(address payable _snt) {
|
||||||
|
snt = MiniMeBase(_snt);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @notice The owner of this contract can change the controller of the SNT token
|
||||||
|
* Please, be sure that the owner is a trusted agent or 0x0 address.
|
||||||
|
* @param _newController The address of the new controller
|
||||||
|
*/
|
||||||
|
function changeController(address payable _newController) public onlyOwner {
|
||||||
|
snt.changeController(_newController);
|
||||||
|
emit ControllerChanged(_newController);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev proxyPayment set to reject all Ether.
|
||||||
|
*/
|
||||||
|
function proxyPayment(address) public payable override returns (bool) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev onTransfer set to accept any transfer
|
||||||
|
*/
|
||||||
|
function onTransfer(address, address, uint256) public pure override returns (bool) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev onApprove set to accept any approval
|
||||||
|
*/
|
||||||
|
function onApprove(address, address, uint256) public pure override returns (bool) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @notice Send tokens or ether from this contract to owner.
|
||||||
|
* @param _token Token contract to recover, 0 to extract ether.
|
||||||
|
*/
|
||||||
|
function claimTokens(MiniMeBase _token) public onlyOwner {
|
||||||
|
uint256 balance;
|
||||||
|
if (address(_token) == address(0)) {
|
||||||
|
balance = address(this).balance;
|
||||||
|
payable(msg.sender).transfer(balance);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
balance = _token.balanceOf(address(this));
|
||||||
|
_token.transfer(msg.sender, balance);
|
||||||
|
}
|
||||||
|
emit ClaimedTokens(address(_token), msg.sender, balance);
|
||||||
|
}
|
||||||
|
|
||||||
|
event ClaimedTokens(address indexed _token, address indexed _controller, uint256 _amount);
|
||||||
|
event ControllerChanged(address indexed _newController);
|
||||||
|
}
|
|
@ -0,0 +1,114 @@
|
||||||
|
// SPDX-License-Identifier: UNLICENSED
|
||||||
|
pragma solidity ^0.8.19;
|
||||||
|
|
||||||
|
import { MiniMeBase } from "@vacp2p/minime/contracts/MiniMeBase.sol";
|
||||||
|
import { MiniMeToken } from "@vacp2p/minime/contracts/MiniMeToken.sol";
|
||||||
|
import { TokenController } from "@vacp2p/minime/contracts/TokenController.sol";
|
||||||
|
import { Ownable2Step } from "@openzeppelin/contracts/access/Ownable2Step.sol";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @title SNTTokenController
|
||||||
|
* @author r4bbit <r4bbit@status.im>
|
||||||
|
* @dev Testnet controller contract for SNTV2 token.
|
||||||
|
* It's a no operation contract that allows for generating tokens.
|
||||||
|
* This is useful for test networks.
|
||||||
|
*/
|
||||||
|
contract SNTTokenController is TokenController, Ownable2Step {
|
||||||
|
error SNTTokenController_NotOpen();
|
||||||
|
|
||||||
|
MiniMeToken public snt;
|
||||||
|
|
||||||
|
bool public open;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param _snt The address of the SNT token
|
||||||
|
*/
|
||||||
|
constructor(address payable _snt, bool _open) {
|
||||||
|
snt = MiniMeToken(_snt);
|
||||||
|
open = _open;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @notice The owner of this contract can set the open variable
|
||||||
|
* This is useful for test networks.
|
||||||
|
* @param _open The new value for the open variable
|
||||||
|
*/
|
||||||
|
function setOpen(bool _open) public onlyOwner {
|
||||||
|
open = _open;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @notice The owner of this contract can change the controller of the SNT token
|
||||||
|
* Please, be sure that the owner is a trusted agent or 0x0 address.
|
||||||
|
* @param _newController The address of the new controller
|
||||||
|
*/
|
||||||
|
function changeController(address payable _newController) public onlyOwner {
|
||||||
|
snt.changeController(_newController);
|
||||||
|
emit ControllerChanged(_newController);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev proxyPayment set to reject all Ether.
|
||||||
|
*/
|
||||||
|
function proxyPayment(address) public payable override returns (bool) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev onTransfer set to accept any transfer
|
||||||
|
*/
|
||||||
|
function onTransfer(address, address, uint256) public pure override returns (bool) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev onApprove set to accept any approval
|
||||||
|
*/
|
||||||
|
function onApprove(address, address, uint256) public pure override returns (bool) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @notice Generate tokens for the given address.
|
||||||
|
* @param _to The address that will receive the minted tokens.
|
||||||
|
* @param _amount The amount of tokens to mint.
|
||||||
|
*/
|
||||||
|
function generateTokens(address _to, uint256 _amount) public {
|
||||||
|
if (!open && msg.sender != owner()) {
|
||||||
|
revert SNTTokenController_NotOpen();
|
||||||
|
}
|
||||||
|
snt.generateTokens(_to, _amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @notice Destroy tokens for the given address.
|
||||||
|
* @param _from The address that gets token removed.
|
||||||
|
* @param _amount The amount of tokens to destroy.
|
||||||
|
*/
|
||||||
|
function destroyTokens(address _from, uint256 _amount) public {
|
||||||
|
if (!open && msg.sender != owner()) {
|
||||||
|
revert SNTTokenController_NotOpen();
|
||||||
|
}
|
||||||
|
snt.destroyTokens(_from, _amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @notice Send tokens or ether from this contract to owner.
|
||||||
|
* @param _token Token contract to recover, 0 to extract ether.
|
||||||
|
*/
|
||||||
|
function claimTokens(MiniMeBase _token) public onlyOwner {
|
||||||
|
uint256 balance;
|
||||||
|
if (address(_token) == address(0)) {
|
||||||
|
balance = address(this).balance;
|
||||||
|
payable(msg.sender).transfer(balance);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
balance = _token.balanceOf(address(this));
|
||||||
|
_token.transfer(msg.sender, balance);
|
||||||
|
}
|
||||||
|
emit ClaimedTokens(address(_token), msg.sender, balance);
|
||||||
|
}
|
||||||
|
|
||||||
|
event ClaimedTokens(address indexed _token, address indexed _controller, uint256 _amount);
|
||||||
|
event ControllerChanged(address indexed _newController);
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
// SPDX-License-Identifier: UNLICENSED
|
||||||
|
pragma solidity >=0.8.19;
|
||||||
|
|
||||||
|
import { MiniMeToken } from "@vacp2p/minime/contracts/MiniMeToken.sol";
|
||||||
|
|
||||||
|
contract SNTV2 is MiniMeToken {
|
||||||
|
constructor(
|
||||||
|
string memory _tokenName,
|
||||||
|
uint8 _decimalUnits,
|
||||||
|
string memory _tokenSymbol
|
||||||
|
)
|
||||||
|
MiniMeToken(MiniMeToken(payable(address(0))), 0, _tokenName, _decimalUnits, _tokenSymbol, true)
|
||||||
|
{ }
|
||||||
|
}
|
|
@ -1,26 +0,0 @@
|
||||||
// SPDX-License-Identifier: UNLICENSED
|
|
||||||
pragma solidity >=0.8.19 <0.9.0;
|
|
||||||
|
|
||||||
import { Test, console } from "forge-std/Test.sol";
|
|
||||||
|
|
||||||
import { Deploy } from "../script/Deploy.s.sol";
|
|
||||||
import { DeploymentConfig } from "../script/DeploymentConfig.s.sol";
|
|
||||||
import { Foo } from "../src/Foo.sol";
|
|
||||||
|
|
||||||
contract FooTest is Test {
|
|
||||||
Foo internal foo;
|
|
||||||
DeploymentConfig internal deploymentConfig;
|
|
||||||
|
|
||||||
address internal deployer;
|
|
||||||
|
|
||||||
function setUp() public virtual {
|
|
||||||
Deploy deployment = new Deploy();
|
|
||||||
(foo, deploymentConfig) = deployment.run();
|
|
||||||
}
|
|
||||||
|
|
||||||
function test_Example() external {
|
|
||||||
console.log("Hello World");
|
|
||||||
uint256 x = 42;
|
|
||||||
assertEq(foo.id(x), x, "value mismatch");
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,136 @@
|
||||||
|
// SPDX-License-Identifier: UNLICENSED
|
||||||
|
pragma solidity >=0.8.19;
|
||||||
|
|
||||||
|
import { Test } from "forge-std/Test.sol";
|
||||||
|
import { Deploy } from "../script/Deploy.s.sol";
|
||||||
|
import { DeploymentConfig } from "../script/DeploymentConfig.s.sol";
|
||||||
|
|
||||||
|
import { NotEnoughBalance } from "@vacp2p/minime/contracts/MiniMeBase.sol";
|
||||||
|
import { SNTV2 } from "../src/SNTV2.sol";
|
||||||
|
import { SNTTokenController } from "../src/SNTTokenController.sol";
|
||||||
|
|
||||||
|
contract TestSNTV2 is Test {
|
||||||
|
SNTV2 internal sntV2;
|
||||||
|
SNTTokenController internal controller;
|
||||||
|
DeploymentConfig internal deploymentConfig;
|
||||||
|
|
||||||
|
address internal deployer;
|
||||||
|
|
||||||
|
function setUp() public virtual {
|
||||||
|
Deploy deployment = new Deploy();
|
||||||
|
(sntV2, controller, deploymentConfig) = deployment.run();
|
||||||
|
(address _deployer,,,) = deploymentConfig.activeNetworkConfig();
|
||||||
|
deployer = _deployer;
|
||||||
|
}
|
||||||
|
|
||||||
|
function testDeployment() public {
|
||||||
|
(, string memory tokenName, string memory tokenSymbol, uint8 decimalUnits) =
|
||||||
|
deploymentConfig.activeNetworkConfig();
|
||||||
|
|
||||||
|
assertEq(sntV2.name(), tokenName);
|
||||||
|
assertEq(sntV2.symbol(), tokenSymbol);
|
||||||
|
assertEq(sntV2.decimals(), decimalUnits);
|
||||||
|
assertEq(sntV2.totalSupply(), 0);
|
||||||
|
assertEq(sntV2.controller(), address(controller));
|
||||||
|
|
||||||
|
assertEq(controller.owner(), deployer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
contract TestGenerateTokens is TestSNTV2 {
|
||||||
|
function setUp() public override {
|
||||||
|
TestSNTV2.setUp();
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_RevertWhen_FaucetIsClosed() public {
|
||||||
|
// ensure faucet is closed
|
||||||
|
vm.prank(deployer);
|
||||||
|
controller.setOpen(false);
|
||||||
|
|
||||||
|
vm.expectRevert(SNTTokenController.SNTTokenController_NotOpen.selector);
|
||||||
|
controller.generateTokens(address(this), 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_GenerateTokensAsOwner() public {
|
||||||
|
vm.startPrank(deployer);
|
||||||
|
controller.setOpen(false);
|
||||||
|
|
||||||
|
uint256 balanceBefore = sntV2.balanceOf(address(this));
|
||||||
|
assertEq(balanceBefore, 0);
|
||||||
|
|
||||||
|
controller.generateTokens(address(this), 100);
|
||||||
|
uint256 balanceAfter = sntV2.balanceOf(address(this));
|
||||||
|
assertEq(balanceAfter, 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_GenerateTokensOpenFaucet() public {
|
||||||
|
// ensure faucet is open
|
||||||
|
vm.prank(deployer);
|
||||||
|
controller.setOpen(true);
|
||||||
|
|
||||||
|
uint256 balanceBefore = sntV2.balanceOf(address(this));
|
||||||
|
assertEq(balanceBefore, 0);
|
||||||
|
|
||||||
|
controller.generateTokens(address(this), 100);
|
||||||
|
uint256 balanceAfter = sntV2.balanceOf(address(this));
|
||||||
|
assertEq(balanceAfter, 100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
contract TestDestroyTokens is TestSNTV2 {
|
||||||
|
function setUp() public override {
|
||||||
|
TestSNTV2.setUp();
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_RevertWhen_FaucetIsClosed() public {
|
||||||
|
// ensure faucet is closed
|
||||||
|
vm.prank(deployer);
|
||||||
|
controller.setOpen(false);
|
||||||
|
|
||||||
|
vm.expectRevert(SNTTokenController.SNTTokenController_NotOpen.selector);
|
||||||
|
controller.destroyTokens(address(this), 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_RevertWhen_NotEnoughBalance() public {
|
||||||
|
// ensure faucet is closed
|
||||||
|
vm.prank(deployer);
|
||||||
|
controller.setOpen(true);
|
||||||
|
|
||||||
|
vm.expectRevert(NotEnoughBalance.selector);
|
||||||
|
controller.destroyTokens(address(this), 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_DestroyTokensAsOwner() public {
|
||||||
|
// ensure faucet is open
|
||||||
|
vm.startPrank(deployer);
|
||||||
|
controller.setOpen(false);
|
||||||
|
|
||||||
|
uint256 balanceBefore = sntV2.balanceOf(address(this));
|
||||||
|
assertEq(balanceBefore, 0);
|
||||||
|
|
||||||
|
controller.generateTokens(address(this), 100);
|
||||||
|
uint256 balanceAfter = sntV2.balanceOf(address(this));
|
||||||
|
assertEq(balanceAfter, 100);
|
||||||
|
|
||||||
|
controller.destroyTokens(address(this), 100);
|
||||||
|
balanceAfter = sntV2.balanceOf(address(this));
|
||||||
|
assertEq(balanceAfter, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_DestroyTokenFaucetIsOpen() public {
|
||||||
|
// ensure faucet is open
|
||||||
|
vm.prank(deployer);
|
||||||
|
controller.setOpen(true);
|
||||||
|
|
||||||
|
uint256 balanceBefore = sntV2.balanceOf(address(this));
|
||||||
|
assertEq(balanceBefore, 0);
|
||||||
|
|
||||||
|
controller.generateTokens(address(this), 100);
|
||||||
|
uint256 balanceAfter = sntV2.balanceOf(address(this));
|
||||||
|
assertEq(balanceAfter, 100);
|
||||||
|
|
||||||
|
controller.destroyTokens(address(this), 100);
|
||||||
|
balanceAfter = sntV2.balanceOf(address(this));
|
||||||
|
assertEq(balanceAfter, 0);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue