Skip to content

Commit e3fa396

Browse files
committed
feat: impl basic ERC-20 token for WLD HUB
1 parent 029d1ab commit e3fa396

6 files changed

Lines changed: 173 additions & 85 deletions

File tree

foundry.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,5 @@ script = "script"
77

88
# See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options
99

10-
[default]
10+
remappings = ["forge-std/=lib/forge-std/src/"]
1111
fs_permissions = [{ access = "read-write", path = "./" }]

lib/forge-std

Submodule forge-std added at 77041d2

src/ERC20Token.sol

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.0;
3+
4+
interface IERC20 {
5+
function totalSupply() external view returns (uint256);
6+
function balanceOf(address account) external view returns (uint256);
7+
function transfer(address recipient, uint256 amount) external returns (bool);
8+
function allowance(address owner, address spender) external view returns (uint256);
9+
function approve(address spender, uint256 amount) external returns (bool);
10+
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
11+
12+
event Transfer(address indexed from, address indexed to, uint256 value);
13+
event Approval(address indexed owner, address indexed spender, uint256 value);
14+
}
15+
16+
contract ERC20Token is IERC20 {
17+
string public name;
18+
string public symbol;
19+
uint8 public decimals;
20+
uint256 private _totalSupply;
21+
22+
mapping(address => uint256) private _balances;
23+
mapping(address => mapping(address => uint256)) private _allowances;
24+
25+
constructor(string memory tokenName, string memory tokenSymbol, uint8 tokenDecimals, uint256 initialSupply) {
26+
name = tokenName;
27+
symbol = tokenSymbol;
28+
decimals = tokenDecimals;
29+
_totalSupply = initialSupply * (10 ** uint256(decimals));
30+
_balances[msg.sender] = _totalSupply;
31+
32+
emit Transfer(address(0), msg.sender, _totalSupply);
33+
}
34+
35+
function totalSupply() external view override returns (uint256) {
36+
return _totalSupply;
37+
}
38+
39+
function balanceOf(address account) external view override returns (uint256) {
40+
return _balances[account];
41+
}
42+
43+
function transfer(address recipient, uint256 amount) external override returns (bool) {
44+
_transfer(msg.sender, recipient, amount);
45+
return true;
46+
}
47+
48+
function allowance(address owner, address spender) external view override returns (uint256) {
49+
return _allowances[owner][spender];
50+
}
51+
52+
function approve(address spender, uint256 amount) external override returns (bool) {
53+
_approve(msg.sender, spender, amount);
54+
return true;
55+
}
56+
57+
function transferFrom(address sender, address recipient, uint256 amount) external override returns (bool) {
58+
_transfer(sender, recipient, amount);
59+
60+
uint256 currentAllowance = _allowances[sender][msg.sender];
61+
require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance");
62+
_approve(sender, msg.sender, currentAllowance - amount);
63+
64+
return true;
65+
}
66+
67+
function _transfer(address sender, address recipient, uint256 amount) internal {
68+
require(sender != address(0), "ERC20: transfer from the zero address");
69+
require(recipient != address(0), "ERC20: transfer to the zero address");
70+
require(_balances[sender] >= amount, "ERC20: transfer amount exceeds balance");
71+
72+
_balances[sender] -= amount;
73+
_balances[recipient] += amount;
74+
75+
emit Transfer(sender, recipient, amount);
76+
}
77+
78+
function _approve(address owner, address spender, uint256 amount) internal {
79+
require(owner != address(0), "ERC20: approve from the zero address");
80+
require(spender != address(0), "ERC20: approve to the zero address");
81+
82+
_allowances[owner][spender] = amount;
83+
emit Approval(owner, spender, amount);
84+
}
85+
}

src/WLDTokenLocker.sol

Lines changed: 51 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,51 @@
1-
// SPDX-License-Identifier: UNLICENSED
2-
pragma solidity ^0.8.13;
3-
4-
interface IWLDToken {
5-
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
6-
function balanceOf(address account) external view returns (uint256);
7-
}
8-
9-
contract WLDTokenLocker {
10-
IWLDToken public wldToken;
11-
uint256 public minLockDuration;
12-
uint256 public maxLockDuration;
13-
14-
struct Lock {
15-
uint256 amount;
16-
uint256 unlockTime;
17-
}
18-
19-
mapping(address => Lock) public locks;
20-
21-
event TokensLocked(address indexed user, uint256 amount, uint256 unlockTime);
22-
event TokensWithdrawn(address indexed user, uint256 amount);
23-
24-
constructor(address _wldTokenAddress, uint256 _minLockDuration, uint256 _maxLockDuration) {
25-
wldToken = IWLDToken(_wldTokenAddress);
26-
minLockDuration = _minLockDuration;
27-
maxLockDuration = _maxLockDuration;
28-
}
29-
30-
function lockTokens(uint256 amount, uint256 lockDuration) external {
31-
require(lockDuration >= minLockDuration, "Lock duration too short");
32-
require(lockDuration <= maxLockDuration, "Lock duration too long");
33-
require(wldToken.transferFrom(msg.sender, address(this), amount), "Transfer failed");
34-
35-
locks[msg.sender] = Lock({
36-
amount: amount,
37-
unlockTime: block.timestamp + lockDuration
38-
});
39-
40-
emit TokensLocked(msg.sender, amount, block.timestamp + lockDuration);
41-
}
42-
43-
function withdrawTokens() external {
44-
Lock storage userLock = locks[msg.sender];
45-
require(block.timestamp >= userLock.unlockTime, "Tokens are still locked");
46-
47-
uint256 amount = userLock.amount;
48-
userLock.amount = 0;
49-
50-
require(wldToken.transferFrom(address(this), msg.sender, amount), "Transfer failed");
51-
52-
emit TokensWithdrawn(msg.sender, amount);
53-
}
54-
}
1+
// SPDX-License-Identifier: UNLICENSED
2+
pragma solidity ^0.8.13;
3+
4+
interface IWLDToken {
5+
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
6+
function balanceOf(address account) external view returns (uint256);
7+
}
8+
9+
contract WLDTokenLocker {
10+
IWLDToken public wldToken;
11+
uint256 public minLockDuration;
12+
uint256 public maxLockDuration;
13+
14+
struct Lock {
15+
uint256 amount;
16+
uint256 unlockTime;
17+
}
18+
19+
mapping(address => Lock) public locks;
20+
21+
event TokensLocked(address indexed user, uint256 amount, uint256 unlockTime);
22+
event TokensWithdrawn(address indexed user, uint256 amount);
23+
24+
constructor(address _wldTokenAddress, uint256 _minLockDuration, uint256 _maxLockDuration) {
25+
wldToken = IWLDToken(_wldTokenAddress);
26+
minLockDuration = _minLockDuration;
27+
maxLockDuration = _maxLockDuration;
28+
}
29+
30+
function lockTokens(uint256 amount, uint256 lockDuration) external {
31+
require(lockDuration >= minLockDuration, "Lock duration too short");
32+
require(lockDuration <= maxLockDuration, "Lock duration too long");
33+
require(wldToken.transferFrom(msg.sender, address(this), amount), "Transfer failed");
34+
35+
locks[msg.sender] = Lock({amount: amount, unlockTime: block.timestamp + lockDuration});
36+
37+
emit TokensLocked(msg.sender, amount, block.timestamp + lockDuration);
38+
}
39+
40+
function withdrawTokens() external {
41+
Lock storage userLock = locks[msg.sender];
42+
require(block.timestamp >= userLock.unlockTime, "Tokens are still locked");
43+
44+
uint256 amount = userLock.amount;
45+
userLock.amount = 0;
46+
47+
require(wldToken.transferFrom(address(this), msg.sender, amount), "Transfer failed");
48+
49+
emit TokensWithdrawn(msg.sender, amount);
50+
}
51+
}

src/WLDTokenVerifier.sol

Lines changed: 30 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,30 @@
1-
// SPDX-License-Identifier: UNLICENSED
2-
pragma solidity ^0.8.13;
3-
4-
interface IWLDToken {
5-
function balanceOf(address account) external view returns (uint256);
6-
}
7-
8-
contract WLDTokenVerifier {
9-
IWLDToken public wldToken;
10-
uint256 public minimumBalance;
11-
12-
event AccessGranted(address indexed user);
13-
event AccessDenied(address indexed user);
14-
15-
constructor(address _wldTokenAddress, uint256 _minimumBalance) {
16-
wldToken = IWLDToken(_wldTokenAddress);
17-
minimumBalance = _minimumBalance;
18-
}
19-
20-
function verifyAccess(address user) public returns (bool) {
21-
uint256 balance = wldToken.balanceOf(user);
22-
if (balance >= minimumBalance) {
23-
emit AccessGranted(user);
24-
return true;
25-
} else {
26-
emit AccessDenied(user);
27-
return false;
28-
}
29-
}
30-
}
1+
// SPDX-License-Identifier: UNLICENSED
2+
pragma solidity ^0.8.13;
3+
4+
interface IWLDToken {
5+
function balanceOf(address account) external view returns (uint256);
6+
}
7+
8+
contract WLDTokenVerifier {
9+
IWLDToken public wldToken;
10+
uint256 public minimumBalance;
11+
12+
event AccessGranted(address indexed user);
13+
event AccessDenied(address indexed user);
14+
15+
constructor(address _wldTokenAddress, uint256 _minimumBalance) {
16+
wldToken = IWLDToken(_wldTokenAddress);
17+
minimumBalance = _minimumBalance;
18+
}
19+
20+
function verifyAccess(address user) public returns (bool) {
21+
uint256 balance = wldToken.balanceOf(user);
22+
if (balance >= minimumBalance) {
23+
emit AccessGranted(user);
24+
return true;
25+
} else {
26+
emit AccessDenied(user);
27+
return false;
28+
}
29+
}
30+
}

test/Counter.t.sol

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,11 @@ contract CounterTest is Test {
1717
assertEq(counter.number(), 1);
1818
}
1919

20+
function test_not_equal_to_zero() public view {
21+
uint256 count = counter.number();
22+
assertEq(count, 0);
23+
}
24+
2025
function testFuzz_SetNumber(uint256 x) public {
2126
counter.setNumber(x);
2227
assertEq(counter.number(), x);

0 commit comments

Comments
 (0)