Skip to content

Commit

Permalink
feat: add getter functions for tokens and destination chains
Browse files Browse the repository at this point in the history
  • Loading branch information
Al3xGROS committed Oct 3, 2024
1 parent d3070f9 commit 5e6cb17
Show file tree
Hide file tree
Showing 3 changed files with 118 additions and 1 deletion.
57 changes: 56 additions & 1 deletion contracts/src/contracts/Teleporter/AvalancheICTTRouter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,13 @@ import {INativeTokenTransferrer} from
import {SendTokensInput} from "@avalabs/avalanche-ictt/interfaces/ITokenTransferrer.sol";
import {IWarpMessenger} from
"@avalabs/[email protected]/contracts/interfaces/IWarpMessenger.sol";
import {SafeERC20TransferFrom} from "@teleporter/SafeERC20TransferFrom.sol";

import {Ownable} from "@openzeppelin/[email protected]/access/Ownable.sol";
import {ReentrancyGuard} from "@openzeppelin/[email protected]/security/ReentrancyGuard.sol";
import {IERC20} from "@openzeppelin/[email protected]/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/[email protected]/token/ERC20/utils/SafeERC20.sol";
import {Address} from "@openzeppelin/[email protected]/utils/Address.sol";
import {SafeERC20TransferFrom} from "@teleporter/SafeERC20TransferFrom.sol";

/**
* @title AvalancheICTTRouter
Expand All @@ -29,6 +30,9 @@ import {SafeERC20TransferFrom} from "@teleporter/SafeERC20TransferFrom.sol";
contract AvalancheICTTRouter is Ownable, ReentrancyGuard, IAvalancheICTTRouter {
using Address for address;

/// @notice List of tokens deployed on the source chain
address[] public tokensList;

/**
* @notice Token address => source bridge address
* @notice Address `0x0` is used for the native token
Expand All @@ -43,6 +47,13 @@ contract AvalancheICTTRouter is Ownable, ReentrancyGuard, IAvalancheICTTRouter {
bytes32 destinationChainID => mapping(address token => DestinationBridge destinationBridge)
) public tokenDestinationChainToDestinationBridge;

/**
* @notice Token Address => list of destination chains
* @notice Address `0x0` is used for the native token
*/
mapping(address token => bytes32[] destinationChainsIDList) public
tokenToDestinationChainsIDList;

/// @notice Router chain ID
bytes32 private immutable routerChainID;

Expand All @@ -62,6 +73,7 @@ contract AvalancheICTTRouter is Ownable, ReentrancyGuard, IAvalancheICTTRouter {
revert AvalancheICTTRouter__BridgeAddrNotAContract(bridgeAddress);
}
tokenToSourceBridge[tokenAddress] = bridgeAddress;
tokensList.push(tokenAddress);

emit RegisterSourceTokenBridge(tokenAddress, bridgeAddress);
}
Expand Down Expand Up @@ -89,13 +101,15 @@ contract AvalancheICTTRouter is Ownable, ReentrancyGuard, IAvalancheICTTRouter {
DestinationBridge(bridgeAddress, requiredGasLimit, isMultihop);
tokenDestinationChainToDestinationBridge[destinationChainID][tokenAddress] =
destinationBridge;
tokenToDestinationChainsIDList[tokenAddress].push(destinationChainID);

emit RegisterDestinationTokenBridge(tokenAddress, destinationChainID, destinationBridge);
}

/// @inheritdoc IAvalancheICTTRouter
function removeSourceTokenBridge(address tokenAddress) external onlyOwner {
delete tokenToSourceBridge[tokenAddress];
_burnToken(tokenAddress);

emit RemoveSourceTokenBridge(tokenAddress);
}
Expand All @@ -106,6 +120,7 @@ contract AvalancheICTTRouter is Ownable, ReentrancyGuard, IAvalancheICTTRouter {
bytes32 destinationChainID
) external onlyOwner {
delete tokenDestinationChainToDestinationBridge[destinationChainID][tokenAddress];
_burnDestinationChainID(tokenAddress, destinationChainID);

emit RemoveDestinationTokenBridge(tokenAddress, destinationChainID);
}
Expand Down Expand Up @@ -207,4 +222,44 @@ contract AvalancheICTTRouter is Ownable, ReentrancyGuard, IAvalancheICTTRouter {
) external view returns (DestinationBridge memory) {
return tokenDestinationChainToDestinationBridge[chainID][token];
}

/// @inheritdoc IAvalancheICTTRouter
function getTokensList() external view returns (address[] memory) {
return (tokensList);
}

/// @inheritdoc IAvalancheICTTRouter
function getDestinationChainsForToken(address token) external view returns (bytes32[] memory) {
return (tokenToDestinationChainsIDList[token]);
}

/**
* @notice Remove a token from the tokensList array (internal function)
* @param _token The address of the token
*/
function _burnToken(address _token) internal {
for (uint256 i; i < tokensList.length; i++) {
if (tokensList[i] == _token) {
tokensList[i] = tokensList[tokensList.length - 1];
tokensList.pop();
break;
}
}
}

/**
* @notice Remove a destination chain from the list of destination chain associated with a token (internal function)
* @param _token The address of the token
* @param _chainID The ID of the destination chain
*/
function _burnDestinationChainID(address _token, bytes32 _chainID) internal {
for (uint256 i; i < tokenToDestinationChainsIDList[_token].length; i++) {
if (tokenToDestinationChainsIDList[_token][i] == _chainID) {
tokenToDestinationChainsIDList[_token][i] =
tokenToDestinationChainsIDList[_token][tokensList.length - 1];
tokenToDestinationChainsIDList[_token].pop();
break;
}
}
}
}
11 changes: 11 additions & 0 deletions contracts/src/interfaces/IAvalancheICTTRouter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -174,4 +174,15 @@ interface IAvalancheICTTRouter {
bytes32 chainID,
address token
) external view returns (DestinationBridge memory);

/**
* @notice Get the list of tokens deployed on the source chain
*/
function getTokensList() external view returns (address[] memory);

/**
* @notice Get the list of the destination chains for a token
* @param token The address of the token
*/
function getDestinationChainsForToken(address token) external view returns (bytes32[] memory);
}
51 changes: 51 additions & 0 deletions contracts/test/Teleporter/AvalancheICTTRouterTest.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -167,4 +167,55 @@ contract AvalancheICTTRouterTest is Test {
tokenBridgeRouter.removeDestinationTokenBridge(address(erc20Token), destinationChainID);
vm.stopPrank();
}

function testTokenAddedToTokensListWhenRegisterTokenSource() public {
vm.startPrank(owner);
address[] memory startList = tokenBridgeRouter.getTokensList();
assert(startList.length == 0);
tokenBridgeRouter.registerSourceTokenBridge(address(erc20Token), address(tokenSource));
address[] memory endList = tokenBridgeRouter.getTokensList();
assert(endList.length == 1 && endList[0] == address(erc20Token));
vm.stopPrank();
}

function testTokenRemovedFromTokensListWhenRemovingTokenSource() public registerTokenBridge {
vm.startPrank(owner);
address[] memory startList = tokenBridgeRouter.getTokensList();
assert(startList.length == 1 && startList[0] == address(erc20Token));
tokenBridgeRouter.removeSourceTokenBridge(address(erc20Token));
address[] memory endList = tokenBridgeRouter.getTokensList();
assert(endList.length == 0);
vm.stopPrank();
}

function testDestinationChainAddedToTokenToDestinationChainsListWhenRegisterTokenDestination()
public
{
vm.startPrank(owner);
bytes32[] memory startList =
tokenBridgeRouter.getDestinationChainsForToken(address(erc20Token));
assert(startList.length == 0);
tokenBridgeRouter.registerDestinationTokenBridge(
address(erc20Token), destinationChainID, tokenDestination, requiredGasLimit, false
);
bytes32[] memory endList =
tokenBridgeRouter.getDestinationChainsForToken(address(erc20Token));
assert(endList.length == 1 && endList[0] == destinationChainID);
vm.stopPrank();
}

function testDestinationChainRemovedFromDestinationChainsListWhenRemovingTokenDestination()
public
registerTokenBridge
{
vm.startPrank(owner);
bytes32[] memory startList =
tokenBridgeRouter.getDestinationChainsForToken(address(erc20Token));
assert(startList.length == 1 && startList[0] == destinationChainID);
tokenBridgeRouter.removeDestinationTokenBridge(address(erc20Token), destinationChainID);
bytes32[] memory endList =
tokenBridgeRouter.getDestinationChainsForToken(address(erc20Token));
assert(endList.length == 0);
vm.stopPrank();
}
}

0 comments on commit 5e6cb17

Please sign in to comment.