diff --git a/contracts/Linea_SpokePool.sol b/contracts/Linea_SpokePool.sol index 562b6c6df..4327f40b7 100644 --- a/contracts/Linea_SpokePool.sol +++ b/contracts/Linea_SpokePool.sol @@ -15,7 +15,6 @@ import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; */ contract Linea_SpokePool is SpokePool { using SafeERC20 for IERC20; - using AddressToBytes32 for address; /** * @notice Address of Linea's Canonical Message Service contract on L2. @@ -123,8 +122,8 @@ contract Linea_SpokePool is SpokePool { * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives * ETH over the canonical token bridge instead of WETH. */ - function _preExecuteLeafHook(bytes32 l2TokenAddress) internal override { - if (l2TokenAddress == address(wrappedNativeToken).toBytes32()) _depositEthToWeth(); + function _preExecuteLeafHook(address l2TokenAddress) internal override { + if (l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth(); } // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because diff --git a/contracts/Ovm_SpokePool.sol b/contracts/Ovm_SpokePool.sol index 90d709573..d21531e3c 100644 --- a/contracts/Ovm_SpokePool.sol +++ b/contracts/Ovm_SpokePool.sol @@ -34,7 +34,7 @@ interface IL2ERC20Bridge { */ contract Ovm_SpokePool is SpokePool, CircleCCTPAdapter { using SafeERC20 for IERC20; - using AddressToBytes32 for address; + // "l1Gas" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently // unused by bridge but included for future compatibility. @@ -135,8 +135,8 @@ contract Ovm_SpokePool is SpokePool, CircleCCTPAdapter { * @notice Wraps any ETH into WETH before executing leaves. This is necessary because SpokePool receives * ETH over the canonical token bridge instead of WETH. */ - function _preExecuteLeafHook(bytes32 l2TokenAddress) internal override { - if (l2TokenAddress == address(wrappedNativeToken).toBytes32()) _depositEthToWeth(); + function _preExecuteLeafHook(address l2TokenAddress) internal override { + if (l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth(); } // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because diff --git a/contracts/PolygonZkEVM_SpokePool.sol b/contracts/PolygonZkEVM_SpokePool.sol index 1817dba35..b9367a75d 100644 --- a/contracts/PolygonZkEVM_SpokePool.sol +++ b/contracts/PolygonZkEVM_SpokePool.sol @@ -158,8 +158,8 @@ contract PolygonZkEVM_SpokePool is SpokePool, IBridgeMessageReceiver { * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives * ETH over the canonical token bridge instead of WETH. */ - function _preExecuteLeafHook(bytes32 l2TokenAddress) internal override { - if (l2TokenAddress == address(wrappedNativeToken).toBytes32()) _depositEthToWeth(); + function _preExecuteLeafHook(address l2TokenAddress) internal override { + if (l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth(); } // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because diff --git a/contracts/Polygon_SpokePool.sol b/contracts/Polygon_SpokePool.sol index 6cebd506c..990c987af 100644 --- a/contracts/Polygon_SpokePool.sol +++ b/contracts/Polygon_SpokePool.sol @@ -231,7 +231,7 @@ contract Polygon_SpokePool is IFxMessageProcessor, SpokePool, CircleCCTPAdapter emit SetPolygonTokenBridger(address(_polygonTokenBridger)); } - function _preExecuteLeafHook(bytes32) internal override { + function _preExecuteLeafHook(address) internal override { // Wraps MATIC --> WMATIC before distributing tokens from this contract. _wrap(); } diff --git a/contracts/SpokePool.sol b/contracts/SpokePool.sol index a9c25858a..8bd27e75f 100644 --- a/contracts/SpokePool.sol +++ b/contracts/SpokePool.sol @@ -71,7 +71,7 @@ abstract contract SpokePool is RootBundle[] public rootBundles; // Origin token to destination token routings can be turned on or off, which can enable or disable deposits. - mapping(bytes32 => mapping(uint256 => bool)) public enabledDepositRoutes; + mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes; // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to @@ -105,7 +105,7 @@ abstract contract SpokePool is // Mapping of L2TokenAddress to relayer to outstanding refund amount. Used when a relayer repayment fails for some // reason (eg blacklist) to track their outstanding liability, thereby letting them claim it later. - mapping(bytes32 => mapping(bytes32 => uint256)) public relayerRefund; + mapping(address => mapping(address => uint256)) public relayerRefund; /************************************************************** * CONSTANT/IMMUTABLE VARIABLES * @@ -173,8 +173,8 @@ abstract contract SpokePool is uint256[] refundAmounts, uint32 indexed rootBundleId, uint32 indexed leafId, - bytes32 l2TokenAddress, - bytes32[] refundAddresses, + address l2TokenAddress, + address[] refundAddresses, bool deferredRefunds, address caller ); @@ -318,7 +318,7 @@ abstract contract SpokePool is uint256 destinationChainId, bool enabled ) public override onlyAdmin nonReentrant { - enabledDepositRoutes[originToken.toBytes32()][destinationChainId] = enabled; + enabledDepositRoutes[originToken][destinationChainId] = enabled; emit EnabledDepositRoute(originToken, destinationChainId, enabled); } @@ -390,9 +390,9 @@ abstract contract SpokePool is uint256 // maxCount. Deprecated. ) public payable override nonReentrant unpausedDeposits { _deposit( - msg.sender.toBytes32(), - recipient.toBytes32(), - originToken.toBytes32(), + msg.sender, + recipient, + originToken, amount, destinationChainId, relayerFeePct, @@ -432,16 +432,7 @@ abstract contract SpokePool is bytes memory message, uint256 // maxCount. Deprecated. ) public payable nonReentrant unpausedDeposits { - _deposit( - depositor.toBytes32(), - recipient.toBytes32(), - originToken.toBytes32(), - amount, - destinationChainId, - relayerFeePct, - quoteTimestamp, - message - ); + _deposit(depositor, recipient, originToken, amount, destinationChainId, relayerFeePct, quoteTimestamp, message); } /******************************************** @@ -514,7 +505,7 @@ abstract contract SpokePool is ) public payable override nonReentrant unpausedDeposits { // Check that deposit route is enabled for the input token. There are no checks required for the output token // which is pulled from the relayer at fill time and passed through this contract atomically to the recipient. - if (!enabledDepositRoutes[inputToken][destinationChainId]) revert DisabledRoute(); + if (!enabledDepositRoutes[inputToken.toAddress()][destinationChainId]) revert DisabledRoute(); // Require that quoteTimestamp has a maximum age so that depositors pay an LP fee based on recent HubPool usage. // It is assumed that cross-chain timestamps are normally loosely in-sync, but clock drift can occur. If the @@ -981,8 +972,11 @@ abstract contract SpokePool is // Exclusivity deadline is inclusive and is the latest timestamp that the exclusive relayer has sole right // to fill the relay. if ( - _fillIsExclusive(relayData.exclusiveRelayer, relayData.exclusivityDeadline, uint32(getCurrentTime())) && - relayData.exclusiveRelayer.toAddress() != msg.sender + _fillIsExclusive( + relayData.exclusiveRelayer.toAddress(), + relayData.exclusivityDeadline, + uint32(getCurrentTime()) + ) && relayData.exclusiveRelayer.toAddress() != msg.sender ) { revert NotExclusiveRelayer(); } @@ -1028,8 +1022,11 @@ abstract contract SpokePool is // Exclusivity deadline is inclusive and is the latest timestamp that the exclusive relayer has sole right // to fill the relay. if ( - _fillIsExclusive(relayData.exclusiveRelayer, relayData.exclusivityDeadline, uint32(getCurrentTime())) && - relayData.exclusiveRelayer.toAddress() != msg.sender + _fillIsExclusive( + relayData.exclusiveRelayer.toAddress(), + relayData.exclusivityDeadline, + uint32(getCurrentTime()) + ) && relayData.exclusiveRelayer.toAddress() != msg.sender ) { revert NotExclusiveRelayer(); } @@ -1078,7 +1075,7 @@ abstract contract SpokePool is // fast fill within this deadline. Moreover, the depositor should expect to get *fast* filled within // this deadline, not slow filled. As a simplifying assumption, we will not allow slow fills to be requested // during this exclusivity period. - if (_fillIsExclusive(relayData.exclusiveRelayer, relayData.exclusivityDeadline, currentTime)) { + if (_fillIsExclusive(relayData.exclusiveRelayer.toAddress(), relayData.exclusivityDeadline, currentTime)) { revert NoSlowFillsInExclusivityWindow(); } if (relayData.fillDeadline < currentTime) revert ExpiredFillDeadline(); @@ -1166,7 +1163,7 @@ abstract contract SpokePool is ) public override nonReentrant { V3RelayData memory relayData = slowFillLeaf.relayData; - _preExecuteLeafHook(relayData.outputToken); + _preExecuteLeafHook(relayData.outputToken.toAddress()); // @TODO In the future consider allowing way for slow fill leaf to be created with updated // deposit params like outputAmount, message and recipient. @@ -1242,9 +1239,9 @@ abstract contract SpokePool is * @param refundAddress Address to send the refund to. */ function claimRelayerRefund(bytes32 l2TokenAddress, bytes32 refundAddress) public { - uint256 refund = relayerRefund[l2TokenAddress][msg.sender.toBytes32()]; + uint256 refund = relayerRefund[l2TokenAddress.toAddress()][msg.sender]; if (refund == 0) revert NoRelayerRefundToClaim(); - relayerRefund[l2TokenAddress][msg.sender.toBytes32()] = 0; + relayerRefund[l2TokenAddress.toAddress()][refundAddress.toAddress()] = 0; IERC20Upgradeable(l2TokenAddress.toAddress()).safeTransfer(refundAddress.toAddress(), refund); emit ClaimedRelayerRefund(l2TokenAddress, refundAddress, refund, msg.sender); @@ -1270,7 +1267,7 @@ abstract contract SpokePool is return block.timestamp; // solhint-disable-line not-rely-on-time } - function getRelayerRefund(bytes32 l2TokenAddress, bytes32 refundAddress) public view returns (uint256) { + function getRelayerRefund(address l2TokenAddress, address refundAddress) public view returns (uint256) { return relayerRefund[l2TokenAddress][refundAddress]; } @@ -1278,9 +1275,9 @@ abstract contract SpokePool is * INTERNAL FUNCTIONS * **************************************/ function _deposit( - bytes32 depositor, - bytes32 recipient, - bytes32 originToken, + address depositor, + address recipient, + address originToken, uint256 amount, uint256 destinationChainId, int64 relayerFeePct, @@ -1308,18 +1305,18 @@ abstract contract SpokePool is // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken. - if (originToken == address(wrappedNativeToken).toBytes32() && msg.value > 0) { + if (originToken == address(wrappedNativeToken) && msg.value > 0) { if (msg.value != amount) revert MsgValueDoesNotMatchInputAmount(); wrappedNativeToken.deposit{ value: msg.value }(); // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal. // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them. // In this case the msg.value will be set to 0, indicating a "normal" ERC20 bridging action. } else { - IERC20Upgradeable(originToken.toAddress()).safeTransferFrom(msg.sender, address(this), amount); + IERC20Upgradeable(originToken).safeTransferFrom(msg.sender, address(this), amount); } emit V3FundsDeposited( - originToken, // inputToken + originToken.toBytes32(), // inputToken bytes32(0), // outputToken. Setting this to 0x0 means that the outputToken should be assumed to be the // canonical token for the destination chain matching the inputToken. Therefore, this deposit // can always be slow filled. @@ -1337,8 +1334,8 @@ abstract contract SpokePool is // expired deposits refunds could be a breaking change for existing users of this function. 0, // exclusivityDeadline. Setting this to 0 along with the exclusiveRelayer to 0x0 means that there // is no exclusive deadline - depositor, - recipient, + depositor.toBytes32(), + recipient.toBytes32(), bytes32(0), // exclusiveRelayer. Setting this to 0x0 will signal to off-chain validator that there // is no exclusive relayer. message @@ -1350,14 +1347,14 @@ abstract contract SpokePool is uint256 amountToReturn, uint256[] memory refundAmounts, uint32 leafId, - bytes32 l2TokenAddress, - bytes32[] memory refundAddresses + address l2TokenAddress, + address[] memory refundAddresses ) internal returns (bool deferredRefunds) { uint256 numRefunds = refundAmounts.length; if (refundAddresses.length != numRefunds) revert InvalidMerkleLeaf(); if (numRefunds > 0) { - uint256 spokeStartBalance = IERC20Upgradeable(l2TokenAddress.toAddress()).balanceOf(address(this)); + uint256 spokeStartBalance = IERC20Upgradeable(l2TokenAddress).balanceOf(address(this)); uint256 totalRefundedAmount = 0; // Track the total amount refunded. // Send each relayer refund address the associated refundAmount for the L2 token address. @@ -1371,11 +1368,7 @@ abstract contract SpokePool is // prevents can only re-pay some of the relayers. if (totalRefundedAmount > spokeStartBalance) revert InsufficientSpokePoolBalanceToExecuteLeaf(); - bool success = _noRevertTransfer( - l2TokenAddress.toAddress(), - refundAddresses[i].toAddress(), - refundAmounts[i] - ); + bool success = _noRevertTransfer(l2TokenAddress, refundAddresses[i], refundAmounts[i]); // If the transfer failed then track a deferred transfer for the relayer. Given this function would // have revered if there was insufficient balance, this will only happen if the transfer call @@ -1391,9 +1384,9 @@ abstract contract SpokePool is // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via // chain-specific bridging method. if (amountToReturn > 0) { - _bridgeTokensToHubPool(amountToReturn, l2TokenAddress.toAddress()); + _bridgeTokensToHubPool(amountToReturn, l2TokenAddress); - emit TokensBridged(amountToReturn, _chainId, leafId, l2TokenAddress, msg.sender); + emit TokensBridged(amountToReturn, _chainId, leafId, l2TokenAddress.toBytes32(), msg.sender); } } @@ -1429,7 +1422,7 @@ abstract contract SpokePool is emit SetWithdrawalRecipient(newWithdrawalRecipient); } - function _preExecuteLeafHook(bytes32) internal virtual { + function _preExecuteLeafHook(address) internal virtual { // This method by default is a no-op. Different child spoke pools might want to execute functionality here // such as wrapping any native tokens owned by the contract into wrapped tokens before proceeding with // executing the leaf. @@ -1633,11 +1626,11 @@ abstract contract SpokePool is // Determine whether the combination of exlcusiveRelayer and exclusivityDeadline implies active exclusivity. function _fillIsExclusive( - bytes32 exclusiveRelayer, + address exclusiveRelayer, uint32 exclusivityDeadline, uint32 currentTime ) internal pure returns (bool) { - return exclusivityDeadline >= currentTime && exclusiveRelayer != bytes32(0); + return exclusivityDeadline >= currentTime && exclusiveRelayer != address(0); } // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute diff --git a/contracts/ZkSync_SpokePool.sol b/contracts/ZkSync_SpokePool.sol index 65fb4b16c..3224e4cb3 100644 --- a/contracts/ZkSync_SpokePool.sol +++ b/contracts/ZkSync_SpokePool.sol @@ -23,7 +23,6 @@ interface IL2ETH { * @custom:security-contact bugs@across.to */ contract ZkSync_SpokePool is SpokePool { - using AddressToBytes32 for address; // On Ethereum, avoiding constructor parameters and putting them into constants reduces some of the gas cost // upon contract deployment. On zkSync the opposite is true: deploying the same bytecode for contracts, // while changing only constructor parameters can lead to substantial fee savings. So, the following params @@ -89,8 +88,8 @@ contract ZkSync_SpokePool is SpokePool { * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives * ETH over the canonical token bridge instead of WETH. */ - function _preExecuteLeafHook(bytes32 l2TokenAddress) internal override { - if (l2TokenAddress == address(wrappedNativeToken).toBytes32()) _depositEthToWeth(); + function _preExecuteLeafHook(address l2TokenAddress) internal override { + if (l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth(); } // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because diff --git a/contracts/interfaces/SpokePoolInterface.sol b/contracts/interfaces/SpokePoolInterface.sol index 248eee292..08bd4aae8 100644 --- a/contracts/interfaces/SpokePoolInterface.sol +++ b/contracts/interfaces/SpokePoolInterface.sol @@ -17,9 +17,9 @@ interface SpokePoolInterface { // Used as the index in the bitmap to track whether this leaf has been executed or not. uint32 leafId; // The associated L2TokenAddress that these claims apply to. - bytes32 l2TokenAddress; + address l2TokenAddress; // Must be same length as refundAmounts and designates each address that must be refunded. - bytes32[] refundAddresses; + address[] refundAddresses; } // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced diff --git a/contracts/test/MockSpokePool.sol b/contracts/test/MockSpokePool.sol index 721bad51d..a19a02138 100644 --- a/contracts/test/MockSpokePool.sol +++ b/contracts/test/MockSpokePool.sol @@ -52,8 +52,8 @@ contract MockSpokePool is SpokePool, MockV2SpokePoolInterface, OwnableUpgradeabl uint256 amountToReturn, uint256[] memory refundAmounts, uint32 leafId, - bytes32 l2TokenAddress, - bytes32[] memory refundAddresses + address l2TokenAddress, + address[] memory refundAddresses ) external { _distributeRelayerRefunds(_chainId, amountToReturn, refundAmounts, leafId, l2TokenAddress, refundAddresses); } @@ -152,8 +152,8 @@ contract MockSpokePool is SpokePool, MockV2SpokePoolInterface, OwnableUpgradeabl return currentTime; } - function _preExecuteLeafHook(bytes32 token) internal override { - emit PreLeafExecuteHook(token); + function _preExecuteLeafHook(address token) internal override { + emit PreLeafExecuteHook(token.toBytes32()); } function _bridgeTokensToHubPool(uint256 amount, address token) internal override { diff --git a/test/evm/foundry/fork/BlacklistedRelayerRecipient.t.sol b/test/evm/foundry/fork/BlacklistedRelayerRecipient.t.sol index c7a5b4831..65bbdbdb5 100644 --- a/test/evm/foundry/fork/BlacklistedRelayerRecipient.t.sol +++ b/test/evm/foundry/fork/BlacklistedRelayerRecipient.t.sol @@ -80,9 +80,9 @@ contract MockSpokePoolTest is Test { uint256[] memory refundAmounts = new uint256[](1); refundAmounts[0] = 420 * 10**6; - bytes32[] memory refundAddresses = new bytes32[](1); - refundAddresses[0] = toBytes32(recipient1); - spokePool.distributeRelayerRefunds(1, 0, refundAmounts, 0, toBytes32(address(usdt)), refundAddresses); + address[] memory refundAddresses = new address[](1); + refundAddresses[0] = recipient1; + spokePool.distributeRelayerRefunds(1, 0, refundAmounts, 0, address(usdt), refundAddresses); assertEq(usdt.balanceOf(recipient1), refundAmounts[0], "Recipient should have received refund"); assertEq(usdt.balanceOf(address(spokePool)), seedAmount - refundAmounts[0], "SpokePool bal should drop"); @@ -91,7 +91,7 @@ contract MockSpokePoolTest is Test { assertEq(usdc.balanceOf(recipient1), 0, "Recipient should start with 0 USDC balance"); assertEq(usdc.balanceOf(address(spokePool)), seedAmount, "SpokePool should have seed USDC balance"); - spokePool.distributeRelayerRefunds(1, 0, refundAmounts, 0, toBytes32(address(usdc)), refundAddresses); + spokePool.distributeRelayerRefunds(1, 0, refundAmounts, 0, address(usdc), refundAddresses); assertEq(usdc.balanceOf(recipient1), refundAmounts[0], "Recipient should have received refund"); assertEq(usdc.balanceOf(address(spokePool)), seedAmount - refundAmounts[0], "SpokePool bal should drop"); @@ -113,16 +113,16 @@ contract MockSpokePoolTest is Test { refundAmounts[0] = 420 * 10**6; refundAmounts[1] = 69 * 10**6; - bytes32[] memory refundAddresses = new bytes32[](2); - refundAddresses[0] = toBytes32(recipient1); - refundAddresses[1] = toBytes32(recipient2); - spokePool.distributeRelayerRefunds(1, 0, refundAmounts, 0, toBytes32(address(usdt)), refundAddresses); + address[] memory refundAddresses = new address[](2); + refundAddresses[0] = recipient1; + refundAddresses[1] = recipient2; + spokePool.distributeRelayerRefunds(1, 0, refundAmounts, 0, address(usdt), refundAddresses); assertEq(usdt.balanceOf(recipient1), refundAmounts[0], "Recipient1 should have received their refund"); assertEq(usdt.balanceOf(recipient2), refundAmounts[1], "Recipient2 should have received their refund"); - assertEq(spokePool.getRelayerRefund(address(usdt).toBytes32(), recipient1.toBytes32()), 0); - assertEq(spokePool.getRelayerRefund(address(usdt).toBytes32(), recipient2.toBytes32()), 0); + assertEq(spokePool.getRelayerRefund(address(usdt), recipient1), 0); + assertEq(spokePool.getRelayerRefund(address(usdt), recipient2), 0); } function testSomeRecipientsBlacklistedDoesNotBlockTheWholeRefundUsdc() public { @@ -140,23 +140,23 @@ contract MockSpokePoolTest is Test { refundAmounts[0] = 420 * 10**6; refundAmounts[1] = 69 * 10**6; - bytes32[] memory refundAddresses = new bytes32[](2); - refundAddresses[0] = toBytes32(recipient1); - refundAddresses[1] = toBytes32(recipient2); - spokePool.distributeRelayerRefunds(1, 0, refundAmounts, 0, toBytes32(address(usdc)), refundAddresses); + address[] memory refundAddresses = new address[](2); + refundAddresses[0] = recipient1; + refundAddresses[1] = recipient2; + spokePool.distributeRelayerRefunds(1, 0, refundAmounts, 0, address(usdc), refundAddresses); assertEq(usdc.balanceOf(recipient1), 0, "Recipient1 should have 0 refund as blacklisted"); assertEq(usdc.balanceOf(recipient2), refundAmounts[1], "Recipient2 should have received their refund"); - assertEq(spokePool.getRelayerRefund(address(usdc).toBytes32(), recipient1.toBytes32()), refundAmounts[0]); - assertEq(spokePool.getRelayerRefund(address(usdc).toBytes32(), recipient2.toBytes32()), 0); + assertEq(spokePool.getRelayerRefund(address(usdc), recipient1), refundAmounts[0]); + assertEq(spokePool.getRelayerRefund(address(usdc), recipient2), 0); // Now, blacklisted recipient should be able to claim refund to a new address. address newRecipient = address(0x6969693333333420); vm.prank(recipient1); spokePool.claimRelayerRefund(address(usdc).toBytes32(), newRecipient.toBytes32()); assertEq(usdc.balanceOf(newRecipient), refundAmounts[0], "New recipient should have received relayer2 refund"); - assertEq(spokePool.getRelayerRefund(address(usdt).toBytes32(), recipient1.toBytes32()), 0); + assertEq(spokePool.getRelayerRefund(address(usdt), recipient1), 0); } function toBytes32(address _address) internal pure returns (bytes32) { diff --git a/test/evm/hardhat/MerkleLib.Proofs.ts b/test/evm/hardhat/MerkleLib.Proofs.ts index ff756e7a8..77e88b035 100644 --- a/test/evm/hardhat/MerkleLib.Proofs.ts +++ b/test/evm/hardhat/MerkleLib.Proofs.ts @@ -4,6 +4,7 @@ import { MerkleTree, EMPTY_MERKLE_ROOT } from "../../../utils/MerkleTree"; import { expect, randomBigNumber, + randomAddress, getParamType, defaultAbiCoder, keccak256, @@ -11,7 +12,6 @@ import { BigNumber, ethers, randomBytes32, - randomAddress, } from "../../../utils/utils"; import { V3RelayData, V3SlowFill } from "../../../test-utils"; @@ -81,14 +81,14 @@ describe("MerkleLib Proofs", async function () { const refundAddresses: string[] = []; const refundAmounts: BigNumber[] = []; for (let j = 0; j < numAddresses; j++) { - refundAddresses.push(randomBytes32()); + refundAddresses.push(randomAddress()); refundAmounts.push(randomBigNumber()); } relayerRefundLeaves.push({ leafId: BigNumber.from(i), chainId: randomBigNumber(2), amountToReturn: randomBigNumber(), - l2TokenAddress: randomBytes32(), + l2TokenAddress: randomAddress(), refundAddresses, refundAmounts, }); diff --git a/test/evm/hardhat/MerkleLib.utils.ts b/test/evm/hardhat/MerkleLib.utils.ts index 39e6aa3a6..ff2b605f9 100644 --- a/test/evm/hardhat/MerkleLib.utils.ts +++ b/test/evm/hardhat/MerkleLib.utils.ts @@ -110,7 +110,7 @@ export async function constructSingleRelayerRefundTree(l2Token: Contract | Strin const leaves = buildRelayerRefundLeaves( [destinationChainId], // Destination chain ID. [amountToReturn], // amountToReturn. - [addressToBytes(l2Token as string)], // l2Token. + [l2Token as string], // l2Token. [[]], // refundAddresses. [[]] // refundAmounts. ); diff --git a/test/evm/hardhat/SpokePool.Admin.ts b/test/evm/hardhat/SpokePool.Admin.ts index f51adf376..149a74909 100644 --- a/test/evm/hardhat/SpokePool.Admin.ts +++ b/test/evm/hardhat/SpokePool.Admin.ts @@ -23,7 +23,7 @@ describe("SpokePool Admin Functions", async function () { await expect(spokePool.connect(owner).setEnableRoute(erc20.address, destinationChainId, true)) .to.emit(spokePool, "EnabledDepositRoute") .withArgs(erc20.address, destinationChainId, true); - expect(await spokePool.enabledDepositRoutes(addressToBytes(erc20.address), destinationChainId)).to.equal(true); + expect(await spokePool.enabledDepositRoutes(erc20.address, destinationChainId)).to.equal(true); }); it("Pause deposits", async function () { diff --git a/test/evm/hardhat/SpokePool.ClaimRelayerRefund.ts b/test/evm/hardhat/SpokePool.ClaimRelayerRefund.ts index 3248d34fd..2c9778fd8 100644 --- a/test/evm/hardhat/SpokePool.ClaimRelayerRefund.ts +++ b/test/evm/hardhat/SpokePool.ClaimRelayerRefund.ts @@ -41,9 +41,7 @@ describe("SpokePool with Blacklisted destErc20", function () { it("Executes repayments and handles blacklisted addresses", async function () { // No starting relayer liability. - expect( - await spokePool.getRelayerRefund(addressToBytes(destErc20.address), addressToBytes(relayer.address)) - ).to.equal(toBN(0)); + expect(await spokePool.getRelayerRefund(destErc20.address, relayer.address)).to.equal(toBN(0)); expect(await destErc20.balanceOf(rando.address)).to.equal(toBN(0)); expect(await destErc20.balanceOf(relayer.address)).to.equal(toBN(0)); // Blacklist the relayer @@ -58,14 +56,12 @@ describe("SpokePool with Blacklisted destErc20", function () { consts.amountToReturn, [consts.amountToRelay, consts.amountToRelay], 0, - addressToBytes(destErc20.address), - [addressToBytes(relayer.address), addressToBytes(rando.address)] + destErc20.address, + [relayer.address, rando.address] ); // Ensure relayerRepaymentLiability is incremented - expect( - await spokePool.getRelayerRefund(addressToBytes(destErc20.address), addressToBytes(relayer.address)) - ).to.equal(consts.amountToRelay); + expect(await spokePool.getRelayerRefund(destErc20.address, relayer.address)).to.equal(consts.amountToRelay); expect(await destErc20.balanceOf(rando.address)).to.equal(consts.amountToRelay); expect(await destErc20.balanceOf(relayer.address)).to.equal(toBN(0)); }); @@ -79,8 +75,8 @@ describe("SpokePool with Blacklisted destErc20", function () { consts.amountToReturn, [consts.amountToRelay], 0, - addressToBytes(destErc20.address), - [addressToBytes(relayer.address)] + destErc20.address, + [relayer.address] ); await expect( diff --git a/test/evm/hardhat/SpokePool.ExecuteRootBundle.ts b/test/evm/hardhat/SpokePool.ExecuteRootBundle.ts index 4e35aa9e6..fefc39678 100644 --- a/test/evm/hardhat/SpokePool.ExecuteRootBundle.ts +++ b/test/evm/hardhat/SpokePool.ExecuteRootBundle.ts @@ -22,8 +22,8 @@ async function constructSimpleTree(l2Token: Contract, destinationChainId: number const leaves = buildRelayerRefundLeaves( [destinationChainId, destinationChainId], // Destination chain ID. [consts.amountToReturn, toBN(0)], // amountToReturn. - [addressToBytes(l2Token.address), addressToBytes(l2Token.address)], // l2Token. - [[addressToBytes(relayer.address), addressToBytes(rando.address)], []], // refundAddresses. + [l2Token.address, l2Token.address], // l2Token. + [[relayer.address, rando.address], []], // refundAddresses. [[consts.amountToRelay, consts.amountToRelay], []] // refundAmounts. ); const leavesRefundAmount = leaves @@ -63,18 +63,14 @@ describe("SpokePool Root Bundle Execution", function () { // Check events. let relayTokensEvents = await spokePool.queryFilter(spokePool.filters.ExecutedRelayerRefundRoot()); - expect(relayTokensEvents[0].args?.l2TokenAddress).to.equal(addressToBytes(destErc20.address)); + expect(relayTokensEvents[0].args?.l2TokenAddress).to.equal(destErc20.address); expect(relayTokensEvents[0].args?.leafId).to.equal(0); expect(relayTokensEvents[0].args?.chainId).to.equal(destinationChainId); expect(relayTokensEvents[0].args?.amountToReturn).to.equal(consts.amountToReturn); expect((relayTokensEvents[0].args?.refundAmounts as BigNumber[]).map((v) => v.toString())).to.deep.equal( [consts.amountToRelay, consts.amountToRelay].map((v) => v.toString()) ); - expect(relayTokensEvents[0].args?.refundAddresses).to.deep.equal([ - addressToBytes(relayer.address), - addressToBytes(rando.address), - ]); - expect(relayTokensEvents[0].args?.deferredRefunds).to.equal(false); + expect(relayTokensEvents[0].args?.refundAddresses).to.deep.equal([relayer.address, rando.address]); // Should emit TokensBridged event if amountToReturn is positive. let tokensBridgedEvents = await spokePool.queryFilter(spokePool.filters.TokensBridged()); @@ -98,8 +94,8 @@ describe("SpokePool Root Bundle Execution", function () { totalSolanaDistributions: evmDistributions, mixLeaves: true, chainId: destinationChainId, - evmTokenAddress: addressToBytes(destErc20.address), - evmRelayers: [addressToBytes(relayer.address), addressToBytes(rando.address)], + evmTokenAddress: destErc20.address, + evmRelayers: [relayer.address, rando.address], evmRefundAmounts: [consts.amountToRelay.div(evmDistributions), consts.amountToRelay.div(evmDistributions)], }); @@ -134,8 +130,8 @@ describe("SpokePool Root Bundle Execution", function () { totalSolanaDistributions: evmDistributions, mixLeaves: false, chainId: destinationChainId, - evmTokenAddress: addressToBytes(destErc20.address), - evmRelayers: [addressToBytes(relayer.address), addressToBytes(rando.address)], + evmTokenAddress: destErc20.address, + evmRelayers: [relayer.address, rando.address], evmRefundAmounts: [consts.amountToRelay.div(evmDistributions), consts.amountToRelay.div(evmDistributions)], }); @@ -236,8 +232,8 @@ describe("SpokePool Root Bundle Execution", function () { toBN(1), [consts.amountToRelay, consts.amountToRelay, toBN(0)], 0, - addressToBytes(destErc20.address), - [addressToBytes(relayer.address), addressToBytes(rando.address)] + destErc20.address, + [relayer.address, rando.address] ) ).to.be.revertedWith("InvalidMerkleLeaf"); }); @@ -246,7 +242,7 @@ describe("SpokePool Root Bundle Execution", function () { await expect( spokePool .connect(dataWorker) - .distributeRelayerRefunds(destinationChainId, toBN(1), [], 0, addressToBytes(destErc20.address), []) + .distributeRelayerRefunds(destinationChainId, toBN(1), [], 0, destErc20.address, []) ) .to.emit(spokePool, "BridgedToHubPool") .withArgs(toBN(1), destErc20.address); @@ -255,7 +251,7 @@ describe("SpokePool Root Bundle Execution", function () { await expect( spokePool .connect(dataWorker) - .distributeRelayerRefunds(destinationChainId, toBN(1), [], 0, addressToBytes(destErc20.address), []) + .distributeRelayerRefunds(destinationChainId, toBN(1), [], 0, destErc20.address, []) ) .to.emit(spokePool, "TokensBridged") .withArgs(toBN(1), destinationChainId, 0, addressToBytes(destErc20.address), dataWorker.address); @@ -266,14 +262,14 @@ describe("SpokePool Root Bundle Execution", function () { await expect( spokePool .connect(dataWorker) - .distributeRelayerRefunds(destinationChainId, toBN(0), [], 0, addressToBytes(destErc20.address), []) + .distributeRelayerRefunds(destinationChainId, toBN(0), [], 0, destErc20.address, []) ).to.not.emit(spokePool, "BridgedToHubPool"); }); it("does not emit TokensBridged", async function () { await expect( spokePool .connect(dataWorker) - .distributeRelayerRefunds(destinationChainId, toBN(0), [], 0, addressToBytes(destErc20.address), []) + .distributeRelayerRefunds(destinationChainId, toBN(0), [], 0, destErc20.address, []) ).to.not.emit(spokePool, "TokensBridged"); }); }); @@ -287,8 +283,8 @@ describe("SpokePool Root Bundle Execution", function () { toBN(1), [consts.amountToRelay, consts.amountToRelay, toBN(0)], 0, - addressToBytes(destErc20.address), - [addressToBytes(relayer.address), addressToBytes(rando.address), addressToBytes(rando.address)] + destErc20.address, + [relayer.address, rando.address, rando.address] ) ).to.changeTokenBalances( destErc20, @@ -307,8 +303,8 @@ describe("SpokePool Root Bundle Execution", function () { toBN(1), [consts.amountToRelay, consts.amountToRelay, toBN(0)], 0, - addressToBytes(destErc20.address), - [addressToBytes(relayer.address), addressToBytes(rando.address), addressToBytes(rando.address)] + destErc20.address, + [relayer.address, rando.address, rando.address] ) ) .to.emit(spokePool, "BridgedToHubPool") @@ -323,8 +319,8 @@ describe("SpokePool Root Bundle Execution", function () { toBN(1), [consts.amountHeldByPool, consts.amountToRelay], // spoke has only amountHeldByPool. 0, - addressToBytes(destErc20.address), - [addressToBytes(relayer.address), addressToBytes(rando.address)] + destErc20.address, + [relayer.address, rando.address] ) ).to.be.revertedWith("InsufficientSpokePoolBalanceToExecuteLeaf"); diff --git a/test/evm/hardhat/chain-specific-spokepools/Arbitrum_SpokePool.ts b/test/evm/hardhat/chain-specific-spokepools/Arbitrum_SpokePool.ts index c76ffe94c..723e513e9 100644 --- a/test/evm/hardhat/chain-specific-spokepools/Arbitrum_SpokePool.ts +++ b/test/evm/hardhat/chain-specific-spokepools/Arbitrum_SpokePool.ts @@ -80,7 +80,7 @@ describe("Arbitrum Spoke Pool", function () { it("Only cross domain owner can enable a route", async function () { await expect(arbitrumSpokePool.setEnableRoute(l2Dai, 1, true)).to.be.reverted; await arbitrumSpokePool.connect(crossDomainAlias).setEnableRoute(l2Dai, 1, true); - expect(await arbitrumSpokePool.enabledDepositRoutes(addressToBytes(l2Dai), 1)).to.equal(true); + expect(await arbitrumSpokePool.enabledDepositRoutes(l2Dai, 1)).to.equal(true); }); it("Only cross domain owner can whitelist a token pair", async function () { diff --git a/test/evm/hardhat/chain-specific-spokepools/Ethereum_SpokePool.ts b/test/evm/hardhat/chain-specific-spokepools/Ethereum_SpokePool.ts index 1b5966135..a7b2d0823 100644 --- a/test/evm/hardhat/chain-specific-spokepools/Ethereum_SpokePool.ts +++ b/test/evm/hardhat/chain-specific-spokepools/Ethereum_SpokePool.ts @@ -55,7 +55,7 @@ describe("Ethereum Spoke Pool", function () { it("Only owner can enable a route", async function () { await expect(spokePool.connect(rando).setEnableRoute(dai.address, 1, true)).to.be.reverted; await spokePool.connect(owner).setEnableRoute(dai.address, 1, true); - expect(await spokePool.enabledDepositRoutes(addressToBytes(dai.address), 1)).to.equal(true); + expect(await spokePool.enabledDepositRoutes(dai.address, 1)).to.equal(true); }); it("Only owner can set the hub pool address", async function () { diff --git a/test/evm/hardhat/chain-specific-spokepools/Optimism_SpokePool.ts b/test/evm/hardhat/chain-specific-spokepools/Optimism_SpokePool.ts index 460e19a3d..f629007fb 100644 --- a/test/evm/hardhat/chain-specific-spokepools/Optimism_SpokePool.ts +++ b/test/evm/hardhat/chain-specific-spokepools/Optimism_SpokePool.ts @@ -94,7 +94,7 @@ describe("Optimism Spoke Pool", function () { await expect(optimismSpokePool.setEnableRoute(l2Dai, 1, true)).to.be.reverted; crossDomainMessenger.xDomainMessageSender.returns(owner.address); await optimismSpokePool.connect(crossDomainMessenger.wallet).setEnableRoute(l2Dai, 1, true); - expect(await optimismSpokePool.enabledDepositRoutes(addressToBytes(l2Dai), 1)).to.equal(true); + expect(await optimismSpokePool.enabledDepositRoutes(l2Dai, 1)).to.equal(true); }); it("Only cross domain owner can set the cross domain admin", async function () { diff --git a/test/evm/hardhat/chain-specific-spokepools/Polygon_SpokePool.ts b/test/evm/hardhat/chain-specific-spokepools/Polygon_SpokePool.ts index 9ef4bff15..650024636 100644 --- a/test/evm/hardhat/chain-specific-spokepools/Polygon_SpokePool.ts +++ b/test/evm/hardhat/chain-specific-spokepools/Polygon_SpokePool.ts @@ -156,7 +156,7 @@ describe("Polygon Spoke Pool", function () { .reverted; await polygonSpokePool.connect(fxChild).processMessageFromRoot(0, owner.address, setEnableRouteData); - expect(await polygonSpokePool.enabledDepositRoutes(addressToBytes(l2Dai), 1)).to.equal(true); + expect(await polygonSpokePool.enabledDepositRoutes(l2Dai, 1)).to.equal(true); }); it("Only correct caller can initialize a relayer refund", async function () { @@ -261,7 +261,7 @@ describe("Polygon Spoke Pool", function () { const leaves = buildRelayerRefundLeaves( [l2ChainId, l2ChainId], // Destination chain ID. [amountToReturn, ethers.constants.Zero], // amountToReturn. - [addressToBytes(dai.address), addressToBytes(dai.address)], // l2Token. + [dai.address, dai.address], // l2Token. [[], []], // refundAddresses. [[], []] // refundAmounts. ); @@ -289,7 +289,7 @@ describe("Polygon Spoke Pool", function () { const leaves = buildRelayerRefundLeaves( [l2ChainId, l2ChainId], // Destination chain ID. [ethers.constants.Zero, ethers.constants.Zero], // amountToReturn. - [addressToBytes(dai.address), addressToBytes(dai.address)], // l2Token. + [dai.address, dai.address], // l2Token. [[], []], // refundAddresses. [[], []] // refundAmounts. ); diff --git a/test/svm/utils.ts b/test/svm/utils.ts index 210e940e7..393305bc8 100644 --- a/test/svm/utils.ts +++ b/test/svm/utils.ts @@ -101,14 +101,6 @@ export function buildRelayerRefundMerkleTree({ }): { relayerRefundLeaves: RelayerRefundLeafType[]; merkleTree: MerkleTree } { const relayerRefundLeaves: RelayerRefundLeafType[] = []; - if (evmTokenAddress && !isBytes32(evmTokenAddress)) { - throw new Error("EVM token address must be a bytes32 address"); - } - - if (evmRelayers && evmRelayers.some((address) => !isBytes32(address))) { - throw new Error("EVM relayers must be bytes32 addresses"); - } - const createSolanaLeaf = (index: number) => ({ isSolana: true, leafId: new BN(index), @@ -125,8 +117,8 @@ export function buildRelayerRefundMerkleTree({ leafId: BigNumber.from(index), chainId: BigNumber.from(chainId), amountToReturn: BigNumber.from(0), - l2TokenAddress: evmTokenAddress ?? addressToBytes(randomAddress()), - refundAddresses: evmRelayers || [addressToBytes(randomAddress()), addressToBytes(randomAddress())], + l2TokenAddress: evmTokenAddress ?? randomAddress(), + refundAddresses: evmRelayers || [randomAddress(), randomAddress()], refundAmounts: evmRefundAmounts || [BigNumber.from(randomBigInt()), BigNumber.from(randomBigInt())], } as RelayerRefundLeaf); @@ -186,7 +178,7 @@ export const relayerRefundHashFn = (input: RelayerRefundLeaf | RelayerRefundLeaf const abiCoder = new ethers.utils.AbiCoder(); const encodedData = abiCoder.encode( [ - "tuple( uint256 amountToReturn, uint256 chainId, uint256[] refundAmounts, uint256 leafId, bytes32 l2TokenAddress, bytes32[] refundAddresses)", + "tuple( uint256 amountToReturn, uint256 chainId, uint256[] refundAmounts, uint256 leafId, address l2TokenAddress, address[] refundAddresses)", ], [ {