Skip to content

Commit a99adee

Browse files
committed
Merge branch 'develop' into staging
2 parents e9a983e + 94677e5 commit a99adee

Some content is hidden

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

55 files changed

+7932
-2987
lines changed

.circleci/config.yml

+1-24
Original file line numberDiff line numberDiff line change
@@ -146,30 +146,7 @@ jobs:
146146
- checkout
147147
- attach_workspace:
148148
at: .
149-
- run:
150-
name: Prepare docker containers
151-
command: |
152-
git clone git@github.com:ethereum-optimism/optimism-integration.git
153-
cd optimism-integration
154-
docker-compose pull
155-
- run:
156-
name: Start chains
157-
background: true
158-
command: |
159-
cd optimism-integration
160-
./up.sh
161-
- cmd-wait-for-port:
162-
port: 8545
163-
- cmd-wait-for-port:
164-
port: 9545
165-
- run:
166-
name: Deploy OVM Synthetix instances
167-
command: |
168-
node publish deploy-ovm-pair
169-
- run:
170-
name: Run OVM production tests
171-
command: |
172-
npm run test:prod:ovm
149+
- run: echo Disabled until ops tool is fixed by Optimism
173150
job-prod-tests:
174151
working_directory: ~/repo
175152
docker:

.circleci/src/jobs/job-prod-tests-ovm.yml

+29-23
Original file line numberDiff line numberDiff line change
@@ -6,26 +6,32 @@ steps:
66
- attach_workspace:
77
at: .
88
- run:
9-
name: Prepare docker containers
10-
command: |
11-
git clone git@github.com:ethereum-optimism/optimism-integration.git
12-
cd optimism-integration
13-
docker-compose pull
14-
- run:
15-
name: Start chains
16-
background: true
17-
command: |
18-
cd optimism-integration
19-
./up.sh
20-
- cmd-wait-for-port:
21-
port: 8545
22-
- cmd-wait-for-port:
23-
port: 9545
24-
- run:
25-
name: Deploy OVM Synthetix instances
26-
command: |
27-
node publish deploy-ovm-pair
28-
- run:
29-
name: Run OVM production tests
30-
command: |
31-
npm run test:prod:ovm
9+
echo Disabled until ops tool is fixed by Optimism
10+
# - run:
11+
# name: Build docker containers
12+
# command: |
13+
# git clone git@github.com:ethereum-optimism/optimism.git
14+
# cd optimism
15+
# yarn
16+
# cd ops
17+
# export COMPOSE_DOCKER_CLI_BUILD=1
18+
# export DOCKER_BUILDKIT=1
19+
# docker-compose build
20+
# - run:
21+
# name: Start chains
22+
# background: true
23+
# command: |
24+
# cd optimism/ops
25+
# docker-compose up -d
26+
# - cmd-wait-for-port:
27+
# port: 8545
28+
# - cmd-wait-for-port:
29+
# port: 9545
30+
# - run:
31+
# name: Deploy OVM Synthetix instances
32+
# command: |
33+
# node publish deploy-ovm-pair
34+
# - run:
35+
# name: Run OVM production tests
36+
# command: |
37+
# npm run test:prod:ovm

.solcover.js

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ module.exports = {
99
'EscrowChecker.sol',
1010
'ExchangeRatesWithoutInvPricing.sol',
1111
'IssuerWithoutLiquidations.sol',
12+
'BridgeMigrator.sol',
1213
],
1314
providerOptions: {
1415
default_balance_ether: 10000000000000, // extra zero just in case (coverage consumes more gas)

contracts/BaseSynthetixBridge.sol

+84
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
pragma solidity ^0.5.16;
2+
pragma experimental ABIEncoderV2;
3+
4+
// Inheritance
5+
import "./Owned.sol";
6+
import "./MixinResolver.sol";
7+
import "./MixinSystemSettings.sol";
8+
import "./interfaces/IBaseSynthetixBridge.sol";
9+
10+
// Internal references
11+
import "./interfaces/ISynthetix.sol";
12+
import "./interfaces/IRewardEscrowV2.sol";
13+
import "@eth-optimism/contracts/iOVM/bridge/messaging/iAbs_BaseCrossDomainMessenger.sol";
14+
15+
contract BaseSynthetixBridge is Owned, MixinSystemSettings, IBaseSynthetixBridge {
16+
/* ========== ADDRESS RESOLVER CONFIGURATION ========== */
17+
bytes32 private constant CONTRACT_EXT_MESSENGER = "ext:Messenger";
18+
bytes32 internal constant CONTRACT_SYNTHETIX = "Synthetix";
19+
bytes32 private constant CONTRACT_REWARDESCROW = "RewardEscrowV2";
20+
21+
bool public initiationActive;
22+
23+
// ========== CONSTRUCTOR ==========
24+
25+
constructor(address _owner, address _resolver) public Owned(_owner) MixinSystemSettings(_resolver) {
26+
initiationActive = true;
27+
}
28+
29+
// ========== INTERNALS ============
30+
31+
function messenger() internal view returns (iAbs_BaseCrossDomainMessenger) {
32+
return iAbs_BaseCrossDomainMessenger(requireAndGetAddress(CONTRACT_EXT_MESSENGER));
33+
}
34+
35+
function synthetix() internal view returns (ISynthetix) {
36+
return ISynthetix(requireAndGetAddress(CONTRACT_SYNTHETIX));
37+
}
38+
39+
function rewardEscrowV2() internal view returns (IRewardEscrowV2) {
40+
return IRewardEscrowV2(requireAndGetAddress(CONTRACT_REWARDESCROW));
41+
}
42+
43+
function initiatingActive() internal view {
44+
require(initiationActive, "Initiation deactivated");
45+
}
46+
47+
/* ========== VIEWS ========== */
48+
49+
function resolverAddressesRequired() public view returns (bytes32[] memory addresses) {
50+
bytes32[] memory existingAddresses = MixinSystemSettings.resolverAddressesRequired();
51+
bytes32[] memory newAddresses = new bytes32[](3);
52+
newAddresses[0] = CONTRACT_EXT_MESSENGER;
53+
newAddresses[1] = CONTRACT_SYNTHETIX;
54+
newAddresses[2] = CONTRACT_REWARDESCROW;
55+
addresses = combineArrays(existingAddresses, newAddresses);
56+
}
57+
58+
// ========== MODIFIERS ============
59+
60+
modifier requireInitiationActive() {
61+
initiatingActive();
62+
_;
63+
}
64+
65+
// ========= RESTRICTED FUNCTIONS ==============
66+
67+
function suspendInitiation() external onlyOwner {
68+
require(initiationActive, "Initiation suspended");
69+
initiationActive = false;
70+
emit InitiationSuspended();
71+
}
72+
73+
function resumeInitiation() external onlyOwner {
74+
require(!initiationActive, "Initiation not suspended");
75+
initiationActive = true;
76+
emit InitiationResumed();
77+
}
78+
79+
// ========== EVENTS ==========
80+
81+
event InitiationSuspended();
82+
83+
event InitiationResumed();
84+
}

contracts/BridgeMigrator.sol

+130
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
pragma solidity ^0.5.16;
2+
3+
import "./interfaces/ISynthetixBridgeToOptimism.sol";
4+
import "./interfaces/ISynthetixBridgeEscrow.sol";
5+
import "./interfaces/IERC20.sol";
6+
7+
interface IOwned {
8+
function owner() external view returns (address);
9+
10+
function nominatedOwner() external view returns (address);
11+
12+
function nominateNewOwner(address _owner) external;
13+
14+
function acceptOwnership() external;
15+
}
16+
17+
interface IOldSynthetixBridgeToOptimism {
18+
function activated() external view returns (bool);
19+
20+
function migrateBridge(address newBridge) external;
21+
}
22+
23+
contract BridgeMigrator {
24+
IERC20 public snx;
25+
26+
address public oldBridge;
27+
address public newBridge;
28+
address public newEscrow;
29+
30+
address public pdao;
31+
address public deployer;
32+
33+
uint256 public migratedBalance;
34+
35+
constructor(
36+
address _newBridge,
37+
address _newEscrow,
38+
string memory _network
39+
) public {
40+
newBridge = _newBridge;
41+
newEscrow = _newEscrow;
42+
43+
if (keccak256(abi.encodePacked(_network)) == keccak256(abi.encodePacked("mainnet"))) {
44+
oldBridge = 0x045e507925d2e05D114534D0810a1abD94aca8d6;
45+
pdao = 0xEb3107117FEAd7de89Cd14D463D340A2E6917769;
46+
deployer = 0xDe910777C787903F78C89e7a0bf7F4C435cBB1Fe;
47+
snx = IERC20(0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F);
48+
} else if (keccak256(abi.encodePacked(_network)) == keccak256(abi.encodePacked("kovan"))) {
49+
oldBridge = 0xE8Bf8fe5ce9e15D30F478E1647A57CB6B0271228;
50+
pdao = 0x73570075092502472E4b61A7058Df1A4a1DB12f2;
51+
deployer = 0x73570075092502472E4b61A7058Df1A4a1DB12f2;
52+
snx = IERC20(0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F);
53+
} else {
54+
revert("Unsupported network");
55+
}
56+
}
57+
58+
// ----------------------------------------
59+
// PUBLIC
60+
// ----------------------------------------
61+
62+
function execute() public {
63+
require(migratedBalance == 0, "Already migrated");
64+
require(msg.sender == deployer, "Only deployer may execute");
65+
66+
_takeOwnership();
67+
_validateBalancesBefore();
68+
_provideAllowance();
69+
_validateStateBefore();
70+
71+
_migrateSNX();
72+
73+
_validateStateAfter();
74+
_validateBalancesAfter();
75+
_relinquishOwnership();
76+
}
77+
78+
// ----------------------------------------
79+
// INTERNAL
80+
// ----------------------------------------
81+
82+
function _takeOwnership() internal {
83+
require(IOwned(oldBridge).owner() == deployer || IOwned(oldBridge).owner() == pdao, "Unexpected old bridge owner");
84+
require(IOwned(newEscrow).owner() == deployer || IOwned(newEscrow).owner() == pdao, "Unexpected new escrow owner");
85+
86+
IOwned(oldBridge).acceptOwnership();
87+
IOwned(newEscrow).acceptOwnership();
88+
89+
require(IOwned(oldBridge).owner() == address(this), "Unable to take old bridge ownership");
90+
require(IOwned(newEscrow).owner() == address(this), "Unable to take new escrow ownership");
91+
}
92+
93+
function _validateBalancesBefore() internal {
94+
require(snx.balanceOf(oldBridge) > 1000000 ether, "Unexpected initial old bridge balance");
95+
require(snx.balanceOf(newEscrow) == 0, "Unexpected initial new escrow balance");
96+
97+
migratedBalance = snx.balanceOf(oldBridge);
98+
}
99+
100+
function _provideAllowance() internal {
101+
ISynthetixBridgeEscrow(newEscrow).approveBridge(address(snx), newBridge, 0);
102+
ISynthetixBridgeEscrow(newEscrow).approveBridge(address(snx), newBridge, uint256(-1));
103+
require(snx.allowance(newEscrow, newBridge) == uint256(-1), "Unexpected final new bridge allowance");
104+
}
105+
106+
function _validateStateBefore() internal {
107+
require(IOldSynthetixBridgeToOptimism(oldBridge).activated() == true, "Unexpected initial old bridge state");
108+
}
109+
110+
function _migrateSNX() internal {
111+
IOldSynthetixBridgeToOptimism(oldBridge).migrateBridge(newEscrow);
112+
}
113+
114+
function _validateStateAfter() internal {
115+
require(IOldSynthetixBridgeToOptimism(oldBridge).activated() == false, "Unexpected final old bridge state");
116+
}
117+
118+
function _validateBalancesAfter() internal {
119+
require(snx.balanceOf(oldBridge) == 0, "Unexpected final old bridge balance");
120+
require(snx.balanceOf(newEscrow) == migratedBalance, "Unexpected final new escrow balance");
121+
}
122+
123+
function _relinquishOwnership() internal {
124+
IOwned(oldBridge).nominateNewOwner(deployer);
125+
IOwned(newEscrow).nominateNewOwner(deployer);
126+
127+
require(IOwned(oldBridge).nominatedOwner() == deployer, "Failed to relinquish old bridge ownership");
128+
require(IOwned(newEscrow).nominatedOwner() == deployer, "Failed to relinquish new escrow ownership");
129+
}
130+
}

contracts/SynthetixBridgeEscrow.sol

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
pragma solidity ^0.5.16;
2+
3+
// Inheritance
4+
import "./Owned.sol";
5+
import "./MixinResolver.sol";
6+
import "./interfaces/ISynthetixBridgeEscrow.sol";
7+
8+
// External references.
9+
import "openzeppelin-solidity-2.3.0/contracts/token/ERC20/SafeERC20.sol";
10+
11+
contract SynthetixBridgeEscrow is Owned, ISynthetixBridgeEscrow {
12+
using SafeERC20 for IERC20;
13+
14+
constructor(address _owner) public Owned(_owner) {}
15+
16+
function approveBridge(
17+
address _token,
18+
address _bridge,
19+
uint256 _amount
20+
) external onlyOwner {
21+
IERC20(_token).safeApprove(_bridge, _amount);
22+
emit BridgeApproval(_token, _bridge, _amount);
23+
}
24+
25+
/* ========== EVENTS ========== */
26+
event BridgeApproval(address _token, address indexed spender, uint value);
27+
}

0 commit comments

Comments
 (0)