Skip to content

Commit 54991e1

Browse files
committed
Merge branch 'master' into develop
2 parents 52d37c3 + 708328f commit 54991e1

File tree

66 files changed

+2592
-12108
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

66 files changed

+2592
-12108
lines changed

contracts/DynamicSynthRedeemer.sol

Lines changed: 37 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ pragma solidity ^0.5.16;
22

33
// Inheritence
44
import "./Owned.sol";
5+
import "./Proxyable.sol";
56
import "./MixinResolver.sol";
67
import "./interfaces/IDynamicSynthRedeemer.sol";
78

@@ -11,11 +12,6 @@ import "./SafeDecimalMath.sol";
1112
// Internal references
1213
import "./interfaces/IIssuer.sol";
1314
import "./interfaces/IExchangeRates.sol";
14-
import "./interfaces/ISynth.sol";
15-
16-
interface IProxy {
17-
function target() external view returns (address);
18-
}
1915

2016
contract DynamicSynthRedeemer is Owned, IDynamicSynthRedeemer, MixinResolver {
2117
using SafeDecimalMath for uint;
@@ -42,63 +38,79 @@ contract DynamicSynthRedeemer is Owned, IDynamicSynthRedeemer, MixinResolver {
4238
addresses[1] = CONTRACT_EXRATES;
4339
}
4440

45-
function issuer() internal view returns (IIssuer) {
41+
/* ========== INTERNAL VIEWS ========== */
42+
43+
function _issuer() internal view returns (IIssuer) {
4644
return IIssuer(requireAndGetAddress(CONTRACT_ISSUER));
4745
}
4846

49-
function exchangeRates() internal view returns (IExchangeRates) {
47+
function _exchangeRates() internal view returns (IExchangeRates) {
5048
return IExchangeRates(requireAndGetAddress(CONTRACT_EXRATES));
5149
}
5250

53-
function redeemingActive() internal view {
51+
function _redeemingActive() internal view {
5452
require(redemptionActive, "Redemption deactivated");
5553
}
5654

57-
/* ========== VIEWS ========== */
55+
/* ========== EXTERNAL VIEWS ========== */
5856

5957
function getDiscountRate() external view returns (uint) {
6058
return discountRate;
6159
}
6260

61+
/* ========== INTERNAL HELPERS ========== */
62+
63+
function _proxyAddressForKey(bytes32 currencyKey) internal returns (address) {
64+
address synth = address(_issuer().synths(currencyKey));
65+
require(synth != address(0), "Invalid synth");
66+
return address(Proxyable(synth).proxy());
67+
}
68+
6369
/* ========== MUTATIVE FUNCTIONS ========== */
6470

65-
function redeemAll(address[] calldata synthProxies) external requireRedemptionActive {
66-
for (uint i = 0; i < synthProxies.length; i++) {
67-
_redeem(synthProxies[i], IERC20(synthProxies[i]).balanceOf(msg.sender));
71+
function redeemAll(bytes32[] calldata currencyKeys) external requireRedemptionActive {
72+
for (uint i = 0; i < currencyKeys.length; i++) {
73+
address synthProxy = _proxyAddressForKey(currencyKeys[i]);
74+
_redeem(synthProxy, currencyKeys[i], IERC20(synthProxy).balanceOf(msg.sender));
6875
}
6976
}
7077

71-
function redeem(address synthProxy) external requireRedemptionActive {
72-
_redeem(synthProxy, IERC20(synthProxy).balanceOf(msg.sender));
78+
function redeem(bytes32 currencyKey) external requireRedemptionActive {
79+
address synthProxy = _proxyAddressForKey(currencyKey);
80+
_redeem(synthProxy, currencyKey, IERC20(synthProxy).balanceOf(msg.sender));
7381
}
7482

75-
function redeemPartial(address synthProxy, uint amountOfSynth) external requireRedemptionActive {
83+
function redeemPartial(bytes32 currencyKey, uint amountOfSynth) external requireRedemptionActive {
84+
address synthProxy = _proxyAddressForKey(currencyKey);
7685
// technically this check isn't necessary - Synth.burn would fail due to safe sub,
7786
// but this is a useful error message to the user
7887
require(IERC20(synthProxy).balanceOf(msg.sender) >= amountOfSynth, "Insufficient balance");
79-
_redeem(synthProxy, amountOfSynth);
88+
_redeem(synthProxy, currencyKey, amountOfSynth);
8089
}
8190

82-
function _redeem(address synthProxy, uint amountOfSynth) internal {
83-
bytes32 currencyKey = ISynth(IProxy(synthProxy).target()).currencyKey();
91+
function _redeem(
92+
address synthProxy,
93+
bytes32 currencyKey,
94+
uint amountOfSynth
95+
) internal {
96+
require(amountOfSynth > 0, "No balance of synth to redeem");
8497
require(currencyKey != sUSD, "Cannot redeem sUSD");
8598

8699
// Discount rate applied to chainlink price for dynamic redemptions
87-
uint rateToRedeem = exchangeRates().rateForCurrency(currencyKey).multiplyDecimalRound(discountRate);
88-
require(rateToRedeem > 0, "Synth not redeemable");
89-
require(amountOfSynth > 0, "No balance of synth to redeem");
100+
(uint rate, bool invalid) = _exchangeRates().rateAndInvalid(currencyKey);
101+
uint rateToRedeem = rate.multiplyDecimalRound(discountRate);
102+
require(rateToRedeem > 0 && !invalid, "Synth not redeemable");
90103

91-
issuer().burnForRedemption(address(synthProxy), msg.sender, amountOfSynth);
92104
uint amountInsUSD = amountOfSynth.multiplyDecimalRound(rateToRedeem);
93-
issuer().issueSynthsWithoutDebt(sUSD, msg.sender, amountInsUSD);
105+
_issuer().burnAndIssueSynthsWithoutDebtCache(msg.sender, currencyKey, amountOfSynth, amountInsUSD);
94106

95-
emit SynthRedeemed(address(synthProxy), msg.sender, amountOfSynth, amountInsUSD);
107+
emit SynthRedeemed(synthProxy, msg.sender, amountOfSynth, amountInsUSD);
96108
}
97109

98110
/* ========== MODIFIERS ========== */
99111

100112
modifier requireRedemptionActive() {
101-
redeemingActive();
113+
_redeemingActive();
102114
_;
103115
}
104116

contracts/Issuer.sol

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -635,6 +635,32 @@ contract Issuer is Owned, MixinSystemSettings, IIssuer {
635635
return rateInvalid;
636636
}
637637

638+
/**
639+
* SIP-2059: Dynamic Redemption
640+
* Function used to burn spot synths and issue the equivalent in sUSD at chainlink price * discount rate
641+
* @param account The address of the account that is redeeming
642+
* @param currencyKey The synth to be redeemed
643+
* @param amountOfSynth The amount of redeeming synth to burn
644+
* @param amountInsUSD The amount of sUSD to issue
645+
*/
646+
function burnAndIssueSynthsWithoutDebtCache(
647+
address account,
648+
bytes32 currencyKey,
649+
uint amountOfSynth,
650+
uint amountInsUSD
651+
) external onlySynthRedeemer {
652+
exchanger().settle(account, currencyKey);
653+
654+
// Burn their redeemed synths
655+
synths[currencyKey].burn(account, amountOfSynth);
656+
657+
// record issue timestamp
658+
_setLastIssueEvent(account);
659+
660+
// Issuer their sUSD equivalent
661+
synths[sUSD].issue(account, amountInsUSD);
662+
}
663+
638664
/**
639665
* SIP-237: Debt Migration
640666
* Function used for the one-way migration of all debt and liquid + escrowed SNX from L1 -> L2

contracts/interfaces/IDynamicSynthRedeemer.sol

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ interface IDynamicSynthRedeemer {
1010
// Rate applied to chainlink price for redemptions
1111
function getDiscountRate() external view returns (uint);
1212

13-
function redeem(address synthProxy) external;
13+
function redeem(bytes32 currencyKey) external;
1414

15-
function redeemAll(address[] calldata synthProxies) external;
15+
function redeemAll(bytes32[] calldata currencyKeys) external;
1616

17-
function redeemPartial(address synthProxy, uint amountOfSynth) external;
17+
function redeemPartial(bytes32 currencyKey, uint amountOfSynth) external;
1818
}

contracts/interfaces/IIssuer.sol

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,5 +131,12 @@ interface IIssuer {
131131
uint amount
132132
) external returns (bool rateInvalid);
133133

134+
function burnAndIssueSynthsWithoutDebtCache(
135+
address account,
136+
bytes32 currencyKey,
137+
uint amountOfSynth,
138+
uint amountInsUSD
139+
) external;
140+
134141
function modifyDebtSharesForMigration(address account, uint amount) external;
135142
}

0 commit comments

Comments
 (0)