-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
1 parent
289eaae
commit f4ea030
Showing
13 changed files
with
452 additions
and
249 deletions.
There are no files selected for viewing
Submodule katana-v3-contracts
updated
39 files
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,5 @@ | ||
@fdk/=lib/foundry-deployment-kit/script/ | ||
@contract-libs/=lib/foundry-deployment-kit/lib/contract-libs/src/ | ||
forge-std/=lib/foundry-deployment-kit/lib/forge-std/src/ | ||
@solady/=lib/foundry-deployment-kit/lib/solady/src/ | ||
@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/ | ||
@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/ | ||
solmate/=lib/solmate/ | ||
permit2/=lib/permit2/ | ||
@katana/v3-contracts/=lib/katana-v3-contracts/src/ |
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
53 changes: 0 additions & 53 deletions
53
src/aggregate-router/interfaces/external/IKatanaV2Pair.sol
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,353 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.23; | ||
|
||
import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; | ||
import { EnumerableSet } from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; | ||
import { IKatanaV2Factory } from "./interfaces/IKatanaV2Factory.sol"; | ||
import { IKatanaV2Pair } from "@katana/v3-contracts/periphery/interfaces/IKatanaV2Pair.sol"; | ||
import { IKatanaGovernance } from "@katana/v3-contracts/external/interfaces/IKatanaGovernance.sol"; | ||
|
||
contract KatanaGovernance is OwnableUpgradeable, IKatanaV2Factory, IKatanaGovernance { | ||
using EnumerableSet for EnumerableSet.AddressSet; | ||
|
||
/// @inheritdoc IKatanaGovernance | ||
address public immutable getPositionManager; | ||
|
||
/// @dev Revert error when the length of the array is invalid. | ||
error InvalidLength(); | ||
/// @dev Revert error when the caller is not authorized. | ||
error Unauthorized(); | ||
|
||
/// @dev Gap for upgradeability. | ||
uint256[50] private __gap; | ||
|
||
/// @dev Indicates the token is unauthorized for trade. | ||
uint40 private constant UNAUTHORIZED = 0; | ||
/// @dev Indicates the token is publicly allowed for trade. | ||
uint40 private constant AUTHORIZED = type(uint40).max; | ||
|
||
/// @dev The factory contract. | ||
IKatanaV2Factory private _factory; | ||
/// @dev The mapping of token to permission. | ||
mapping(address token => Permission) private _permission; | ||
/// @dev The unique set of tokens. | ||
EnumerableSet.AddressSet private _tokens; | ||
/// @dev The router address | ||
address private _router; | ||
|
||
/// @dev Only use this modifier for boolean-returned methods | ||
modifier skipIfAllowedAllOrOwner(address account) { | ||
_skipIfAllowedAllOrOwner(account); | ||
_; | ||
} | ||
|
||
constructor(address nonfungiblePositionManager) { | ||
getPositionManager = nonfungiblePositionManager; | ||
_disableInitializers(); | ||
} | ||
|
||
function initialize(address admin, address factory) external initializer { | ||
_setFactory(factory); | ||
__Ownable_init_unchained(admin); | ||
|
||
IKatanaV2Pair pair; | ||
uint40 until = AUTHORIZED; | ||
bool[] memory statusesPlaceHolder; | ||
address[] memory allowedPlaceHolder; | ||
uint256 length = IKatanaV2Factory(factory).allPairsLength(); | ||
|
||
for (uint256 i; i < length; ++i) { | ||
pair = IKatanaV2Pair(IKatanaV2Factory(factory).allPairs(i)); | ||
_setPermission(pair.token0(), until, allowedPlaceHolder, statusesPlaceHolder); | ||
_setPermission(pair.token1(), until, allowedPlaceHolder, statusesPlaceHolder); | ||
} | ||
} | ||
|
||
function initializeV2(address router) external reinitializer(2) { | ||
_router = router; | ||
} | ||
|
||
/// @inheritdoc IKatanaGovernance | ||
function setRouter(address router) external onlyOwner { | ||
_router = router; | ||
} | ||
|
||
/** | ||
* @inheritdoc IKatanaV2Factory | ||
*/ | ||
function createPair(address tokenA, address tokenB) external returns (address pair) { | ||
address sender = _msgSender(); | ||
address[] memory tokens = new address[](2); | ||
tokens[0] = tokenA; | ||
tokens[1] = tokenB; | ||
if (!this.isAuthorized(tokens, sender)) revert Unauthorized(); | ||
|
||
pair = _factory.createPair(tokenA, tokenB); | ||
} | ||
|
||
/** | ||
* @inheritdoc IKatanaGovernance | ||
*/ | ||
function createPairAndSetPermission( | ||
address tokenA, | ||
address tokenB, | ||
uint40 whitelistUntil, | ||
address[] calldata alloweds, | ||
bool[] calldata statuses | ||
) external onlyOwner returns (address pair) { | ||
pair = _factory.createPair(tokenA, tokenB); | ||
_setPermission(tokenA, whitelistUntil, alloweds, statuses); | ||
_setPermission(tokenB, whitelistUntil, alloweds, statuses); | ||
} | ||
|
||
/** | ||
* @inheritdoc IKatanaGovernance | ||
*/ | ||
function setPermission(address token, uint40 whitelistUntil, address[] calldata alloweds, bool[] calldata statuses) | ||
external | ||
onlyOwner | ||
{ | ||
_setPermission(token, whitelistUntil, alloweds, statuses); | ||
} | ||
|
||
/** | ||
* @inheritdoc IKatanaV2Factory | ||
*/ | ||
function setPairImplementation(address impl) external onlyOwner { | ||
_factory.setPairImplementation(impl); | ||
} | ||
|
||
/** | ||
* @inheritdoc IKatanaV2Factory | ||
*/ | ||
function setAllowedAll(bool shouldAllow) external onlyOwner { | ||
_factory.setAllowedAll(shouldAllow); | ||
} | ||
|
||
/** | ||
* @inheritdoc IKatanaGovernance | ||
*/ | ||
function setFactory(address factory) external onlyOwner { | ||
_setFactory(factory); | ||
} | ||
|
||
/** | ||
* @inheritdoc IKatanaV2Factory | ||
*/ | ||
function setTreasury(address newTreasury) external onlyOwner { | ||
_factory.setTreasury(newTreasury); | ||
} | ||
|
||
/** | ||
* @inheritdoc IKatanaV2Factory | ||
*/ | ||
function getPair(address tokenA, address tokenB) external view returns (address pair) { | ||
return _factory.getPair(tokenA, tokenB); | ||
} | ||
|
||
/** | ||
* @inheritdoc IKatanaV2Factory | ||
*/ | ||
function allPairs(uint256 index) external view returns (address pair) { | ||
return _factory.allPairs(index); | ||
} | ||
|
||
/** | ||
* @inheritdoc IKatanaV2Factory | ||
*/ | ||
function allPairsLength() external view returns (uint256) { | ||
return _factory.allPairsLength(); | ||
} | ||
|
||
/** | ||
* @inheritdoc IKatanaV2Factory | ||
*/ | ||
function treasury() external view returns (address) { | ||
return _factory.treasury(); | ||
} | ||
|
||
/** | ||
* @inheritdoc IKatanaV2Factory | ||
*/ | ||
function pairImplementation() external view returns (address) { | ||
return _factory.pairImplementation(); | ||
} | ||
|
||
/** | ||
* @inheritdoc IKatanaV2Factory | ||
*/ | ||
function INIT_CODE_PAIR_HASH() external view returns (bytes32) { | ||
return _factory.INIT_CODE_PAIR_HASH(); | ||
} | ||
|
||
/** | ||
* @inheritdoc IKatanaV2Factory | ||
*/ | ||
function getRouter() external view returns (address) { | ||
return _router; | ||
} | ||
|
||
/** | ||
* @inheritdoc IKatanaGovernance | ||
*/ | ||
function getFactory() external view returns (address) { | ||
return address(_factory); | ||
} | ||
|
||
/** | ||
* @inheritdoc IKatanaGovernance | ||
*/ | ||
function isAuthorized(address token, address account) | ||
external | ||
view | ||
skipIfAllowedAllOrOwner(account) | ||
returns (bool authorized) | ||
{ | ||
authorized = _isAuthorized(_permission[token], account); | ||
} | ||
|
||
/** | ||
* @inheritdoc IKatanaGovernance | ||
*/ | ||
function isAuthorized(address[] calldata tokens, address account) | ||
external | ||
view | ||
skipIfAllowedAllOrOwner(account) | ||
returns (bool authorized) | ||
{ | ||
uint256 length = tokens.length; | ||
|
||
for (uint256 i; i < length; ++i) { | ||
if (!_isAuthorized(_permission[tokens[i]], account)) return false; | ||
} | ||
|
||
return true; | ||
} | ||
|
||
/** | ||
* @inheritdoc IKatanaGovernance | ||
*/ | ||
function getWhitelistUntil(address token) external view returns (uint40) { | ||
return _permission[token].whitelistUntil; | ||
} | ||
|
||
/** | ||
* @inheritdoc IKatanaGovernance | ||
*/ | ||
function getWhitelistedTokensFor(address account) | ||
external | ||
view | ||
returns (address[] memory tokens, uint40[] memory whitelistUntils) | ||
{ | ||
unchecked { | ||
uint256 length = _tokens.length(); | ||
tokens = new address[](length); | ||
whitelistUntils = new uint40[](length); | ||
uint256 count; | ||
address token; | ||
uint40 whitelistUntil; | ||
Permission storage $; | ||
|
||
for (uint256 i; i < length; ++i) { | ||
token = _tokens.at(i); | ||
$ = _permission[token]; | ||
whitelistUntil = $.whitelistUntil; | ||
|
||
if (block.timestamp < whitelistUntil && $.allowed[account]) { | ||
tokens[count] = token; | ||
whitelistUntils[count] = whitelistUntil; | ||
++count; | ||
} | ||
} | ||
|
||
assembly { | ||
mstore(tokens, count) | ||
mstore(whitelistUntils, count) | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* @inheritdoc IKatanaGovernance | ||
*/ | ||
function getManyTokensWhitelistInfo() | ||
external | ||
view | ||
returns (address[] memory tokens, uint40[] memory whitelistedUntils) | ||
{ | ||
tokens = _tokens.values(); | ||
uint256 length = tokens.length; | ||
whitelistedUntils = new uint40[](length); | ||
|
||
for (uint256 i; i < length; ++i) { | ||
whitelistedUntils[i] = _permission[tokens[i]].whitelistUntil; | ||
} | ||
} | ||
|
||
/** | ||
* @inheritdoc IKatanaV2Factory | ||
*/ | ||
function allowedAll() public view returns (bool) { | ||
return _factory.allowedAll(); | ||
} | ||
|
||
/** | ||
* @dev Sets the address of the factory contract. | ||
* Can only be called by the contract owner. | ||
*/ | ||
function _setFactory(address factory) private { | ||
_factory = IKatanaV2Factory(factory); | ||
|
||
emit FactoryUpdated(_msgSender(), factory); | ||
} | ||
|
||
/** | ||
* @dev Sets the permission for a token. | ||
* @param token The address of the token. | ||
* @param whitelistUntil The end of the whitelist duration in seconds. | ||
* @param alloweds The array of addresses to be allowed in whitelist duration. | ||
* @param statuses The corresponding array of statuses (whether allowed or not). | ||
*/ | ||
function _setPermission(address token, uint40 whitelistUntil, address[] memory alloweds, bool[] memory statuses) | ||
private | ||
{ | ||
uint256 length = alloweds.length; | ||
if (length != statuses.length) revert InvalidLength(); | ||
|
||
Permission storage $ = _permission[token]; | ||
$.whitelistUntil = whitelistUntil; | ||
_tokens.add(token); | ||
|
||
for (uint256 i; i < length; ++i) { | ||
$.allowed[alloweds[i]] = statuses[i]; | ||
} | ||
|
||
emit PermissionUpdated(_msgSender(), token, whitelistUntil, alloweds, statuses); | ||
} | ||
|
||
/** | ||
* @dev Checks if an account is authorized. | ||
* @param account The address of the account to check authorization for. | ||
* @return A boolean indicating whether the account is authorized or not. | ||
*/ | ||
function _isAuthorized(Permission storage $, address account) private view returns (bool) { | ||
uint256 expiry = $.whitelistUntil; | ||
if (expiry == UNAUTHORIZED) return false; | ||
if (expiry == AUTHORIZED || block.timestamp > expiry) return true; | ||
|
||
return $.allowed[account]; | ||
} | ||
|
||
/** | ||
* @dev Skips the function if the caller is allowed all or the owner. | ||
* WARNING: This function can return and exit current context and skip the function. | ||
*/ | ||
function _skipIfAllowedAllOrOwner(address account) internal view { | ||
if (allowedAll() || account == owner()) { | ||
assembly ("memory-safe") { | ||
mstore(0x0, true) | ||
return(0x0, returndatasize()) | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity >=0.5.17 <0.9.0; | ||
|
||
/** | ||
* @title IKatanaFactory | ||
* | ||
* @dev IKatanaFactory interface. | ||
* @notice Imported from https://github.com/axieinfinity/contract-infinity/blob/main/contracts/interfaces/IKatanaFactory.sol | ||
*/ | ||
interface IKatanaV2Factory { | ||
/** | ||
* @dev Emitted when a pair for `token0` token and `token1` token is created. | ||
*/ | ||
event PairCreated(address indexed token0, address indexed token1, address pair, uint256 allPairsLength); | ||
|
||
/** | ||
* @dev Emitted when pair implement is changed from `old` to `new`. | ||
*/ | ||
event PairProxyUpdated(address indexed newImpl, address indexed oldImpl); | ||
|
||
function INIT_CODE_PAIR_HASH() external view returns (bytes32); | ||
|
||
/** | ||
* @dev Flag whether allowed all users to call. | ||
*/ | ||
function allowedAll() external view returns (bool); | ||
|
||
/** | ||
* | ||
* @dev Set allowed all. | ||
* | ||
* Requirements: | ||
* | ||
* - The method caller is admin. | ||
* | ||
*/ | ||
function setAllowedAll(bool) external; | ||
|
||
/** | ||
* @dev Returns implementation address for pair token. | ||
*/ | ||
function pairImplementation() external view returns (address); | ||
|
||
/** | ||
* @dev Set implementation address for all pairs. | ||
* | ||
* Requirements: | ||
* | ||
* - The method caller is admin. | ||
* | ||
* Emit a {PairProxyUpdated} event. | ||
*/ | ||
function setPairImplementation(address) external; | ||
|
||
/** | ||
* @dev Returns treasury address. | ||
*/ | ||
function treasury() external view returns (address); | ||
|
||
/** | ||
* @dev Sets treasury address. | ||
* | ||
* Requirements: | ||
* | ||
* - The method caller is admin. | ||
* | ||
*/ | ||
function setTreasury(address addr) external; | ||
|
||
/** | ||
* @dev Returns pair address for `tokenA` and `tokenB`. | ||
*/ | ||
function getPair(address tokenA, address tokenB) external view returns (address pair); | ||
|
||
/** | ||
* @dev Returns pair address at `index` position. | ||
*/ | ||
function allPairs(uint256 index) external view returns (address pair); | ||
|
||
/** | ||
* @dev Returns all pairs length. | ||
*/ | ||
function allPairsLength() external view returns (uint256); | ||
|
||
/** | ||
* @dev Create pair. | ||
* | ||
* Requirements: | ||
* | ||
* - The default method caller is contract admin. | ||
* - All addresses is allowed if `allowedAll` is true. | ||
* | ||
*/ | ||
function createPair(address tokenA, address tokenB) external returns (address pair); | ||
} |