diff --git a/src/JBBuybackHook.sol b/src/JBBuybackHook.sol index ff10759..8354c94 100644 --- a/src/JBBuybackHook.sol +++ b/src/JBBuybackHook.sol @@ -560,12 +560,15 @@ contract JBBuybackHook is ERC165, JBPermissioned, IJBBuybackHook { // Get a reference to the pool that'll be used to make the swap. IUniswapV3Pool pool = poolOf[projectId][address(terminalToken)]; - // Make sure the pool exists. + // Make sure the pool exists, if not, return an empty quote. + if (address(pool).code.length == 0) return 0; + + // If there is a contract at the address, try to get the pool's slot 0. try pool.slot0() returns (uint160, int24, uint16, uint16, uint16, uint8, bool unlocked) { // If the pool hasn't been initialized, return an empty quote. if (!unlocked) return 0; } catch { - // If the address is invalid, or if the pool has not been deployed yet, return an empty quote. + // If the address is invalid, return an empty quote. return 0; } diff --git a/test/Unit.t.sol b/test/Unit.t.sol index a5aea6f..170e2fe 100644 --- a/test/Unit.t.sol +++ b/test/Unit.t.sol @@ -326,6 +326,35 @@ contract Test_BuybackHook_Unit is Test { /// minting /// from the terminal. function test_beforePayRecordedContext_useTwapNonDeployedPool(uint256 tokenCount) public { + vm.etch(address(pool), ""); + assert(address(pool).code.length == 0); + + tokenCount = bound(tokenCount, 1, type(uint120).max); + + // Set the relevant context. + beforePayRecordedContext.weight = tokenCount; + beforePayRecordedContext.metadata = ""; + + // Return values to catch: + JBPayHookSpecification[] memory specificationsReturned; + uint256 weightReturned; + + // Test: call `beforePayRecordedWith` - notice we don't mock the pool, as the address should remain empty + vm.prank(terminalStore); + (weightReturned, specificationsReturned) = hook.beforePayRecordedWith(beforePayRecordedContext); + + // No hook specifications should be returned. + assertEq(specificationsReturned.length, 0); + + // The weight should be returned unchanged. + assertEq(weightReturned, tokenCount); + } + + /// @notice Test `beforePayRecordedWith` with a TWAP but an invalid pool address, which should lead to the payment + /// minting from the terminal. + function test_beforePayRecordedContext_useTwapInvalidPool(uint256 tokenCount) public { + vm.etch(address(pool), "12345678"); + tokenCount = bound(tokenCount, 1, type(uint120).max); // Set the relevant context.