-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathPortalV2.sol
130 lines (113 loc) · 4.42 KB
/
PortalV2.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
// SPDX-License-Identifier: UNLICENSED
// Copyright (c) Eywa.Fi, 2021-2023 - all rights reserved
pragma solidity 0.8.17;
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "./EndPoint.sol";
import "./interfaces/IWhitelist.sol";
import "./interfaces/IAddressBook.sol";
contract PortalV2 is EndPoint, Ownable {
/// @dev fee denominator
uint256 public constant FEE_DENOMINATOR = 10000;
/// @dev locked balances
mapping(address => uint256) public balanceOf;
event Locked(address token, uint256 amount, address from, address to);
event Unlocked(address token, uint256 amount, address from, address to);
modifier checkAmount(uint256 amount, address token) {
address whitelist = IAddressBook(addressBook).whitelist();
require(
amount >= IWhitelist(whitelist).tokenMin(token) && amount <= IWhitelist(whitelist).tokenMax(token),
"Portal: wrong amount"
);
_;
}
modifier onlyRouter() {
address router = IAddressBook(addressBook).router(uint64(block.chainid));
require(router == msg.sender, "Portal: router only");
_;
}
constructor (address addressBook_) EndPoint(addressBook_) {}
/**
* @dev Sets address book.
*
* Controlled by DAO and\or multisig (3 out of 5, Gnosis Safe).
*
* @param addressBook_ address book contract address.
*/
function setAddressBook(address addressBook_) external onlyOwner {
_setAddressBook(addressBook_);
}
/**
* @dev Lock token.
*
* @param token token address to synthesize;
* @param amount amount to synthesize;
* @param from sender address;
* @param to receiver address.
*/
function lock(
address token,
uint256 amount,
address from,
address to
) external onlyRouter checkAmount(amount, token) {
address whitelist = IAddressBook(addressBook).whitelist();
require(IWhitelist(whitelist).tokenState(token) == uint8(IWhitelist.TokenState.InOut), "Portal: token must be whitelisted");
_updateBalance(token, amount);
emit Locked(token, amount, from, to);
}
/**
* @dev Unlock. Can be called only by router after initiation on a second chain.
*
* @param otoken token address to unsynth;
* @param amount amount to unsynth;
* @param from sender address;
* @param to recipient address.
*/
function unlock(
address otoken,
uint256 amount,
address from,
address to
) external onlyRouter returns (uint256 amountOut) {
IAddressBook addressBookImpl = IAddressBook(addressBook);
address whitelist = addressBookImpl.whitelist();
address treasury = addressBookImpl.treasury();
require(IWhitelist(whitelist).tokenState(otoken) == uint8(IWhitelist.TokenState.InOut), "Portal: token must be whitelisted");
uint256 feeAmount = amount * IWhitelist(whitelist).bridgeFee(otoken) / FEE_DENOMINATOR;
amountOut = amount - feeAmount;
SafeERC20.safeTransfer(IERC20(otoken), to, amountOut);
SafeERC20.safeTransfer(IERC20(otoken), treasury, feeAmount);
balanceOf[otoken] -= amount;
emit Unlocked(otoken, amount, from, to);
}
/**
* @dev Emergency unlock. Can be called only by router after initiation on opposite chain.
*
* @param otoken token address to unsynth;
* @param amount amount to unsynth;
* @param from sender address;
* @param to recipient address.
*/
function emergencyUnlock(
address otoken,
uint256 amount,
address from,
address to
) external onlyRouter returns (uint256 amountOut) {
address whitelist = IAddressBook(addressBook).whitelist();
require(IWhitelist(whitelist).tokenState(otoken) == uint8(IWhitelist.TokenState.InOut), "Portal: token must be whitelisted");
amountOut = amount;
SafeERC20.safeTransfer(IERC20(otoken), to, amountOut);
balanceOf[otoken] -= amount;
emit Unlocked(otoken, amount, from, to);
}
function _updateBalance(address token, uint256 expectedAmount) private {
uint256 oldBalance = balanceOf[token];
require(
(IERC20(token).balanceOf(address(this)) - oldBalance) >= expectedAmount,
"Portal: insufficient balance"
);
balanceOf[token] += expectedAmount;
}
}