[EURS] ERC20 Token SC Assessment
- Symbol: EURS
- Address: 0xdb25f211ab05b1c97d595516f45794528a807ad8 - EURSToken
- Deployment Date: Jun-22-2018 04:46:52 PM +UTC
- Contract size : 891 loc (Solidity + assembly)
- Total supply: 31,979,207 (as of 2020-08-17)
- Developers allotment: 0
- Project website: https://eurs.stasis.net/
- Github repository: https://github.com/STASISNET/STASIS-EURS-token-smart-contract
- Can use existing MCD collateral type adapter? Standard ERC-20 so the GemJoin adapter should work
- Does the contract implement the ERC20 token standards? Yes
- Risk analysis: MEDIUM
- The contract can have delegation but the delegate is not public.
- Compiler version: v0.4.21+commit.dfe3193c
- Decimals: 2
- Overflow checks: Yes safemath (custom SafeMath contract)
- Mitigation against allowance race-condition: No, the approve function does have a race condition
- Upgradeable contract patterns: yes with a custom delegatable modifier
- Access control or restriction lists: yes
- Non-standard features or behaviors: possible delegation to another contract,fee collector, pausing and freezing, minting and burning
Formal Verification Considerations:
- Does transfer have simple semantics? Yes it seems
- Does transferFrom have simple semantics? Yes it seems
- Can balances be arbitrarily modified by some actor? Only the owner can mint and burn tokens on his own address. But the owner can also freeze (and unfreeze) accounts. Fees can also be set to 100% or even higher (with fixed fee). Fees can be waived for some accounts.
- Are there any external calls? Most methods can be delegated to another contract using a method modifier.
- Two on ropsten (with fees):
Contract Logic Summary
How the contract is upgraded
There is a delegate modifier on most methods. The owner of the contract can set the delegate smart contract address with the setDelegate method. A Delegation event is then logged.
When using the delegation call, the owner and the delegate can’t be changed (if they are, there is a revert).
Couldn’t find if delegate == 0x0 currently.
Administrative addresses (EOAs, controller contracts, and similar)
Owner: non public field
feeCollector: non public field but it’s 0x70250fcfef983c9b912c8eefb7021b4b7bae836e
delegate: non public field
All can be changed by the owner using methods.
The fee structure contains a variable fee (% of the transferred amount) that can range between 0% and 100% plus a fixed fee (by default @ 5 EURS, currently 0). Those fees are on top of the value transferred. It can be changed by the contract owner. There are currently no fees.
fixedFee = 0;
minVariableFee = 0;
maxVariableFee = 0;
variableFeeNumerator = 0; // <= MAX_FEE_NUMERATOR
FEE_DENOMINATOR = 100000;
MAX_FEE_NUMERATOR = FEE_DENOMINATOR;
MIN_FEE_NUMERATIOR = 0; // Never used
DEFAULT_FEE = 5e2; // 5 EURS for fixedFee at contract init
fees = max(minVariableFee, min(maxVariableFee, amount * variableFeeNumerator / FEE_DENOMINATOR)) + fixedFee
A fee event transfer is generated even in the absence of actual fees. That explains why there are always two transfers per transaction. The current feeCollector is 0x70250fcfef983c9b912c8eefb7021b4b7bae836e
When fees parameters are changed (with setFeeParameters) a FeeChange event is logged.
Allows a delegate to pay for the gas by paying him with the token.
delegatedTransfer change some accounts and can fail later. I would hit an assert and revert, but not sure it is clean code by solidity standard.
uint256 balance = accounts [_from];
if (_value > balance) return false;
balance = safeSub (balance, _value);
if (fee > balance) return false;
balance = safeSub (balance, fee);
Contract Risk Summary
This is a medium risk contract. The ERC20 functions are implemented to the industry standard. The ERC20 allowance race condition is not mitigated. The contract makes use a SafeMath contract inheritance to avoid overflows. The owner can freeze some accounts from wallets, mint and burn tokens on it’s own account. These features are similar to other real asset and custodial tokens. Some settings (like the owner, feeCollector or delegate) are not public.
Two majors points should be monitored closely if this token is onboarded:
- The contract has a complex fees structure that can be 100% (rendering liquidation impossible). No fees currently but should follow FeeChange events.
- The contract can be updated by delegation. Should follow Delegation events.
Contracts Description Table
|Function can modify state|
|Function is payable|