From 7472a732573f7ae4697f491724bd02b45c380fe3 Mon Sep 17 00:00:00 2001 From: ptisserand Date: Wed, 2 Oct 2024 09:36:14 +0200 Subject: [PATCH 1/4] ethereum: apply `forge fmt` (#249) --- apps/blockchain/ethereum/script/ERC1155.s.sol | 14 +- apps/blockchain/ethereum/script/ERC721.s.sol | 18 +- .../ethereum/script/LocalMessaging.s.sol | 5 +- .../ethereum/script/LocalTesting.s.sol | 44 +- .../ethereum/script/Starklane.s.sol | 1 - apps/blockchain/ethereum/script/Utils.sol | 17 +- apps/blockchain/ethereum/src/Bridge.sol | 214 ++++----- apps/blockchain/ethereum/src/Escrow.sol | 68 ++- apps/blockchain/ethereum/src/IStarklane.sol | 129 +++--- .../ethereum/src/IStarklaneEvent.sol | 61 +-- apps/blockchain/ethereum/src/Messaging.sol | 87 ++-- apps/blockchain/ethereum/src/Protocol.sol | 166 +++---- apps/blockchain/ethereum/src/State.sol | 53 +-- .../blockchain/ethereum/src/TestMessaging.sol | 1 + apps/blockchain/ethereum/src/UUPSProxied.sol | 44 +- apps/blockchain/ethereum/src/sn/Cairo.sol | 407 +++++++----------- .../src/sn/IStarknetMessagingLocal.sol | 11 +- .../src/sn/StarknetMessagingLocal.sol | 50 +-- .../ethereum/src/token/CollectionManager.sol | 114 ++--- .../ethereum/src/token/Deployer.sol | 60 +-- .../ethereum/src/token/ERC1155Bridgeable.sol | 95 ++-- .../ethereum/src/token/ERC721Bridgeable.sol | 119 ++--- .../ethereum/src/token/IERC1155Bridgeable.sol | 42 +- .../ethereum/src/token/IERC721Bridgeable.sol | 36 +- .../ethereum/src/token/TokenUtil.sol | 98 ++--- apps/blockchain/ethereum/test/Bridge.t.sol | 159 ++----- apps/blockchain/ethereum/test/Cairo.t.sol | 44 +- apps/blockchain/ethereum/test/Escrow.t.sol | 31 +- apps/blockchain/ethereum/test/Protocol.t.sol | 79 +--- .../blockchain/ethereum/test/TokenUtils.t.sol | 14 +- .../ethereum/test/token/ERC1155NoSupply.sol | 87 ++-- .../ethereum/test/token/ERC721MintFree.sol | 26 +- .../test/token/IERC721MintRangeFree.sol | 11 +- apps/blockchain/ethereum/test/utils/Users.sol | 13 +- 34 files changed, 839 insertions(+), 1579 deletions(-) diff --git a/apps/blockchain/ethereum/script/ERC1155.s.sol b/apps/blockchain/ethereum/script/ERC1155.s.sol index 41bbe0ed..0decae63 100644 --- a/apps/blockchain/ethereum/script/ERC1155.s.sol +++ b/apps/blockchain/ethereum/script/ERC1155.s.sol @@ -7,23 +7,17 @@ import "./Utils.sol"; import "src/token/ERC1155Bridgeable.sol"; import "openzeppelin-contracts/contracts/proxy/ERC1967/ERC1967Proxy.sol"; - contract Deploy is Script { - - function setUp() public { - } + function setUp() public {} function run() public { Config memory config = Utils.loadConfig(); - + vm.startBroadcast(config.deployerPrivateKey); address impl = address(new ERC1155Bridgeable()); - - bytes memory dataInit = abi.encodeWithSelector( - ERC1155Bridgeable.initialize.selector, - abi.encode("") - ); + + bytes memory dataInit = abi.encodeWithSelector(ERC1155Bridgeable.initialize.selector, abi.encode("")); address proxyAddress = vm.envAddress("ERC1155_PROXY_ADDRESS"); diff --git a/apps/blockchain/ethereum/script/ERC721.s.sol b/apps/blockchain/ethereum/script/ERC721.s.sol index 6abe10fa..29958981 100644 --- a/apps/blockchain/ethereum/script/ERC721.s.sol +++ b/apps/blockchain/ethereum/script/ERC721.s.sol @@ -7,26 +7,18 @@ import "./Utils.sol"; import "src/token/ERC721Bridgeable.sol"; import "openzeppelin-contracts/contracts/proxy/ERC1967/ERC1967Proxy.sol"; - contract Deploy is Script { - - function setUp() public { - } + function setUp() public {} function run() public { Config memory config = Utils.loadConfig(); - + vm.startBroadcast(config.deployerPrivateKey); address impl = address(new ERC721Bridgeable()); - - bytes memory dataInit = abi.encodeWithSelector( - ERC721Bridgeable.initialize.selector, - abi.encode( - "everai_123", - "EVR_123" - ) - ); + + bytes memory dataInit = + abi.encodeWithSelector(ERC721Bridgeable.initialize.selector, abi.encode("everai_123", "EVR_123")); address proxyAddress = vm.envAddress("ERC721_PROXY_ADDRESS"); diff --git a/apps/blockchain/ethereum/script/LocalMessaging.s.sol b/apps/blockchain/ethereum/script/LocalMessaging.s.sol index bea536e4..ebd5324d 100644 --- a/apps/blockchain/ethereum/script/LocalMessaging.s.sol +++ b/apps/blockchain/ethereum/script/LocalMessaging.s.sol @@ -5,7 +5,6 @@ import "forge-std/Script.sol"; import "./Utils.sol"; - import "src/sn/StarknetMessagingLocal.sol"; contract LocalMessaging is Script { @@ -13,7 +12,7 @@ contract LocalMessaging is Script { function run() public { Config memory config = Utils.loadConfig(); - + string memory json = "local_messaging"; vm.startBroadcast(config.deployerPrivateKey); @@ -23,4 +22,4 @@ contract LocalMessaging is Script { Utils.writeJson(json, "local_messaging_deploy.json"); } -} \ No newline at end of file +} diff --git a/apps/blockchain/ethereum/script/LocalTesting.s.sol b/apps/blockchain/ethereum/script/LocalTesting.s.sol index 6bd5517b..92ddf5c2 100644 --- a/apps/blockchain/ethereum/script/LocalTesting.s.sol +++ b/apps/blockchain/ethereum/script/LocalTesting.s.sol @@ -13,14 +13,13 @@ import "src/token/ERC721Bridgeable.sol"; import "openzeppelin-contracts/contracts/proxy/ERC1967/ERC1967Proxy.sol"; import "openzeppelin-contracts/contracts/token/ERC721/IERC721.sol"; - /** - Deploys a local setup with: - 1. Local SN Core contract to receive/send messages. - 2. Starklane bridge. - 3. One ERC721b collection with 10 tokens minted for the deployer. - 4. One request on the bridge depositing tokens. -*/ + * Deploys a local setup with: + * 1. Local SN Core contract to receive/send messages. + * 2. Starklane bridge. + * 3. One ERC721b collection with 10 tokens minted for the deployer. + * 4. One request on the bridge depositing tokens. + */ contract LocalSetup is Script { function setUp() public {} @@ -38,25 +37,15 @@ contract LocalSetup is Script { bytes memory dataInit = abi.encodeWithSelector( Starklane.initialize.selector, - abi.encode( - config.deployerAddress, - snCoreAddress, - config.starklaneL2Address, - config.starklaneL2Selector - ) + abi.encode(config.deployerAddress, snCoreAddress, config.starklaneL2Address, config.starklaneL2Selector) ); address starklaneProxyAddress = address(new ERC1967Proxy(starklaneImpl, dataInit)); // ERC721b. address erc721Impl = address(new ERC721Bridgeable()); - bytes memory erc721DataInit = abi.encodeWithSelector( - ERC721Bridgeable.initialize.selector, - abi.encode( - "collection_1", - "C1" - ) - ); + bytes memory erc721DataInit = + abi.encodeWithSelector(ERC721Bridgeable.initialize.selector, abi.encode("collection_1", "C1")); address erc721ProxyAddress = address(new ERC1967Proxy(erc721Impl, erc721DataInit)); @@ -68,12 +57,7 @@ contract LocalSetup is Script { // Mint some tokens. (bool success, bytes memory data) = erc721ProxyAddress.call( - abi.encodeWithSignature( - "mintRangeFree(address,uint256,uint256)", - config.deployerAddress, - 0, - 20 - ) + abi.encodeWithSignature("mintRangeFree(address,uint256,uint256)", config.deployerAddress, 0, 20) ); // set approval to then deposit tokens. @@ -87,13 +71,7 @@ contract LocalSetup is Script { uint256 salt = 0x1; snaddress to = Cairo.snaddressWrap(0x12345); - IStarklane(starklaneProxyAddress).depositTokens{value: 30000}( - salt, - address(erc721ProxyAddress), - to, - ids, - false - ); + IStarklane(starklaneProxyAddress).depositTokens{value: 30000}(salt, address(erc721ProxyAddress), to, ids, false); vm.stopBroadcast(); diff --git a/apps/blockchain/ethereum/script/Starklane.s.sol b/apps/blockchain/ethereum/script/Starklane.s.sol index 0333623b..917b7ae9 100644 --- a/apps/blockchain/ethereum/script/Starklane.s.sol +++ b/apps/blockchain/ethereum/script/Starklane.s.sol @@ -11,7 +11,6 @@ import "src/token/ERC721Bridgeable.sol"; import "openzeppelin-contracts/contracts/proxy/ERC1967/ERC1967Proxy.sol"; - contract Deploy is Script { function setUp() public {} diff --git a/apps/blockchain/ethereum/script/Utils.sol b/apps/blockchain/ethereum/script/Utils.sol index b793bb10..8009328e 100644 --- a/apps/blockchain/ethereum/script/Utils.sol +++ b/apps/blockchain/ethereum/script/Utils.sol @@ -8,38 +8,29 @@ address constant HEVM_ADDRESS = address(bytes20(uint160(uint256(keccak256("hevm struct Config { address deployerAddress; uint256 deployerPrivateKey; - address starknetCoreAddress; address starklaneL1ProxyAddress; - uint256 starklaneL2Address; uint256 starklaneL2Selector; } library Utils { - // - function loadConfig() - internal - view - returns (Config memory) { + function loadConfig() internal view returns (Config memory) { VmSafe vm = VmSafe(HEVM_ADDRESS); - + return Config({ deployerAddress: vm.envAddress("ACCOUNT_ADDRESS"), deployerPrivateKey: vm.envUint("ACCOUNT_PRIVATE_KEY"), - starknetCoreAddress: vm.envAddress("STARKNET_CORE_L1_ADDRESS"), starklaneL1ProxyAddress: vm.envAddress("STARKLANE_L1_PROXY_ADDRESS"), - starklaneL2Address: vm.envUint("STARKLANE_L2_ADDRESS"), starklaneL2Selector: vm.envUint("STARKLANE_L2_SELECTOR") - }); + }); } // - function writeJson(string memory json, string memory fileName) - internal { + function writeJson(string memory json, string memory fileName) internal { VmSafe vm = VmSafe(HEVM_ADDRESS); string memory data = vm.serializeBool(json, "success", true); diff --git a/apps/blockchain/ethereum/src/Bridge.sol b/apps/blockchain/ethereum/src/Bridge.sol index 663a4232..e7f0fbd7 100644 --- a/apps/blockchain/ethereum/src/Bridge.sol +++ b/apps/blockchain/ethereum/src/Bridge.sol @@ -27,37 +27,30 @@ error InvalidL2AddressError(); uint256 constant MAX_PAYLOAD_LENGTH = 300; /** - @title Starklane bridge contract. -*/ -contract Starklane is IStarklaneEvent, UUPSOwnableProxied, StarklaneState, StarklaneEscrow, StarklaneMessaging, CollectionManager { - + * @title Starklane bridge contract. + */ +contract Starklane is + IStarklaneEvent, + UUPSOwnableProxied, + StarklaneState, + StarklaneEscrow, + StarklaneMessaging, + CollectionManager +{ // Mapping (collectionAddress => bool) mapping(address => bool) _whiteList; address[] _collections; bool _enabled; bool _whiteListEnabled; - /** - @notice Initializes the implementation, only callable once. - - @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) - ); + * @notice Initializes the implementation, only callable once. + * + * @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)); _enabled = false; _starknetCoreAddress = starknetCoreAddress; @@ -68,25 +61,22 @@ contract Starklane is IStarklaneEvent, UUPSOwnableProxied, StarklaneState, Stark } /** - @notice Deposits token in escrow and initiates the - transfer to Starknet. Will revert if any of the token is missing approval - for the bridge as operator. - - @param salt A salt used to generate the request hash. - @param collectionL1 Address of the collection contract. - @param ownerL2 New owner address on Starknet. - @param ids Ids of the token to transfer. At least 1 token is required. - */ + * @notice Deposits token in escrow and initiates the + * transfer to Starknet. Will revert if any of the token is missing approval + * for the bridge as operator. + * + * @param salt A salt used to generate the request hash. + * @param collectionL1 Address of the collection contract. + * @param ownerL2 New owner address on Starknet. + * @param ids Ids of the token to transfer. At least 1 token is required. + */ function depositTokens( uint256 salt, address collectionL1, snaddress ownerL2, uint256[] calldata ids, bool useAutoBurn - ) - external - payable - { + ) external payable { if (!Cairo.isFelt252(snaddress.unwrap(ownerL2))) { revert CairoWrapError(); } @@ -120,10 +110,7 @@ contract Starklane is IStarklaneEvent, UUPSOwnableProxied, StarklaneState, Stark 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); } @@ -137,28 +124,20 @@ contract Starklane is IStarklaneEvent, UUPSOwnableProxied, StarklaneState, Stark revert TooManyTokensError(); } IStarknetMessaging(_starknetCoreAddress).sendMessageToL2{value: msg.value}( - snaddress.unwrap(_starklaneL2Address), - felt252.unwrap(_starklaneL2Selector), - payload + snaddress.unwrap(_starklaneL2Address), felt252.unwrap(_starklaneL2Selector), payload ); emit DepositRequestInitiated(req.hash, block.timestamp, payload); } /** - @notice Withdraw tokens received from L2. - - @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) - { + * @notice Withdraw tokens received from L2. + * + * @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) { if (!_enabled) { revert BridgeNotEnabledError(); } @@ -184,12 +163,7 @@ contract Starklane is IStarklaneEvent, UUPSOwnableProxied, StarklaneState, Stark 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 { @@ -217,40 +191,28 @@ contract Starklane is IStarklaneEvent, UUPSOwnableProxied, StarklaneState, Stark } /** - @notice Start the cancellation of a given request. - - @param payload Request to cancel - @param nonce Nonce used for request sending. + * @notice Start the cancellation of a given request. + * + * @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); } /** - @notice Cancel a given request. - - @param payload Request to cancel - @param nonce Nonce used for request sending. + * @notice Cancel a given request. + * + * @param payload Request to cancel + * @param nonce Nonce used for request sending. */ - function cancelRequest( - uint256[] memory payload, - uint256 nonce - ) external { + 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); @@ -263,14 +225,14 @@ contract Starklane is IStarklaneEvent, UUPSOwnableProxied, StarklaneState, Stark address collectionL1 = req.collectionL1; for (uint256 i = 0; i < req.tokenIds.length; i++) { uint256 id = req.tokenIds[i]; - _withdrawFromEscrow(ctype, collectionL1, req.ownerL1, id); + _withdrawFromEscrow(ctype, collectionL1, req.ownerL1, id); } } /** - @notice Enable collection whitelist for deposit - - @param enable white list is enabled if true + * @notice Enable collection whitelist for deposit + * + * @param enable white list is enabled if true */ function enableWhiteList(bool enable) external onlyOwner { _whiteListEnabled = enable; @@ -278,47 +240,46 @@ contract Starklane is IStarklaneEvent, UUPSOwnableProxied, StarklaneState, Stark } /** - @notice Update whitelist status for given collection - - @param collection Collection address - @param enable white list is enabled if true + * @notice Update whitelist status for given collection + * + * @param collection Collection address + * @param enable white list is enabled if true */ function whiteList(address collection, bool enable) external onlyOwner { _whiteListCollection(collection, enable); emit CollectionWhiteListUpdated(collection, enable); } - - - /** - @notice Check if white list is globally enabled - @return true if enabled - */ + /** + * @notice Check if white list is globally enabled + * + * @return true if enabled + */ function isWhiteListEnabled() external view returns (bool) { return _whiteListEnabled; } /** - @notice Check if a collection is white listed - - @param collection Address of collection - @return true if white listed + * @notice Check if a collection is white listed + * + * @param collection Address of collection + * @return true if white listed */ function isWhiteListed(address collection) external view returns (bool) { return _isWhiteListed(collection); } - - /** - @notice Get list of white listed collections - @return array of white listed collections + /** + * @notice Get list of white listed collections + * + * @return array of white listed collections */ function getWhiteListedCollections() external view returns (address[] memory) { uint256 offset = 0; uint256 nbElem = _collections.length; // solidity doesn't support dynamic length array in memory address[] memory ret = new address[](nbElem); - for (uint256 i = 0; i < nbElem ;++i) { + for (uint256 i = 0; i < nbElem; ++i) { address cur = _collections[i]; if (_whiteList[cur]) { ret[offset] = cur; @@ -329,13 +290,11 @@ contract Starklane is IStarklaneEvent, UUPSOwnableProxied, StarklaneState, Stark assembly { mstore(ret, offset) } - + return ret; } - function _isWhiteListed( - address collection - ) internal view returns (bool) { + function _isWhiteListed(address collection) internal view returns (bool) { return !_whiteListEnabled || _whiteList[collection]; } @@ -343,7 +302,7 @@ contract Starklane is IStarklaneEvent, UUPSOwnableProxied, StarklaneState, Stark if (enable && !_whiteList[collection]) { bool toAdd = true; uint256 i = 0; - while(i < _collections.length) { + while (i < _collections.length) { if (collection == _collections[i]) { toAdd = false; break; @@ -357,29 +316,22 @@ contract Starklane is IStarklaneEvent, UUPSOwnableProxied, StarklaneState, Stark _whiteList[collection] = enable; } - function enableBridge( - bool enable - ) external onlyOwner { + function enableBridge(bool enable) external onlyOwner { _enabled = enable; } - function isEnabled() external view returns(bool) { + function isEnabled() external view returns (bool) { return _enabled; } - function setL1L2CollectionMapping( - address collectionL1, - snaddress collectionL2, - bool force - ) external onlyOwner { - if (collectionL1 == address(0x0)) { - revert InvalidL1AddressError(); - } - if (snaddress.unwrap(collectionL2) == 0x0) { - revert InvalidL2AddressError(); - } + function setL1L2CollectionMapping(address collectionL1, snaddress collectionL2, bool force) external onlyOwner { + if (collectionL1 == address(0x0)) { + revert InvalidL1AddressError(); + } + if (snaddress.unwrap(collectionL2) == 0x0) { + revert InvalidL2AddressError(); + } _setL1L2AddressMapping(collectionL1, collectionL2, force); emit L1L2CollectionMappingUpdated(collectionL1, snaddress.unwrap(collectionL2)); } - } diff --git a/apps/blockchain/ethereum/src/Escrow.sol b/apps/blockchain/ethereum/src/Escrow.sol index c58bce97..dbaebace 100644 --- a/apps/blockchain/ethereum/src/Escrow.sol +++ b/apps/blockchain/ethereum/src/Escrow.sol @@ -8,28 +8,21 @@ import "openzeppelin-contracts/contracts/token/ERC1155/IERC1155.sol"; import "./token/TokenUtil.sol"; /** - @title Contract responsible of escrowing tokens. -*/ + * @title Contract responsible of escrowing tokens. + */ contract StarklaneEscrow is Context { - // Escrowed token. // Mapping (collectionAddres => (tokenId => depositor)). mapping(address => mapping(uint256 => address)) _escrow; /** - @notice Deposits the given tokens into escrow. - - @param collectionType The token type, - @param collection Token collection address. - @param ids Tokens to be deposited. + * @notice Deposits the given tokens into escrow. + * + * @param collectionType The token type, + * @param collection Token collection address. + * @param ids Tokens to be deposited. */ - function _depositIntoEscrow( - CollectionType collectionType, - address collection, - uint256[] memory ids - ) - internal - { + function _depositIntoEscrow(CollectionType collectionType, address collection, uint256[] memory ids) internal { assert(ids.length > 0); for (uint256 i = 0; i < ids.length; i++) { @@ -51,21 +44,16 @@ contract StarklaneEscrow is Context { } /** - @notice Withdraw a token from escrow. - - @param collectionType The token type, - @param collection Token collection address. - @param to Owner withdrawing the token. - @param id Token to be deposited. - - @return True if the token was into escrow, false otherwise. + * @notice Withdraw a token from escrow. + * + * @param collectionType The token type, + * @param collection Token collection address. + * @param to Owner withdrawing the token. + * @param id Token to be deposited. + * + * @return True if the token was into escrow, false otherwise. */ - function _withdrawFromEscrow( - CollectionType collectionType, - address collection, - address to, - uint256 id - ) + function _withdrawFromEscrow(CollectionType collectionType, address collection, address to, uint256 id) internal returns (bool) { @@ -89,22 +77,14 @@ contract StarklaneEscrow is Context { } /** - @notice Verifies if the given token is in escrow. - - @param collection Token collection address. - @param id Token id. - - @return True if the token is in escrow, false otherwise. + * @notice Verifies if the given token is in escrow. + * + * @param collection Token collection address. + * @param id Token id. + * + * @return True if the token is in escrow, false otherwise. */ - function _isEscrowed( - address collection, - uint256 id - ) - internal - view - returns (bool) - { + function _isEscrowed(address collection, uint256 id) internal view returns (bool) { return _escrow[collection][id] > address(0x0); } - } diff --git a/apps/blockchain/ethereum/src/IStarklane.sol b/apps/blockchain/ethereum/src/IStarklane.sol index e913774d..6afaa5a6 100644 --- a/apps/blockchain/ethereum/src/IStarklane.sol +++ b/apps/blockchain/ethereum/src/IStarklane.sol @@ -8,97 +8,73 @@ import "./sn/Cairo.sol"; */ interface IStarklane { /** - @notice Deposits token in escrow and initiates the - transfer to Starknet. Will revert if any of the token is missing approval - for the bridge as operator. - - @param salt A salt used to generate the request hash. - @param collectionL1 Address of the collection contract. - @param ownerL2 New owner address on Starknet. - @param ids Ids of the token to transfer. At least 1 token is required. - @param useAutoBurn If true, ensures the token is burnt after being bridged. - */ + * @notice Deposits token in escrow and initiates the + * transfer to Starknet. Will revert if any of the token is missing approval + * for the bridge as operator. + * + * @param salt A salt used to generate the request hash. + * @param collectionL1 Address of the collection contract. + * @param ownerL2 New owner address on Starknet. + * @param ids Ids of the token to transfer. At least 1 token is required. + * @param useAutoBurn If true, ensures the token is burnt after being bridged. + */ function depositTokens( uint256 salt, address collectionL1, snaddress ownerL2, uint256[] calldata ids, bool useAutoBurn - ) - external - payable; + ) external payable; /** - @notice Withdraw tokens received from L2. - - @param request Serialized request containing the tokens to be withdrawed. - */ - function withdrawTokens( - uint256[] calldata request - ) - external - payable - returns (address); + * @notice Withdraw tokens received from L2. + * + * @param request Serialized request containing the tokens to be withdrawed. + */ + function withdrawTokens(uint256[] calldata request) external payable returns (address); /** - @notice Start the cancellation of a given request. - - @param payload Request to cancel - @param nonce Nonce used for request sending. + * @notice Start the cancellation of a given request. + * + * @param payload Request to cancel + * @param nonce Nonce used for request sending. */ - function startRequestCancellation( - uint256[] memory payload, - uint256 nonce - ) external; + function startRequestCancellation(uint256[] memory payload, uint256 nonce) external; /** - @notice Cancel a given request. - - @param payload Request to cancel - @param nonce Nonce used for request sending. + * @notice Cancel a given request. + * + * @param payload Request to cancel + * @param nonce Nonce used for request sending. */ - function cancelRequest( - uint256[] memory payload, - uint256 nonce - ) external; + function cancelRequest(uint256[] memory payload, uint256 nonce) external; /** - @notice Adds the hash of a message that can be consumed with the auto - method. - - @param msgHash Hash of the message to be considered as consumable. - */ - function addMessageHashForAutoWithdraw( - uint256 msgHash - ) - external - payable; + * @notice Adds the hash of a message that can be consumed with the auto + * method. + * + * @param msgHash Hash of the message to be considered as consumable. + */ + function addMessageHashForAutoWithdraw(uint256 msgHash) external payable; /** */ - function l2Info() - external - returns (snaddress, felt252); - - /** - @notice Enable whitelist for deposit + function l2Info() external returns (snaddress, felt252); - @param enable enabled if true + /** + * @notice Enable whitelist for deposit + * + * @param enable enabled if true */ - function enableWhiteList( - bool enable - ) external; + function enableWhiteList(bool enable) external; /** - @notice Update whitelist status for given collection - - @param collection Collection address - @param enable white list is enabled if true + * @notice Update whitelist status for given collection + * + * @param collection Collection address + * @param enable white list is enabled if true */ - function whiteList( - address collection, - bool enable - ) external; + function whiteList(address collection, bool enable) external; /** * @return true if white list is enabled @@ -116,13 +92,11 @@ interface IStarklane { function getWhiteListedCollections() external view returns (address[] memory); /** - @notice Enable bridge - - @param enable enabled if true + * @notice Enable bridge + * + * @param enable enabled if true */ - function enableBridge( - bool enable - ) external; + function enableBridge(bool enable) external; /** * @return true if bridge is enabled @@ -130,15 +104,10 @@ interface IStarklane { function isEnabled() external view returns (bool); /** - * + * * @param collectionL1 Collection address on L1 * @param collectionL2 Collection address on L2 * @param force Force flag */ - function setL1L2CollectionMapping( - address collectionL1, - snaddress collectionL2, - bool force - ) external; - + function setL1L2CollectionMapping(address collectionL1, snaddress collectionL2, bool force) external; } diff --git a/apps/blockchain/ethereum/src/IStarklaneEvent.sol b/apps/blockchain/ethereum/src/IStarklaneEvent.sol index 0815067f..2977540f 100644 --- a/apps/blockchain/ethereum/src/IStarklaneEvent.sol +++ b/apps/blockchain/ethereum/src/IStarklaneEvent.sol @@ -3,61 +3,38 @@ pragma solidity ^0.8.0; interface IStarklaneEvent { - /** - @notice Request initiated on L1. - */ - event DepositRequestInitiated( - uint256 indexed hash, - uint256 block_timestamp, - uint256[] reqContent - ); + * @notice Request initiated on L1. + */ + event DepositRequestInitiated(uint256 indexed hash, uint256 block_timestamp, uint256[] reqContent); /** - @notice Request from L2 completed. - */ - event WithdrawRequestCompleted( - uint256 indexed hash, - uint256 block_timestamp, - uint256[] reqContent - ); + * @notice Request from L2 completed. + */ + event WithdrawRequestCompleted(uint256 indexed hash, uint256 block_timestamp, uint256[] reqContent); /** - @notice A request cancellation is started - */ - event CancelRequestStarted( - uint256 indexed hash, - uint256 block_timestamp - ); + * @notice A request cancellation is started + */ + event CancelRequestStarted(uint256 indexed hash, uint256 block_timestamp); /** - @notice A request cancellation is completed - */ - event CancelRequestCompleted( - uint256 indexed hash, - uint256 block_timestamp - ); + * @notice A request cancellation is completed + */ + event CancelRequestCompleted(uint256 indexed hash, uint256 block_timestamp); /** - @notice White list for deposit. + * @notice White list for deposit. */ - event WhiteListUpdated( - bool enable - ); + event WhiteListUpdated(bool enable); /** - @notice White list status updated for collection. + * @notice White list status updated for collection. */ - event CollectionWhiteListUpdated( - address indexed collection, - bool enable - ); + event CollectionWhiteListUpdated(address indexed collection, bool enable); /** - @notice L1 L2 collection mapping updated + * @notice L1 L2 collection mapping updated */ - event L1L2CollectionMappingUpdated( - address indexed colllectionL1, - uint256 indexed collectionL2 - ); -} \ No newline at end of file + event L1L2CollectionMappingUpdated(address indexed colllectionL1, uint256 indexed collectionL2); +} diff --git a/apps/blockchain/ethereum/src/Messaging.sol b/apps/blockchain/ethereum/src/Messaging.sol index 9247407f..159634f8 100644 --- a/apps/blockchain/ethereum/src/Messaging.sol +++ b/apps/blockchain/ethereum/src/Messaging.sol @@ -15,18 +15,17 @@ error WithdrawMethodError(); error WithdrawAlreadyError(); /** - @title Contract responsible of withdrawing token from messaging. - - @dev If any message is configured to be withdraw with the auto methods, - then the regular starknet messaging will always be ignored and vice-versa. - - In solidity, when we query a mapping, if the key does not exist, 0 is returned when - the value is an uint256. - - For this reason, we use here a enum-like to ensure the correct state of the message. -*/ + * @title Contract responsible of withdrawing token from messaging. + * + * @dev If any message is configured to be withdraw with the auto methods, + * then the regular starknet messaging will always be ignored and vice-versa. + * + * In solidity, when we query a mapping, if the key does not exist, 0 is returned when + * the value is an uint256. + * + * For this reason, we use here a enum-like to ensure the correct state of the message. + */ contract StarklaneMessaging is Ownable { - // Messages sent directly from L2 indexer, that can be withdrawn with // the auto method. // @@ -38,18 +37,12 @@ contract StarklaneMessaging is Ownable { event MessageHashAutoWithdrawAdded(bytes32 msgHash); /** - @notice Adds the hash of a message that can be consumed with the auto - method. - - @param msgHash Hash of the message to be considered as consumable. - */ - function addMessageHashForAutoWithdraw( - uint256 msgHash - ) - external - payable - onlyOwner - { + * @notice Adds the hash of a message that can be consumed with the auto + * method. + * + * @param msgHash Hash of the message to be considered as consumable. + */ + function addMessageHashForAutoWithdraw(uint256 msgHash) external payable onlyOwner { bytes32 hash = bytes32(msgHash); if (_autoWithdrawn[hash] != WITHDRAW_AUTO_NONE) { @@ -61,23 +54,14 @@ contract StarklaneMessaging is Ownable { } /** - @notice Consumes a message with the Auto withdraw method. - - @param fromL2Address Address of the L2 contract that send the message. - @param request Request containing the tokens to withdraw. - */ - function _consumeMessageAutoWithdraw( - snaddress fromL2Address, - uint256[] memory request - ) - internal - { + * @notice Consumes a message with the Auto withdraw method. + * + * @param fromL2Address Address of the L2 contract that send the message. + * @param request Request containing the tokens to withdraw. + */ + function _consumeMessageAutoWithdraw(snaddress fromL2Address, uint256[] memory request) internal { bytes32 msgHash = keccak256( - abi.encodePacked( - snaddress.unwrap(fromL2Address), - uint256(uint160(address(this))), - request.length, - request) + abi.encodePacked(snaddress.unwrap(fromL2Address), uint256(uint160(address(this))), request.length, request) ); uint256 status = _autoWithdrawn[msgHash]; @@ -90,24 +74,17 @@ contract StarklaneMessaging is Ownable { } /** - @notice Consumes a message from Starknet core contract. - - @param starknetCore Address of the Starknet Core contract. - @param fromL2Address Address of the L2 contract that send the message. - @param request Request containing the tokens to withdraw. - */ - function _consumeMessageStarknet( - IStarknetMessaging starknetCore, - snaddress fromL2Address, - uint256[] memory request - ) + * @notice Consumes a message from Starknet core contract. + * + * @param starknetCore Address of the Starknet Core contract. + * @param fromL2Address Address of the L2 contract that send the message. + * @param request Request containing the tokens to withdraw. + */ + function _consumeMessageStarknet(IStarknetMessaging starknetCore, snaddress fromL2Address, uint256[] memory request) internal { // Will revert if the message is not consumable. - bytes32 msgHash = starknetCore.consumeMessageFromL2( - snaddress.unwrap(fromL2Address), - request - ); + bytes32 msgHash = starknetCore.consumeMessageFromL2(snaddress.unwrap(fromL2Address), request); // If the message were configured to be withdrawn with auto method, // starknet method is denied. @@ -115,6 +92,4 @@ contract StarklaneMessaging is Ownable { revert WithdrawMethodError(); } } - - } diff --git a/apps/blockchain/ethereum/src/Protocol.sol b/apps/blockchain/ethereum/src/Protocol.sol index bc727e64..f431097e 100644 --- a/apps/blockchain/ethereum/src/Protocol.sol +++ b/apps/blockchain/ethereum/src/Protocol.sol @@ -6,22 +6,18 @@ import "./sn/Cairo.sol"; import "./token/TokenUtil.sol"; /** - @notice Request to bridge tokens. -*/ + * @notice Request to bridge tokens. + */ struct Request { felt252 header; uint256 hash; - address collectionL1; snaddress collectionL2; - address ownerL1; snaddress ownerL2; - string name; string symbol; string uri; - uint256[] tokenIds; uint256[] tokenValues; string[] tokenURIs; @@ -31,10 +27,9 @@ struct Request { error CollectionTypeMaskUnsupported(); /** - @title Library related to the protocol for bridging tokens. -*/ + * @title Library related to the protocol for bridging tokens. + */ library Protocol { - // Byte 0 of the header: Version. uint256 private constant HEADER_V1 = 0x01; @@ -50,36 +45,24 @@ library Protocol { uint256 private constant WITHDRAW_AUTO = (0x01 << (8 * 3)); /** - @notice Verifies if the given header supports the withdraw auto. - - @return True if withdraw auto is supported, false otherwise. - */ - function canUseWithdrawAuto( - uint256 header - ) - internal - pure - returns (bool) - { + * @notice Verifies if the given header supports the withdraw auto. + * + * @return True if withdraw auto is supported, false otherwise. + */ + function canUseWithdrawAuto(uint256 header) internal pure returns (bool) { return (header & WITHDRAW_AUTO) == WITHDRAW_AUTO; } /** - @notice Retrieves the collection type from the header. - - @return Collection type found in the header. - */ - function collectionTypeFromHeader( - uint256 header - ) - internal - pure - returns (CollectionType) - { + * @notice Retrieves the collection type from the header. + * + * @return Collection type found in the header. + */ + function collectionTypeFromHeader(uint256 header) internal pure returns (CollectionType) { uint256 ct = header & COLLECTION_TYPE_MASK; if (ct == ERC721_TYPE) { return CollectionType.ERC721; - } else if (ct == ERC1155_TYPE) { + } else if (ct == ERC1155_TYPE) { return CollectionType.ERC1155; } else { revert CollectionTypeMaskUnsupported(); @@ -87,21 +70,17 @@ library Protocol { } /** - @notice Computes the V1 header value. - - @dev Header is a felt252 (31 bits). - Byte 0 is the version (0x1). - Byte 1 is the contract interface (0x1 = ERC721, 0x2 = ERC1155). - Byte 2 is the deposit config. - Byte 3 is the withdraw config. - - @param ctype The collection type. - */ - function requestHeaderV1( - CollectionType ctype, - bool useDepositAutoBurn, - bool useWithdrawAuto - ) + * @notice Computes the V1 header value. + * + * @dev Header is a felt252 (31 bits). + * Byte 0 is the version (0x1). + * Byte 1 is the contract interface (0x1 = ERC721, 0x2 = ERC1155). + * Byte 2 is the deposit config. + * Byte 3 is the withdraw config. + * + * @param ctype The collection type. + */ + function requestHeaderV1(CollectionType ctype, bool useDepositAutoBurn, bool useWithdrawAuto) internal pure returns (felt252) @@ -117,7 +96,7 @@ library Protocol { if (useDepositAutoBurn) { h |= DEPOSIT_AUTO_BURN; } - + if (useWithdrawAuto) { h |= WITHDRAW_AUTO; } @@ -126,21 +105,16 @@ library Protocol { } /** - @notice Computes the request hash. - - @param salt Random salt. - @param collection Token collection contract address (L1). - @param toL2Address New owner on Starknet (L2). - @param tokenIds List of token ids to be transfered. - - @return Request hash. - */ - function requestHash( - uint256 salt, - address collection, - snaddress toL2Address, - uint256[] memory tokenIds - ) + * @notice Computes the request hash. + * + * @param salt Random salt. + * @param collection Token collection contract address (L1). + * @param toL2Address New owner on Starknet (L2). + * @param tokenIds List of token ids to be transfered. + * + * @return Request hash. + */ + function requestHash(uint256 salt, address collection, snaddress toL2Address, uint256[] memory tokenIds) internal pure returns (uint256) @@ -160,19 +134,13 @@ library Protocol { } /** - @notice Computes the serialized length of a request. - - @param req Request of which the length is computed. - - @return Length of the uint256[] that can contain the serialized request. - */ - function requestSerializedLength( - Request memory req - ) - internal - pure - returns (uint256) - { + * @notice Computes the serialized length of a request. + * + * @param req Request of which the length is computed. + * + * @return Length of the uint256[] that can contain the serialized request. + */ + function requestSerializedLength(Request memory req) internal pure returns (uint256) { // Constant length part of the request is always 7 uint256 long. uint256 len = 7; @@ -197,20 +165,14 @@ library Protocol { } /** - @notice Serializes a bridge request into an array of uint256 - that is compatible with serialization expected by Starknet messaging. - - @param req Request to serialize. - - @return uint256[] with the serialized request. - */ - function requestSerialize( - Request memory req - ) - internal - pure - returns (uint256[] memory) - { + * @notice Serializes a bridge request into an array of uint256 + * that is compatible with serialization expected by Starknet messaging. + * + * @param req Request to serialize. + * + * @return uint256[] with the serialized request. + */ + function requestSerialize(Request memory req) internal pure returns (uint256[] memory) { uint256[] memory buf = new uint256[](requestSerializedLength(req)); // Constant length part of the request. @@ -239,21 +201,14 @@ library Protocol { } /** - @notice Deserializes a request from uint256[] from starknet messaging. - - @param buf Uint256[] buffer with the serialized request. - @param offset Offset in the buffer where deserialization starts. - - @return Request. - */ - function requestDeserialize( - uint256[] memory buf, - uint256 offset - ) - internal - pure - returns (Request memory) - { + * @notice Deserializes a request from uint256[] from starknet messaging. + * + * @param buf Uint256[] buffer with the serialized request. + * @param offset Offset in the buffer where deserialization starts. + * + * @return Request. + */ + function requestDeserialize(uint256[] memory buf, uint256 offset) internal pure returns (Request memory) { Request memory req; req.header = Cairo.felt252Wrap(buf[offset++]); @@ -291,5 +246,4 @@ library Protocol { return req; } - } diff --git a/apps/blockchain/ethereum/src/State.sol b/apps/blockchain/ethereum/src/State.sol index 1719a27c..ad7056a7 100644 --- a/apps/blockchain/ethereum/src/State.sol +++ b/apps/blockchain/ethereum/src/State.sol @@ -8,10 +8,9 @@ import "starknet/IStarknetMessaging.sol"; import "openzeppelin-contracts/contracts/access/Ownable.sol"; /** - @title Starklane state. -*/ + * @title Starklane state. + */ contract StarklaneState is Ownable { - // StarknetCore. IStarknetMessaging _starknetCoreAddress; @@ -22,46 +21,30 @@ contract StarklaneState is Ownable { felt252 _starklaneL2Selector; /** - @notice Retrieves info about Starklane L2 mapping. - - @return (starklane L2 address, starklane L2 selector). - */ - function l2Info() - external - view - returns (snaddress, felt252) - { + * @notice Retrieves info about Starklane L2 mapping. + * + * @return (starklane L2 address, starklane L2 selector). + */ + function l2Info() external view returns (snaddress, felt252) { return (_starklaneL2Address, _starklaneL2Selector); } /** - @notice Sets Starklane L2 address. - - @param l2Address Starklane L2 address. - */ - function setStarklaneL2Address( - uint256 l2Address - ) - public - onlyOwner - { + * @notice Sets Starklane L2 address. + * + * @param l2Address Starklane L2 address. + */ + function setStarklaneL2Address(uint256 l2Address) public onlyOwner { _starklaneL2Address = Cairo.snaddressWrap(l2Address); } /** - @notice Sets Starklane L2 selector of Starklane L2 contract to be - called when a message arrives into Starknet. - - @param l2Selector Starklane L2 selector. - */ - function setStarklaneL2Selector( - uint256 l2Selector - ) - public - onlyOwner - { + * @notice Sets Starklane L2 selector of Starklane L2 contract to be + * called when a message arrives into Starknet. + * + * @param l2Selector Starklane L2 selector. + */ + function setStarklaneL2Selector(uint256 l2Selector) public onlyOwner { _starklaneL2Selector = Cairo.felt252Wrap(l2Selector); } - - } diff --git a/apps/blockchain/ethereum/src/TestMessaging.sol b/apps/blockchain/ethereum/src/TestMessaging.sol index e69de29b..8b137891 100644 --- a/apps/blockchain/ethereum/src/TestMessaging.sol +++ b/apps/blockchain/ethereum/src/TestMessaging.sol @@ -0,0 +1 @@ + diff --git a/apps/blockchain/ethereum/src/UUPSProxied.sol b/apps/blockchain/ethereum/src/UUPSProxied.sol index 98918d54..eb42be86 100644 --- a/apps/blockchain/ethereum/src/UUPSProxied.sol +++ b/apps/blockchain/ethereum/src/UUPSProxied.sol @@ -9,10 +9,9 @@ error NotSupportedError(); error NotPayableError(); /** - @title Convenient contract to have ownable UUPS proxied contract. -*/ + * @title Convenient contract to have ownable UUPS proxied contract. + */ contract UUPSOwnableProxied is Ownable, UUPSUpgradeable { - // Mapping for implementations initialization. mapping(address implementation => bool initialized) _initializedImpls; @@ -26,34 +25,21 @@ contract UUPSOwnableProxied is Ownable, UUPSUpgradeable { } /** - @notice Only owner should be able to upgrade. - */ - function _authorizeUpgrade( - address - ) - internal - override - onlyOwner - { } + * @notice Only owner should be able to upgrade. + */ + function _authorizeUpgrade(address) internal override onlyOwner {} /** - @notice Ensures unsupported function is directly reverted. - */ - fallback() - external - payable - { - revert NotSupportedError(); - } + * @notice Ensures unsupported function is directly reverted. + */ + fallback() external payable { + revert NotSupportedError(); + } /** - @notice Ensures no ether is received without a function call. - */ - receive() - external - payable - { - revert NotPayableError(); - } + * @notice Ensures no ether is received without a function call. + */ + receive() external payable { + revert NotPayableError(); + } } - diff --git a/apps/blockchain/ethereum/src/sn/Cairo.sol b/apps/blockchain/ethereum/src/sn/Cairo.sol index 519f830d..66eb3fa0 100644 --- a/apps/blockchain/ethereum/src/sn/Cairo.sol +++ b/apps/blockchain/ethereum/src/sn/Cairo.sol @@ -5,6 +5,7 @@ pragma solidity ^0.8.8; import "openzeppelin-contracts/contracts/utils/Strings.sol"; type felt252 is uint256; + type snaddress is uint256; // TODO: add offset / array size checks for serialization. @@ -17,8 +18,7 @@ type snaddress is uint256; https://github.com/starkware-libs/cairo/blob/08efd7158bf1ef012fa6b42b3429a398e1a75e26/crates/cairo-lang-runner/src/casm_run/mod.rs#L52 2 251 + 17 2 192 + 1; */ -uint256 constant SN_MODULUS = - 3618502788666131213697322783095070105623107215331596699973092056135872020481; +uint256 constant SN_MODULUS = 3618502788666131213697322783095070105623107215331596699973092056135872020481; /* Cairo Short String are 31 characters long. @@ -32,49 +32,36 @@ uint256 constant CAIRO_STR_LEN = 31; error CairoWrapError(); /** - @title Adapter library to ensure compatibility with Cairo. - - Cairo works with felts (252 bits), so a felt always fits into a single uint256, - but a uint256 may overflow. - To convert a uint256 into a felt, the first 6 bits must be cleared. -*/ + * @title Adapter library to ensure compatibility with Cairo. + * + * Cairo works with felts (252 bits), so a felt always fits into a single uint256, + * but a uint256 may overflow. + * To convert a uint256 into a felt, the first 6 bits must be cleared. + */ library Cairo { - /** - @notice Verifies if the given uint256 can be considered - as a felt252. - - @param val Value to be checked as a felt252. - - @return True if the value can fit into a felt252, false otherwise. - */ - function isFelt252( - uint256 val - ) - internal - pure - returns (bool) - { + * @notice Verifies if the given uint256 can be considered + * as a felt252. + * + * @param val Value to be checked as a felt252. + * + * @return True if the value can fit into a felt252, false otherwise. + */ + function isFelt252(uint256 val) internal pure returns (bool) { return val < SN_MODULUS; } /** - @notice Wraps an uint256 into a felt252. - Ensures that the val can fit into a felt252. - - @param val Value to be wrapped. - - @return felt252 with wrapped value. - - @dev Reverts if val is too large for felt252. + * @notice Wraps an uint256 into a felt252. + * Ensures that the val can fit into a felt252. + * + * @param val Value to be wrapped. + * + * @return felt252 with wrapped value. + * + * @dev Reverts if val is too large for felt252. */ - function felt252Wrap( - uint256 val - ) - internal - pure - returns (felt252) - { + function felt252Wrap(uint256 val) internal pure returns (felt252) { if (!isFelt252(val)) { revert CairoWrapError(); } @@ -83,22 +70,16 @@ library Cairo { } /** - @notice Wraps an uint256 into a snaddress. - Ensures that the val can fit into a felt252. - - @param val Value to be wrapped. - - @return snaddress with wrapped value. - - @dev Reverts if val is too large for felt252. - */ - function snaddressWrap( - uint256 val - ) - internal - pure - returns (snaddress) - { + * @notice Wraps an uint256 into a snaddress. + * Ensures that the val can fit into a felt252. + * + * @param val Value to be wrapped. + * + * @return snaddress with wrapped value. + * + * @dev Reverts if val is too large for felt252. + */ + function snaddressWrap(uint256 val) internal pure returns (snaddress) { if (!isFelt252(val)) { revert CairoWrapError(); } @@ -107,62 +88,43 @@ library Cairo { } /** - @notice Serializes the given uint256 as a felt252 (low and high parts). - - @param val Value to be serialized. - @param buf Buffer where serialized form is saved. - @param offset Offset in `buf` where serialization must start. - - @return Offset increment applied to serialize the value. - */ - function uint256Serialize( - uint256 val, - uint256[] memory buf, - uint256 offset - ) - internal - pure - returns (uint256) - { + * @notice Serializes the given uint256 as a felt252 (low and high parts). + * + * @param val Value to be serialized. + * @param buf Buffer where serialized form is saved. + * @param offset Offset in `buf` where serialization must start. + * + * @return Offset increment applied to serialize the value. + */ + function uint256Serialize(uint256 val, uint256[] memory buf, uint256 offset) internal pure returns (uint256) { buf[offset] = uint128(val); buf[offset + 1] = uint128(val >> 128); return 2; } /** - @notice Deserializes an uint256 from the given buffer. - - @param buf Buffer where data is serialized. - @param offset Offset in `buf` where deserialization must start. - - @return The deserialized value. - */ - function uint256Deserialize( - uint256[] memory buf, - uint256 offset - ) - internal - pure - returns (uint256) - { + * @notice Deserializes an uint256 from the given buffer. + * + * @param buf Buffer where data is serialized. + * @param offset Offset in `buf` where deserialization must start. + * + * @return The deserialized value. + */ + function uint256Deserialize(uint256[] memory buf, uint256 offset) internal pure returns (uint256) { // u256 in cairo is 2 felts long with low and high parts. return (buf[offset + 1] << 128) | uint128(buf[offset]); } /** - @notice Serializes an array of uint256. - - @param arr Array to be serialized. - @param buf Buffer where serialized form is saved. - @param offset Offset in `buf` where serialization must start. - - @return Offset increment applied to serialize the value. - */ - function uint256ArraySerialize( - uint256[] memory arr, - uint256[] memory buf, - uint256 offset - ) + * @notice Serializes an array of uint256. + * + * @param arr Array to be serialized. + * @param buf Buffer where serialized form is saved. + * @param offset Offset in `buf` where serialization must start. + * + * @return Offset increment applied to serialize the value. + */ + function uint256ArraySerialize(uint256[] memory arr, uint256[] memory buf, uint256 offset) internal pure returns (uint256) @@ -181,19 +143,15 @@ library Cairo { } /** - @notice Serializes an array of addresses. - - @param arr Array of addresses to be serialized. - @param buf Buffer where serialized form is saved. - @param offset Offset in `buf` where serialization must start. - - @return Offset increment applied to serialize the value. - */ - function addressArraySerialize( - address[] memory arr, - uint256[] memory buf, - uint256 offset - ) + * @notice Serializes an array of addresses. + * + * @param arr Array of addresses to be serialized. + * @param buf Buffer where serialized form is saved. + * @param offset Offset in `buf` where serialization must start. + * + * @return Offset increment applied to serialize the value. + */ + function addressArraySerialize(address[] memory arr, uint256[] memory buf, uint256 offset) internal pure returns (uint256) @@ -211,19 +169,15 @@ library Cairo { return _offset - offset; } - /** - @notice Deserializes an array of uint256 from the given buffer. - - @param buf Buffer where data is serialized. - @param offset Offset in `buf` where deserialization must start. - - @return The offset increment applied to deserialize and the deserialized value. - */ - function uint256ArrayDeserialize( - uint256[] memory buf, - uint256 offset - ) + * @notice Deserializes an array of uint256 from the given buffer. + * + * @param buf Buffer where data is serialized. + * @param offset Offset in `buf` where deserialization must start. + * + * @return The offset increment applied to deserialize and the deserialized value. + */ + function uint256ArrayDeserialize(uint256[] memory buf, uint256 offset) internal pure returns (uint256, uint256[] memory) @@ -241,24 +195,15 @@ library Cairo { return ((len * 2) + 1, uints); } - - /** - @notice Unpacks a cairo string (byte array) into a string. - - @param buf Buffer where the string is packed as a cairo string. - @param offset Offset where the unpack must start. - - @return Unpacked string. + * @notice Unpacks a cairo string (byte array) into a string. + * + * @param buf Buffer where the string is packed as a cairo string. + * @param offset Offset where the unpack must start. + * + * @return Unpacked string. */ - function cairoStringUnpack( - uint256[] memory buf, - uint256 offset - ) - internal - pure - returns (string memory) - { + function cairoStringUnpack(uint256[] memory buf, uint256 offset) internal pure returns (string memory) { string memory s; uint256 dataLen = buf[offset]; offset += 1; @@ -266,7 +211,7 @@ library Cairo { s = string.concat(s, uint256AsciiNbcharsToString(buf[i], uint8(CAIRO_STR_LEN))); } offset += dataLen; - + // handle pending word uint8 nbChars = uint8(buf[offset + 1] & 0xFF); s = string.concat(s, uint256AsciiNbcharsToString(buf[offset], nbChars)); @@ -274,24 +219,18 @@ library Cairo { } /** - @notice Packs a string into an array of uint256 (Cairo byte array string) - - @dev Cairo (byte array) string are chunk by 31 bytes. + * @notice Packs a string into an array of uint256 (Cairo byte array string) + * + * @dev Cairo (byte array) string are chunk by 31 bytes. */ - function cairoStringPack( - string memory str - ) - internal - pure - returns (uint256[] memory) - { + function cairoStringPack(string memory str) internal pure returns (uint256[] memory) { bytes memory strBytes = bytes(str); uint256 dataLen = strBytes.length / CAIRO_STR_LEN; uint256 pendingLen = strBytes.length % CAIRO_STR_LEN; uint256 packedLen = 1 + dataLen + 1 + 1; uint256[] memory packedData = new uint256[](packedLen); - + uint256 index = 0; uint256 v; uint256 offset = 0x20; // length is first u256 @@ -299,11 +238,11 @@ library Cairo { packedData[index] = dataLen; index++; - for (uint256 i = 0; i < dataLen; i ++) { - assembly { - v := mload(add(strBytes, offset)) + for (uint256 i = 0; i < dataLen; i++) { + assembly { + v := mload(add(strBytes, offset)) v := shr(8, v) - } + } packedData[index] = v; index++; @@ -311,11 +250,11 @@ library Cairo { } // pending word - assembly { + assembly { v := mload(add(strBytes, offset)) - v := shr(mul(sub(32, pendingLen), 8),v) + v := shr(mul(sub(32, pendingLen), 8), v) } - + packedData[index] = v; index++; @@ -325,17 +264,14 @@ library Cairo { } /** - @notice Deserializes a cairo (byte array) string from the given buffer - - @param buf Buffer where data is serialized. - @param offset Offset in `buf` where deserialization must start. - - @return The offset increment applied to deserialize and the deserialized value. - */ - function cairoStringDeserialize( - uint256[] memory buf, - uint256 offset - ) + * @notice Deserializes a cairo (byte array) string from the given buffer + * + * @param buf Buffer where data is serialized. + * @param offset Offset in `buf` where deserialization must start. + * + * @return The offset increment applied to deserialize and the deserialized value. + */ + function cairoStringDeserialize(uint256[] memory buf, uint256 offset) internal pure returns (uint256, string memory) @@ -346,23 +282,19 @@ library Cairo { } /** - @notice Deserialize a cairo address array from the given buffer - - @param buf Buffer where data is serialized - @param offset Offset in 'buf' where deserialization must start - - @return The offset increment applied to deserialize and the deserialized value. - */ - - function cairoAddressArrayDeserialize( - uint256[] memory buf, - uint256 offset - ) + * @notice Deserialize a cairo address array from the given buffer + * + * @param buf Buffer where data is serialized + * @param offset Offset in 'buf' where deserialization must start + * + * @return The offset increment applied to deserialize and the deserialized value. + */ + function cairoAddressArrayDeserialize(uint256[] memory buf, uint256 offset) internal pure returns (uint256, address[] memory) { - uint256 len = buf[offset++]; + uint256 len = buf[offset++]; address[] memory result = new address[](len); for (uint256 i = 0; i < len; i++) { @@ -372,18 +304,12 @@ library Cairo { return (offset, result); } - /** - @notice Commputes the length of the packed cairo string. - - @dev Same schema as Cairo byteArray serialize. - */ - function cairoStringSerializedLength( - string memory str - ) - internal - pure - returns (uint256) - { + /** + * @notice Commputes the length of the packed cairo string. + * + * @dev Same schema as Cairo byteArray serialize. + */ + function cairoStringSerializedLength(string memory str) internal pure returns (uint256) { bytes memory strBytes = bytes(str); uint256 dataLen = strBytes.length / CAIRO_STR_LEN; uint256 packedLen = 1 + dataLen + 1 + 1; @@ -391,19 +317,15 @@ library Cairo { } /** - @notice Serializes a string into a cairo (byte array) string. - - @param str String to be serialized. - @param buf Buffer where serialized form is saved. - @param offset Offset in `buf` where serialization must start. - - @return Offset increment applied to serialize the value. + * @notice Serializes a string into a cairo (byte array) string. + * + * @param str String to be serialized. + * @param buf Buffer where serialized form is saved. + * @param offset Offset in `buf` where serialization must start. + * + * @return Offset increment applied to serialize the value. */ - function cairoStringSerialize( - string memory str, - uint256[] memory buf, - uint256 offset - ) + function cairoStringSerialize(string memory str, uint256[] memory buf, uint256 offset) internal pure returns (uint256) @@ -416,19 +338,15 @@ library Cairo { } /** - @notice Serializes an array for strings as cairo array of strings. - - @param arr Array to be serialized. - @param buf Buffer where serialized form is saved. - @param offset Offset in `buf` where serialization must start. - - @return Offset increment applied to serialize the value. + * @notice Serializes an array for strings as cairo array of strings. + * + * @param arr Array to be serialized. + * @param buf Buffer where serialized form is saved. + * @param offset Offset in `buf` where serialization must start. + * + * @return Offset increment applied to serialize the value. */ - function cairoStringArraySerialize( - string[] memory arr, - uint256[] memory buf, - uint256 offset - ) + function cairoStringArraySerialize(string[] memory arr, uint256[] memory buf, uint256 offset) internal pure returns (uint256) @@ -445,17 +363,14 @@ library Cairo { } /** - @notice Deserializes an array of cairo strin from the given buffer. - - @param buf Buffer where data is serialized. - @param offset Offset in `buf` where deserialization must start. - - @return The offset increment applied to deserialize and the deserialized value. + * @notice Deserializes an array of cairo strin from the given buffer. + * + * @param buf Buffer where data is serialized. + * @param offset Offset in `buf` where deserialization must start. + * + * @return The offset increment applied to deserialize and the deserialized value. */ - function cairoStringArrayDeserialize( - uint256[] memory buf, - uint256 offset - ) + function cairoStringArrayDeserialize(uint256[] memory buf, uint256 offset) internal pure returns (uint256, string[] memory) @@ -466,10 +381,7 @@ library Cairo { string[] memory strs = new string[](len); for (uint256 i = 0; i < len; i++) { - ( - uint256 inc, - string memory s - ) = cairoStringDeserialize(buf, _offset); + (uint256 inc, string memory s) = cairoStringDeserialize(buf, _offset); _offset += inc; strs[i] = s; @@ -479,29 +391,16 @@ library Cairo { } /** - @notice Converts an uint256 containing ascii characters - as a string. - - @param value String from ascii characters. - */ - function uint256AsciiToString( - uint256 value - ) - internal - pure - returns (string memory) - { + * @notice Converts an uint256 containing ascii characters + * as a string. + * + * @param value String from ascii characters. + */ + function uint256AsciiToString(uint256 value) internal pure returns (string memory) { return uint256AsciiNbcharsToString(value, uint8(CAIRO_STR_LEN)); } - function uint256AsciiNbcharsToString( - uint256 value, - uint8 length - ) - internal - pure - returns (string memory) - { + function uint256AsciiNbcharsToString(uint256 value, uint8 length) internal pure returns (string memory) { string memory s = new string(length); bytes memory byteString = bytes(s); @@ -513,6 +412,4 @@ library Cairo { return s; } - - } diff --git a/apps/blockchain/ethereum/src/sn/IStarknetMessagingLocal.sol b/apps/blockchain/ethereum/src/sn/IStarknetMessagingLocal.sol index 81a2dfcf..fe6eae22 100644 --- a/apps/blockchain/ethereum/src/sn/IStarknetMessagingLocal.sol +++ b/apps/blockchain/ethereum/src/sn/IStarknetMessagingLocal.sol @@ -5,16 +5,9 @@ pragma solidity ^0.8.0; /** */ interface IStarknetMessagingLocal { - /** */ - function addMessageHashesFromL2( - uint256[] calldata msgHashes - ) - external - payable; + function addMessageHashesFromL2(uint256[] calldata msgHashes) external payable; - function setMessageCancellationDelay( - uint256 delayInSeconds - ) external; + function setMessageCancellationDelay(uint256 delayInSeconds) external; } diff --git a/apps/blockchain/ethereum/src/sn/StarknetMessagingLocal.sol b/apps/blockchain/ethereum/src/sn/StarknetMessagingLocal.sol index 4431ef34..253cd088 100644 --- a/apps/blockchain/ethereum/src/sn/StarknetMessagingLocal.sol +++ b/apps/blockchain/ethereum/src/sn/StarknetMessagingLocal.sol @@ -4,37 +4,29 @@ pragma solidity ^0.8.0; import "starknet/StarknetMessaging.sol"; /** - @title A superset of StarknetMessaging to support - local development by adding a way to directly register - a message hash ready to be consumed, without waiting the block - to be verified. - - @dev The idea is that, to now wait on the block to be proved, - this messaging contract can receive directly a hash of a message - to be considered as `received`. This message can then be consumed. - - The goal of this contract is local development only. -*/ + * @title A superset of StarknetMessaging to support + * local development by adding a way to directly register + * a message hash ready to be consumed, without waiting the block + * to be verified. + * + * @dev The idea is that, to now wait on the block to be proved, + * this messaging contract can receive directly a hash of a message + * to be considered as `received`. This message can then be consumed. + * + * The goal of this contract is local development only. + */ contract StarknetMessagingLocal is StarknetMessaging { - - /** - @notice Hashes were added. - */ - event MessageHashesAddedFromL2( - uint256[] hashes - ); - /** - @notice Adds the hashes of messages from L2. + * @notice Hashes were added. + */ + event MessageHashesAddedFromL2(uint256[] hashes); - @param msgHashes Hashes to register as consumable. - */ - function addMessageHashesFromL2( - uint256[] calldata msgHashes - ) - external - payable - { + /** + * @notice Adds the hashes of messages from L2. + * + * @param msgHashes Hashes to register as consumable. + */ + function addMessageHashesFromL2(uint256[] calldata msgHashes) external payable { // TODO: You can add here a whitelist of senders if you wish. for (uint256 i = 0; i < msgHashes.length; i++) { bytes32 hash = bytes32(msgHashes[i]); @@ -44,10 +36,8 @@ contract StarknetMessagingLocal is StarknetMessaging { emit MessageHashesAddedFromL2(msgHashes); } - // expose internal for testing purpose function setMessageCancellationDelay(uint256 delayInSeconds) external { messageCancellationDelay(delayInSeconds); } - } diff --git a/apps/blockchain/ethereum/src/token/CollectionManager.sol b/apps/blockchain/ethereum/src/token/CollectionManager.sol index ec9429aa..b21ad993 100644 --- a/apps/blockchain/ethereum/src/token/CollectionManager.sol +++ b/apps/blockchain/ethereum/src/token/CollectionManager.sol @@ -13,10 +13,9 @@ error ErrorVerifyingAddressMapping(); error CollectionMappingAlreadySet(); /** - @title Collection manager to verify collection address matching and deploy them. -*/ + * @title Collection manager to verify collection address matching and deploy them. + */ contract CollectionManager { - // Mapping between L2<->L1 contracts addresses. mapping(snaddress => address) _l2ToL1Addresses; @@ -24,34 +23,26 @@ contract CollectionManager { mapping(address => snaddress) _l1ToL2Addresses; /** - @notice A collection has been deployed due to the - first token being bridged from L2. - - TODO: add the name and symbol here? + * @notice A collection has been deployed due to the + * first token being bridged from L2. + * + * TODO: add the name and symbol here? */ event CollectionDeployedFromL2( - uint256 indexed reqHash, - uint256 block_timestamp, - address l1Address, - uint256 l2Address + uint256 indexed reqHash, uint256 block_timestamp, address l1Address, uint256 l2Address ); /** - @notice Deploys ERC721Bridgeable contracts. - - @param name Descriptive name of the collection. - @param symbol Abbreviated name of the collection. - @param collectionL2 The collection's address on L2. - @param reqHash Hash of the request. - - @return Address of the ERC721Bridgeable deployed (proxy address). - */ - function _deployERC721Bridgeable( - string memory name, - string memory symbol, - snaddress collectionL2, - uint256 reqHash - ) + * @notice Deploys ERC721Bridgeable contracts. + * + * @param name Descriptive name of the collection. + * @param symbol Abbreviated name of the collection. + * @param collectionL2 The collection's address on L2. + * @param reqHash Hash of the request. + * + * @return Address of the ERC721Bridgeable deployed (proxy address). + */ + function _deployERC721Bridgeable(string memory name, string memory symbol, snaddress collectionL2, uint256 reqHash) internal returns (address) { @@ -59,30 +50,21 @@ contract CollectionManager { _l1ToL2Addresses[proxy] = collectionL2; _l2ToL1Addresses[collectionL2] = proxy; - emit CollectionDeployedFromL2( - reqHash, - block.timestamp, - proxy, - snaddress.unwrap(collectionL2) - ); + emit CollectionDeployedFromL2(reqHash, block.timestamp, proxy, snaddress.unwrap(collectionL2)); return proxy; } /** - @notice Deploys ERC1155Bridgeable contracts. - - @param uri URI with token placeholder. - @param collectionL2 The collection's address on L2. - @param reqHash Hash of the request. - - @return Address of the ERC1155Bridgeable deployed (proxy address). - */ - function _deployERC1155Bridgeable( - string memory uri, - snaddress collectionL2, - uint256 reqHash - ) + * @notice Deploys ERC1155Bridgeable contracts. + * + * @param uri URI with token placeholder. + * @param collectionL2 The collection's address on L2. + * @param reqHash Hash of the request. + * + * @return Address of the ERC1155Bridgeable deployed (proxy address). + */ + function _deployERC1155Bridgeable(string memory uri, snaddress collectionL2, uint256 reqHash) internal returns (address) { @@ -90,28 +72,20 @@ contract CollectionManager { _l1ToL2Addresses[proxy] = collectionL2; _l2ToL1Addresses[collectionL2] = proxy; - emit CollectionDeployedFromL2( - reqHash, - block.timestamp, - proxy, - snaddress.unwrap(collectionL2) - ); + emit CollectionDeployedFromL2(reqHash, block.timestamp, proxy, snaddress.unwrap(collectionL2)); return proxy; } /** - @notice Verifies the mapping between the request addresses and the storage. - - @param collectionL1Req The collection on L1 from the request. - @param collectionL2Req The collection on L2 from the request. - - @return Address of the already deployed collection on L1, address(0) otherwise. - */ - function _verifyRequestAddresses( - address collectionL1Req, - snaddress collectionL2Req - ) + * @notice Verifies the mapping between the request addresses and the storage. + * + * @param collectionL1Req The collection on L1 from the request. + * @param collectionL2Req The collection on L2 from the request. + * + * @return Address of the already deployed collection on L1, address(0) otherwise. + */ + function _verifyRequestAddresses(address collectionL1Req, snaddress collectionL2Req) internal view returns (address) @@ -148,21 +122,15 @@ contract CollectionManager { revert ErrorVerifyingAddressMapping(); } - function _setL1L2AddressMapping( - address collectionL1, - snaddress collectionL2, - bool force - ) - internal - { - if (((snaddress.unwrap(_l1ToL2Addresses[collectionL1]) == 0) && (_l2ToL1Addresses[collectionL2] == address(0))) - || (force == true)) { + function _setL1L2AddressMapping(address collectionL1, snaddress collectionL2, bool force) internal { + if ( + ((snaddress.unwrap(_l1ToL2Addresses[collectionL1]) == 0) && (_l2ToL1Addresses[collectionL2] == address(0))) + || (force == true) + ) { _l1ToL2Addresses[collectionL1] = collectionL2; _l2ToL1Addresses[collectionL2] = collectionL1; } else { revert CollectionMappingAlreadySet(); } } - } - diff --git a/apps/blockchain/ethereum/src/token/Deployer.sol b/apps/blockchain/ethereum/src/token/Deployer.sol index 94c8022d..b0932e84 100644 --- a/apps/blockchain/ethereum/src/token/Deployer.sol +++ b/apps/blockchain/ethereum/src/token/Deployer.sol @@ -8,54 +8,36 @@ import "./ERC721Bridgeable.sol"; import "./ERC1155Bridgeable.sol"; /** - @title Collection contract deployer. -*/ + * @title Collection contract deployer. + */ library Deployer { - /** - @notice Deploys a UUPS proxied ERC721 contract. - - @param name Descriptive name for the token collection. - @param symbol Abbreviated name for the token collection. - - @return Address of the proxy. - */ - function deployERC721Bridgeable( - string memory name, - string memory symbol - ) - public - returns (address) - { + * @notice Deploys a UUPS proxied ERC721 contract. + * + * @param name Descriptive name for the token collection. + * @param symbol Abbreviated name for the token collection. + * + * @return Address of the proxy. + */ + function deployERC721Bridgeable(string memory name, string memory symbol) public returns (address) { address impl = address(new ERC721Bridgeable()); - - bytes memory dataInit = abi.encodeWithSelector( - ERC721Bridgeable.initialize.selector, - abi.encode(name, symbol) - ); + + bytes memory dataInit = abi.encodeWithSelector(ERC721Bridgeable.initialize.selector, abi.encode(name, symbol)); return address(new ERC1967Proxy(impl, dataInit)); } /** - @notice Deploys a UUPS proxied ERC1155 contract. - - @param uri URI with token id placeholder. - - @return Address of the proxy. - */ - function deployERC1155Bridgeable( - string memory uri - ) - public - returns (address) - { + * @notice Deploys a UUPS proxied ERC1155 contract. + * + * @param uri URI with token id placeholder. + * + * @return Address of the proxy. + */ + function deployERC1155Bridgeable(string memory uri) public returns (address) { address impl = address(new ERC1155Bridgeable()); - - bytes memory dataInit = abi.encodeWithSelector( - ERC1155Bridgeable.initialize.selector, - abi.encode(uri) - ); + + bytes memory dataInit = abi.encodeWithSelector(ERC1155Bridgeable.initialize.selector, abi.encode(uri)); return address(new ERC1967Proxy(impl, dataInit)); } diff --git a/apps/blockchain/ethereum/src/token/ERC1155Bridgeable.sol b/apps/blockchain/ethereum/src/token/ERC1155Bridgeable.sol index 2647c81f..67214e24 100644 --- a/apps/blockchain/ethereum/src/token/ERC1155Bridgeable.sol +++ b/apps/blockchain/ethereum/src/token/ERC1155Bridgeable.sol @@ -9,32 +9,24 @@ import "./IERC1155Bridgeable.sol"; import "../UUPSProxied.sol"; /** - @title ERC1155 that can be minted by the bridge. - - @dev As this ERC1155 must be upgradable, the name and symbol must - be overriden to work correctly, as the constructor can't be called, - but initialization function instead. -*/ + * @title ERC1155 that can be minted by the bridge. + * + * @dev As this ERC1155 must be upgradable, the name and symbol must + * be overriden to work correctly, as the constructor can't be called, + * but initialization function instead. + */ contract ERC1155Bridgeable is ERC1155Supply, UUPSOwnableProxied, IERC1155Bridgeable { - /** - @notice Default constructor, but intialize is used instead. - */ - constructor() - ERC1155("") - { } + * @notice Default constructor, but intialize is used instead. + */ + constructor() ERC1155("") {} /** - @notice Initializes the implementation, only callable once. - - @param data Data to init the implementation. - */ - function initialize( - bytes calldata data - ) - public - onlyInit - { + * @notice Initializes the implementation, only callable once. + * + * @param data Data to init the implementation. + */ + function initialize(bytes calldata data) public onlyInit { (string memory uri_) = abi.decode(data, (string)); _setURI(uri_); @@ -43,54 +35,33 @@ contract ERC1155Bridgeable is ERC1155Supply, UUPSOwnableProxied, IERC1155Bridgea } /** - @notice A free mint for testing. - - @param to The new owner. - @param id The token type to mint. - @param value Amount of the token. - */ - function mintFree( - address to, - uint256 id, - uint256 value - ) - external - { + * @notice A free mint for testing. + * + * @param to The new owner. + * @param id The token type to mint. + * @param value Amount of the token. + */ + function mintFree(address to, uint256 id, uint256 value) external { _mint(to, id, value, ""); } /** - @inheritdoc IERC1155Bridgeable - - @dev In this implementation, the owner is the bridge by default. So `onlyOwner` - is enough. - */ - function mintFromBridge( - address to, - uint256 id, - uint256 value - ) - public - onlyOwner - { + * @inheritdoc IERC1155Bridgeable + * + * @dev In this implementation, the owner is the bridge by default. So `onlyOwner` + * is enough. + */ + function mintFromBridge(address to, uint256 id, uint256 value) public onlyOwner { _mint(to, id, value, ""); } /** - @inheritdoc IERC1155Bridgeable - - @dev In this implementation, the owner is the bridge by default. So `onlyOwner` - is enough. - */ - function burnFromBridge( - address from, - uint256 id, - uint256 value - ) - public - onlyOwner - { + * @inheritdoc IERC1155Bridgeable + * + * @dev In this implementation, the owner is the bridge by default. So `onlyOwner` + * is enough. + */ + function burnFromBridge(address from, uint256 id, uint256 value) public onlyOwner { _burn(from, id, value); } - } diff --git a/apps/blockchain/ethereum/src/token/ERC721Bridgeable.sol b/apps/blockchain/ethereum/src/token/ERC721Bridgeable.sol index 2fa639ce..28c26f76 100644 --- a/apps/blockchain/ethereum/src/token/ERC721Bridgeable.sol +++ b/apps/blockchain/ethereum/src/token/ERC721Bridgeable.sol @@ -8,14 +8,13 @@ import "./IERC721Bridgeable.sol"; import "../UUPSProxied.sol"; /** - @title ERC721 that can be minted by the bridge. - - @dev As this ERC721 must be upgradable, the name and symbol must - be overriden to work correctly, as the constructor can't be called, - but initialization function instead. -*/ + * @title ERC721 that can be minted by the bridge. + * + * @dev As this ERC721 must be upgradable, the name and symbol must + * be overriden to work correctly, as the constructor can't be called, + * but initialization function instead. + */ contract ERC721Bridgeable is ERC721, UUPSOwnableProxied, IERC721Bridgeable { - // Descriptive name for the token collection. string private _name; @@ -23,23 +22,16 @@ contract ERC721Bridgeable is ERC721, UUPSOwnableProxied, IERC721Bridgeable { string private _symbol; /** - @notice Default constructor, but intialize is used instead. - */ - constructor() - ERC721("", "") - { } + * @notice Default constructor, but intialize is used instead. + */ + constructor() ERC721("", "") {} /** - @notice Initializes the implementation, only callable once. - - @param data Data to init the implementation. - */ - function initialize( - bytes calldata data - ) - public - onlyInit - { + * @notice Initializes the implementation, only callable once. + * + * @param data Data to init the implementation. + */ + function initialize(bytes calldata data) public onlyInit { (string memory n, string memory s) = abi.decode(data, (string, string)); _name = n; @@ -49,74 +41,53 @@ contract ERC721Bridgeable is ERC721, UUPSOwnableProxied, IERC721Bridgeable { } /** - @inheritdoc IERC721Bridgeable - - @dev In this implementation, the owner is the bridge by default. So `onlyOwner` - is enough. - */ - function mintFromBridge(address to, uint256 id) - public - onlyOwner { - + * @inheritdoc IERC721Bridgeable + * + * @dev In this implementation, the owner is the bridge by default. So `onlyOwner` + * is enough. + */ + function mintFromBridge(address to, uint256 id) public onlyOwner { _mint(to, id); } /** - @inheritdoc IERC721Bridgeable - - @dev In this implementation, the owner is the bridge by default. So `onlyOwner` - is enough. - */ - function burnFromBridge(uint256 id) - public - onlyOwner { - + * @inheritdoc IERC721Bridgeable + * + * @dev In this implementation, the owner is the bridge by default. So `onlyOwner` + * is enough. + */ + function burnFromBridge(uint256 id) public onlyOwner { _burn(id); } /** - @notice base URI for the tokens. - - @dev By default empty, or perhaps we can target a default URI? - */ - function _baseURI() - internal - pure - override - returns (string memory) { + * @notice base URI for the tokens. + * + * @dev By default empty, or perhaps we can target a default URI? + */ + function _baseURI() internal pure override returns (string memory) { return ""; } /** - @notice A descriptive name for the token collection. - - @dev `name()` must be overriden as the underlying value - is private, then not accessible for this contract (which extends - the base ERC721 contract). - */ - function name() - public - view - override - returns (string memory) - { + * @notice A descriptive name for the token collection. + * + * @dev `name()` must be overriden as the underlying value + * is private, then not accessible for this contract (which extends + * the base ERC721 contract). + */ + function name() public view override returns (string memory) { return _name; } /** - @notice An abbreviated name for the token collection. - - @dev `symbol()` must be overriden as the underlying value - is private, then not accessible for this contract (which extends - the base ERC721 contract). - */ - function symbol() - public - view - override - returns (string memory) - { + * @notice An abbreviated name for the token collection. + * + * @dev `symbol()` must be overriden as the underlying value + * is private, then not accessible for this contract (which extends + * the base ERC721 contract). + */ + function symbol() public view override returns (string memory) { return _symbol; } } - diff --git a/apps/blockchain/ethereum/src/token/IERC1155Bridgeable.sol b/apps/blockchain/ethereum/src/token/IERC1155Bridgeable.sol index e6bfcca7..e2860449 100644 --- a/apps/blockchain/ethereum/src/token/IERC1155Bridgeable.sol +++ b/apps/blockchain/ethereum/src/token/IERC1155Bridgeable.sol @@ -3,31 +3,27 @@ pragma solidity ^0.8.0; /** - @title ERC1155Bridgeable token. - - @notice This interface allows a contract to expose functions - that allows a bridge to mint and burn token. -*/ + * @title ERC1155Bridgeable token. + * + * @notice This interface allows a contract to expose functions + * that allows a bridge to mint and burn token. + */ interface IERC1155Bridgeable { - /** - @notice Mints a token from the bridge. - - @param to The new owner. - @param id The token type to mint. - @param value Amount of the token. - */ - function mintFromBridge(address to, uint256 id, uint256 value) - external; + * @notice Mints a token from the bridge. + * + * @param to The new owner. + * @param id The token type to mint. + * @param value Amount of the token. + */ + function mintFromBridge(address to, uint256 id, uint256 value) external; /** - @notice Burns a token from the bridge. - - @param from The owner burning tokens. - @param id The token type to burn. - @param value Amount to burn. - */ - function burnFromBridge(address from, uint256 id, uint256 value) - external; - + * @notice Burns a token from the bridge. + * + * @param from The owner burning tokens. + * @param id The token type to burn. + * @param value Amount to burn. + */ + function burnFromBridge(address from, uint256 id, uint256 value) external; } diff --git a/apps/blockchain/ethereum/src/token/IERC721Bridgeable.sol b/apps/blockchain/ethereum/src/token/IERC721Bridgeable.sol index 6474f042..81e42cfb 100644 --- a/apps/blockchain/ethereum/src/token/IERC721Bridgeable.sol +++ b/apps/blockchain/ethereum/src/token/IERC721Bridgeable.sol @@ -3,28 +3,24 @@ pragma solidity ^0.8.0; /** - @title ERC721Bridgeable token. - - @notice This interface allows a contract to expose functions - that allows a bridge to mint and burn token. -*/ + * @title ERC721Bridgeable token. + * + * @notice This interface allows a contract to expose functions + * that allows a bridge to mint and burn token. + */ interface IERC721Bridgeable { - /** - @notice Mints a token from the bridge. - - @param to The new owner. - @param id The token to mint. - */ - function mintFromBridge(address to, uint256 id) - external; + * @notice Mints a token from the bridge. + * + * @param to The new owner. + * @param id The token to mint. + */ + function mintFromBridge(address to, uint256 id) external; /** - @notice Burns a token from the bridge. - - @param id The token to burn. - */ - function burnFromBridge(uint256 id) - external; - + * @notice Burns a token from the bridge. + * + * @param id The token to burn. + */ + function burnFromBridge(uint256 id) external; } diff --git a/apps/blockchain/ethereum/src/token/TokenUtil.sol b/apps/blockchain/ethereum/src/token/TokenUtil.sol index 41cc17d3..2f481724 100644 --- a/apps/blockchain/ethereum/src/token/TokenUtil.sol +++ b/apps/blockchain/ethereum/src/token/TokenUtil.sol @@ -10,7 +10,7 @@ import "openzeppelin-contracts/contracts/token/ERC1155/extensions/ERC1155Supply. import "openzeppelin-contracts/contracts/utils/introspection/ERC165Checker.sol"; /** - @notice Collection type that are supported by the bridge. + * @notice Collection type that are supported by the bridge. */ enum CollectionType { ERC721, @@ -19,39 +19,25 @@ enum CollectionType { error UnsupportedTokenStandard(); - /** - @title Utils functions for token related stuff. -*/ + * @title Utils functions for token related stuff. + */ library TokenUtil { - /** - @notice Detects the token contract interface. - - @param collection Address of the contract to be verified. - - @return CollectionType. + * @notice Detects the token contract interface. + * + * @param collection Address of the contract to be verified. + * + * @return CollectionType. */ - function detectInterface( - address collection - ) - internal - view - returns (CollectionType) - { - bool supportsERC721 = ERC165Checker.supportsInterface( - collection, - type(IERC721).interfaceId - ); + function detectInterface(address collection) internal view returns (CollectionType) { + bool supportsERC721 = ERC165Checker.supportsInterface(collection, type(IERC721).interfaceId); if (supportsERC721) { return CollectionType.ERC721; } - bool supportsERC1155 = ERC165Checker.supportsInterface( - collection, - type(IERC1155).interfaceId - ); + bool supportsERC1155 = ERC165Checker.supportsInterface(collection, type(IERC1155).interfaceId); if (supportsERC1155) { return CollectionType.ERC1155; @@ -61,26 +47,20 @@ library TokenUtil { } /** - @notice Retrieves metadata from ERC721 token, if it supports it. - - @param collection Address of the ERC721 contract. - @param tokenIds Ids of the tokens to get tokenURI from. - - @return (name, symbol, baseuri, tokenURIs). + * @notice Retrieves metadata from ERC721 token, if it supports it. + * + * @param collection Address of the ERC721 contract. + * @param tokenIds Ids of the tokens to get tokenURI from. + * + * @return (name, symbol, baseuri, tokenURIs). */ - function erc721Metadata( - address collection, - uint256[] memory tokenIds - ) + function erc721Metadata(address collection, uint256[] memory tokenIds) internal view returns (string memory, string memory, string memory, string[] memory) - { - bool supportsMetadata = ERC165Checker.supportsInterface( - collection, - type(IERC721Metadata).interfaceId - ); - + { + bool supportsMetadata = ERC165Checker.supportsInterface(collection, type(IERC721Metadata).interfaceId); + if (!supportsMetadata) { return ("", "", "", new string[](0)); } @@ -93,8 +73,7 @@ library TokenUtil { (bool success, string memory _baseUri) = _callBaseUri(collection); if (success) { return (c.name(), c.symbol(), _baseUri, new string[](0)); - } - else { + } else { string[] memory URIs = new string[](tokenIds.length); for (uint256 i = 0; i < tokenIds.length; i++) { URIs[i] = c.tokenURI(tokenIds[i]); @@ -104,25 +83,19 @@ library TokenUtil { } /** - @notice Retrieves metadata from ERC1155, if it supports it. - - @param collection Address of the ERC1155 contract. - - @return baseURI. + * @notice Retrieves metadata from ERC1155, if it supports it. + * + * @param collection Address of the ERC1155 contract. + * + * @return baseURI. */ - function erc1155Metadata( - address collection - ) - internal - view - returns (string memory) - { + function erc1155Metadata(address collection) internal view returns (string memory) { return ""; /* bool supportsMetadata = ERC165Checker.supportsInterface( */ /* collection, */ /* type(IERC1155MetadataURI).interfaceId */ /* ); */ - + /* if (!supportsMetadata) { */ /* return ""; */ /* } else { */ @@ -133,21 +106,15 @@ library TokenUtil { /* //return IERC1155MetadataURI(collection).uri(WhichTokenId?); */ /* return "TODO"; */ /* } */ - } - function _callBaseUri( - address collection - ) - internal - view - returns (bool, string memory) - { + function _callBaseUri(address collection) internal view returns (bool, string memory) { bool success; uint256 returnSize; uint256 returnValue; bytes memory ret; - bytes[2] memory encodedSignatures = [abi.encodeWithSignature("_baseUri()"), abi.encodeWithSignature("baseUri()")]; + bytes[2] memory encodedSignatures = + [abi.encodeWithSignature("_baseUri()"), abi.encodeWithSignature("baseUri()")]; for (uint256 i = 0; i < 2; i++) { bytes memory encodedParams = encodedSignatures[i]; @@ -169,5 +136,4 @@ library TokenUtil { } return (false, ""); } - } diff --git a/apps/blockchain/ethereum/test/Bridge.t.sol b/apps/blockchain/ethereum/test/Bridge.t.sol index 14605f9f..f6da84e4 100644 --- a/apps/blockchain/ethereum/test/Bridge.t.sol +++ b/apps/blockchain/ethereum/test/Bridge.t.sol @@ -20,19 +20,17 @@ import "./token/ERC721MintFree.sol"; import "./token/IERC721MintRangeFree.sol"; /** - @title Bridge testing. -*/ + * @title Bridge testing. + */ contract BridgeTest is Test, IStarklaneEvent { - address bridge; address erc721C1; address erc1155C1; address snCore; - address collectionL1= address(0x1); + address collectionL1 = address(0x1); snaddress collectionL2 = Cairo.snaddressWrap(0x2); - address payable internal alice; address payable internal bob; @@ -49,16 +47,9 @@ contract BridgeTest is Test, IStarklaneEvent { snCore = address(new StarknetMessagingLocal()); address impl = address(new Starklane()); - - bytes memory dataInit = abi.encodeWithSelector( - Starklane.initialize.selector, - abi.encode( - address(this), - snCore, - 0x1, - 0x2 - ) - ); + + bytes memory dataInit = + abi.encodeWithSelector(Starklane.initialize.selector, abi.encode(address(this), snCore, 0x1, 0x2)); bridge = address(new ERC1967Proxy(impl, dataInit)); IStarklane(bridge).enableBridge(true); @@ -71,13 +62,7 @@ contract BridgeTest is Test, IStarklaneEvent { uint256 salt = 0x1; snaddress to = Cairo.snaddressWrap(0x1); - IStarklane(bridge).depositTokens{value: 30000}( - salt, - address(erc721C1), - to, - ids, - false - ); + IStarklane(bridge).depositTokens{value: 30000}(salt, address(erc721C1), to, ids, false); } // @@ -89,13 +74,7 @@ contract BridgeTest is Test, IStarklaneEvent { uint256 salt = 0x1; snaddress to = Cairo.snaddressWrap(0x0); - IStarklane(bridge).depositTokens{value: 30000}( - salt, - address(erc721C1), - to, - ids, - false - ); + IStarklane(bridge).depositTokens{value: 30000}(salt, address(erc721C1), to, ids, false); } // @@ -105,13 +84,7 @@ contract BridgeTest is Test, IStarklaneEvent { uint256 salt = 0x0; snaddress to = Cairo.snaddressWrap(0x0); - IStarklane(bridge).depositTokens{value: 30000}( - salt, - address(erc721C1), - to, - ids, - false - ); + IStarklane(bridge).depositTokens{value: 30000}(salt, address(erc721C1), to, ids, false); } function test_L2OwnerOverflow() public { @@ -121,13 +94,7 @@ contract BridgeTest is Test, IStarklaneEvent { snaddress to = snaddress.wrap(SN_MODULUS); vm.expectRevert(CairoWrapError.selector); - IStarklane(bridge).depositTokens{value: 30000}( - salt, - address(erc721C1), - to, - ids, - false - ); + IStarklane(bridge).depositTokens{value: 30000}(salt, address(erc721C1), to, ids, false); } // @@ -143,13 +110,7 @@ contract BridgeTest is Test, IStarklaneEvent { vm.startPrank(alice); IERC721(erc721C1).setApprovalForAll(address(bridge), true); - IStarklane(bridge).depositTokens{value: 30000}( - salt, - address(erc721C1), - to, - ids, - false - ); + IStarklane(bridge).depositTokens{value: 30000}(salt, address(erc721C1), to, ids, false); vm.stopPrank(); // TODO: test event emission to verify the request. @@ -170,13 +131,7 @@ contract BridgeTest is Test, IStarklaneEvent { vm.startPrank(alice); IERC721(erc721C1).setApprovalForAll(address(bridge), true); vm.expectRevert(BridgeNotEnabledError.selector); - IStarklane(bridge).depositTokens{value: 30000}( - salt, - address(erc721C1), - to, - ids, - false - ); + IStarklane(bridge).depositTokens{value: 30000}(salt, address(erc721C1), to, ids, false); vm.stopPrank(); } @@ -194,15 +149,9 @@ contract BridgeTest is Test, IStarklaneEvent { vm.startPrank(alice); IERC721(erc721C1).setApprovalForAll(address(bridge), true); - + vm.expectRevert(NotWhiteListedError.selector); - IStarklane(bridge).depositTokens{value: 30000}( - salt, - address(erc721C1), - to, - ids, - false - ); + IStarklane(bridge).depositTokens{value: 30000}(salt, address(erc721C1), to, ids, false); vm.stopPrank(); } @@ -222,14 +171,8 @@ contract BridgeTest is Test, IStarklaneEvent { vm.startPrank(alice); IERC721(erc721C1).setApprovalForAll(address(bridge), true); - - IStarklane(bridge).depositTokens{value: 30000}( - salt, - address(erc721C1), - to, - ids, - false - ); + + IStarklane(bridge).depositTokens{value: 30000}(salt, address(erc721C1), to, ids, false); vm.stopPrank(); } @@ -250,7 +193,6 @@ contract BridgeTest is Test, IStarklaneEvent { vm.expectEmit(bridge); emit CollectionWhiteListUpdated(erc721C1, false); IStarklane(bridge).whiteList(erc721C1, false); - } function test_isWhiteListEnabled() public { @@ -262,7 +204,7 @@ contract BridgeTest is Test, IStarklaneEvent { IStarklane(bridge).whiteList(erc721C1, true); assert(IStarklane(bridge).isWhiteListed(erc721C1)); - + IStarklane(bridge).whiteList(erc721C1, false); assert(!IStarklane(bridge).isWhiteListed(erc721C1)); } @@ -474,7 +416,6 @@ contract BridgeTest is Test, IStarklaneEvent { assert(IERC721(erc721C1).ownerOf(ids[0]) == bridge); assert(IERC721(erc721C1).ownerOf(ids[1]) == bridge); - vm.startPrank(alice); vm.expectRevert(); IStarklane(bridge).startRequestCancellation(payload, nonce); @@ -514,21 +455,12 @@ contract BridgeTest is Test, IStarklaneEvent { assert(IERC721(erc721C1).ownerOf(ids[1]) == alice); } - // Build a request that should trigger a deploy of a new collection on L1. - function buildRequestDeploy( - felt252 header, - uint256 id, - address newOwner - ) - public - pure - returns (Request memory) - { + function buildRequestDeploy(felt252 header, uint256 id, address newOwner) public pure returns (Request memory) { uint256[] memory ids = new uint256[](1); ids[0] = id; - Request memory req = Request ({ + Request memory req = Request({ header: header, hash: 0x1, collectionL1: address(0x0), @@ -542,56 +474,35 @@ contract BridgeTest is Test, IStarklaneEvent { tokenValues: new uint256[](0), tokenURIs: new string[](0), newOwners: new address[](0) - }); + }); return req; } // - function computeMessageHashFromL2( - uint256[] memory request - ) - public - returns (bytes32) - { - (snaddress starklaneL2Address, felt252 starklaneL2Selector) - = IStarklane(bridge).l2Info(); + function computeMessageHashFromL2(uint256[] memory request) public returns (bytes32) { + (snaddress starklaneL2Address, felt252 starklaneL2Selector) = IStarklane(bridge).l2Info(); // To remove warning. Is there a better way? assertTrue(felt252.unwrap(starklaneL2Selector) > 0); bytes32 msgHash = keccak256( - abi.encodePacked( - snaddress.unwrap(starklaneL2Address), - uint256(uint160(bridge)), - request.length, - request) + abi.encodePacked(snaddress.unwrap(starklaneL2Address), uint256(uint160(bridge)), request.length, request) ); return msgHash; } - function setupCancelRequest( - address user, - uint256[] memory tokenIds - ) internal returns(uint256, uint256[] memory) { - + function setupCancelRequest(address user, uint256[] memory tokenIds) internal returns (uint256, uint256[] memory) { IERC721MintRangeFree(erc721C1).mintRangeFree(user, 0, 10); - uint256 salt = 0x1; snaddress to = Cairo.snaddressWrap(0x1); vm.startPrank(user); IERC721(erc721C1).setApprovalForAll(bridge, true); vm.recordLogs(); - IStarklane(bridge).depositTokens{value: 30000}( - salt, - address(erc721C1), - to, - tokenIds, - false - ); + IStarklane(bridge).depositTokens{value: 30000}(salt, address(erc721C1), to, tokenIds, false); Vm.Log[] memory entries = vm.getRecordedLogs(); vm.stopPrank(); @@ -599,25 +510,24 @@ contract BridgeTest is Test, IStarklaneEvent { assertEq(entries.length, 4); Vm.Log memory logMessageToL2 = entries[2]; Vm.Log memory depositRequestEvent = entries[3]; - (uint256[] memory payload, uint256 nonce, ) = abi.decode(logMessageToL2.data, (uint256[], uint256, uint256)); - ( ,uint256[] memory reqContent) = abi.decode(depositRequestEvent.data, (uint256, uint256[])); + (uint256[] memory payload, uint256 nonce,) = abi.decode(logMessageToL2.data, (uint256[], uint256, uint256)); + (, uint256[] memory reqContent) = abi.decode(depositRequestEvent.data, (uint256, uint256[])); assert(payload.length == reqContent.length); return (nonce, payload); } - - // here is test for set L1 L2 collection - + + // here is test for set L1 L2 collection + function test_SetL1L2CollectionMapping() public { - // Check for the event emission vm.expectEmit(true, true, true, true); emit L1L2CollectionMappingUpdated(collectionL1, snaddress.unwrap(collectionL2)); - IStarklane(bridge).setL1L2CollectionMapping(collectionL1, collectionL2, false); + IStarklane(bridge).setL1L2CollectionMapping(collectionL1, collectionL2, false); } function test_SetL1L2CollectionMappingWith_InvalidL1Address() public { - vm.expectRevert(InvalidL1AddressError.selector); - IStarklane(bridge).setL1L2CollectionMapping(address(0), collectionL2, false); + vm.expectRevert(InvalidL1AddressError.selector); + IStarklane(bridge).setL1L2CollectionMapping(address(0), collectionL2, false); } function test_SetL1L2CollectionMappingWith_InvalidL2Address() public { @@ -626,9 +536,8 @@ contract BridgeTest is Test, IStarklaneEvent { } function test_SetL1L2CollectionMappingWith_InvalidUnwrappedL2Address() public { - snaddress invalidCollectionL2 = Cairo.snaddressWrap(0x0); + snaddress invalidCollectionL2 = Cairo.snaddressWrap(0x0); vm.expectRevert(InvalidL2AddressError.selector); IStarklane(bridge).setL1L2CollectionMapping(collectionL1, invalidCollectionL2, false); } - } diff --git a/apps/blockchain/ethereum/test/Cairo.t.sol b/apps/blockchain/ethereum/test/Cairo.t.sol index ed14a8ee..48327972 100644 --- a/apps/blockchain/ethereum/test/Cairo.t.sol +++ b/apps/blockchain/ethereum/test/Cairo.t.sol @@ -5,13 +5,11 @@ import "forge-std/Test.sol"; import "../src/sn/Cairo.sol"; /** - @title Cairo testing. -*/ + * @title Cairo testing. + */ contract CairoTest is Test { - // - function setUp() public { - } + function setUp() public {} // function test_isFelt252() public { @@ -21,7 +19,7 @@ contract CairoTest is Test { } // - function test_felt252Wrap() public { + function test_felt252Wrap() public { felt252 f = Cairo.felt252Wrap(1); uint256 v = 1; assertTrue(felt252.unwrap(f) == v); @@ -31,7 +29,7 @@ contract CairoTest is Test { } // - function test_snaddressWrap() public { + function test_snaddressWrap() public { snaddress a = Cairo.snaddressWrap(1); uint256 v = 1; assertTrue(snaddress.unwrap(a) == v); @@ -112,14 +110,10 @@ contract CairoTest is Test { function test_cairoStringSerializedLength() public { assertEq(Cairo.cairoStringSerializedLength(""), 3); assertEq(Cairo.cairoStringSerializedLength("ABCD"), 3); - assertEq( - Cairo.cairoStringSerializedLength( - "ABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefg"), - 4); + assertEq(Cairo.cairoStringSerializedLength("ABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefg"), 4); } // - function test_cairoAddressArrayDeserialize() public { uint256[] memory buf1 = new uint256[](1); uint256[] memory buf2 = new uint256[](3); @@ -127,9 +121,9 @@ contract CairoTest is Test { buf1[0] = 0; (uint256 newOffset1, address[] memory result1) = Cairo.cairoAddressArrayDeserialize(buf1, 0); assertEq(result1.length, 0); - assertEq(newOffset1, 1); + assertEq(newOffset1, 1); - buf2[0] = 2; + buf2[0] = 2; buf2[1] = uint160(address(0x1234567890AbcdEF1234567890aBcdef12345678)); buf2[2] = uint160(address(0xABcdEFABcdEFabcdEfAbCdefabcdeFABcDEFabCD)); @@ -139,14 +133,13 @@ contract CairoTest is Test { assertEq(result2[1], address(0xABcdEFABcdEFabcdEfAbCdefabcdeFABcDEFabCD)); assertEq(newOffset2, 3); - buf3[0] = 1; + buf3[0] = 1; buf3[1] = uint160(address(0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF)); (uint256 newOffset3, address[] memory result3) = Cairo.cairoAddressArrayDeserialize(buf3, 0); assertEq(result3.length, 1); assertEq(result3[0], address(0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF)); - assertEq(newOffset3, 2); - + assertEq(newOffset3, 2); } // @@ -158,9 +151,9 @@ contract CairoTest is Test { uint256[] memory buf1 = new uint256[](3); uint256 offset1 = Cairo.addressArraySerialize(arr1, buf1, 0); - assertEq(buf1[0], 2); - assertEq(buf1[1], uint160(address(0x1234567890AbcdEF1234567890aBcdef12345678))); - assertEq(buf1[2], uint160(address(0xABcdEFABcdEFabcdEfAbCdefabcdeFABcDEFabCD))); + assertEq(buf1[0], 2); + assertEq(buf1[1], uint160(address(0x1234567890AbcdEF1234567890aBcdef12345678))); + assertEq(buf1[2], uint160(address(0xABcdEFABcdEFabcdEfAbCdefabcdeFABcDEFabCD))); assertEq(offset1, 3); address[] memory arr2 = new address[](1); @@ -170,7 +163,7 @@ contract CairoTest is Test { uint256 offset2 = Cairo.addressArraySerialize(arr2, buf2, 0); assertEq(buf2[0], 1); - assertEq(buf2[1], uint160(address(0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF))); + assertEq(buf2[1], uint160(address(0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF))); assertEq(offset2, 2); address[] memory arr3 = new address[](0); @@ -181,10 +174,8 @@ contract CairoTest is Test { assertEq(buf3[0], 0); assertEq(offset3, 1); - } - // function test_cairoStringPack() public { uint256[] memory bufEmpty = Cairo.cairoStringPack(""); @@ -204,7 +195,6 @@ contract CairoTest is Test { assertEq(bufLong[2], 0x0035363738393061626364656667); assertEq(bufLong[3], 13); assertEq(bufLong.length, 4); - } // @@ -233,9 +223,7 @@ contract CairoTest is Test { offset += Cairo.cairoStringSerialize("ABCD", buf, offset); assertEq(offset, 3); assertEq(buf[0], 0); - assertEq( - buf[1], - 0x0041424344); + assertEq(buf[1], 0x0041424344); assertEq(buf[2], 4); } @@ -297,6 +285,4 @@ contract CairoTest is Test { assertEq(inc, 1); assertEq(strs.length, 0); } - } - diff --git a/apps/blockchain/ethereum/test/Escrow.t.sol b/apps/blockchain/ethereum/test/Escrow.t.sol index 321a19aa..d4ef39e0 100644 --- a/apps/blockchain/ethereum/test/Escrow.t.sol +++ b/apps/blockchain/ethereum/test/Escrow.t.sol @@ -13,10 +13,9 @@ import "./token/ERC721MintFree.sol"; import "./token/IERC721MintRangeFree.sol"; /** - @title Escrow testing. -*/ + * @title Escrow testing. + */ contract EscrowTest is Test { - EscrowPublic escrow; address erc721; @@ -76,32 +75,20 @@ contract EscrowTest is Test { } /** - @title Escrow interface exposed for test. + * @title Escrow interface exposed for test. */ contract EscrowPublic is StarklaneEscrow { - /** - @notice test _depositIntoEscrow. - */ - function depositIntoEscrow( - CollectionType collectionType, - address collection, - uint256[] memory ids - ) - public - { + * @notice test _depositIntoEscrow. + */ + function depositIntoEscrow(CollectionType collectionType, address collection, uint256[] memory ids) public { _depositIntoEscrow(collectionType, collection, ids); } /** - @notice test _withdrawFromEscrow. - */ - function withdrawFromEscrow( - CollectionType collectionType, - address collection, - address to, - uint256 id - ) + * @notice test _withdrawFromEscrow. + */ + function withdrawFromEscrow(CollectionType collectionType, address collection, address to, uint256 id) public returns (bool) { diff --git a/apps/blockchain/ethereum/test/Protocol.t.sol b/apps/blockchain/ethereum/test/Protocol.t.sol index 6dfa57dc..55300cd9 100644 --- a/apps/blockchain/ethereum/test/Protocol.t.sol +++ b/apps/blockchain/ethereum/test/Protocol.t.sol @@ -5,20 +5,18 @@ import "forge-std/Test.sol"; import "../src/Protocol.sol"; /** - @title Protocol testing. -*/ + * @title Protocol testing. + */ contract ProtocolTest is Test { - // - function setUp() public { - } + function setUp() public {} // function buildRequestDummy() public pure returns (Request memory) { uint256[] memory ids = new uint256[](1); ids[0] = 1; - Request memory req = Request ({ + Request memory req = Request({ header: Cairo.felt252Wrap(0x1), hash: 0x1, collectionL1: address(0x0), @@ -32,7 +30,7 @@ contract ProtocolTest is Test { tokenValues: new uint256[](0), tokenURIs: new string[](0), newOwners: new address[](0) - }); + }); return req; } @@ -51,7 +49,7 @@ contract ProtocolTest is Test { address[] memory newOwners = new address[](1); values[0] = 0x123; - Request memory req = Request ({ + Request memory req = Request({ header: Cairo.felt252Wrap(0x1), hash: 0x1, collectionL1: address(0x0), @@ -65,48 +63,24 @@ contract ProtocolTest is Test { tokenValues: values, tokenURIs: uris, newOwners: newOwners - }); + }); return req; } // function test_requestHeader() public { - felt252 header = Protocol.requestHeaderV1( - CollectionType.ERC721, - false, - false); - assertEq( - felt252.unwrap(header), - 0x0101 - ); - - header = Protocol.requestHeaderV1( - CollectionType.ERC1155, - false, - false); - assertEq( - felt252.unwrap(header), - 0x0201 - ); - - header = Protocol.requestHeaderV1( - CollectionType.ERC721, - true, - false); - assertEq( - felt252.unwrap(header), - 0x010101 - ); - - header = Protocol.requestHeaderV1( - CollectionType.ERC721, - true, - true); - assertEq( - felt252.unwrap(header), - 0x01010101 - ); + felt252 header = Protocol.requestHeaderV1(CollectionType.ERC721, false, false); + assertEq(felt252.unwrap(header), 0x0101); + + header = Protocol.requestHeaderV1(CollectionType.ERC1155, false, false); + assertEq(felt252.unwrap(header), 0x0201); + + header = Protocol.requestHeaderV1(CollectionType.ERC721, true, false); + assertEq(felt252.unwrap(header), 0x010101); + + header = Protocol.requestHeaderV1(CollectionType.ERC721, true, true); + assertEq(felt252.unwrap(header), 0x01010101); assertTrue(Protocol.canUseWithdrawAuto(felt252.unwrap(header))); } @@ -115,17 +89,10 @@ contract ProtocolTest is Test { uint256[] memory ids = new uint256[](1); ids[0] = 88; - uint256 hash = Protocol.requestHash( - 123, - 0x0000000000000000000000000000000000000000, - Cairo.snaddressWrap(0x1), - ids - ); - - assertEq( - hash, - 0xbb7ca67ee263bd2bb68dc88b530300222a3700bceca4e537079047fff89a0402 - ); + uint256 hash = + Protocol.requestHash(123, 0x0000000000000000000000000000000000000000, Cairo.snaddressWrap(0x1), ids); + + assertEq(hash, 0xbb7ca67ee263bd2bb68dc88b530300222a3700bceca4e537079047fff89a0402); } // @@ -212,6 +179,4 @@ contract ProtocolTest is Test { assertEq(req.tokenURIs.length, 0); assertEq(req.newOwners.length, 0); } - - } diff --git a/apps/blockchain/ethereum/test/TokenUtils.t.sol b/apps/blockchain/ethereum/test/TokenUtils.t.sol index f4c7a85e..ecc27e40 100644 --- a/apps/blockchain/ethereum/test/TokenUtils.t.sol +++ b/apps/blockchain/ethereum/test/TokenUtils.t.sol @@ -5,30 +5,31 @@ import "forge-std/Test.sol"; import "../src/token/TokenUtil.sol"; interface IUnderscoreBaseUri { - function _baseUri() view external returns(string memory); + function _baseUri() external view returns (string memory); } interface IBaseUri { - function baseUri() view external returns(string memory); + function baseUri() external view returns (string memory); } contract WithUnderscoreBaseUri is IUnderscoreBaseUri { - function _baseUri() view external returns (string memory) { + function _baseUri() external view returns (string memory) { return "_baseURI here"; } } contract WithBaseUri is IBaseUri { - function baseUri() view external returns (string memory) { + function baseUri() external view returns (string memory) { return "baseUri here"; } } contract WithoutBaseUri { - function dummy() pure external returns (string memory) { + function dummy() external pure returns (string memory) { return "dummy"; } } + contract WithFallback { fallback() external payable {} } @@ -40,7 +41,6 @@ contract WithInternaBaseUri { } contract TokenUtilTest is Test { - function test_with_baseuri() public { bool success = false; string memory uri = ""; @@ -75,4 +75,4 @@ contract TokenUtilTest is Test { assert(!success); assert(keccak256(abi.encodePacked(uri)) == keccak256(abi.encodePacked(""))); } -} \ No newline at end of file +} diff --git a/apps/blockchain/ethereum/test/token/ERC1155NoSupply.sol b/apps/blockchain/ethereum/test/token/ERC1155NoSupply.sol index 15038c86..ed24b97d 100644 --- a/apps/blockchain/ethereum/test/token/ERC1155NoSupply.sol +++ b/apps/blockchain/ethereum/test/token/ERC1155NoSupply.sol @@ -8,28 +8,20 @@ import "../../src/token/IERC1155Bridgeable.sol"; import "../../src/UUPSProxied.sol"; /** - @title ERC1155 with no supply support for testing. -*/ + * @title ERC1155 with no supply support for testing. + */ contract ERC1155NoSupply is ERC1155, UUPSOwnableProxied, IERC1155Bridgeable { - /** - @notice Default constructor, but intialize is used instead. - */ - constructor() - ERC1155("") - { } + * @notice Default constructor, but intialize is used instead. + */ + constructor() ERC1155("") {} /** - @notice Initializes the implementation, only callable once. - - @param data Data to init the implementation. - */ - function initialize( - bytes calldata data - ) - public - onlyInit - { + * @notice Initializes the implementation, only callable once. + * + * @param data Data to init the implementation. + */ + function initialize(bytes calldata data) public onlyInit { (string memory uri_) = abi.decode(data, (string)); _setURI(uri_); @@ -38,54 +30,33 @@ contract ERC1155NoSupply is ERC1155, UUPSOwnableProxied, IERC1155Bridgeable { } /** - @notice A free mint for testing. - - @param to The new owner. - @param id The token type to mint. - @param value Amount of the token. - */ - function mintFree( - address to, - uint256 id, - uint256 value - ) - external - { + * @notice A free mint for testing. + * + * @param to The new owner. + * @param id The token type to mint. + * @param value Amount of the token. + */ + function mintFree(address to, uint256 id, uint256 value) external { _mint(to, id, value, ""); } /** - @inheritdoc IERC1155Bridgeable - - @dev In this implementation, the owner is the bridge by default. So `onlyOwner` - is enough. - */ - function mintFromBridge( - address to, - uint256 id, - uint256 value - ) - public - onlyOwner - { + * @inheritdoc IERC1155Bridgeable + * + * @dev In this implementation, the owner is the bridge by default. So `onlyOwner` + * is enough. + */ + function mintFromBridge(address to, uint256 id, uint256 value) public onlyOwner { _mint(to, id, value, ""); } /** - @inheritdoc IERC1155Bridgeable - - @dev In this implementation, the owner is the bridge by default. So `onlyOwner` - is enough. - */ - function burnFromBridge( - address from, - uint256 id, - uint256 value - ) - public - onlyOwner - { + * @inheritdoc IERC1155Bridgeable + * + * @dev In this implementation, the owner is the bridge by default. So `onlyOwner` + * is enough. + */ + function burnFromBridge(address from, uint256 id, uint256 value) public onlyOwner { _burn(from, id, value); } - } diff --git a/apps/blockchain/ethereum/test/token/ERC721MintFree.sol b/apps/blockchain/ethereum/test/token/ERC721MintFree.sol index fb21f517..1a49f05d 100644 --- a/apps/blockchain/ethereum/test/token/ERC721MintFree.sol +++ b/apps/blockchain/ethereum/test/token/ERC721MintFree.sol @@ -6,27 +6,18 @@ import "openzeppelin-contracts/contracts/token/ERC721/ERC721.sol"; import "./IERC721MintRangeFree.sol"; /** - @title ERC721 with free mint. -*/ + * @title ERC721 with free mint. + */ contract ERC721MintFree is ERC721, IERC721MintRangeFree { - /** - @notice Default constructor, but intialize is used instead. - */ - constructor(string memory name, string memory symbol) - ERC721(name, symbol) - { } + * @notice Default constructor, but intialize is used instead. + */ + constructor(string memory name, string memory symbol) ERC721(name, symbol) {} /** - @notice A free minting for testing. - */ - function mintRangeFree( - address to, - uint256 idStart, - uint256 idEnd - ) - external - { + * @notice A free minting for testing. + */ + function mintRangeFree(address to, uint256 idStart, uint256 idEnd) external { require(idStart < idEnd, "Bad range"); uint256 id = idStart; @@ -36,4 +27,3 @@ contract ERC721MintFree is ERC721, IERC721MintRangeFree { } } } - diff --git a/apps/blockchain/ethereum/test/token/IERC721MintRangeFree.sol b/apps/blockchain/ethereum/test/token/IERC721MintRangeFree.sol index 20f39e81..ab9489a8 100644 --- a/apps/blockchain/ethereum/test/token/IERC721MintRangeFree.sol +++ b/apps/blockchain/ethereum/test/token/IERC721MintRangeFree.sol @@ -6,12 +6,7 @@ pragma solidity ^0.8.0; */ interface IERC721MintRangeFree { /** - @notice A free minting for testing. - */ - function mintRangeFree( - address to, - uint256 idStart, - uint256 idEnd - ) - external; + * @notice A free minting for testing. + */ + function mintRangeFree(address to, uint256 idStart, uint256 idEnd) external; } diff --git a/apps/blockchain/ethereum/test/utils/Users.sol b/apps/blockchain/ethereum/test/utils/Users.sol index 13ef7994..c0202395 100644 --- a/apps/blockchain/ethereum/test/utils/Users.sol +++ b/apps/blockchain/ethereum/test/utils/Users.sol @@ -5,14 +5,14 @@ import {DSTest} from "ds-test/test.sol"; import {Vm} from "forge-std/Vm.sol"; /** - @title Common utilities taken from https://github.com/FrankieIsLost/forge-template/blob/master/src/test/utils/Utilities.sol. + * @title Common utilities taken from https://github.com/FrankieIsLost/forge-template/blob/master/src/test/utils/Utilities.sol. */ contract Users is DSTest { Vm internal immutable vm = Vm(HEVM_ADDRESS); bytes32 internal nextUser = keccak256(abi.encodePacked("user address")); /** - @notice Generates a new random user payable address. + * @notice Generates a new random user payable address. */ function getNextUserAddress() external returns (address payable) { //bytes32 to address conversion @@ -22,12 +22,9 @@ contract Users is DSTest { } /** - @notice create users with 100 ethers. - */ - function create(uint256 userNum) - external - returns (address payable[] memory) - { + * @notice create users with 100 ethers. + */ + function create(uint256 userNum) external returns (address payable[] memory) { address payable[] memory users = new address payable[](userNum); for (uint256 i = 0; i < userNum; i++) { address payable user = this.getNextUserAddress(); From acb3cb1566d237a2ff35783b245aaaa02e02af5a Mon Sep 17 00:00:00 2001 From: BlockyJ Date: Wed, 2 Oct 2024 09:18:43 +0100 Subject: [PATCH 2/4] fix: resolve infinite loop in _white_list_collection (#244) * fix: resolve infinite loop in _white_list_collection * update tests * fix tests and cleanup * adjust position of event checker --- apps/blockchain/starknet/src/bridge.cairo | 1 + .../starknet/src/tests/bridge_t.cairo | 112 ++++++++++++++---- 2 files changed, 92 insertions(+), 21 deletions(-) diff --git a/apps/blockchain/starknet/src/bridge.cairo b/apps/blockchain/starknet/src/bridge.cairo index 0b734875..2478e2e1 100644 --- a/apps/blockchain/starknet/src/bridge.cairo +++ b/apps/blockchain/starknet/src/bridge.cairo @@ -540,6 +540,7 @@ mod bridge { self.white_listed_list.write(prev, (active, target)); break; } + prev = next; }; self.white_listed_list.write(collection, (false, no_value)); } diff --git a/apps/blockchain/starknet/src/tests/bridge_t.cairo b/apps/blockchain/starknet/src/tests/bridge_t.cairo index cafde030..0cf22a77 100644 --- a/apps/blockchain/starknet/src/tests/bridge_t.cairo +++ b/apps/blockchain/starknet/src/tests/bridge_t.cairo @@ -694,74 +694,142 @@ mod tests { let collection1 = starknet::contract_address_const::<'collection1'>(); let collection2 = starknet::contract_address_const::<'collection2'>(); let collection3 = starknet::contract_address_const::<'collection3'>(); - + let collection4 = starknet::contract_address_const::<'collection4'>(); + let collection5 = starknet::contract_address_const::<'collection5'>(); + start_prank(CheatTarget::One(bridge_address), BRIDGE_ADMIN); bridge.white_list_collection(collection1, true); bridge.white_list_collection(collection2, true); bridge.white_list_collection(collection3, true); + bridge.white_list_collection(collection4, true); + bridge.white_list_collection(collection5, true); stop_prank(CheatTarget::One(bridge_address)); let white_listed = bridge.get_white_listed_collections(); - assert_eq!(white_listed.len(), 3, "White list shall contain 3 elements"); + assert_eq!(white_listed.len(), 5, "White list shall contain 5 elements"); assert_eq!(*white_listed.at(0), collection1, "Wrong collection address in white list"); assert_eq!(*white_listed.at(1), collection2, "Wrong collection address in white list"); assert_eq!(*white_listed.at(2), collection3, "Wrong collection address in white list"); + assert_eq!(*white_listed.at(3), collection4, "Wrong collection address in white list"); + assert_eq!(*white_listed.at(4), collection5, "Wrong collection address in white list"); assert!(bridge.is_white_listed(collection1), "Collection1 should be whitelisted"); assert!(bridge.is_white_listed(collection2), "Collection1 should be whitelisted"); assert!(bridge.is_white_listed(collection3), "Collection1 should be whitelisted"); + assert!(bridge.is_white_listed(collection4), "Collection1 should be whitelisted"); + assert!(bridge.is_white_listed(collection5), "Collection1 should be whitelisted"); + + let mut spy = spy_events(SpyOn::One(bridge_address)); start_prank(CheatTarget::One(bridge_address), BRIDGE_ADMIN); - bridge.white_list_collection(collection2, false); + bridge.white_list_collection(collection3, false); stop_prank(CheatTarget::One(bridge_address)); let white_listed = bridge.get_white_listed_collections(); - assert_eq!(white_listed.len(), 2, "White list shall contain 2 elements"); + assert_eq!(white_listed.len(), 4, "White list shall contain 4 elements"); assert_eq!(*white_listed.at(0), collection1, "Wrong collection address in white list"); - assert_eq!(*white_listed.at(1), collection3, "Wrong collection address in white list"); + assert_eq!(*white_listed.at(1), collection2, "Wrong collection address in white list"); + assert_eq!(*white_listed.at(2), collection4, "Wrong collection address in white list"); + assert_eq!(*white_listed.at(3), collection5, "Wrong collection address in white list"); assert!(bridge.is_white_listed(collection1), "Collection1 should be whitelisted"); - assert!(!bridge.is_white_listed(collection2), "Collection1 should not be whitelisted"); - assert!(bridge.is_white_listed(collection3), "Collection1 should be whitelisted"); + assert!(bridge.is_white_listed(collection2), "Collection1 should be whitelisted"); + assert!(!bridge.is_white_listed(collection3), "Collection1 should not be whitelisted"); + assert!(bridge.is_white_listed(collection4), "Collection1 should be whitelisted"); + assert!(bridge.is_white_listed(collection5), "Collection1 should be whitelisted"); + + spy.assert_emitted(@array![ + ( + bridge_address, + bridge::Event::CollectionWhiteListUpdated( + bridge::CollectionWhiteListUpdated { + collection: collection3, + enabled: false, + } + ) + ) + ]); start_prank(CheatTarget::One(bridge_address), BRIDGE_ADMIN); bridge.white_list_collection(collection1, false); - bridge.white_list_collection(collection3, false); + bridge.white_list_collection(collection4, false); stop_prank(CheatTarget::One(bridge_address)); + let white_listed = bridge.get_white_listed_collections(); - assert!(white_listed.is_empty(), "White list shall be empty"); + assert_eq!(white_listed.len(), 2, "White list shall contain 2 elements"); + assert_eq!(*white_listed.at(0), collection2, "Wrong collection address in white list"); + assert_eq!(*white_listed.at(1), collection5, "Wrong collection address in white list"); assert!(!bridge.is_white_listed(collection1), "Collection1 should not be whitelisted"); - assert!(!bridge.is_white_listed(collection2), "Collection1 should not be whitelisted"); - assert!(!bridge.is_white_listed(collection3), "Collection1 should not be whitelisted"); + assert!(!bridge.is_white_listed(collection4), "Collection1 should not be whitelisted"); + + spy.assert_emitted(@array![ + ( + bridge_address, + bridge::Event::CollectionWhiteListUpdated( + bridge::CollectionWhiteListUpdated { + collection: collection1, + enabled: false, + } + ) + ), + ( + bridge_address, + bridge::Event::CollectionWhiteListUpdated( + bridge::CollectionWhiteListUpdated { + collection: collection4, + enabled: false, + } + ) + ) + ]); start_prank(CheatTarget::One(bridge_address), BRIDGE_ADMIN); - bridge.white_list_collection(collection1, true); bridge.white_list_collection(collection3, true); + bridge.white_list_collection(collection2, false); stop_prank(CheatTarget::One(bridge_address)); let white_listed = bridge.get_white_listed_collections(); assert_eq!(white_listed.len(), 2, "White list shall contain 2 elements"); - assert_eq!(*white_listed.at(0), collection1, "Wrong collection address in white list"); + assert_eq!(*white_listed.at(0), collection5, "Wrong collection address in white list"); assert_eq!(*white_listed.at(1), collection3, "Wrong collection address in white list"); - assert!(bridge.is_white_listed(collection1), "Collection1 should be whitelisted"); + assert!(bridge.is_white_listed(collection5), "Collection1 should be whitelisted"); assert!(!bridge.is_white_listed(collection2), "Collection1 should not be whitelisted"); assert!(bridge.is_white_listed(collection3), "Collection1 should be whitelisted"); + spy.assert_emitted(@array![ + ( + bridge_address, + bridge::Event::CollectionWhiteListUpdated( + bridge::CollectionWhiteListUpdated { + collection: collection3, + enabled: true, + } + ) + ), + ( + bridge_address, + bridge::Event::CollectionWhiteListUpdated( + bridge::CollectionWhiteListUpdated { + collection: collection2, + enabled: false, + } + ) + ) + ]); + start_prank(CheatTarget::One(bridge_address), BRIDGE_ADMIN); - bridge.white_list_collection(collection1, false); + bridge.white_list_collection(collection3, false); bridge.white_list_collection(collection2, true); stop_prank(CheatTarget::One(bridge_address)); let white_listed = bridge.get_white_listed_collections(); assert_eq!(white_listed.len(), 2, "White list shall contain 2 elements"); - assert_eq!(*white_listed.at(0), collection3, "Wrong collection address in white list"); + assert_eq!(*white_listed.at(0), collection5, "Wrong collection address in white list"); assert_eq!(*white_listed.at(1), collection2, "Wrong collection address in white list"); - assert!(!bridge.is_white_listed(collection1), "Collection1 should not be whitelisted"); + assert!(!bridge.is_white_listed(collection3), "Collection1 should not be whitelisted"); assert!(bridge.is_white_listed(collection2), "Collection1 should be whitelisted"); - assert!(bridge.is_white_listed(collection3), "Collection1 should be whitelisted"); + assert!(bridge.is_white_listed(collection5), "Collection1 should be whitelisted"); start_prank(CheatTarget::One(bridge_address), BRIDGE_ADMIN); + bridge.white_list_collection(collection5, false); bridge.white_list_collection(collection2, false); - bridge.white_list_collection(collection3, false); - bridge.white_list_collection(collection1, false); - bridge.white_list_collection(collection1, false); stop_prank(CheatTarget::One(bridge_address)); let white_listed = bridge.get_white_listed_collections(); @@ -769,6 +837,8 @@ mod tests { assert!(!bridge.is_white_listed(collection1), "Collection1 should not be whitelisted"); assert!(!bridge.is_white_listed(collection2), "Collection1 should not be whitelisted"); assert!(!bridge.is_white_listed(collection3), "Collection1 should not be whitelisted"); + assert!(!bridge.is_white_listed(collection4), "Collection1 should not be whitelisted"); + assert!(!bridge.is_white_listed(collection5), "Collection1 should not be whitelisted"); } #[test] From f597146b91622b30487f20eb325cc2961ab26c8e Mon Sep 17 00:00:00 2001 From: Yohan Date: Wed, 2 Oct 2024 15:20:41 +0200 Subject: [PATCH 3/4] feat: removed unvailable banner (#250) --- apps/web/src/app/_components/Banner.tsx | 12 ------------ apps/web/src/app/_components/Header.tsx | 2 -- 2 files changed, 14 deletions(-) delete mode 100644 apps/web/src/app/_components/Banner.tsx diff --git a/apps/web/src/app/_components/Banner.tsx b/apps/web/src/app/_components/Banner.tsx deleted file mode 100644 index 2e48c033..00000000 --- a/apps/web/src/app/_components/Banner.tsx +++ /dev/null @@ -1,12 +0,0 @@ -export default function Banner() { - return ( -
-

- Important Notice: The Bridge will be temporarily unavailable from - 07/30/2024 for at least 3 weeks due to a comprehensive audit. We - apologize for any inconvenience this may cause and appreciate your - understanding. -

-
- ); -} diff --git a/apps/web/src/app/_components/Header.tsx b/apps/web/src/app/_components/Header.tsx index 5de98248..35b8b305 100644 --- a/apps/web/src/app/_components/Header.tsx +++ b/apps/web/src/app/_components/Header.tsx @@ -12,7 +12,6 @@ import useNftSelection from "../(routes)/bridge/_hooks/useNftSelection"; import useAccountFromChain from "../_hooks/useAccountFromChain"; import useCurrentChain from "../_hooks/useCurrentChain"; import useIsFullyConnected from "../_hooks/useIsFullyConnected"; -import Banner from "./Banner"; import ConnectEthereumButton from "./ConnectEthereumButton"; import ConnectStarkNetButton from "./ConnectStarkNetButton"; import Logo from "./Logo"; @@ -91,7 +90,6 @@ export default function Header() { return (
-
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 4/4] 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); +} }