forked from Synthetixio/synthetix
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathSynthRedeemer.sol
97 lines (76 loc) · 3.81 KB
/
SynthRedeemer.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
pragma solidity ^0.5.16;
// Inheritence
import "./MixinResolver.sol";
import "./interfaces/ISynthRedeemer.sol";
// Libraries
import "./SafeDecimalMath.sol";
// Internal references
import "./interfaces/IERC20.sol";
import "./interfaces/IIssuer.sol";
contract SynthRedeemer is ISynthRedeemer, MixinResolver {
using SafeDecimalMath for uint;
bytes32 public constant CONTRACT_NAME = "SynthRedeemer";
mapping(address => uint) public redemptions;
bytes32 private constant CONTRACT_ISSUER = "Issuer";
bytes32 private constant CONTRACT_SYNTHSUSD = "SynthsUSD";
constructor(address _resolver) public MixinResolver(_resolver) {}
function resolverAddressesRequired() public view returns (bytes32[] memory addresses) {
addresses = new bytes32[](2);
addresses[0] = CONTRACT_ISSUER;
addresses[1] = CONTRACT_SYNTHSUSD;
}
function issuer() internal view returns (IIssuer) {
return IIssuer(requireAndGetAddress(CONTRACT_ISSUER));
}
function sUSD() internal view returns (IERC20) {
return IERC20(requireAndGetAddress(CONTRACT_SYNTHSUSD));
}
function totalSupply(IERC20 synthProxy) public view returns (uint supplyInsUSD) {
supplyInsUSD = synthProxy.totalSupply().multiplyDecimal(redemptions[address(synthProxy)]);
}
function balanceOf(IERC20 synthProxy, address account) external view returns (uint balanceInsUSD) {
balanceInsUSD = synthProxy.balanceOf(account).multiplyDecimal(redemptions[address(synthProxy)]);
}
function redeemAll(IERC20[] calldata synthProxies) external {
for (uint i = 0; i < synthProxies.length; i++) {
_redeem(synthProxies[i], synthProxies[i].balanceOf(msg.sender));
}
}
function redeem(IERC20 synthProxy) external {
_redeem(synthProxy, synthProxy.balanceOf(msg.sender));
}
function redeemPartial(IERC20 synthProxy, uint amountOfSynth) external {
// technically this check isn't necessary - Synth.burn would fail due to safe sub,
// but this is a useful error message to the user
require(synthProxy.balanceOf(msg.sender) >= amountOfSynth, "Insufficient balance");
_redeem(synthProxy, amountOfSynth);
}
function _redeem(IERC20 synthProxy, uint amountOfSynth) internal {
uint rateToRedeem = redemptions[address(synthProxy)];
require(rateToRedeem > 0, "Synth not redeemable");
require(amountOfSynth > 0, "No balance of synth to redeem");
issuer().burnForRedemption(address(synthProxy), msg.sender, amountOfSynth);
uint amountInsUSD = amountOfSynth.multiplyDecimal(rateToRedeem);
sUSD().transfer(msg.sender, amountInsUSD);
emit SynthRedeemed(address(synthProxy), msg.sender, amountOfSynth, amountInsUSD);
}
function deprecate(IERC20 synthProxy, uint rateToRedeem) external onlyIssuer {
address synthProxyAddress = address(synthProxy);
require(redemptions[synthProxyAddress] == 0, "Synth is already deprecated");
require(rateToRedeem > 0, "No rate for synth to redeem");
uint totalSynthSupply = synthProxy.totalSupply();
uint supplyInsUSD = totalSynthSupply.multiplyDecimal(rateToRedeem);
require(sUSD().balanceOf(address(this)) >= supplyInsUSD, "sUSD must first be supplied");
redemptions[synthProxyAddress] = rateToRedeem;
emit SynthDeprecated(address(synthProxy), rateToRedeem, totalSynthSupply, supplyInsUSD);
}
function requireOnlyIssuer() internal view {
require(msg.sender == address(issuer()), "Restricted to Issuer contract");
}
modifier onlyIssuer() {
requireOnlyIssuer();
_;
}
event SynthRedeemed(address synth, address account, uint amountOfSynth, uint amountInsUSD);
event SynthDeprecated(address synth, uint rateToRedeem, uint totalSynthSupply, uint supplyInsUSD);
}