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:
Qian
2026-07-17 02:36:14 +00:00
commit f39b69d445
28 changed files with 2828 additions and 0 deletions
@@ -0,0 +1,52 @@
// SPDX-License-Identifier: MIT
// Qian Exchange - https://qian.ag
pragma solidity ^0.8.24;
import "./IPoolManager.sol";
/**
* @title IConfigurableHook
* @notice Generic interface for hooks that can be configured by the factory
* @dev All hooks that want to be auto-configured by QianFactoryV4 must implement this interface
*
* This allows the factory to remain hook-agnostic - new hooks can be added
* without modifying the factory contract. Each hook:
* 1. Defines its own config format (decoded from bytes)
* 2. Validates its own constraints (tax limits, thresholds, etc.)
* 3. Stores per-pool configuration
*
* Example config encoding:
* - AutoBuyBurnHook: abi.encode(uint16 buyTaxBps, uint16 sellTaxBps, uint256 threshold)
* - QianTaxHook: abi.encode(uint16 buyTaxBps, uint16 sellTaxBps, uint16 snipeStartBps, uint16 snipeEndBps, uint32 snipeDecaySeconds)
* - FutureHook: abi.encode(param1, param2, param3, ...)
*/
interface IConfigurableHook {
/**
* @notice Configure the hook for a newly deployed token's pool
* @param poolId The pool identifier (keccak256 of PoolKey)
* @param tokenAddress The token address being configured
* @param config Hook-specific configuration data (abi.encoded)
* @dev Called by factory during deployCoin(). Must validate and store config.
* Should revert if already configured (immutability) or invalid params.
*/
function configureHook(
bytes32 poolId,
address tokenAddress,
bytes calldata config
) external;
/**
* @notice Get the pool ID from a PoolKey
* @param key The pool key
* @return poolId The computed pool identifier
*/
function getPoolId(PoolKey calldata key) external pure returns (bytes32);
/**
* @notice Check if a pool has been configured for this hook
* @param poolId The pool identifier
* @return True if the pool is configured and enabled
*/
function isConfigured(bytes32 poolId) external view returns (bool);
}
+31
View File
@@ -0,0 +1,31 @@
// SPDX-License-Identifier: MIT
// Qian Exchange - https://qian.ag
pragma solidity ^0.8.24;
/// @notice Currency type for Uniswap V4
/// Wraps an address to represent a token or native ETH
type Currency is address;
/// @notice Currency library for V4
library CurrencyLibrary {
/// @notice Wrap an address as Currency
function wrap(address token) internal pure returns (Currency) {
return Currency.wrap(token);
}
/// @notice Unwrap Currency to address
function unwrap(Currency currency) internal pure returns (address) {
return Currency.unwrap(currency);
}
/// @notice Native ETH currency
function native() internal pure returns (Currency) {
return Currency.wrap(address(0));
}
/// @notice Check if currency is native ETH
function isNative(Currency currency) internal pure returns (bool) {
return Currency.unwrap(currency) == address(0);
}
}
@@ -0,0 +1,18 @@
// SPDX-License-Identifier: MIT
// Qian Exchange - https://qian.ag
pragma solidity ^0.8.24;
/// @notice Optional interface for hooks to expose fee configuration
/// This allows the factory/fee collector to understand hook fee behavior
interface IHookFeeConfig {
/// @notice Get the fee split configuration
/// @return platformBps Platform fee in basis points (out of 10000)
/// @return hookBps Hook fee in basis points (out of 10000)
/// @return creatorBps Creator fee in basis points (out of 10000)
/// @dev Sum should equal 10000
function getFeeSplit() external view returns (uint256 platformBps, uint256 hookBps, uint256 creatorBps);
/// @notice Get hook name/identifier
function getHookName() external view returns (string memory);
}
+50
View File
@@ -0,0 +1,50 @@
// SPDX-License-Identifier: MIT
// Qian Exchange - https://qian.ag
pragma solidity ^0.8.24;
import "./IPoolManager.sol";
/// @notice Swap parameters for hook callbacks
struct SwapParams {
bool zeroForOne;
int256 amountSpecified;
uint160 sqrtPriceLimitX96;
}
/// @notice Uniswap V4 Hooks interface
/// Hooks can implement various callbacks to customize pool behavior
interface IHooks {
/// @notice Called before a pool is initialized
function beforeInitialize(address sender, PoolKey calldata key, uint160 sqrtPriceX96) external returns (bytes4);
/// @notice Called after a pool is initialized
function afterInitialize(address sender, PoolKey calldata key, uint160 sqrtPriceX96, int24 tick) external returns (bytes4);
/// @notice Called before a swap
function beforeSwap(address sender, PoolKey calldata key, SwapParams calldata params, bytes calldata hookData) external returns (bytes4, BeforeSwapDelta, uint24);
/// @notice Called after a swap
function afterSwap(address sender, PoolKey calldata key, SwapParams calldata params, BalanceDelta delta, bytes calldata hookData) external returns (bytes4, int128);
/// @notice Called before liquidity is added
function beforeAddLiquidity(address sender, PoolKey calldata key, ModifyLiquidityParams calldata params, bytes calldata hookData) external returns (bytes4);
/// @notice Called after liquidity is added
function afterAddLiquidity(address sender, PoolKey calldata key, ModifyLiquidityParams calldata params, BalanceDelta delta, BalanceDelta feesAccrued, bytes calldata hookData) external returns (bytes4, BalanceDelta);
/// @notice Called before liquidity is removed
function beforeRemoveLiquidity(address sender, PoolKey calldata key, ModifyLiquidityParams calldata params, bytes calldata hookData) external returns (bytes4);
/// @notice Called after liquidity is removed
function afterRemoveLiquidity(address sender, PoolKey calldata key, ModifyLiquidityParams calldata params, BalanceDelta delta, BalanceDelta feesAccrued, bytes calldata hookData) external returns (bytes4, BalanceDelta);
/// @notice Called before a donate
function beforeDonate(address sender, PoolKey calldata key, uint256 amount0, uint256 amount1, bytes calldata hookData) external returns (bytes4);
/// @notice Called after a donate
function afterDonate(address sender, PoolKey calldata key, uint256 amount0, uint256 amount1, bytes calldata hookData) external returns (bytes4);
}
/// @notice Before swap delta type - encodes (specifiedDelta, unspecifiedDelta)
type BeforeSwapDelta is int256;
@@ -0,0 +1,77 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import "./ICurrency.sol";
import "./IHooks.sol";
// BalanceDelta is a packed int256 where:
// - Upper 128 bits = amount0 (int128)
// - Lower 128 bits = amount1 (int128)
type BalanceDelta is int256;
/// @notice Library for getting amount0/amount1 from BalanceDelta
library BalanceDeltaLibrary {
function amount0(BalanceDelta balanceDelta) internal pure returns (int128 _amount0) {
assembly ("memory-safe") {
_amount0 := sar(128, balanceDelta)
}
}
function amount1(BalanceDelta balanceDelta) internal pure returns (int128 _amount1) {
assembly ("memory-safe") {
_amount1 := signextend(15, balanceDelta)
}
}
}
/// @notice PoolKey identifies a V4 pool
struct PoolKey {
Currency currency0;
Currency currency1;
uint24 fee;
int24 tickSpacing;
IHooks hooks;
}
/// @notice Parameters for modifyLiquidity
struct ModifyLiquidityParams {
int24 tickLower;
int24 tickUpper;
int256 liquidityDelta;
bytes32 salt;
}
/// @notice Interface for Uniswap V4 PoolManager
interface IPoolManager {
/// @notice Initialize the state for a given pool
function initialize(PoolKey memory key, uint160 sqrtPriceX96) external returns (int24 tick);
/// @notice Modify the liquidity for the given pool
function modifyLiquidity(PoolKey memory key, ModifyLiquidityParams memory params, bytes calldata hookData)
external
returns (BalanceDelta callerDelta, BalanceDelta feesAccrued);
/// @notice All interactions on the contract that account deltas require unlocking
function unlock(bytes calldata data) external returns (bytes memory);
/// @notice Sync the currency to its current balance in the PoolManager
function sync(Currency currency) external;
/// @notice Settle the currency, paying what is owed
function settle() external payable returns (uint256 paid);
/// @notice Take currency from the PoolManager
/// @param currency The currency to take
/// @param to The address to receive the currency
/// @param amount The amount to take
function take(Currency currency, address to, uint256 amount) external;
/// @notice Execute a swap
/// @param key The pool key
/// @param params The swap parameters
/// @param hookData Any data to be passed to hooks
function swap(PoolKey memory key, SwapParams memory params, bytes calldata hookData)
external
returns (BalanceDelta swapDelta);
}
@@ -0,0 +1,12 @@
// SPDX-License-Identifier: MIT
// Qian Exchange - https://qian.ag
pragma solidity ^0.8.24;
/// @notice Interface for the callback executed when an address unlocks the pool manager
interface IUnlockCallback {
/// @notice Called by the pool manager on `msg.sender` when the manager is unlocked
/// @param data The data that was passed to the call to unlock
/// @return Any data that you want to be returned from the unlock call
function unlockCallback(bytes calldata data) external returns (bytes memory);
}
+13
View File
@@ -0,0 +1,13 @@
// SPDX-License-Identifier: MIT
// Qian Exchange - https://qian.ag
pragma solidity ^0.8.24;
interface IWETH {
function deposit() external payable;
function withdraw(uint256 amount) external;
function transfer(address to, uint256 amount) external returns (bool);
function transferFrom(address from, address to, uint256 amount) external returns (bool);
function approve(address spender, uint256 amount) external returns (bool);
function balanceOf(address account) external view returns (uint256);
}