-
Notifications
You must be signed in to change notification settings - Fork 595
/
Synthetix.sol
215 lines (183 loc) · 7.36 KB
/
Synthetix.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
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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
pragma solidity ^0.5.16;
// Inheritance
import "./BaseSynthetix.sol";
// Internal references
import "./interfaces/IRewardEscrow.sol";
import "./interfaces/IRewardEscrowV2.sol";
import "./interfaces/ISupplySchedule.sol";
// https://docs.synthetix.io/contracts/source/contracts/synthetix
contract Synthetix is BaseSynthetix {
bytes32 public constant CONTRACT_NAME = "Synthetix";
// ========== ADDRESS RESOLVER CONFIGURATION ==========
bytes32 private constant CONTRACT_REWARD_ESCROW = "RewardEscrow";
bytes32 private constant CONTRACT_REWARDESCROW_V2 = "RewardEscrowV2";
bytes32 private constant CONTRACT_SUPPLYSCHEDULE = "SupplySchedule";
// ========== CONSTRUCTOR ==========
constructor(
address payable _proxy,
TokenState _tokenState,
address _owner,
uint _totalSupply,
address _resolver
) public BaseSynthetix(_proxy, _tokenState, _owner, _totalSupply, _resolver) {}
function resolverAddressesRequired() public view returns (bytes32[] memory addresses) {
bytes32[] memory existingAddresses = BaseSynthetix.resolverAddressesRequired();
bytes32[] memory newAddresses = new bytes32[](3);
newAddresses[0] = CONTRACT_REWARD_ESCROW;
newAddresses[1] = CONTRACT_REWARDESCROW_V2;
newAddresses[2] = CONTRACT_SUPPLYSCHEDULE;
return combineArrays(existingAddresses, newAddresses);
}
// ========== VIEWS ==========
function rewardEscrow() internal view returns (IRewardEscrow) {
return IRewardEscrow(requireAndGetAddress(CONTRACT_REWARD_ESCROW));
}
function rewardEscrowV2() internal view returns (IRewardEscrowV2) {
return IRewardEscrowV2(requireAndGetAddress(CONTRACT_REWARDESCROW_V2));
}
function supplySchedule() internal view returns (ISupplySchedule) {
return ISupplySchedule(requireAndGetAddress(CONTRACT_SUPPLYSCHEDULE));
}
// ========== OVERRIDDEN FUNCTIONS ==========
function exchangeWithVirtual(
bytes32 sourceCurrencyKey,
uint sourceAmount,
bytes32 destinationCurrencyKey,
bytes32 trackingCode
)
external
exchangeActive(sourceCurrencyKey, destinationCurrencyKey)
optionalProxy
returns (uint amountReceived, IVirtualSynth vSynth)
{
return
exchanger().exchange(
messageSender,
messageSender,
sourceCurrencyKey,
sourceAmount,
destinationCurrencyKey,
messageSender,
true,
messageSender,
trackingCode
);
}
// SIP-140 The initiating user of this exchange will receive the proceeds of the exchange
// Note: this function may have unintended consequences if not understood correctly. Please
// read SIP-140 for more information on the use-case
function exchangeWithTrackingForInitiator(
bytes32 sourceCurrencyKey,
uint sourceAmount,
bytes32 destinationCurrencyKey,
address rewardAddress,
bytes32 trackingCode
) external exchangeActive(sourceCurrencyKey, destinationCurrencyKey) optionalProxy returns (uint amountReceived) {
(amountReceived, ) = exchanger().exchange(
messageSender,
messageSender,
sourceCurrencyKey,
sourceAmount,
destinationCurrencyKey,
// solhint-disable avoid-tx-origin
tx.origin,
false,
rewardAddress,
trackingCode
);
}
function exchangeAtomically(
bytes32 sourceCurrencyKey,
uint sourceAmount,
bytes32 destinationCurrencyKey,
bytes32 trackingCode,
uint minAmount
) external exchangeActive(sourceCurrencyKey, destinationCurrencyKey) optionalProxy returns (uint amountReceived) {
return
exchanger().exchangeAtomically(
messageSender,
sourceCurrencyKey,
sourceAmount,
destinationCurrencyKey,
messageSender,
trackingCode,
minAmount
);
}
function settle(bytes32 currencyKey)
external
optionalProxy
returns (
uint reclaimed,
uint refunded,
uint numEntriesSettled
)
{
return exchanger().settle(messageSender, currencyKey);
}
function mint() external issuanceActive returns (bool) {
require(address(rewardsDistribution()) != address(0), "RewardsDistribution not set");
ISupplySchedule _supplySchedule = supplySchedule();
IRewardsDistribution _rewardsDistribution = rewardsDistribution();
uint supplyToMint = _supplySchedule.mintableSupply();
require(supplyToMint > 0, "No supply is mintable");
emitTransfer(address(0), address(this), supplyToMint);
// record minting event before mutation to token supply
uint minterReward = _supplySchedule.recordMintEvent(supplyToMint);
// Set minted SNX balance to RewardEscrow's balance
// Minus the minterReward and set balance of minter to add reward
uint amountToDistribute = supplyToMint.sub(minterReward);
// Set the token balance to the RewardsDistribution contract
tokenState.setBalanceOf(
address(_rewardsDistribution),
tokenState.balanceOf(address(_rewardsDistribution)).add(amountToDistribute)
);
emitTransfer(address(this), address(_rewardsDistribution), amountToDistribute);
// Kick off the distribution of rewards
_rewardsDistribution.distributeRewards(amountToDistribute);
// Assign the minters reward.
tokenState.setBalanceOf(msg.sender, tokenState.balanceOf(msg.sender).add(minterReward));
emitTransfer(address(this), msg.sender, minterReward);
// Increase total supply by minted amount
totalSupply = totalSupply.add(supplyToMint);
return true;
}
/* Once off function for SIP-60 to migrate SNX balances in the RewardEscrow contract
* To the new RewardEscrowV2 contract
*/
function migrateEscrowBalanceToRewardEscrowV2() external onlyOwner {
// Record balanceOf(RewardEscrow) contract
uint rewardEscrowBalance = tokenState.balanceOf(address(rewardEscrow()));
// transfer all of RewardEscrow's balance to RewardEscrowV2
// _internalTransfer emits the transfer event
_internalTransfer(address(rewardEscrow()), address(rewardEscrowV2()), rewardEscrowBalance);
}
// ========== EVENTS ==========
event AtomicSynthExchange(
address indexed account,
bytes32 fromCurrencyKey,
uint256 fromAmount,
bytes32 toCurrencyKey,
uint256 toAmount,
address toAddress
);
bytes32 internal constant ATOMIC_SYNTH_EXCHANGE_SIG =
keccak256("AtomicSynthExchange(address,bytes32,uint256,bytes32,uint256,address)");
function emitAtomicSynthExchange(
address account,
bytes32 fromCurrencyKey,
uint256 fromAmount,
bytes32 toCurrencyKey,
uint256 toAmount,
address toAddress
) external onlyExchanger {
proxy._emit(
abi.encode(fromCurrencyKey, fromAmount, toCurrencyKey, toAmount, toAddress),
2,
ATOMIC_SYNTH_EXCHANGE_SIG,
addressToBytes32(account),
0,
0
);
}
}