Skip to content

Commit

Permalink
add sample using AxelarGateway to send tokens between chains
Browse files Browse the repository at this point in the history
  • Loading branch information
devton committed Apr 21, 2024
1 parent e27196d commit f06d1e4
Show file tree
Hide file tree
Showing 4 changed files with 252 additions and 64 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
node_modules
.vscode
42 changes: 42 additions & 0 deletions AxelarIntegration.sol
Original file line number Diff line number Diff line change
@@ -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);
}
}
83 changes: 19 additions & 64 deletions FeeCollectorV3PositionTimeLockV1.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand All @@ -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)
Expand Down Expand Up @@ -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;

Expand All @@ -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));
Expand Down
190 changes: 190 additions & 0 deletions interfaces/IAxelarGateway.sol
Original file line number Diff line number Diff line change
@@ -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;
}

0 comments on commit f06d1e4

Please sign in to comment.