11pragma solidity ^ 0.6.0 ;
22pragma experimental ABIEncoderV2;
33
4- // Forked from Compound 's COMP
5- // Reference: https://github.com/compound-finance/compound-protocol/blob/master/contracts/Governance/Comp.sol
4+ // Forked from Tribeswap 's UNI
5+ // Reference: https://etherscan.io/address/0x1f9840a85d5af5bf1d1762f925bdaddc4201f984#code
66
77contract Tribe {
88 /// @notice EIP-20 token name for this token
99 // solhint-disable-next-line const-name-snakecase
10- string public constant name = "Fei Protocol Tribe " ;
10+ string public constant name = "Tribe " ;
1111
1212 /// @notice EIP-20 token symbol for this token
1313 // solhint-disable-next-line const-name-snakecase
@@ -19,7 +19,10 @@ contract Tribe {
1919
2020 /// @notice Total number of tokens in circulation
2121 // solhint-disable-next-line const-name-snakecase
22- uint public constant totalSupply = 1_000_000_000e18 ; // 1 billion Tribe
22+ uint public totalSupply = 1_000_000_000e18 ; // 1 billion Tribe
23+
24+ /// @notice Address which may mint new tokens
25+ address public minter;
2326
2427 /// @notice Allowance amounts on behalf of others
2528 mapping (address => mapping (address => uint96 )) internal allowances;
@@ -48,9 +51,15 @@ contract Tribe {
4851 /// @notice The EIP-712 typehash for the delegation struct used by the contract
4952 bytes32 public constant DELEGATION_TYPEHASH = keccak256 ("Delegation(address delegatee,uint256 nonce,uint256 expiry) " );
5053
54+ /// @notice The EIP-712 typehash for the permit struct used by the contract
55+ bytes32 public constant PERMIT_TYPEHASH = keccak256 ("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline) " );
56+
5157 /// @notice A record of states for signing / validating signatures
5258 mapping (address => uint ) public nonces;
5359
60+ /// @notice An event thats emitted when the minter address is changed
61+ event MinterChanged (address minter , address newMinter );
62+
5463 /// @notice An event thats emitted when an account changes its delegate
5564 event DelegateChanged (address indexed delegator , address indexed fromDelegate , address indexed toDelegate );
5665
@@ -66,10 +75,45 @@ contract Tribe {
6675 /**
6776 * @notice Construct a new Tribe token
6877 * @param account The initial account to grant all the tokens
78+ * @param minter_ The account with minting ability
6979 */
70- constructor (address account ) public {
80+ constructor (address account , address minter_ ) public {
7181 balances[account] = uint96 (totalSupply);
7282 emit Transfer (address (0 ), account, totalSupply);
83+ minter = minter_;
84+ emit MinterChanged (address (0 ), minter);
85+ }
86+
87+ /**
88+ * @notice Change the minter address
89+ * @param minter_ The address of the new minter
90+ */
91+ function setMinter (address minter_ ) external {
92+ require (msg .sender == minter, "Tribe::setMinter: only the minter can change the minter address " );
93+ emit MinterChanged (minter, minter_);
94+ minter = minter_;
95+ }
96+
97+ /**
98+ * @notice Mint new tokens
99+ * @param dst The address of the destination account
100+ * @param rawAmount The number of tokens to be minted
101+ */
102+ function mint (address dst , uint rawAmount ) external {
103+ require (msg .sender == minter, "Tribe::mint: only the minter can mint " );
104+ require (dst != address (0 ), "Tribe::mint: cannot transfer to the zero address " );
105+
106+ // mint the amount
107+ uint96 amount = safe96 (rawAmount, "Tribe::mint: amount exceeds 96 bits " );
108+ uint96 safeSupply = safe96 (totalSupply, "Tribe::mint: totalSupply exceeds 96 bits " );
109+ totalSupply = add96 (safeSupply, amount, "Tribe::mint: totalSupply exceeds 96 bits " );
110+
111+ // transfer the amount to the recipient
112+ balances[dst] = add96 (balances[dst], amount, "Tribe::mint: transfer amount overflows " );
113+ emit Transfer (address (0 ), dst, amount);
114+
115+ // move delegates
116+ _moveDelegates (address (0 ), delegates[dst], amount);
73117 }
74118
75119 /**
@@ -104,6 +148,37 @@ contract Tribe {
104148 return true ;
105149 }
106150
151+ /**
152+ * @notice Triggers an approval from owner to spends
153+ * @param owner The address to approve from
154+ * @param spender The address to be approved
155+ * @param rawAmount The number of tokens that are approved (2^256-1 means infinite)
156+ * @param deadline The time at which to expire the signature
157+ * @param v The recovery byte of the signature
158+ * @param r Half of the ECDSA signature pair
159+ * @param s Half of the ECDSA signature pair
160+ */
161+ function permit (address owner , address spender , uint rawAmount , uint deadline , uint8 v , bytes32 r , bytes32 s ) external {
162+ uint96 amount;
163+ if (rawAmount == uint (- 1 )) {
164+ amount = uint96 (- 1 );
165+ } else {
166+ amount = safe96 (rawAmount, "Tribe::permit: amount exceeds 96 bits " );
167+ }
168+
169+ bytes32 domainSeparator = keccak256 (abi.encode (DOMAIN_TYPEHASH, keccak256 (bytes (name)), getChainId (), address (this )));
170+ bytes32 structHash = keccak256 (abi.encode (PERMIT_TYPEHASH, owner, spender, rawAmount, nonces[owner]++ , deadline));
171+ bytes32 digest = keccak256 (abi.encodePacked ("\x19\x01 " , domainSeparator, structHash));
172+ address signatory = ecrecover (digest, v, r, s);
173+ require (signatory != address (0 ), "Tribe::permit: invalid signature " );
174+ require (signatory == owner, "Tribe::permit: unauthorized " );
175+ require (now <= deadline, "Tribe::permit: signature expired " );
176+
177+ allowances[owner][spender] = amount;
178+
179+ emit Approval (owner, spender, amount);
180+ }
181+
107182 /**
108183 * @notice Get the number of tokens held by the `account`
109184 * @param account The address of the account to get the balance of
0 commit comments