Qian V2 Contracts
Onchain token launch with permanently locked liquidity and DEX routing (Uniswap v3 + v4). No admin keys, no mint/blacklist. MIT licensed. Deployed addresses in README.
This commit is contained in:
@@ -0,0 +1,112 @@
|
||||
// ~ https://Qian.ag ~
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.24;
|
||||
|
||||
import "../../interfaces/IPoolManager.sol";
|
||||
import "../../interfaces/IHooks.sol";
|
||||
import "../../errors/Errors.sol";
|
||||
import { Hooks } from "./Hooks.sol";
|
||||
|
||||
/**
|
||||
* @title GuardHook
|
||||
* @notice Restricts pool initialization to the factory. A Qian PoolKey is derivable from
|
||||
* a pending deployCoin, and v4's initialize is permissionless and reverts on an
|
||||
* already-initialized pool, so without this anyone can front-run the initialize and the
|
||||
* launch reverts.
|
||||
*
|
||||
* This is the hook for launches that want no hook behaviour: every swap-time flag is
|
||||
* false, so the PoolManager never calls it on a trade. The creator's tax is the pool fee.
|
||||
*
|
||||
* Required hook flags: 0x2000 (beforeInitialize only). That is bit 13 — the SECOND byte
|
||||
* of the address, not the last. A miner matching only the final byte will never find a
|
||||
* valid salt.
|
||||
*/
|
||||
contract GuardHook is IHooks {
|
||||
/// @notice Immutable: this hook has no admin functions and no owner. Deploy the
|
||||
/// factory first, then this (an arg, not msg.sender — CREATE2 deploy).
|
||||
address public immutable factory;
|
||||
|
||||
constructor(address _factory) {
|
||||
if (_factory == address(0)) revert InvalidConfig();
|
||||
factory = _factory;
|
||||
}
|
||||
|
||||
// ------------------------------------------------ hook permissions
|
||||
|
||||
function getHookPermissions() external pure returns (Hooks.Permissions memory) {
|
||||
return Hooks.Permissions({
|
||||
beforeInitialize: true,
|
||||
afterInitialize: false,
|
||||
beforeAddLiquidity: false,
|
||||
afterAddLiquidity: false,
|
||||
beforeRemoveLiquidity: false,
|
||||
afterRemoveLiquidity: false,
|
||||
beforeSwap: false,
|
||||
afterSwap: false,
|
||||
beforeDonate: false,
|
||||
afterDonate: false,
|
||||
beforeSwapReturnDelta: false,
|
||||
afterSwapReturnDelta: false,
|
||||
afterAddLiquidityReturnDelta: false,
|
||||
afterRemoveLiquidityReturnDelta: false
|
||||
});
|
||||
}
|
||||
|
||||
// ------------------------------------------------ the gate
|
||||
|
||||
function beforeInitialize(address sender, PoolKey calldata, uint160) external view returns (bytes4) {
|
||||
if (sender != factory) revert Unauthorized();
|
||||
return IHooks.beforeInitialize.selector;
|
||||
}
|
||||
|
||||
// ------------------------------------------------ unused callbacks
|
||||
// Every flag above is false, so the PoolManager never calls these. IHooks only.
|
||||
|
||||
function afterInitialize(address, PoolKey calldata, uint160, int24) external pure returns (bytes4) {
|
||||
return IHooks.afterInitialize.selector;
|
||||
}
|
||||
|
||||
function beforeSwap(address, PoolKey calldata, SwapParams calldata, bytes calldata)
|
||||
external pure returns (bytes4, BeforeSwapDelta, uint24)
|
||||
{
|
||||
return (IHooks.beforeSwap.selector, BeforeSwapDelta.wrap(0), 0);
|
||||
}
|
||||
|
||||
function afterSwap(address, PoolKey calldata, SwapParams calldata, BalanceDelta, bytes calldata)
|
||||
external pure returns (bytes4, int128)
|
||||
{
|
||||
return (IHooks.afterSwap.selector, int128(0));
|
||||
}
|
||||
|
||||
function beforeAddLiquidity(address, PoolKey calldata, ModifyLiquidityParams calldata, bytes calldata)
|
||||
external pure returns (bytes4)
|
||||
{
|
||||
return IHooks.beforeAddLiquidity.selector;
|
||||
}
|
||||
|
||||
function afterAddLiquidity(address, PoolKey calldata, ModifyLiquidityParams calldata, BalanceDelta, BalanceDelta, bytes calldata)
|
||||
external pure returns (bytes4, BalanceDelta)
|
||||
{
|
||||
return (IHooks.afterAddLiquidity.selector, BalanceDelta.wrap(0));
|
||||
}
|
||||
|
||||
function beforeRemoveLiquidity(address, PoolKey calldata, ModifyLiquidityParams calldata, bytes calldata)
|
||||
external pure returns (bytes4)
|
||||
{
|
||||
return IHooks.beforeRemoveLiquidity.selector;
|
||||
}
|
||||
|
||||
function afterRemoveLiquidity(address, PoolKey calldata, ModifyLiquidityParams calldata, BalanceDelta, BalanceDelta, bytes calldata)
|
||||
external pure returns (bytes4, BalanceDelta)
|
||||
{
|
||||
return (IHooks.afterRemoveLiquidity.selector, BalanceDelta.wrap(0));
|
||||
}
|
||||
|
||||
function beforeDonate(address, PoolKey calldata, uint256, uint256, bytes calldata) external pure returns (bytes4) {
|
||||
return IHooks.beforeDonate.selector;
|
||||
}
|
||||
|
||||
function afterDonate(address, PoolKey calldata, uint256, uint256, bytes calldata) external pure returns (bytes4) {
|
||||
return IHooks.afterDonate.selector;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
// ~ https://Qian.ag ~
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.24;
|
||||
|
||||
/// @notice Uniswap v4 hook permission flags, mirroring the canonical layout.
|
||||
/// @dev Declarative only. v4 reads a hook's real permissions from the low 14 bits of its
|
||||
/// address, not from this struct — if getHookPermissions() and the mined address disagree,
|
||||
/// the address wins.
|
||||
library Hooks {
|
||||
struct Permissions {
|
||||
bool beforeInitialize;
|
||||
bool afterInitialize;
|
||||
bool beforeAddLiquidity;
|
||||
bool afterAddLiquidity;
|
||||
bool beforeRemoveLiquidity;
|
||||
bool afterRemoveLiquidity;
|
||||
bool beforeSwap;
|
||||
bool afterSwap;
|
||||
bool beforeDonate;
|
||||
bool afterDonate;
|
||||
bool beforeSwapReturnDelta;
|
||||
bool afterSwapReturnDelta;
|
||||
bool afterAddLiquidityReturnDelta;
|
||||
bool afterRemoveLiquidityReturnDelta;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user