diff --git a/.gitignore b/.gitignore index 3c3629e..76efb07 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ node_modules +.vscode diff --git a/AxelarIntegration.sol b/AxelarIntegration.sol new file mode 100644 index 0000000..fd7965b --- /dev/null +++ b/AxelarIntegration.sol @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.16; +pragma abicoder v2; + + +import "@openzeppelin/contracts/access/Ownable.sol"; +import "@uniswap/v3-periphery/contracts/libraries/TransferHelper.sol"; +// import "@uniswap/v3-periphery/contracts/interfaces/ISwapRouter.sol"; +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "./interfaces/IAxelarGateway.sol"; +import "@openzeppelin/contracts/utils/ReentrancyGuard.sol"; +// import "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol"; + + +contract AxelarIntegration is Ownable, ReentrancyGuard { + IAxelarGateway public axelarGateway; + + IERC20 private axlUSDC; + + constructor(address firstOwner, address _axelarGatewayAddress, address _axlUSDCAddress) Ownable(firstOwner) { + axelarGateway = IAxelarGateway(_axelarGatewayAddress); + axlUSDC = IERC20(_axlUSDCAddress); + } + + function sendTokensToAnotherChain(string calldata destChain, string calldata destination, string memory symbol, uint256 amount) public nonReentrant onlyOwner { + uint256 balance = axlUSDC.balanceOf(address(this)); + require(balance >= amount, "amount > balance"); + require(keccak256(bytes(symbol)) == keccak256(bytes("axlUSDC")), "only axlUSDC enabled"); + + // Polygon + TransferHelper.safeApprove(address(axlUSDC), address(axelarGateway), amount); + axelarGateway.sendToken(destChain, destination, symbol, amount); + } + + function recoverToken(address _tokenAddress, address recipient, uint256 _amount) external nonReentrant onlyOwner { + IERC20 _token = IERC20(_tokenAddress); + uint256 balance = _token.balanceOf(address(this)); + require(balance >= _amount, "_amount > balance"); + + TransferHelper.safeTransferFrom(_tokenAddress, address(this), recipient, _amount); + } +} \ No newline at end of file diff --git a/FeeCollectorV3PositionTimeLockV1.sol b/FeeCollectorV3PositionTimeLockV1.sol index 86adfb4..325508d 100644 --- a/FeeCollectorV3PositionTimeLockV1.sol +++ b/FeeCollectorV3PositionTimeLockV1.sol @@ -4,7 +4,7 @@ pragma abicoder v2; import "@openzeppelin/contracts/access/Ownable.sol"; -// import "@uniswap/v3-periphery/contracts/libraries/TransferHelper.sol" as TH; +import "@uniswap/v3-periphery/contracts/libraries/TransferHelper.sol"; import "@uniswap/v3-periphery/contracts/interfaces/ISwapRouter.sol"; // import "@uniswap/v3-periphery/contracts/interfaces/INonfungiblePositionManager.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; @@ -14,64 +14,6 @@ import "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol"; // import "@openzeppelin/contracts/utils/math/SafeMath.sol"; - -library TransferHelper { - /// @notice Transfers tokens from the targeted address to the given destination - /// @notice Errors with 'STF' if transfer fails - /// @param token The contract address of the token to be transferred - /// @param from The originating address from which the tokens will be transferred - /// @param to The destination address of the transfer - /// @param value The amount to be transferred - function safeTransferFrom( - address token, - address from, - address to, - uint256 value - ) internal { - (bool success, bytes memory data) = - token.call(abi.encodeWithSelector(IERC20.transferFrom.selector, from, to, value)); - require(success && (data.length == 0 || abi.decode(data, (bool))), 'STF'); - } - - /// @notice Transfers tokens from msg.sender to a recipient - /// @dev Errors with ST if transfer fails - /// @param token The contract address of the token which will be transferred - /// @param to The recipient of the transfer - /// @param value The value of the transfer - function safeTransfer( - address token, - address to, - uint256 value - ) internal { - (bool success, bytes memory data) = token.call(abi.encodeWithSelector(IERC20.transfer.selector, to, value)); - require(success && (data.length == 0 || abi.decode(data, (bool))), 'ST'); - } - - /// @notice Approves the stipulated contract to spend the given allowance in the given token - /// @dev Errors with 'SA' if transfer fails - /// @param token The contract address of the token to be approved - /// @param to The target of the approval - /// @param value The amount of the given token the target will be allowed to spend - function safeApprove( - address token, - address to, - uint256 value - ) internal { - (bool success, bytes memory data) = token.call(abi.encodeWithSelector(IERC20.approve.selector, to, value)); - require(success && (data.length == 0 || abi.decode(data, (bool))), 'SA'); - } - - /// @notice Transfers ETH to the recipient address - /// @dev Fails with `STE` - /// @param to The destination of the transfer - /// @param value The value to be transferred - function safeTransferETH(address to, uint256 value) internal { - (bool success, ) = to.call{value: value}(new bytes(0)); - require(success, 'STE'); - } -} - - interface INonfungiblePositionManager { function positions(uint256 tokenId) @@ -116,7 +58,7 @@ contract FeeCollectorV3PositionTimeLockV1 is IERC721Receiver, Ownable, Reentranc } // mapping(address => mapping(address => uint256)) public userLockedPositionsTokenId; - mapping(address => mapping(bytes32 => LockedPosition)) public lockedPositions; + mapping(address => mapping(bytes32 => LockedPosition)) private lockedPositions; // INonfungiblePositionManager public positionManager; @@ -127,15 +69,28 @@ contract FeeCollectorV3PositionTimeLockV1 is IERC721Receiver, Ownable, Reentranc event PositionUnlocked(address indexed user, address indexed positionManager, uint256 tokenId); function onERC721Received( - address _operator, - address _from, - uint256 _tokenId, - bytes calldata _data) external pure override returns (bytes4) { + address, + address, + uint256, + bytes calldata) external pure override returns (bytes4) { // require(address(whitelistedNftContract) == _msgSender()); // _stakeNft(tokenId, from); return IERC721Receiver.onERC721Received.selector; } + function getPositionWithKey(address _from, bytes32 _key) external returns (memory LockedPosition) { + LockedPosition memory lockedPosition = lockedPositions[_from][_key]; + return lockedPosition; + } + + function getPositionWithAddress(address _from, address _positionManager, uint256 tokenId) external view returns(memory LockedPosition) { + bytes32 _key = keyForPosition(_from, _positionManager, tokenId); + return getPositionWithKey(_from, _key); + } + + function keyForPosition(address _from, address _positionManger, uint256 tokenId) external view returns(bytes32) { + return keccak256(abi.encodePacked(_from, _positionManager, tokenId)); + } function _hashLockedPositionKey(address _positionManager, uint256 tokenId) private view returns(bytes32) { return keccak256(abi.encodePacked(_msgSender(), _positionManager, tokenId)); diff --git a/interfaces/IAxelarGateway.sol b/interfaces/IAxelarGateway.sol new file mode 100644 index 0000000..d3655b7 --- /dev/null +++ b/interfaces/IAxelarGateway.sol @@ -0,0 +1,190 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.9; + +interface IAxelarGateway { + /**********\ + |* Errors *| + \**********/ + + error NotSelf(); + error NotProxy(); + error InvalidCodeHash(); + error SetupFailed(); + error InvalidAuthModule(); + error InvalidTokenDeployer(); + error InvalidAmount(); + error InvalidChainId(); + error InvalidCommands(); + error TokenDoesNotExist(string symbol); + error TokenAlreadyExists(string symbol); + error TokenDeployFailed(string symbol); + error TokenContractDoesNotExist(address token); + error BurnFailed(string symbol); + error MintFailed(string symbol); + error InvalidSetMintLimitsParams(); + error ExceedMintLimit(string symbol); + + /**********\ + |* Events *| + \**********/ + + event TokenSent(address indexed sender, string destinationChain, string destinationAddress, string symbol, uint256 amount); + + event ContractCall( + address indexed sender, + string destinationChain, + string destinationContractAddress, + bytes32 indexed payloadHash, + bytes payload + ); + + event ContractCallWithToken( + address indexed sender, + string destinationChain, + string destinationContractAddress, + bytes32 indexed payloadHash, + bytes payload, + string symbol, + uint256 amount + ); + + event Executed(bytes32 indexed commandId); + + event TokenDeployed(string symbol, address tokenAddresses); + + event ContractCallApproved( + bytes32 indexed commandId, + string sourceChain, + string sourceAddress, + address indexed contractAddress, + bytes32 indexed payloadHash, + bytes32 sourceTxHash, + uint256 sourceEventIndex + ); + + event ContractCallApprovedWithMint( + bytes32 indexed commandId, + string sourceChain, + string sourceAddress, + address indexed contractAddress, + bytes32 indexed payloadHash, + string symbol, + uint256 amount, + bytes32 sourceTxHash, + uint256 sourceEventIndex + ); + + event TokenMintLimitUpdated(string symbol, uint256 limit); + + event OperatorshipTransferred(bytes newOperatorsData); + + event Upgraded(address indexed implementation); + + /********************\ + |* Public Functions *| + \********************/ + + function sendToken( + string calldata destinationChain, + string calldata destinationAddress, + string calldata symbol, + uint256 amount + ) external; + + function callContract( + string calldata destinationChain, + string calldata contractAddress, + bytes calldata payload + ) external; + + function callContractWithToken( + string calldata destinationChain, + string calldata contractAddress, + bytes calldata payload, + string calldata symbol, + uint256 amount + ) external; + + function isContractCallApproved( + bytes32 commandId, + string calldata sourceChain, + string calldata sourceAddress, + address contractAddress, + bytes32 payloadHash + ) external view returns (bool); + + function isContractCallAndMintApproved( + bytes32 commandId, + string calldata sourceChain, + string calldata sourceAddress, + address contractAddress, + bytes32 payloadHash, + string calldata symbol, + uint256 amount + ) external view returns (bool); + + function validateContractCall( + bytes32 commandId, + string calldata sourceChain, + string calldata sourceAddress, + bytes32 payloadHash + ) external returns (bool); + + function validateContractCallAndMint( + bytes32 commandId, + string calldata sourceChain, + string calldata sourceAddress, + bytes32 payloadHash, + string calldata symbol, + uint256 amount + ) external returns (bool); + + /***********\ + |* Getters *| + \***********/ + + function authModule() external view returns (address); + + function tokenDeployer() external view returns (address); + + function tokenMintLimit(string memory symbol) external view returns (uint256); + + function tokenMintAmount(string memory symbol) external view returns (uint256); + + function allTokensFrozen() external view returns (bool); + + function implementation() external view returns (address); + + function tokenAddresses(string memory symbol) external view returns (address); + + function tokenFrozen(string memory symbol) external view returns (bool); + + function isCommandExecuted(bytes32 commandId) external view returns (bool); + + function adminEpoch() external view returns (uint256); + + function adminThreshold(uint256 epoch) external view returns (uint256); + + function admins(uint256 epoch) external view returns (address[] memory); + + /*******************\ + |* Admin Functions *| + \*******************/ + + function setTokenMintLimits(string[] calldata symbols, uint256[] calldata limits) external; + + function upgrade( + address newImplementation, + bytes32 newImplementationCodeHash, + bytes calldata setupParams + ) external; + + /**********************\ + |* External Functions *| + \**********************/ + + function setup(bytes calldata params) external; + + function execute(bytes calldata input) external; +} \ No newline at end of file