-
Notifications
You must be signed in to change notification settings - Fork 10
/
RedemptionReceiver.sol
117 lines (105 loc) · 3.53 KB
/
RedemptionReceiver.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
// SPDX-License-Identifier: MIT
pragma solidity 0.8.13;
import "LayerZero/interfaces/ILayerZeroEndpoint.sol";
import "LayerZero/interfaces/ILayerZeroReceiver.sol";
import "../interfaces/IERC20.sol";
import "../interfaces/IVelo.sol";
/// @notice Part 2 of 2 in the WeVE (FTM) -> USDC + VELO (OP) redemption process
/// This contract is responsible for receiving the LZ message and distributing USDC + VELO
contract RedemptionReceiver is ILayerZeroReceiver {
IERC20 public immutable USDC;
IVelo public immutable VELO;
uint16 public immutable fantomChainId; // 12 for FTM, 10012 for FTM testnet
address public immutable endpoint;
address public immutable deployer;
constructor(
address _usdc,
address _velo,
uint16 _fantomChainId,
address _endpoint
) {
require(_fantomChainId == 12 || _fantomChainId == 10012, "CHAIN_ID_NOT_FTM");
USDC = IERC20(_usdc);
VELO = IVelo(_velo);
fantomChainId = _fantomChainId;
endpoint = _endpoint;
deployer = msg.sender;
}
address public fantomSender;
uint256 public eligibleWEVE;
uint256 public redeemableUSDC;
uint256 public redeemableVELO;
function initializeReceiverWith(
address _fantomSender,
uint256 _eligibleWEVE,
uint256 _redeemableUSDC,
uint256 _redeemableVELO
) external {
require(msg.sender == deployer, "ONLY_DEPLOYER");
require(fantomSender == address(0), "ALREADY_INITIALIZED");
require(
USDC.transferFrom(msg.sender, address(this), _redeemableUSDC),
"USDC_TRANSFER_FAILED"
);
require(
VELO.mintToRedemptionReceiver(_redeemableVELO),
"VELO_MINT_FAILED"
);
fantomSender = _fantomSender;
eligibleWEVE = _eligibleWEVE;
redeemableUSDC = _redeemableUSDC;
redeemableVELO = _redeemableVELO;
}
uint256 public redeemedWEVE;
function previewRedeem(uint256 amountWEVE)
public
view
returns (uint256 shareOfUSDC, uint256 shareOfVELO)
{
// pro rata USDC
shareOfUSDC = (amountWEVE * redeemableUSDC) / eligibleWEVE;
// pro rata VELO
shareOfVELO = (amountWEVE * redeemableVELO) / eligibleWEVE;
}
function lzReceive(
uint16 srcChainId,
bytes memory srcAddress,
uint64,
bytes memory payload
) external override {
require(fantomSender != address(0), "NOT_INITIALIZED");
require(
msg.sender == endpoint &&
srcChainId == fantomChainId &&
addressFromPackedBytes(srcAddress) == fantomSender,
"UNAUTHORIZED_CALLER"
);
(address redemptionAddress, uint256 amountWEVE) = abi.decode(
payload,
(address, uint256)
);
require(
(redeemedWEVE += amountWEVE) <= eligibleWEVE,
"cannot redeem more than eligible"
);
(uint256 shareOfUSDC, uint256 shareOfVELO) = previewRedeem(amountWEVE);
require(
USDC.transfer(redemptionAddress, shareOfUSDC),
"USDC_TRANSFER_FAILED"
);
require(
VELO.transfer(redemptionAddress, shareOfVELO),
"VELO_TRANSFER_FAILED"
);
}
function addressFromPackedBytes(bytes memory toAddressBytes)
public
pure
returns (address toAddress)
{
// solhint-disable-next-line no-inline-assembly
assembly {
toAddress := mload(add(toAddressBytes, 20))
}
}
}