forked from luanpontolio/trident
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathTridentFranchisedERC20.sol
168 lines (152 loc) · 6.53 KB
/
TridentFranchisedERC20.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity >=0.8.0;
import "../../interfaces/IWhiteListManager.sol";
/// @notice Trident franchised pool ERC-20 with EIP-2612 extension.
/// @author Adapted from RariCapital, https://github.com/Rari-Capital/solmate/blob/main/src/erc20/ERC20.sol,
/// License-Identifier: AGPL-3.0-only.
abstract contract TridentFranchisedERC20 {
event Approval(address indexed owner, address indexed spender, uint256 amount);
event Transfer(address indexed sender, address indexed recipient, uint256 amount);
string public constant name = "Sushi Franchised LP Token";
string public constant symbol = "SLP";
uint8 public constant decimals = 18;
address public whiteListManager;
address public operator;
bool public level2;
uint256 public totalSupply;
/// @notice owner -> balance mapping.
mapping(address => uint256) public balanceOf;
/// @notice owner -> spender -> allowance mapping.
mapping(address => mapping(address => uint256)) public allowance;
/// @notice The EIP-712 typehash for this contract's {permit} struct.
bytes32 public constant PERMIT_TYPEHASH =
keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
/// @notice The EIP-712 typehash for this contract's domain.
bytes32 public immutable DOMAIN_SEPARATOR;
/// @notice owner -> nonce mapping used in {permit}.
mapping(address => uint256) public nonces;
constructor() {
DOMAIN_SEPARATOR = keccak256(
abi.encode(
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
keccak256(bytes(name)),
keccak256(bytes("1")),
block.chainid,
address(this)
)
);
}
/// @dev Initializes whitelist settings from pool.
function initialize(
address _whiteListManager,
address _operator,
bool _level2
) internal {
whiteListManager = _whiteListManager;
operator = _operator;
if (_level2) level2 = true;
}
/// @notice Approves `amount` from `msg.sender` to be spent by `spender`.
/// @param spender Address of the party that can pull tokens from `msg.sender`'s account.
/// @param amount The maximum collective `amount` that `spender` can pull.
/// @return (bool) Returns 'true' if succeeded.
function approve(address spender, uint256 amount) external returns (bool) {
allowance[msg.sender][spender] = amount;
emit Approval(msg.sender, spender, amount);
return true;
}
/// @notice Transfers `amount` tokens from `msg.sender` to `recipient`.
/// @param recipient The address to move tokens to.
/// @param amount The token `amount` to move.
/// @return (bool) Returns 'true' if succeeded.
function transfer(address recipient, uint256 amount) external returns (bool) {
if (level2) _checkWhiteList(recipient);
balanceOf[msg.sender] -= amount;
// @dev This is safe from overflow - the sum of all user
// balances can't exceed 'type(uint256).max'.
unchecked {
balanceOf[recipient] += amount;
}
emit Transfer(msg.sender, recipient, amount);
return true;
}
/// @notice Transfers `amount` tokens from `sender` to `recipient`. Caller needs approval from `from`.
/// @param sender Address to pull tokens `from`.
/// @param recipient The address to move tokens to.
/// @param amount The token `amount` to move.
/// @return (bool) Returns 'true' if succeeded.
function transferFrom(
address sender,
address recipient,
uint256 amount
) external returns (bool) {
if (level2) _checkWhiteList(recipient);
if (allowance[sender][msg.sender] != type(uint256).max) {
allowance[sender][msg.sender] -= amount;
}
balanceOf[sender] -= amount;
// @dev This is safe from overflow - the sum of all user
// balances can't exceed 'type(uint256).max'.
unchecked {
balanceOf[recipient] += amount;
}
emit Transfer(sender, recipient, amount);
return true;
}
/// @notice Triggers an approval from `owner` to `spender`.
/// @param owner The address to approve from.
/// @param spender The address to be approved.
/// @param amount The number of tokens that are approved (2^256-1 means infinite).
/// @param deadline The time at which to expire the signature.
/// @param v The recovery byte of the signature.
/// @param r Half of the ECDSA signature pair.
/// @param s Half of the ECDSA signature pair.
function permit(
address owner,
address spender,
uint256 amount,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external {
require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED");
bytes32 digest = keccak256(
abi.encodePacked(
"\x19\x01",
DOMAIN_SEPARATOR,
keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, amount, nonces[owner]++, deadline))
)
);
address recoveredAddress = ecrecover(digest, v, r, s);
require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_PERMIT_SIGNATURE");
allowance[recoveredAddress][spender] = amount;
emit Approval(owner, spender, amount);
}
function _mint(address recipient, uint256 amount) internal {
totalSupply += amount;
// @dev This is safe from overflow - the sum of all user
// balances can't exceed 'type(uint256).max'.
unchecked {
balanceOf[recipient] += amount;
}
emit Transfer(address(0), recipient, amount);
}
function _burn(address sender, uint256 amount) internal {
balanceOf[sender] -= amount;
// @dev This is safe from underflow - users won't ever
// have a balance larger than `totalSupply`.
unchecked {
totalSupply -= amount;
}
emit Transfer(sender, address(0), amount);
}
/// @dev Checks `whiteListManager` for pool `operator` and given user `account`.
function _checkWhiteList(address account) internal view {
(, bytes memory _whitelisted) = whiteListManager.staticcall(
abi.encodeWithSelector(IWhiteListManager.whitelistedAccounts.selector, operator, account)
);
bool whitelisted = abi.decode(_whitelisted, (bool));
require(whitelisted, "NOT_WHITELISTED");
}
}