-
Notifications
You must be signed in to change notification settings - Fork 0
/
TokenConnectorLogic.sol
109 lines (92 loc) · 3.61 KB
/
TokenConnectorLogic.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
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
import {TransferFailed, InsufficientFunds} from "../errors/CommonErrors.sol";
import {NotBridge, InvalidEpoch, NoFinalizedState} from "../errors/ConnectorErrors.sol";
import {TokenState, Transfer} from "./TokenState.sol";
import {BridgeBase} from "../lib/BridgeBase.sol";
import {IBridgeConnector} from "../connectors/IBridgeConnector.sol";
abstract contract TokenConnectorLogic is IBridgeConnector {
BridgeBase public bridge;
address public token;
address public otherNetworkAddress;
TokenState public state;
bytes public finalizedState;
/// Events
event Finalized(uint256 indexed epoch);
event AssetBridged(address indexed connector, address indexed account, uint256 value);
modifier onlySettled() {
uint256 fee = estimateSettlementFee(msg.sender);
if (msg.value < fee) {
revert InsufficientFunds(fee, msg.value);
}
_;
}
modifier onlyBridge() {
if (msg.sender != address(bridge)) {
revert NotBridge(msg.sender);
}
_;
}
function estimateSettlementFee(address locker) public view returns (uint256) {
bool alreadyHasBalance = state.hasBalance(locker);
uint256 fee = bridge.settlementFee();
if (!alreadyHasBalance) {
return fee;
}
return 0;
}
function epoch() public view returns (uint256) {
return state.epoch();
}
function decodeTransfers(bytes memory data) internal pure returns (Transfer[] memory) {
return abi.decode(data, (Transfer[]));
}
function isStateEmpty() external view override returns (bool) {
return state.empty();
}
function getStateLength() external view returns (uint256) {
return state.getStateLength();
}
function finalize(uint256 epoch_to_finalize) public virtual override onlyBridge returns (bytes32) {
// if epoch == 0 then it is the first epoch for this connector and epoch sohuld be synced with the bridge contract
if (state.epoch() != 0 && epoch_to_finalize != state.epoch()) {
revert InvalidEpoch({expected: state.epoch(), actual: epoch_to_finalize});
}
Transfer[] memory transfers = state.getTransfers();
state.increaseEpoch();
// if no transfers was made, then the finalized state should be empty
if (transfers.length == 0) {
finalizedState = new bytes(0);
} else {
finalizedState = abi.encode(transfers);
state.cleanup();
uint256 settlementFeesToForward = bridge.settlementFee() * transfers.length;
(bool success,) = address(bridge).call{value: settlementFeesToForward}("");
if (!success) {
revert TransferFailed(address(bridge), settlementFeesToForward);
}
}
emit Finalized(epoch_to_finalize);
return keccak256(finalizedState);
}
/**
* @dev Retrieves the finalized state of the bridgeable contract.
* @return A bytes serialized finalized state
*/
function getFinalizedState() public view override returns (bytes memory) {
return finalizedState;
}
/**
* @dev Returns the address of the underlying contract in this network
*/
function getSourceContract() external view returns (address) {
return token;
}
/**
* @dev Returns the address of the bridged contract on the other network
*/
function getDestinationContract() external view returns (address) {
return otherNetworkAddress;
}
function applyState(bytes calldata) external virtual;
}