From 229d3dca9a30515010742a886bd4c75d09a218ea Mon Sep 17 00:00:00 2001 From: Deon <110722148+DanielEmmanuel1@users.noreply.github.com> Date: Fri, 4 Oct 2024 07:07:40 +0100 Subject: [PATCH] Ark Minimun_gasFee Fix (#251) * Update Bridge.sol * Update IStarklaneEvent.sol * Update Bridge.sol * Update Bridge.t.sol * Update IStarklane.sol * Update Bridge.sol * Update Bridge.sol --- apps/blockchain/ethereum/src/Bridge.sol | 101 ++++++++++++++---- apps/blockchain/ethereum/src/IStarklane.sol | 12 +++ .../ethereum/src/IStarklaneEvent.sol | 7 ++ apps/blockchain/ethereum/test/Bridge.t.sol | 26 +++++ 4 files changed, 128 insertions(+), 18 deletions(-) diff --git a/apps/blockchain/ethereum/src/Bridge.sol b/apps/blockchain/ethereum/src/Bridge.sol index e7f0fbd7..078ac40b 100644 --- a/apps/blockchain/ethereum/src/Bridge.sol +++ b/apps/blockchain/ethereum/src/Bridge.sol @@ -23,6 +23,7 @@ error BridgeNotEnabledError(); error TooManyTokensError(); error InvalidL1AddressError(); error InvalidL2AddressError(); +error MinimumGasFeeError(); uint256 constant MAX_PAYLOAD_LENGTH = 300; @@ -42,6 +43,10 @@ contract Starklane is address[] _collections; bool _enabled; bool _whiteListEnabled; +// updatable the minimum gas fee +// Using an arbitrary gas value here for L1-L2 messaging fees, adjustable as network conditions evolve. +// This value serves as a flexible baseline, allowing for real-time adjustments to reflect gas changes. + uint256 _minimumGasFee = 5e13;// 0.00005 ETH /** * @notice Initializes the implementation, only callable once. @@ -49,8 +54,12 @@ contract Starklane is * @param data Data to init the implementation. */ function initialize(bytes calldata data) public onlyInit { - (address owner, IStarknetMessaging starknetCoreAddress, uint256 starklaneL2Address, uint256 starklaneL2Selector) - = abi.decode(data, (address, IStarknetMessaging, uint256, uint256)); + ( + address owner, + IStarknetMessaging starknetCoreAddress, + uint256 starklaneL2Address, + uint256 starklaneL2Selector + ) = abi.decode(data, (address, IStarknetMessaging, uint256, uint256)); _enabled = false; _starknetCoreAddress = starknetCoreAddress; @@ -77,6 +86,9 @@ contract Starklane is uint256[] calldata ids, bool useAutoBurn ) external payable { + if (msg.value < _minimumGasFee) { + revert MinimumGasFeeError(); + } if (!Cairo.isFelt252(snaddress.unwrap(ownerL2))) { revert CairoWrapError(); } @@ -110,7 +122,8 @@ contract Starklane is req.ownerL2 = ownerL2; if (ctype == CollectionType.ERC721) { - (req.name, req.symbol, req.uri, req.tokenURIs) = TokenUtil.erc721Metadata(collectionL1, ids); + (req.name, req.symbol, req.uri, req.tokenURIs) = TokenUtil + .erc721Metadata(collectionL1, ids); } else { (req.uri) = TokenUtil.erc1155Metadata(collectionL1); } @@ -123,8 +136,12 @@ contract Starklane is if (payload.length >= MAX_PAYLOAD_LENGTH) { revert TooManyTokensError(); } - IStarknetMessaging(_starknetCoreAddress).sendMessageToL2{value: msg.value}( - snaddress.unwrap(_starklaneL2Address), felt252.unwrap(_starklaneL2Selector), payload + IStarknetMessaging(_starknetCoreAddress).sendMessageToL2{ + value: msg.value + }( + snaddress.unwrap(_starklaneL2Address), + felt252.unwrap(_starklaneL2Selector), + payload ); emit DepositRequestInitiated(req.hash, block.timestamp, payload); @@ -133,11 +150,13 @@ contract Starklane is /** * @notice Withdraw tokens received from L2. * - * @param request Serialized request containing the tokens to be withdrawed. + * @param request Serialized request containing the tokens to be withdrawed. * * @return Address of the collection targetted by the request (or newly deployed). */ - function withdrawTokens(uint256[] calldata request) external payable returns (address) { + function withdrawTokens( + uint256[] calldata request + ) external payable returns (address) { if (!_enabled) { revert BridgeNotEnabledError(); } @@ -152,18 +171,30 @@ contract Starklane is // _consumeMessageAutoWithdraw(_starklaneL2Address, request); revert NotSupportedYetError(); } else { - _consumeMessageStarknet(_starknetCoreAddress, _starklaneL2Address, request); + _consumeMessageStarknet( + _starknetCoreAddress, + _starklaneL2Address, + request + ); } Request memory req = Protocol.requestDeserialize(request, 0); - address collectionL1 = _verifyRequestAddresses(req.collectionL1, req.collectionL2); + address collectionL1 = _verifyRequestAddresses( + req.collectionL1, + req.collectionL2 + ); CollectionType ctype = Protocol.collectionTypeFromHeader(header); if (collectionL1 == address(0x0)) { if (ctype == CollectionType.ERC721) { - collectionL1 = _deployERC721Bridgeable(req.name, req.symbol, req.collectionL2, req.hash); + collectionL1 = _deployERC721Bridgeable( + req.name, + req.symbol, + req.collectionL2, + req.hash + ); // update whitelist if needed _whiteListCollection(collectionL1, true); } else { @@ -174,7 +205,12 @@ contract Starklane is for (uint256 i = 0; i < req.tokenIds.length; i++) { uint256 id = req.tokenIds[i]; - bool wasEscrowed = _withdrawFromEscrow(ctype, collectionL1, req.ownerL1, id); + bool wasEscrowed = _withdrawFromEscrow( + ctype, + collectionL1, + req.ownerL1, + id + ); if (!wasEscrowed) { // TODO: perhaps, implement the same interface for ERC721 and ERC1155 @@ -196,10 +232,16 @@ contract Starklane is * @param payload Request to cancel * @param nonce Nonce used for request sending. */ - function startRequestCancellation(uint256[] memory payload, uint256 nonce) external onlyOwner { + function startRequestCancellation( + uint256[] memory payload, + uint256 nonce + ) external onlyOwner { IStarknetMessaging(_starknetCoreAddress).startL1ToL2MessageCancellation( - snaddress.unwrap(_starklaneL2Address), felt252.unwrap(_starklaneL2Selector), payload, nonce - ); + snaddress.unwrap(_starklaneL2Address), + felt252.unwrap(_starklaneL2Selector), + payload, + nonce + ); Request memory req = Protocol.requestDeserialize(payload, 0); emit CancelRequestStarted(req.hash, block.timestamp); } @@ -212,7 +254,10 @@ contract Starklane is */ function cancelRequest(uint256[] memory payload, uint256 nonce) external { IStarknetMessaging(_starknetCoreAddress).cancelL1ToL2Message( - snaddress.unwrap(_starklaneL2Address), felt252.unwrap(_starklaneL2Selector), payload, nonce + snaddress.unwrap(_starklaneL2Address), + felt252.unwrap(_starklaneL2Selector), + payload, + nonce ); Request memory req = Protocol.requestDeserialize(payload, 0); _cancelRequest(req); @@ -274,7 +319,11 @@ contract Starklane is * * @return array of white listed collections */ - function getWhiteListedCollections() external view returns (address[] memory) { + function getWhiteListedCollections() + external + view + returns (address[] memory) + { uint256 offset = 0; uint256 nbElem = _collections.length; // solidity doesn't support dynamic length array in memory @@ -324,7 +373,11 @@ contract Starklane is return _enabled; } - function setL1L2CollectionMapping(address collectionL1, snaddress collectionL2, bool force) external onlyOwner { + function setL1L2CollectionMapping( + address collectionL1, + snaddress collectionL2, + bool force + ) external onlyOwner { if (collectionL1 == address(0x0)) { revert InvalidL1AddressError(); } @@ -332,6 +385,18 @@ contract Starklane is revert InvalidL2AddressError(); } _setL1L2AddressMapping(collectionL1, collectionL2, force); - emit L1L2CollectionMappingUpdated(collectionL1, snaddress.unwrap(collectionL2)); + emit L1L2CollectionMappingUpdated( + collectionL1, + snaddress.unwrap(collectionL2) + ); + } + + function updateMinimumGasFee(uint256 newMinimumGasFee) external onlyOwner { + _minimumGasFee = newMinimumGasFee; + emit MinimumGasFeeUpdated(newMinimumGasFee); + } + + function getMinimumGasFee() external view returns (uint256) { + return _minimumGasFee; } } diff --git a/apps/blockchain/ethereum/src/IStarklane.sol b/apps/blockchain/ethereum/src/IStarklane.sol index 6afaa5a6..53f7c91e 100644 --- a/apps/blockchain/ethereum/src/IStarklane.sol +++ b/apps/blockchain/ethereum/src/IStarklane.sol @@ -110,4 +110,16 @@ interface IStarklane { * @param force Force flag */ function setL1L2CollectionMapping(address collectionL1, snaddress collectionL2, bool force) external; + + /** + * @param newMinimumGasFee New minimum gas fee + */ + function updateMinimumGasFee( + uint256 newMinimumGasFee + ) external; + + /** + * @return Minimum gas fee + */ + function getMinimumGasFee() external view returns (uint256); } diff --git a/apps/blockchain/ethereum/src/IStarklaneEvent.sol b/apps/blockchain/ethereum/src/IStarklaneEvent.sol index 2977540f..7f00f442 100644 --- a/apps/blockchain/ethereum/src/IStarklaneEvent.sol +++ b/apps/blockchain/ethereum/src/IStarklaneEvent.sol @@ -37,4 +37,11 @@ interface IStarklaneEvent { * @notice L1 L2 collection mapping updated */ event L1L2CollectionMappingUpdated(address indexed colllectionL1, uint256 indexed collectionL2); + + /** + @notice Minimum gas fee updated + */ + event MinimumGasFeeUpdated( + uint256 indexed gasFee + ); } diff --git a/apps/blockchain/ethereum/test/Bridge.t.sol b/apps/blockchain/ethereum/test/Bridge.t.sol index f6da84e4..0c28795e 100644 --- a/apps/blockchain/ethereum/test/Bridge.t.sol +++ b/apps/blockchain/ethereum/test/Bridge.t.sol @@ -540,4 +540,30 @@ contract BridgeTest is Test, IStarklaneEvent { vm.expectRevert(InvalidL2AddressError.selector); IStarklane(bridge).setL1L2CollectionMapping(collectionL1, invalidCollectionL2, false); } + + //Here is the test for minimum gas validation + function testFail_minimumGasFee() public { + IERC721MintRangeFree(erc721C1).mintRangeFree(alice, 0, 10); + + uint256[] memory ids = new uint256[](2); + ids[0] = 0; + ids[1] = 9; + + uint256 salt = 0x1; + snaddress to = Cairo.snaddressWrap(0x1); + + vm.startPrank(alice); + IERC721(erc721C1).setApprovalForAll(address(bridge), true); + vm.expectRevert(MinimumGasFeeError.selector); + IStarklane(bridge).depositTokens{value: 1000}(salt, address(erc721C1), to, ids, false); + vm.stopPrank(); +} + +function test_updateMinimumGasFee() public { + IStarklane(bridge).updateMinimumGasFee(0.0001 ether); + assertEq(IStarklane(bridge).getMinimumGasFee(), 0.0001 ether); + + IStarklane(bridge).updateMinimumGasFee(0.00001 ether); + assertEq(IStarklane(bridge).getMinimumGasFee(), 0.00001 ether); +} }