-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #3 from subspace/improve-cleanup-faucet-contracts
Improve cleanup faucet smart contracts
- Loading branch information
Showing
35 changed files
with
5,002 additions
and
4,889 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
name: Run Foundry Test with NPM | ||
|
||
on: [push] | ||
|
||
jobs: | ||
test_foundry_npm: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v2 | ||
- uses: actions/setup-node@v3 | ||
with: | ||
node-version: 16 | ||
- name: Install Foundry | ||
uses: onbjerg/foundry-toolchain@v1 | ||
with: | ||
version: nightly | ||
- name: NPM Clean Install | ||
run: cd smart_contract && npm ci | ||
- name: Run Forge Test | ||
run: forge test |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
name: Run Hardhat Test with NPM | ||
|
||
on: | ||
push: | ||
workflow_dispatch: | ||
|
||
jobs: | ||
test_hardhat_npm: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v2 | ||
- name: NPM Clean Install | ||
run: cd smart_contract && npm ci | ||
- name: Hardhat Compile | ||
run: cd smart_contract && npx hardhat compile | ||
- name: Hardhat Test | ||
run: cd smart_contract && npx hardhat test | ||
- name: Hardhat Coverage Result | ||
run: cd smart_contract && npx hardhat coverage |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
{ | ||
"recommendations": [ | ||
"JuanBlanco.solidity", | ||
"tintinweb.solidity-visual-auditor", | ||
"esbenp.prettier-vscode", | ||
"dbaeumer.vscode-eslint", | ||
"eamodio.gitlens", | ||
"streetsidesoftware.code-spell-checker" | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
{ | ||
"folders": [ | ||
{ | ||
"name": "root", | ||
"path": ".." | ||
}, | ||
{ | ||
"name": "discord-bot", | ||
"path": "../discord-botp" | ||
}, | ||
{ | ||
"name": "smart-contracts", | ||
"path": "../smart_contract" | ||
} | ||
], | ||
"settings": { | ||
"editor.codeActionsOnSave": { | ||
"source.fixAll.eslint": true, | ||
"source.fixAll.tslint": true | ||
}, | ||
"editor.defaultFormatter": "esbenp.prettier-vscode", | ||
"eslint.workingDirectories": [{ "mode": "auto" }], | ||
"javascript.format.enable": false, | ||
"window.zoomLevel": -1, | ||
"editor.tabSize": 2, | ||
"typescript.format.insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis": true, | ||
"editor.formatOnSave": true | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
{ | ||
"editor.codeActionsOnSave": { | ||
"source.fixAll.eslint": true, | ||
"source.fixAll.tslint": true | ||
}, | ||
"editor.defaultFormatter": "esbenp.prettier-vscode", | ||
"eslint.workingDirectories": [{ "mode": "auto" }], | ||
"javascript.format.enable": false, | ||
"window.zoomLevel": -1, | ||
"editor.tabSize": 2, | ||
"typescript.format.insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis": true, | ||
"editor.formatOnSave": true | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
# Subspace - Gemini | ||
RPC_URL_GEMINI="https://domain-3.evm.gemini-3f.subspace.network/ws" | ||
PRIVATE_KEY_GEMINI="" | ||
|
||
# Goerli | ||
RPC_URL_GOERLI="https://goerli.infura.io/v3/" | ||
PRIVATE_KEY_GOERLI="" | ||
|
||
# Blockscout - Gemini | ||
GEMINI_SCAN_API_KEY="" | ||
|
||
# Etherscan | ||
ETHERSCAN_API_KEY="" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
node_modules | ||
.env | ||
coverage | ||
coverage.json | ||
typechain | ||
typechain-types | ||
|
||
# Hardhat files | ||
cache | ||
artifacts | ||
|
||
Flat*.sol | ||
deployments | ||
|
||
# Foundry/lcov coverage report | ||
report | ||
lcov.info | ||
|
||
# Wok in progress | ||
.wip |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
node_modules |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
{ | ||
"bracketSpacing": true, | ||
"printWidth": 120, | ||
"semi": false, | ||
"singleQuote": true, | ||
"tabWidth": 2, | ||
"useTabs": false | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
module.exports = { | ||
skipFiles: ['mocks/', 'test/'], | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,42 @@ | ||
Project to facilitate work on Subspace Faucet, including discord bot, HTTP API server, and Smart Contact. | ||
# Faucet Smart Contract for Subspace Network | ||
|
||
## General info | ||
|
||
Project to facilitate work on Subspace Faucet, including discord bot, HTTP API server, and Smart Contact. | ||
|
||
## Functionality | ||
|
||
- Request tokens from faucet | ||
|
||
## Setup smart contract project | ||
|
||
To run, test and/or deploy the smart contracts, first install the dependencies | ||
|
||
### Install Dependencies | ||
|
||
```bash | ||
npm install | ||
``` | ||
|
||
### Run test with Hardhat | ||
|
||
```bash | ||
npx hardhat test | ||
``` | ||
|
||
### List all Hardhat tasks | ||
|
||
```bash | ||
npx hardhat help | ||
``` | ||
|
||
### Run test with Foundry | ||
|
||
```bash | ||
forge test | ||
``` | ||
|
||
## Documentation | ||
|
||
- [Hardhat Documentation](https://hardhat.org/getting-started/) | ||
- [Foundry Documentation](https://book.getfoundry.sh/index.html) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
{ | ||
"MinterRole": { | ||
"NotAdmin": "MinterRole_FunctionRestrictedToAdmin()", | ||
"NotMinter": "MinterRole_FunctionRestrictedToMinter()" | ||
}, | ||
"Faucet": { | ||
"FailSendingNativeToken": "Faucet_SendingTokensFailed()", | ||
"NoNativeTokenLeft": "Faucet_ContractBalanceIsZero()", | ||
"InsufficientTimeElapsed": "Faucet_InsufficientTimeElapsed()" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
{ | ||
"Faucet": { | ||
"CONTRACT_FILE_NAME": "Faucet" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,60 +1,65 @@ | ||
// SPDX-License-Identifier: MIT | ||
|
||
pragma solidity ^0.8.17; | ||
pragma solidity ^0.8.19; | ||
|
||
contract Faucet { | ||
address payable public owner = payable(msg.sender); | ||
import './abstracts/MinterRole.sol'; | ||
|
||
error Faucet_InsufficientTimeElapsed(); | ||
error Faucet_SendingTokensFailed(); | ||
error Faucet_ContractBalanceIsZero(); | ||
|
||
contract Faucet is MinterRole { | ||
uint256 public withdrawalAmount = 0.0006 * (10**18); | ||
uint256 public lockTime = 1 minutes; | ||
|
||
event Withdrawal(address indexed to, uint256 indexed amount); | ||
event Deposit(address indexed from, uint256 indexed amount); | ||
|
||
mapping(address => uint256) nextAccessTime; | ||
|
||
function requestTokens(address payable recipient) public onlyOwner { | ||
require( | ||
msg.sender != address(0), | ||
"Request must not originate from a zero account" | ||
); | ||
require( | ||
address(this).balance >= withdrawalAmount, | ||
"Insufficient balance in faucet for withdrawal request" | ||
); | ||
require( | ||
block.timestamp >= nextAccessTime[recipient], | ||
"Insufficient time elapsed since last withdrawal" | ||
); | ||
nextAccessTime[recipient] = block.timestamp + lockTime; | ||
recipient.transfer(withdrawalAmount); | ||
mapping(address => uint256) private _lastAccessTime; | ||
|
||
constructor() { | ||
_grantRole(DEFAULT_ADMIN_ROLE, msg.sender); | ||
} | ||
|
||
receive() external payable { | ||
emit Deposit(msg.sender, msg.value); | ||
/// @notice Allow faucet owner to dispatch native tokens to the given address. | ||
/// @param recipient The address to send tokens to. | ||
function requestTokens(address recipient) public hasMinterRole { | ||
if (nextAccessTime(recipient) > block.timestamp) revert Faucet_InsufficientTimeElapsed(); | ||
|
||
// If check pass set the next access time | ||
_lastAccessTime[recipient] = block.timestamp; | ||
|
||
// If check pass transfer the tokens | ||
if (!payable(recipient).send(withdrawalAmount)) revert Faucet_SendingTokensFailed(); | ||
} | ||
|
||
/// @notice Show the next access time for the given addres | ||
/// @param recipient The address to send tokens to. | ||
/// @return The next access time for the given address | ||
function nextAccessTime(address recipient) public view returns (uint256) { | ||
return _lastAccessTime[recipient] + lockTime; | ||
} | ||
|
||
function setWithdrawalAmount(uint256 amount) public onlyOwner { | ||
withdrawalAmount = amount * (10**18); | ||
/// @notice Allow faucet owner to change the withdrawal amount. (native and ERC20 tokens) | ||
/// @param amount The amount to send. | ||
function setWithdrawalAmount(uint256 amount) public hasAdminRole { | ||
withdrawalAmount = amount; | ||
} | ||
|
||
function setLockTime(uint256 amount) public onlyOwner { | ||
lockTime = amount * 1 minutes; | ||
/// @notice Allow faucet owner to change the delay between withdrawals. | ||
/// @param amount The amount of time to lock the faucet for. (for each receiver/type) | ||
function setLockTime(uint256 amount) public hasAdminRole { | ||
lockTime = amount; | ||
} | ||
|
||
function withdraw() external onlyOwner { | ||
require( | ||
address(this).balance > 0, | ||
"No balance left in the contract" | ||
); | ||
owner.transfer(address(this).balance); | ||
/// @notice Allow faucet owner to withdraw the native tokens from the contract. | ||
function withdraw() external hasAdminRole { | ||
if (address(this).balance == 0) revert Faucet_ContractBalanceIsZero(); | ||
address payable receiver = payable(_msgSender()); | ||
receiver.transfer(address(this).balance); | ||
} | ||
|
||
modifier onlyOwner() { | ||
require( | ||
msg.sender == owner, | ||
"Only the contract owner can call this function" | ||
); | ||
_; | ||
receive() external payable { | ||
emit Deposit(msg.sender, msg.value); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.19; | ||
|
||
import '@openzeppelin/contracts/access/AccessControlEnumerable.sol'; | ||
|
||
error MinterRole_FunctionRestrictedToAdmin(); | ||
error MinterRole_FunctionRestrictedToMinter(); | ||
|
||
contract MinterRole is AccessControlEnumerable { | ||
bytes32 public constant MINTER_ROLE = keccak256('MINTER_ROLE'); | ||
|
||
modifier hasAdminRole() { | ||
if (!isAdmin(msg.sender)) revert MinterRole_FunctionRestrictedToAdmin(); | ||
_; | ||
} | ||
|
||
modifier hasMinterRole() { | ||
if (!isMinter(msg.sender)) revert MinterRole_FunctionRestrictedToMinter(); | ||
_; | ||
} | ||
|
||
/// @notice Return if an address has admin role | ||
/// @param admin The address to verify | ||
/// @return True if the address has admin role | ||
function isAdmin(address admin) public view returns (bool) { | ||
return hasRole(DEFAULT_ADMIN_ROLE, admin); | ||
} | ||
|
||
/// @notice Give Admin Role to the given address. | ||
/// @param admin The address to give the Admin Role. | ||
/// @dev The call must originate from an admin. | ||
function addAdmin(address admin) public hasAdminRole { | ||
grantRole(DEFAULT_ADMIN_ROLE, admin); | ||
} | ||
|
||
/// @notice Revoke Admin Role from the given address. | ||
/// @param admin The address to revoke the Admin Role. | ||
/// @dev The call must originate from an admin. | ||
function removeAdmin(address admin) public hasAdminRole { | ||
revokeRole(DEFAULT_ADMIN_ROLE, admin); | ||
} | ||
|
||
/// @notice Return if an address has minter role | ||
/// @param minter The address to verify | ||
/// @return True if the address has minter role | ||
function isMinter(address minter) public view returns (bool) { | ||
return hasRole(MINTER_ROLE, minter); | ||
} | ||
|
||
/// @notice Give minter role to the given address. | ||
/// @param minter The address to give the Minter Role. | ||
/// @dev The call must originate from an admin. | ||
function addMinter(address minter) public hasAdminRole { | ||
grantRole(MINTER_ROLE, minter); | ||
} | ||
|
||
/// @notice Revoke minter role from the given address. | ||
/// @param minter The address to revoke the Minter Role. | ||
/// @dev The call must originate from an admin. | ||
function removeMinter(address minter) public hasAdminRole { | ||
revokeRole(MINTER_ROLE, minter); | ||
} | ||
} |
Oops, something went wrong.