-
Notifications
You must be signed in to change notification settings - Fork 95
Expand file tree
/
Copy pathFei.sol
More file actions
134 lines (120 loc) · 4.97 KB
/
Copy pathFei.sol
File metadata and controls
134 lines (120 loc) · 4.97 KB
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
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.4;
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol";
import "./IIncentive.sol";
import "../refs/CoreRef.sol";
/// @title FEI stablecoin
/// @author Fei Protocol
contract Fei is IFei, ERC20Burnable, CoreRef {
/// @notice get associated incentive contract, 0 address if N/A
mapping(address => address) public override incentiveContract;
// solhint-disable-next-line var-name-mixedcase
bytes32 public DOMAIN_SEPARATOR;
// keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
bytes32 public constant PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;
mapping(address => uint256) public nonces;
/// @notice Fei token constructor
/// @param core Fei Core address to reference
constructor(address core) ERC20("Fei USD", "FEI") CoreRef(core) {
uint256 chainId;
// solhint-disable-next-line no-inline-assembly
assembly {
chainId := chainid()
}
DOMAIN_SEPARATOR = keccak256(
abi.encode(
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
keccak256(bytes(name())),
keccak256(bytes("1")),
chainId,
address(this)
)
);
}
/// @param account the account to incentivize
/// @param incentive the associated incentive contract
function setIncentiveContract(address account, address incentive) external override onlyGovernor {
incentiveContract[account] = incentive;
emit IncentiveContractUpdate(account, incentive);
}
/// @notice mint FEI tokens
/// @param account the account to mint to
/// @param amount the amount to mint
function mint(address account, uint256 amount) external override onlyMinter whenNotPaused {
_mint(account, amount);
emit Minting(account, msg.sender, amount);
}
/// @notice burn FEI tokens from caller
/// @param amount the amount to burn
function burn(uint256 amount) public override(IFei, ERC20Burnable) {
super.burn(amount);
emit Burning(msg.sender, msg.sender, amount);
}
/// @notice burn FEI tokens from specified account
/// @param account the account to burn from
/// @param amount the amount to burn
function burnFrom(address account, uint256 amount) public override(IFei, ERC20Burnable) onlyBurner whenNotPaused {
_burn(account, amount);
emit Burning(account, msg.sender, amount);
}
function _transfer(
address sender,
address recipient,
uint256 amount
) internal override {
super._transfer(sender, recipient, amount);
_checkAndApplyIncentives(sender, recipient, amount);
}
function _checkAndApplyIncentives(
address sender,
address recipient,
uint256 amount
) internal {
// incentive on sender
address senderIncentive = incentiveContract[sender];
if (senderIncentive != address(0)) {
IIncentive(senderIncentive).incentivize(sender, recipient, msg.sender, amount);
}
// incentive on recipient
address recipientIncentive = incentiveContract[recipient];
if (recipientIncentive != address(0)) {
IIncentive(recipientIncentive).incentivize(sender, recipient, msg.sender, amount);
}
// incentive on operator
address operatorIncentive = incentiveContract[msg.sender];
if (msg.sender != sender && msg.sender != recipient && operatorIncentive != address(0)) {
IIncentive(operatorIncentive).incentivize(sender, recipient, msg.sender, amount);
}
// all incentive, if active applies to every transfer
address allIncentive = incentiveContract[address(0)];
if (allIncentive != address(0)) {
IIncentive(allIncentive).incentivize(sender, recipient, msg.sender, amount);
}
}
/// @notice permit spending of FEI
/// @param owner the FEI holder
/// @param spender the approved operator
/// @param value the amount approved
/// @param deadline the deadline after which the approval is no longer valid
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external override {
require(deadline >= block.timestamp, "Fei: EXPIRED");
bytes32 digest = keccak256(
abi.encodePacked(
"\x19\x01",
DOMAIN_SEPARATOR,
keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline))
)
);
address recoveredAddress = ecrecover(digest, v, r, s);
require(recoveredAddress != address(0) && recoveredAddress == owner, "Fei: INVALID_SIGNATURE");
_approve(owner, spender, value);
}
}