Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Teleporter registry upgrade #43

Merged
merged 95 commits into from
Oct 30, 2023
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
95 commits
Select commit Hold shift + click to select a range
b668c24
initial draft example for teleporter/warp registry
Aug 26, 2023
45039f3
Merge remote-tracking branch 'origin/main' into teleporter-registry
Sep 4, 2023
38faae3
fix msg sender and version variable name
Sep 7, 2023
e77c890
update version and registry funcs
Sep 25, 2023
8f6a68a
Merge remote-tracking branch 'origin/main' into teleporter-registry
Sep 25, 2023
b82f3df
registry contracts and erc20bridge using registry
Sep 26, 2023
016c039
move addressToVersion to teleporter registry
Sep 26, 2023
115fd96
update erc20bridge registry checks
Sep 26, 2023
0a12bf3
update crossChainApps to use registry
Sep 27, 2023
d50fef6
Merge remote-tracking branch 'origin/main' into teleporter-registry
Sep 27, 2023
6c8cf3f
add docs, license, and event
Sep 27, 2023
61e8d48
registry accepts initial values and v0.5.6 compatible
Sep 27, 2023
0c244ed
lint fixes
Sep 27, 2023
b676a2b
fix erc20bridge tests with registry integration
Sep 27, 2023
a5039b7
init teleporter registry tests
Sep 27, 2023
7195814
add registry unit tests
Sep 28, 2023
6d14e84
deploy registry in tests and erc20bridge test working
Sep 29, 2023
733c3c2
use registry for cross chain app tests
Sep 29, 2023
3376507
Merge remote-tracking branch 'origin/main' into teleporter-registry
Sep 29, 2023
051c6bb
draft teleporterUpgradeable contract
Oct 2, 2023
8dfb4fe
use TeleporterUpgradeable in cross chain apps
Oct 2, 2023
7552339
docs and cleanup
Oct 2, 2023
2474f2e
refactor and test TeleporterUprgradeable
Oct 2, 2023
a1de5d8
lint fixes
Oct 2, 2023
95b9951
Merge remote-tracking branch 'origin/main' into teleporter-registry
Oct 2, 2023
34d6ea5
Update contracts/src/Teleporter/upgrades/TeleporterUpgradeable.sol
Oct 3, 2023
eb67e67
Update contracts/src/Teleporter/upgrades/TeleporterUpgradeable.sol
Oct 3, 2023
ff1c1c4
remove extra onlyAllowedTeleporter calls and nits
Oct 3, 2023
c449bdd
remove check for duplicate protocol address and rename funcs
Oct 4, 2023
951cbf4
fix up naming and tests
Oct 4, 2023
3654e48
fix unit tests
Oct 4, 2023
feebce8
remove contract address requirement and docs
Oct 4, 2023
6286393
change to private variable
Oct 4, 2023
689c515
Merge remote-tracking branch 'origin/main' into teleporter-registry
Oct 5, 2023
cc3a1ec
doc about invalid version 0
Oct 5, 2023
0ea24d9
move _addressToVersion to WarpProtocolRegistry
Oct 5, 2023
52de62d
use protocol registry entry struct
Oct 5, 2023
7a518a5
Update contracts/src/WarpProtocolRegistry.sol
Oct 6, 2023
05c714c
Update contracts/src/WarpProtocolRegistry.sol
Oct 6, 2023
cea7d19
Update contracts/src/WarpProtocolRegistry.sol
Oct 6, 2023
44fd2c1
rename blockchainID and add virtuals
Oct 13, 2023
8a89233
add comment and fix typo
Oct 13, 2023
307d7ec
Merge remote-tracking branch 'origin/main' into teleporter-registry
Oct 13, 2023
eb9b3ed
update abi bindings
Oct 13, 2023
77ec078
fix integration tests and log
Oct 13, 2023
1f38e6c
draft new registry mapping approach
Oct 17, 2023
1530a0e
add unit tests and use require statements
Oct 17, 2023
201416e
update documentation and abi bindings
Oct 17, 2023
823e50d
Merge remote-tracking branch 'origin/main' into teleporter-registry
Oct 18, 2023
b2fb0a7
Merge remote-tracking branch 'origin/main' into teleporter-registry
Oct 18, 2023
2f526de
add additional requirements to doc
Oct 18, 2023
3330c22
add README for upgrades
Oct 19, 2023
4a152a6
change to upgradeability
Oct 19, 2023
ca15150
Update contracts/src/Teleporter/upgrades/README.md
Oct 19, 2023
8a0187b
Update contracts/src/Teleporter/upgrades/README.md
Oct 19, 2023
313c305
Update contracts/src/Teleporter/upgrades/README.md
Oct 19, 2023
f6377da
Update contracts/src/Teleporter/upgrades/README.md
Oct 19, 2023
aac50e8
Update contracts/src/Teleporter/upgrades/README.md
Oct 19, 2023
4cff973
update readme to include rollback and remove we
Oct 19, 2023
3c9bc0f
Merge remote-tracking branch 'origin/main' into teleporter-registry
Oct 19, 2023
d18c657
make zero error consistent and add unit test
Oct 19, 2023
e699689
fix function ordering
Oct 19, 2023
83f139f
update abi bindings
Oct 19, 2023
9c3d636
Update contracts/src/Teleporter/upgrades/README.md
Oct 24, 2023
4064d33
Update contracts/src/Teleporter/upgrades/README.md
Oct 24, 2023
26de2d5
update README with getLatestVersion
Oct 24, 2023
9e5a3ef
punctuation
Oct 24, 2023
3606e7a
make minTeleporterVersion public
Oct 24, 2023
880bf16
update tests and event MinTeleporterVersionUpdated
Oct 24, 2023
7b7a6c4
Update contracts/src/Teleporter/upgrades/README.md
Oct 24, 2023
8004496
add index and doc
Oct 24, 2023
02cf81b
fix unit tests and update bindings
Oct 24, 2023
6450e21
add virtual to TeleporterUpgradeable
Oct 25, 2023
93b379a
require derived contracts to implement updateMinTeleporterVersion
Oct 25, 2023
f08ae17
readme updates
Oct 25, 2023
dfa1a3d
update abi bindings
Oct 25, 2023
261e50e
add test for erc20Bridge updateMinTeleporterVersion
Oct 25, 2023
7935ed0
Update contracts/src/Teleporter/upgrades/README.md
Oct 25, 2023
4d37ee3
* make BlockHashReceiver Ownable
Oct 25, 2023
70c80d0
update doc for updateMinTeleporterVersion
Oct 25, 2023
834b677
update blockHashReceiver bindings
Oct 25, 2023
6d0712a
Update contracts/src/CrossChainApplications/ERC20Bridge/ERC20Bridge.sol
Oct 26, 2023
5c7c940
Update contracts/src/CrossChainApplications/VerifiedBlockHash/BlockHa…
Oct 26, 2023
24610ad
exampleCrossChainMessenger ownable
Oct 26, 2023
791d9d8
update unit test and doc
Oct 26, 2023
c64d13f
extra assert for unit test
Oct 26, 2023
0711b2f
update bindings
Oct 26, 2023
9794c86
Merge remote-tracking branch 'origin/main' into teleporter-registry
Oct 26, 2023
f4f27bb
update go work sum
Oct 27, 2023
a2d0d44
Merge remote-tracking branch 'origin/main' into teleporter-registry
Oct 27, 2023
011796a
Merge remote-tracking branch 'origin/main' into teleporter-registry
Oct 27, 2023
000a894
move --constructor-args to last argument
Oct 27, 2023
42b7dbf
Merge remote-tracking branch 'origin/main' into teleporter-registry
Oct 27, 2023
1532fa4
Merge branch 'main' into teleporter-registry
Oct 30, 2023
afc114e
update foundry version
Oct 30, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ subnetGenesis_*
vars.sh
NETWORK_READY
NETWORK_RUNNING
.awm-relayer-storage/

# Raw Contract Deployment Transaction
UniversalTeleporterDeployerTransaction.txt
Expand Down
1 change: 0 additions & 1 deletion contracts/src/.solhint.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
"strict": true
}
],
"reason-string": ["off"],
"ordering": "warn",
"immutable-vars-naming": [
"warn",
Expand Down
85 changes: 57 additions & 28 deletions contracts/src/CrossChainApplications/ERC20Bridge/ERC20Bridge.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import "@subnet-evm-contracts/interfaces/IWarpMessenger.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "../../Teleporter/TeleporterRegistry.sol";

struct TokenID {
bytes32 chainID;
Expand Down Expand Up @@ -44,8 +45,9 @@ contract ERC20Bridge is IERC20Bridge, ITeleporterReceiver, ReentrancyGuard {
0x0200000000000000000000000000000000000005;
bytes32 public immutable currentChainID;

// Used for sending an receiving Teleporter messages.
ITeleporterMessenger public immutable teleporterMessenger;
// Used for sending and receiving Teleporter messages.
TeleporterRegistry public immutable teleporterRegistry;
uint256 internal _minTeleporterVersion;
Fixed Show fixed Hide fixed

// Tracks which bridge tokens have been submitted to be created other bridge instances.
// (destinationChainID, destinationBridgeAddress) -> nativeTokenContract -> tokenCreationSubmitted
Expand Down Expand Up @@ -79,24 +81,28 @@ contract ERC20Bridge is IERC20Bridge, ITeleporterReceiver, ReentrancyGuard {
error CannotBridgeWrappedToken(address nativeTokenAddress);
error InsufficientAdjustedAmount(uint256 adjustedAmount, uint256 feeAmount);
error InsufficientTotalAmount(uint256 totalAmount, uint256 feeAmount);
error InsufficientWrappedTokenBalance(uint256 currentBalance, uint256 requestAmount);
error InsufficientWrappedTokenBalance(
uint256 currentBalance,
uint256 requestAmount
);
error InvalidAction();
error InvalidBridgeTokenAddress();
error InvalidDestinationBridgeAddress();
error InvalidRecipientAddress();
error InvalidTeleporterMessengerAddress();
error InvalidTeleporterRegistryAddress();
error Unauthorized();

/**
* @dev Initializes the Teleporter messenger used for sending and receiving messages,
* and initializes the current chain ID.
*/
constructor(address teleporterMessengerAddress) {
if (teleporterMessengerAddress == address(0)) {
revert InvalidTeleporterMessengerAddress();
constructor(address teleporterRegistryAddress) {
if (teleporterRegistryAddress == address(0)) {
revert InvalidTeleporterRegistryAddress();
}

teleporterMessenger = ITeleporterMessenger(teleporterMessengerAddress);
teleporterRegistry = TeleporterRegistry(teleporterRegistryAddress);
_minTeleporterVersion = teleporterRegistry.getLatestVersion();
currentChainID = WarpMessenger(WARP_PRECOMPILE_ADDRESS)
.getBlockchainID();
}
Expand Down Expand Up @@ -144,7 +150,10 @@ contract ERC20Bridge is IERC20Bridge, ITeleporterReceiver, ReentrancyGuard {
// is not a "fee/burn on transfer" token, since it was deployed by this
// contract itself.
if (totalAmount <= primaryFeeAmount + secondaryFeeAmount) {
revert InsufficientTotalAmount(totalAmount, primaryFeeAmount + secondaryFeeAmount);
revert InsufficientTotalAmount(
totalAmount,
primaryFeeAmount + secondaryFeeAmount
);
}

return
Expand All @@ -162,9 +171,11 @@ contract ERC20Bridge is IERC20Bridge, ITeleporterReceiver, ReentrancyGuard {
}

// Otherwise, this is a token "native" to this chain.
if (!submittedBridgeTokenCreations[destinationChainID][
destinationBridgeAddress
][tokenContractAddress]) {
if (
!submittedBridgeTokenCreations[destinationChainID][
destinationBridgeAddress
][tokenContractAddress]
) {
revert InvalidBridgeTokenAddress();
}

Expand Down Expand Up @@ -214,6 +225,8 @@ contract ERC20Bridge is IERC20Bridge, ITeleporterReceiver, ReentrancyGuard {
if (destinationBridgeAddress == address(0)) {
revert InvalidDestinationBridgeAddress();
}
ITeleporterMessenger teleporterMessenger = teleporterRegistry
.getLatestTeleporter();

// For non-zero fee amounts, transfer the fee into the control of this contract first, and then
// allow the Teleporter contract to spend it.
Expand Down Expand Up @@ -274,8 +287,11 @@ contract ERC20Bridge is IERC20Bridge, ITeleporterReceiver, ReentrancyGuard {
address nativeBridgeAddress,
bytes calldata message
) external {
// Only allow the Teleporter messenger to deliver messages.
if (msg.sender != address(teleporterMessenger)) {
// Only allow Teleporter messengers above the minimum version to deliver messages.
if (
teleporterRegistry.getAddressToVersion(msg.sender) <
_minTeleporterVersion
) {
revert Unauthorized();
}

Expand Down Expand Up @@ -341,6 +357,10 @@ contract ERC20Bridge is IERC20Bridge, ITeleporterReceiver, ReentrancyGuard {
}
}

function updateMinTeleporterVersion() external {
_minTeleporterVersion = teleporterRegistry.getLatestVersion();
}

/**
* @dev Encodes the parameters for the Create action to be decoded and executed on the destination.
*/
Expand Down Expand Up @@ -408,6 +428,9 @@ contract ERC20Bridge is IERC20Bridge, ITeleporterReceiver, ReentrancyGuard {
* @dev Teleporter message receiver for creating a new bridge token on this chain.
*
* Emits a {CreateBridgeToken} event.
*
* Note: This function is only called within `receiveTeleporterMessage`, which can only be
* called by the Teleporter messenger.
*/
function _createBridgeToken(
bytes32 nativeChainID,
Expand All @@ -418,9 +441,11 @@ contract ERC20Bridge is IERC20Bridge, ITeleporterReceiver, ReentrancyGuard {
uint8 nativeDecimals
) private {
// Check that the bridge token doesn't already exist.
if (nativeToWrappedTokens[nativeChainID][nativeBridgeAddress][
nativeContractAddress
] != address(0)) {
if (
nativeToWrappedTokens[nativeChainID][nativeBridgeAddress][
nativeContractAddress
] != address(0)
) {
revert BridgeTokenAlreadyExists(
nativeToWrappedTokens[nativeChainID][nativeBridgeAddress][
nativeContractAddress
Expand Down Expand Up @@ -456,6 +481,9 @@ contract ERC20Bridge is IERC20Bridge, ITeleporterReceiver, ReentrancyGuard {
* @dev Teleporter message receiver for minting of an existing bridge token on this chain.
*
* Emits a {MintBridgeTokens} event.
*
* Note: This function is only called within `receiveTeleporterMessage`, which can only be
* called by the Teleporter messenger.
*/
function _mintBridgeTokens(
bytes32 nativeChainID,
Expand All @@ -464,11 +492,6 @@ contract ERC20Bridge is IERC20Bridge, ITeleporterReceiver, ReentrancyGuard {
address recipient,
uint256 amount
) private nonReentrant {
// Only allow the Teleporter messenger to deliver messages.
if (msg.sender != address(teleporterMessenger)) {
revert Unauthorized();
}

// The recipient cannot be the zero address.
if (recipient == address(0)) {
revert InvalidRecipientAddress();
Expand All @@ -493,6 +516,9 @@ contract ERC20Bridge is IERC20Bridge, ITeleporterReceiver, ReentrancyGuard {
/**
* @dev Teleporter message receiver for handling bridge tokens transfers back from another chain
* and optionally routing them to a different third chain.
*
* Note: This function is only called within `receiveTeleporterMessage`, which can only be
* called by the Teleporter messenger.
*/
function _transferBridgeTokens(
bytes32 sourceChainID,
Expand All @@ -504,11 +530,6 @@ contract ERC20Bridge is IERC20Bridge, ITeleporterReceiver, ReentrancyGuard {
uint256 totalAmount,
uint256 secondaryFeeAmount
) private nonReentrant {
// Only allow the teleporter messenger to deliver messages.
if (msg.sender != address(teleporterMessenger)) {
revert Unauthorized();
}

// Neither the recipient nor the destination bridge can be the zero address.
if (recipient == address(0)) {
revert InvalidRecipientAddress();
Expand Down Expand Up @@ -591,6 +612,8 @@ contract ERC20Bridge is IERC20Bridge, ITeleporterReceiver, ReentrancyGuard {
if (destinationChainID == currentChainID) {
revert CannotBridgeTokenWithinSameChain();
}
ITeleporterMessenger teleporterMessenger = teleporterRegistry
.getLatestTeleporter();

// Allow the Teleporter messenger to spend the fee amount.
if (feeAmount > 0) {
Expand Down Expand Up @@ -647,6 +670,9 @@ contract ERC20Bridge is IERC20Bridge, ITeleporterReceiver, ReentrancyGuard {
function _processWrappedTokenTransfer(
WrappedTokenTransferInfo memory wrappedTransferInfo
) private {
ITeleporterMessenger teleporterMessenger = teleporterRegistry
.getLatestTeleporter();

// If necessary, transfer the primary fee amount to this contract and approve the
// Teleporter messenger to spend it when the first message back to the native subnet
// is submitted. The secondary fee amount is then handled by the native subnet when
Expand Down Expand Up @@ -684,7 +710,10 @@ contract ERC20Bridge is IERC20Bridge, ITeleporterReceiver, ReentrancyGuard {
bytes32 nativeChainID = bridgeToken.nativeChainID();
address nativeBridgeAddress = bridgeToken.nativeBridge();
if (wrappedTransferInfo.destinationChainID == nativeChainID) {
if (wrappedTransferInfo.destinationBridgeAddress != nativeBridgeAddress) {
if (
wrappedTransferInfo.destinationBridgeAddress !=
nativeBridgeAddress
) {
revert InvalidDestinationBridgeAddress();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import "../../../Mocks/UnitTestMockERC20.sol";
contract ERC20BridgeTest is Test {
address public constant MOCK_TELEPORTER_MESSENGER_ADDRESS =
0x644E5b7c5D4Bc8073732CEa72c66e0BB90dFC00f;
address public constant MOCK_TELEPORTER_REGISTRY_ADDRESS =
0xf9FA4a0c696b659328DDaaBCB46Ae4eBFC9e68e4;
address public constant WARP_PRECOMPILE_ADDRESS =
address(0x0200000000000000000000000000000000000005);
bytes32 private constant _MOCK_BLOCKCHAIN_ID = bytes32(uint256(123456));
Expand Down Expand Up @@ -65,11 +67,60 @@ contract ERC20BridgeTest is Test {
abi.encodeWithSelector(WarpMessenger.getBlockchainID.selector),
abi.encode(_MOCK_BLOCKCHAIN_ID)
);
vm.expectCall(
WARP_PRECOMPILE_ADDRESS,
abi.encodeWithSelector(WarpMessenger.getBlockchainID.selector)
);

initMockTeleporterRegistry();

vm.expectCall(
MOCK_TELEPORTER_REGISTRY_ADDRESS,
abi.encodeWithSelector(
WarpProtocolRegistry.getLatestVersion.selector
)
);

erc20Bridge = new ERC20Bridge(MOCK_TELEPORTER_MESSENGER_ADDRESS);
erc20Bridge = new ERC20Bridge(MOCK_TELEPORTER_REGISTRY_ADDRESS);
mockERC20 = new UnitTestMockERC20();
}

function initMockTeleporterRegistry() internal {
vm.mockCall(
MOCK_TELEPORTER_REGISTRY_ADDRESS,
abi.encodeWithSelector(
WarpProtocolRegistry.getLatestVersion.selector
),
abi.encode(1)
);

vm.mockCall(
MOCK_TELEPORTER_REGISTRY_ADDRESS,
abi.encodeWithSelector(
TeleporterRegistry.getAddressToVersion.selector,
(MOCK_TELEPORTER_MESSENGER_ADDRESS)
),
abi.encode(1)
);

vm.mockCall(
MOCK_TELEPORTER_REGISTRY_ADDRESS,
abi.encodeWithSelector(
WarpProtocolRegistry.getVersionToAddress.selector,
(1)
),
abi.encode(MOCK_TELEPORTER_MESSENGER_ADDRESS)
);

vm.mockCall(
MOCK_TELEPORTER_REGISTRY_ADDRESS,
abi.encodeWithSelector(
TeleporterRegistry.getLatestTeleporter.selector
),
abi.encode(ITeleporterMessenger(MOCK_TELEPORTER_MESSENGER_ADDRESS))
);
}

function testSameChainID() public {
vm.expectRevert(ERC20Bridge.CannotBridgeTokenWithinSameChain.selector);
erc20Bridge.bridgeTokens({
Expand All @@ -90,9 +141,13 @@ contract ERC20BridgeTest is Test {
_DEFAULT_OTHER_BRIDGE_ADDRESS,
address(mockERC20)
);
vm.expectRevert(abi.encodePacked(
ERC20Bridge.InsufficientAdjustedAmount.selector,
uint256(130), uint256(130)));
vm.expectRevert(
abi.encodePacked(
ERC20Bridge.InsufficientAdjustedAmount.selector,
uint256(130),
uint256(130)
)
);
erc20Bridge.bridgeTokens({
destinationChainID: _DEFAULT_OTHER_CHAIN_ID,
destinationBridgeAddress: _DEFAULT_OTHER_BRIDGE_ADDRESS,
Expand All @@ -115,9 +170,13 @@ contract ERC20BridgeTest is Test {
contractNonce: 1
});

vm.expectRevert(abi.encodePacked(
ERC20Bridge.InsufficientTotalAmount.selector,
uint256(130), uint256(130)));
vm.expectRevert(
abi.encodePacked(
ERC20Bridge.InsufficientTotalAmount.selector,
uint256(130),
uint256(130)
)
);
erc20Bridge.bridgeTokens({
destinationChainID: _DEFAULT_OTHER_CHAIN_ID,
destinationBridgeAddress: _DEFAULT_OTHER_BRIDGE_ADDRESS,
Expand Down Expand Up @@ -494,9 +553,13 @@ contract ERC20BridgeTest is Test {
address(mockERC20)
);

vm.expectRevert(abi.encodePacked(
ERC20Bridge.InsufficientAdjustedAmount.selector,
uint256(totalAmount - tokenFeeOnTransferAmount), uint256(bridgeFeeAmount)));
vm.expectRevert(
abi.encodePacked(
ERC20Bridge.InsufficientAdjustedAmount.selector,
uint256(totalAmount - tokenFeeOnTransferAmount),
uint256(bridgeFeeAmount)
)
);
erc20Bridge.bridgeTokens({
destinationChainID: _DEFAULT_OTHER_CHAIN_ID,
destinationBridgeAddress: _DEFAULT_OTHER_BRIDGE_ADDRESS,
Expand Down
Loading
Loading