Skip to content

feat(SpokePool): Remove enabledDepositRoutes check for unsafeDeposit #926

New issue

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

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

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 1 addition & 27 deletions contracts/SpokePool.sol
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,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(address => mapping(uint256 => bool)) public enabledDepositRoutes;
mapping(address => mapping(uint256 => bool)) public DEPRECATED_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
Expand Down Expand Up @@ -315,21 +315,6 @@ abstract contract SpokePool is
_setWithdrawalRecipient(newWithdrawalRecipient);
}

/**
* @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.
* @param originToken Token that depositor can deposit to this contract.
* @param destinationChainId Chain ID for where depositor wants to receive funds.
* @param enabled True to enable deposits, False otherwise.
*/
function setEnableRoute(
address originToken,
uint256 destinationChainId,
bool enabled
) public override onlyAdmin nonReentrant {
enabledDepositRoutes[originToken][destinationChainId] = enabled;
emit EnabledDepositRoute(originToken, destinationChainId, enabled);
}

/**
* @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill
* slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is
Expand Down Expand Up @@ -627,10 +612,6 @@ abstract contract SpokePool is
* corresponding fill might collide with an existing relay hash on the destination chain SpokePool,
* which would make this deposit unfillable. In this case, the depositor would subsequently receive a refund
* of `inputAmount` of `inputToken` on the origin chain after the fill deadline.
* @dev On the destination chain, the hash of the deposit data will be used to uniquely identify this deposit, so
* modifying any params in it will result in a different hash and a different deposit. The hash will comprise
* all parameters to this function along with this chain's chainId(). Relayers are only refunded for filling
* deposits with deposit hashes that map exactly to the one emitted by this contract.
* @param depositNonce The nonce that uniquely identifies this deposit. This function will combine this parameter
* with the msg.sender address to create a unique uint256 depositNonce and ensure that the msg.sender cannot
* use this function to front-run another depositor's unsafe deposit. This function guarantees that the resultant
Expand Down Expand Up @@ -1311,10 +1292,6 @@ abstract contract SpokePool is
// Verify depositor is a valid EVM address.
params.depositor.checkAddress();

// 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[params.inputToken.toAddress()][params.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
// SpokePool time stalls or lags significantly, it is still possible to make deposits by setting quoteTimestamp
Expand Down Expand Up @@ -1400,9 +1377,6 @@ abstract contract SpokePool is
uint32 quoteTimestamp,
bytes memory message
) internal {
// Check that deposit route is enabled.
if (!enabledDepositRoutes[originToken][destinationChainId]) revert DisabledRoute();

// We limit the relay fees to prevent the user spending all their funds on fees.
if (SignedMath.abs(relayerFeePct) >= 0.5e18) revert InvalidRelayerFeePct();
if (amount > MAX_TRANSFER_SIZE) revert MaxTransferSizeExceeded();
Expand Down
46 changes: 1 addition & 45 deletions contracts/chain-adapters/Solana_Adapter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,6 @@ contract Solana_Adapter is AdapterInterface, CircleCCTPAdapter {
// Solana spoke pool address, mapped to its EVM address representation.
address public immutable SOLANA_SPOKE_POOL_ADDRESS;

// USDC mint address on Solana, decoded from Base58 to bytes32.
bytes32 public immutable SOLANA_USDC_BYTES32;

// USDC mint address on Solana, mapped to its EVM address representation.
address public immutable SOLANA_USDC_ADDRESS;

Expand All @@ -56,8 +53,6 @@ contract Solana_Adapter is AdapterInterface, CircleCCTPAdapter {

// Custom errors for relayMessage validation.
error InvalidRelayMessageTarget(address target);
error InvalidOriginToken(address originToken);
error InvalidDestinationChainId(uint256 destinationChainId);

// Custom errors for relayTokens validation.
error InvalidL1Token(address l1Token);
Expand Down Expand Up @@ -95,7 +90,6 @@ contract Solana_Adapter is AdapterInterface, CircleCCTPAdapter {
SOLANA_SPOKE_POOL_BYTES32 = solanaSpokePool;
SOLANA_SPOKE_POOL_ADDRESS = solanaSpokePool.toAddressUnchecked();

SOLANA_USDC_BYTES32 = solanaUsdc;
SOLANA_USDC_ADDRESS = solanaUsdc.toAddressUnchecked();

SOLANA_SPOKE_POOL_USDC_VAULT = solanaSpokePoolUsdcVault;
Expand All @@ -111,17 +105,7 @@ contract Solana_Adapter is AdapterInterface, CircleCCTPAdapter {
if (target != SOLANA_SPOKE_POOL_ADDRESS) {
revert InvalidRelayMessageTarget(target);
}

bytes4 selector = bytes4(message[:4]);
if (selector == SpokePoolInterface.setEnableRoute.selector) {
cctpMessageTransmitter.sendMessage(
CircleDomainIds.Solana,
SOLANA_SPOKE_POOL_BYTES32,
_translateSetEnableRoute(message)
);
} else {
cctpMessageTransmitter.sendMessage(CircleDomainIds.Solana, SOLANA_SPOKE_POOL_BYTES32, message);
}
cctpMessageTransmitter.sendMessage(CircleDomainIds.Solana, SOLANA_SPOKE_POOL_BYTES32, message);

// TODO: consider if we need also to emit the translated message.
emit MessageRelayed(target, message);
Expand Down Expand Up @@ -159,32 +143,4 @@ contract Solana_Adapter is AdapterInterface, CircleCCTPAdapter {
// TODO: consider if we need also to emit the translated addresses.
emit TokensRelayed(l1Token, l2Token, amount, to);
}

/**
* @notice Translates a message to enable/disable a route on Solana spoke pool.
* @param message Message to translate, expecting setEnableRoute(address,uint256,bool).
* @return Translated message, using setEnableRoute(bytes32,uint64,bool).
*/
function _translateSetEnableRoute(bytes calldata message) internal view returns (bytes memory) {
(address originToken, uint256 destinationChainId, bool enable) = abi.decode(
message[4:],
(address, uint256, bool)
);

if (originToken != SOLANA_USDC_ADDRESS) {
revert InvalidOriginToken(originToken);
}

if (destinationChainId > type(uint64).max) {
revert InvalidDestinationChainId(destinationChainId);
}

return
abi.encodeWithSignature(
"setEnableRoute(bytes32,uint64,bool)",
SOLANA_USDC_BYTES32,
uint64(destinationChainId),
enable
);
}
}
6 changes: 0 additions & 6 deletions contracts/interfaces/SpokePoolInterface.sol
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,6 @@ interface SpokePoolInterface {

function setWithdrawalRecipient(address newWithdrawalRecipient) external;

function setEnableRoute(
address originToken,
uint256 destinationChainId,
bool enable
) external;

function pauseDeposits(bool pause) external;

function pauseFills(bool pause) external;
Expand Down
2 changes: 1 addition & 1 deletion storage-layouts/AlephZero_SpokePool.json
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@
},
{
"contract": "contracts/AlephZero_SpokePool.sol:AlephZero_SpokePool",
"label": "enabledDepositRoutes",
"label": "DEPRECATED_enabledDepositRoutes",
"offset": 0,
"slot": "2157"
},
Expand Down
2 changes: 1 addition & 1 deletion storage-layouts/Arbitrum_SpokePool.json
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@
},
{
"contract": "contracts/Arbitrum_SpokePool.sol:Arbitrum_SpokePool",
"label": "enabledDepositRoutes",
"label": "DEPRECATED_enabledDepositRoutes",
"offset": 0,
"slot": "2157"
},
Expand Down
2 changes: 1 addition & 1 deletion storage-layouts/Base_SpokePool.json
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@
},
{
"contract": "contracts/Base_SpokePool.sol:Base_SpokePool",
"label": "enabledDepositRoutes",
"label": "DEPRECATED_enabledDepositRoutes",
"offset": 0,
"slot": "2157"
},
Expand Down
2 changes: 1 addition & 1 deletion storage-layouts/Blast_SpokePool.json
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@
},
{
"contract": "contracts/Blast_SpokePool.sol:Blast_SpokePool",
"label": "enabledDepositRoutes",
"label": "DEPRECATED_enabledDepositRoutes",
"offset": 0,
"slot": "2157"
},
Expand Down
2 changes: 1 addition & 1 deletion storage-layouts/Ethereum_SpokePool.json
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@
},
{
"contract": "contracts/Ethereum_SpokePool.sol:Ethereum_SpokePool",
"label": "enabledDepositRoutes",
"label": "DEPRECATED_enabledDepositRoutes",
"offset": 0,
"slot": "2157"
},
Expand Down
2 changes: 1 addition & 1 deletion storage-layouts/Linea_SpokePool.json
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@
},
{
"contract": "contracts/Linea_SpokePool.sol:Linea_SpokePool",
"label": "enabledDepositRoutes",
"label": "DEPRECATED_enabledDepositRoutes",
"offset": 0,
"slot": "2157"
},
Expand Down
2 changes: 1 addition & 1 deletion storage-layouts/Mode_SpokePool.json
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@
},
{
"contract": "contracts/Mode_SpokePool.sol:Mode_SpokePool",
"label": "enabledDepositRoutes",
"label": "DEPRECATED_enabledDepositRoutes",
"offset": 0,
"slot": "2157"
},
Expand Down
2 changes: 1 addition & 1 deletion storage-layouts/Optimism_SpokePool.json
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@
},
{
"contract": "contracts/Optimism_SpokePool.sol:Optimism_SpokePool",
"label": "enabledDepositRoutes",
"label": "DEPRECATED_enabledDepositRoutes",
"offset": 0,
"slot": "2157"
},
Expand Down
2 changes: 1 addition & 1 deletion storage-layouts/PolygonZkEVM_SpokePool.json
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@
},
{
"contract": "contracts/PolygonZkEVM_SpokePool.sol:PolygonZkEVM_SpokePool",
"label": "enabledDepositRoutes",
"label": "DEPRECATED_enabledDepositRoutes",
"offset": 0,
"slot": "2157"
},
Expand Down
2 changes: 1 addition & 1 deletion storage-layouts/Polygon_SpokePool.json
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@
},
{
"contract": "contracts/Polygon_SpokePool.sol:Polygon_SpokePool",
"label": "enabledDepositRoutes",
"label": "DEPRECATED_enabledDepositRoutes",
"offset": 0,
"slot": "2157"
},
Expand Down
2 changes: 1 addition & 1 deletion storage-layouts/Redstone_SpokePool.json
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@
},
{
"contract": "contracts/Redstone_SpokePool.sol:Redstone_SpokePool",
"label": "enabledDepositRoutes",
"label": "DEPRECATED_enabledDepositRoutes",
"offset": 0,
"slot": "2157"
},
Expand Down
2 changes: 1 addition & 1 deletion storage-layouts/Scroll_SpokePool.json
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@
},
{
"contract": "contracts/Scroll_SpokePool.sol:Scroll_SpokePool",
"label": "enabledDepositRoutes",
"label": "DEPRECATED_enabledDepositRoutes",
"offset": 0,
"slot": "2157"
},
Expand Down
2 changes: 1 addition & 1 deletion storage-layouts/WorldChain_SpokePool.json
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@
},
{
"contract": "contracts/WorldChain_SpokePool.sol:WorldChain_SpokePool",
"label": "enabledDepositRoutes",
"label": "DEPRECATED_enabledDepositRoutes",
"offset": 0,
"slot": "2157"
},
Expand Down
2 changes: 1 addition & 1 deletion storage-layouts/ZkSync_SpokePool.json
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@
},
{
"contract": "contracts/ZkSync_SpokePool.sol:ZkSync_SpokePool",
"label": "enabledDepositRoutes",
"label": "DEPRECATED_enabledDepositRoutes",
"offset": 0,
"slot": "2157"
},
Expand Down
2 changes: 1 addition & 1 deletion storage-layouts/Zora_SpokePool.json
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@
},
{
"contract": "contracts/Zora_SpokePool.sol:Zora_SpokePool",
"label": "enabledDepositRoutes",
"label": "DEPRECATED_enabledDepositRoutes",
"offset": 0,
"slot": "2157"
},
Expand Down
2 changes: 0 additions & 2 deletions test/evm/foundry/local/SpokePoolDeprecatedMethods.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,6 @@ contract SpokePoolOverloadedDeprecatedMethodsTest is Test {
);
spokePool = MockSpokePool(payable(proxy));

spokePool.setEnableRoute(address(mockWETH), destinationChainId, true);

vm.stopPrank();

deal(depositor, depositAmount * 2);
Expand Down
2 changes: 0 additions & 2 deletions test/evm/foundry/local/SpokePoolVerifier.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,6 @@ contract SpokePoolVerifierTest is Test {
new ERC1967Proxy(address(implementation), abi.encodeCall(Ethereum_SpokePool.initialize, (0, owner)))
);
ethereumSpokePool = Ethereum_SpokePool(payable(proxy));
ethereumSpokePool.setEnableRoute(address(mockWETH), destinationChainId, true);
ethereumSpokePool.setEnableRoute(address(mockERC20), destinationChainId, true);
spokePoolVerifier = new SpokePoolVerifier();
vm.stopPrank();

Expand Down
44 changes: 1 addition & 43 deletions test/evm/hardhat/HubPool.Admin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,7 @@ describe("HubPool Admin functions", function () {
).to.be.reverted;
});
it("Only owner can relay spoke pool admin message", async function () {
const functionData = mockSpoke.interface.encodeFunctionData("setEnableRoute", [
weth.address,
destinationChainId,
false,
]);
const functionData = mockSpoke.interface.encodeFunctionData("pauseDeposits", [true]);
await expect(hubPool.connect(other).relaySpokePoolAdminFunction(destinationChainId, functionData)).to.be.reverted;

// Cannot relay admin function if spoke pool is set to zero address or adapter is set to non contract..
Expand All @@ -91,44 +87,6 @@ describe("HubPool Admin functions", function () {
.to.emit(hubPool, "SpokePoolAdminFunctionTriggered")
.withArgs(destinationChainId, functionData);
});
it("Only owner can whitelist route for deposits and rebalances", async function () {
await hubPool.setCrossChainContracts(destinationChainId, mockAdapter.address, mockSpoke.address);
await expect(hubPool.connect(other).setPoolRebalanceRoute(destinationChainId, weth.address, usdc.address)).to.be
.reverted;
await expect(hubPool.setPoolRebalanceRoute(destinationChainId, weth.address, usdc.address))
.to.emit(hubPool, "SetPoolRebalanceRoute")
.withArgs(destinationChainId, weth.address, usdc.address);

// Relay deposit route to spoke pool. Check content of messages sent to mock spoke pool.
await expect(hubPool.connect(other).setDepositRoute(originChainId, destinationChainId, weth.address, true)).to.be
.reverted;
await expect(hubPool.setDepositRoute(originChainId, destinationChainId, weth.address, true))
.to.emit(hubPool, "SetEnableDepositRoute")
.withArgs(originChainId, destinationChainId, weth.address, true);

// Disable deposit route on SpokePool right after:
await hubPool.setDepositRoute(originChainId, destinationChainId, weth.address, false);

// Since the mock adapter is delegatecalled, when querying, its address should be the hubPool address.
const mockAdapterAtHubPool = mockAdapter.attach(hubPool.address);
const relayMessageEvents = await mockAdapterAtHubPool.queryFilter(
mockAdapterAtHubPool.filters.RelayMessageCalled()
);
expect(relayMessageEvents[relayMessageEvents.length - 1].args?.message).to.equal(
mockSpoke.interface.encodeFunctionData("setEnableRoute", [
weth.address,
destinationChainId,
false, // Latest call disabled the route
])
);
expect(relayMessageEvents[relayMessageEvents.length - 2].args?.message).to.equal(
mockSpoke.interface.encodeFunctionData("setEnableRoute", [
weth.address,
destinationChainId,
true, // Second to last call enabled the route
])
);
});

it("Can change the bond token and amount", async function () {
expect(await hubPool.callStatic.bondToken()).to.equal(weth.address); // Default set in the fixture.
Expand Down
6 changes: 0 additions & 6 deletions test/evm/hardhat/SpokePool.Admin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,6 @@ describe("SpokePool Admin Functions", async function () {
);
expect(await spokePool.numberOfDeposits()).to.equal(1);
});
it("Enable token path", 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(erc20.address, destinationChainId)).to.equal(true);
});

it("Pause deposits", async function () {
expect(await spokePool.pausedDeposits()).to.equal(false);
Expand Down
Loading
Loading